[PATCH] local-pull: implement fetch_ref()
[git.git] / apply.c
diff --git a/apply.c b/apply.c
index ec63a0c..af97537 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -437,6 +437,8 @@ static int parse_git_header(char *line, int len, unsigned int size, struct patch
                        { "copy to ", gitdiff_copydst },
                        { "rename old ", gitdiff_renamesrc },
                        { "rename new ", gitdiff_renamedst },
+                       { "rename from ", gitdiff_renamesrc },
+                       { "rename to ", gitdiff_renamedst },
                        { "similarity index ", gitdiff_similarity },
                        { "dissimilarity index ", gitdiff_dissimilarity },
                        { "", gitdiff_unrecognized },
@@ -566,10 +568,13 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
                 */
                if (!memcmp("diff --git ", line, 11)) {
                        int git_hdr_len = parse_git_header(line, len, size, patch);
-                       if (git_hdr_len < 0)
+                       if (git_hdr_len <= len)
                                continue;
-                       if (!patch->old_name && !patch->new_name)
-                               die("git diff header lacks filename information (line %d)", linenr);
+                       if (!patch->old_name && !patch->new_name) {
+                               if (!patch->def_name)
+                                       die("git diff header lacks filename information (line %d)", linenr);
+                               patch->old_name = patch->new_name = patch->def_name;
+                       }
                        *hdrsize = git_hdr_len;
                        return offset;
                }
@@ -628,8 +633,11 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
 
        if (patch->is_new != !oldlines)
                return error("new file depends on old contents");
-       if (patch->is_delete != !newlines)
-               return error("deleted file still has contents");
+       if (patch->is_delete != !newlines) {
+               if (newlines)
+                       return error("deleted file still has contents");
+               fprintf(stderr, "** warning: file %s becomes empty but is not deleted\n", patch->new_name);
+       }
 
        /* Parse the thing.. */
        line += len;
@@ -743,9 +751,11 @@ static void show_stats(struct patch *patch)
        del = patch->lines_deleted;
        total = add + del;
 
-       total = (total * max + max_change / 2) / max_change;
-       add = (add * max + max_change / 2) / max_change;
-       del = total - add;
+       if (max_change > 0) {
+               total = (total * max + max_change / 2) / max_change;
+               add = (add * max + max_change / 2) / max_change;
+               del = total - add;
+       }
        printf(" %-*s |%5d %.*s%.*s\n",
                len, name, patch->lines_added + patch->lines_deleted,
                add, pluses, del, minuses);
@@ -984,7 +994,7 @@ static int check_patch(struct patch *patch)
                int changed;
 
                if (lstat(old_name, &st) < 0)
-                       return error("%s: %s\n", strerror(errno));
+                       return error("%s: %s", old_name, strerror(errno));
                if (check_index) {
                        int pos = cache_name_pos(old_name, strlen(old_name));
                        if (pos < 0)
@@ -995,6 +1005,7 @@ static int check_patch(struct patch *patch)
                }
                if (patch->is_new < 0)
                        patch->is_new = 0;
+               st.st_mode = ntohl(create_ce_mode(st.st_mode));
                if (!patch->old_mode)
                        patch->old_mode = st.st_mode;
                if ((st.st_mode ^ patch->old_mode) & S_IFMT)
@@ -1133,6 +1144,51 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
                die("unable to add cache entry for %s", path);
 }
 
+static void create_subdirectories(const char *path)
+{
+       int len = strlen(path);
+       char *buf = xmalloc(len + 1);
+       const char *slash = path;
+
+       while ((slash = strchr(slash+1, '/')) != NULL) {
+               len = slash - path;
+               memcpy(buf, path, len);
+               buf[len] = 0;
+               if (mkdir(buf, 0755) < 0) {
+                       if (errno != EEXIST)
+                               break;
+               }
+       }
+       free(buf);
+}
+
+/*
+ * We optimistically assume that the directories exist,
+ * which is true 99% of the time anyway. If they don't,
+ * we create them and try again.
+ */
+static int create_regular_file(const char *path, unsigned int mode)
+{
+       int ret = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+
+       if (ret < 0 && errno == ENOENT) {
+               create_subdirectories(path);
+               ret = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+       }
+       return ret;
+}
+
+static int create_symlink(const char *buf, const char *path)
+{
+       int ret = symlink(buf, path);
+
+       if (ret < 0 && errno == ENOENT) {
+               create_subdirectories(path);
+               ret = symlink(buf, path);
+       }
+       return ret;
+}
+
 static void create_file(struct patch *patch)
 {
        const char *path = patch->new_name;
@@ -1145,7 +1201,7 @@ static void create_file(struct patch *patch)
        if (S_ISREG(mode)) {
                int fd;
                mode = (mode & 0100) ? 0777 : 0666;
-               fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+               fd = create_regular_file(path, mode);
                if (fd < 0)
                        die("unable to create file %s (%s)", path, strerror(errno));
                if (write(fd, buf, size) != size)
@@ -1158,7 +1214,7 @@ static void create_file(struct patch *patch)
                if (size && buf[size-1] == '\n')
                        size--;
                buf[size] = 0;
-               if (symlink(buf, path) < 0)
+               if (create_symlink(buf, path) < 0)
                        die("unable to write symlink %s", path);
                add_index_file(path, mode, buf, size);
                return;