[PATCH] ssh-push: Don't add '/' to pathname
[git.git] / apply.c
diff --git a/apply.c b/apply.c
index 195acdb..c0cd152 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -26,6 +26,7 @@
 //
 static int merge_patch = 1;
 static int check_index = 0;
+static int write_index = 0;
 static int diffstat = 0;
 static int check = 0;
 static int apply = 1;
@@ -60,7 +61,7 @@ struct patch {
        int is_rename, is_copy, is_new, is_delete;
        int lines_added, lines_deleted;
        struct fragment *fragments;
-       const char *result;
+       char *result;
        unsigned long resultsize;
        struct patch *next;
 };
@@ -434,6 +435,8 @@ static int parse_git_header(char *line, int len, unsigned int size, struct patch
                        { "new file mode ", gitdiff_newfile },
                        { "copy from ", gitdiff_copysrc },
                        { "copy to ", gitdiff_copydst },
+                       { "rename old ", gitdiff_renamesrc },
+                       { "rename new ", gitdiff_renamedst },
                        { "rename from ", gitdiff_renamesrc },
                        { "rename to ", gitdiff_renamedst },
                        { "similarity index ", gitdiff_similarity },
@@ -565,10 +568,10 @@ 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");
+                               die("git diff header lacks filename information (line %d)", linenr);
                        *hdrsize = git_hdr_len;
                        return offset;
                }
@@ -606,7 +609,7 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
 {
        int added, deleted;
        int len = linelen(line, size), offset;
-       unsigned long pos[4], oldlines, newlines;
+       unsigned long oldlines, newlines;
 
        offset = parse_fragment_header(line, len, fragment);
        if (offset < 0)
@@ -614,10 +617,24 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
        oldlines = fragment->oldlines;
        newlines = fragment->newlines;
 
-       if (patch->is_new < 0 && (pos[0] || oldlines))
-               patch->is_new = 0;
-       if (patch->is_delete < 0 && (pos[1] || newlines))
-               patch->is_delete = 0;
+       if (patch->is_new < 0) {
+               patch->is_new =  !oldlines;
+               if (!oldlines)
+                       patch->old_name = NULL;
+       }
+       if (patch->is_delete < 0) {
+               patch->is_delete = !newlines;
+               if (!newlines)
+                       patch->new_name = NULL;
+       }
+
+       if (patch->is_new != !oldlines)
+               return error("new file depends on old 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;
@@ -928,6 +945,7 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch)
                        return error("patch failed: %s:%d", patch->old_name, frag->oldpos);
                frag = frag->next;
        }
+       return 0;
 }
 
 static int apply_data(struct patch *patch, struct stat *st)
@@ -936,13 +954,16 @@ static int apply_data(struct patch *patch, struct stat *st)
        unsigned long size, alloc;
        struct buffer_desc desc;
 
-       if (!patch->old_name || !patch->fragments)
-               return 0;
-       size = st->st_size;
-       alloc = size + 8192;
-       buf = xmalloc(alloc);
-       if (read_old_data(st, patch->old_name, buf, alloc) != size)
-               return error("read of %s failed", patch->old_name);
+       size = 0;
+       alloc = 0;
+       buf = NULL;
+       if (patch->old_name) {
+               size = st->st_size;
+               alloc = size + 8192;
+               buf = xmalloc(alloc);
+               if (read_old_data(st, patch->old_name, buf, alloc) != size)
+                       return error("read of %s failed", patch->old_name);
+       }
 
        desc.size = size;
        desc.alloc = alloc;
@@ -951,6 +972,10 @@ static int apply_data(struct patch *patch, struct stat *st)
                return -1;
        patch->result = desc.buffer;
        patch->resultsize = desc.size;
+
+       if (patch->is_delete && patch->resultsize)
+               return error("removal patch leaves file contents");
+
        return 0;
 }
 
@@ -964,7 +989,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)
@@ -975,6 +1000,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)
@@ -991,6 +1017,8 @@ static int check_patch(struct patch *patch)
                        return error("%s: already exists in working directory", new_name);
                if (errno != ENOENT)
                        return error("%s: %s", new_name, strerror(errno));
+               if (!patch->new_mode)
+                       patch->new_mode = S_IFREG | 0644;
        }
 
        if (new_name && old_name) {
@@ -1078,8 +1106,106 @@ static void patch_stats(struct patch *patch)
        }
 }
 
+static void remove_file(struct patch *patch)
+{
+       if (write_index) {
+               if (remove_file_from_cache(patch->old_name) < 0)
+                       die("unable to remove %s from index", patch->old_name);
+       }
+       unlink(patch->old_name);
+}
+
+static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
+{
+       struct stat st;
+       struct cache_entry *ce;
+       int namelen = strlen(path);
+       unsigned ce_size = cache_entry_size(namelen);
+
+       if (!write_index)
+               return;
+
+       ce = xmalloc(ce_size);
+       memset(ce, 0, ce_size);
+       memcpy(ce->name, path, namelen);
+       ce->ce_mode = create_ce_mode(mode);
+       ce->ce_flags = htons(namelen);
+       if (lstat(path, &st) < 0)
+               die("unable to stat newly created file %s", path);
+       fill_stat_cache_info(ce, &st);
+       if (write_sha1_file(buf, size, "blob", ce->sha1) < 0)
+               die("unable to create backing store for newly created file %s", path);
+       if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
+               die("unable to add cache entry for %s", path);
+}
+
+static void create_file(struct patch *patch)
+{
+       const char *path = patch->new_name;
+       unsigned mode = patch->new_mode;
+       unsigned long size = patch->resultsize;
+       char *buf = patch->result;
+
+       if (!mode)
+               mode = S_IFREG | 0644;
+       if (S_ISREG(mode)) {
+               int fd;
+               mode = (mode & 0100) ? 0777 : 0666;
+               fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+               if (fd < 0)
+                       die("unable to create file %s (%s)", path, strerror(errno));
+               if (write(fd, buf, size) != size)
+                       die("unable to write file %s", path);
+               close(fd);
+               add_index_file(path, mode, buf, size);
+               return;
+       }
+       if (S_ISLNK(mode)) {
+               if (size && buf[size-1] == '\n')
+                       size--;
+               buf[size] = 0;
+               if (symlink(buf, path) < 0)
+                       die("unable to write symlink %s", path);
+               add_index_file(path, mode, buf, size);
+               return;
+       }
+       die("unable to write file mode %o", mode);
+}
+
+static void write_out_one_result(struct patch *patch)
+{
+       if (patch->is_delete > 0) {
+               remove_file(patch);
+               return;
+       }
+       if (patch->is_new > 0 || patch->is_copy) {
+               create_file(patch);
+               return;
+       }
+       /*
+        * Rename or modification boils down to the same
+        * thing: remove the old, write the new
+        */
+       remove_file(patch);
+       create_file(patch);
+}
+
+static void write_out_results(struct patch *list)
+{
+       if (!list)
+               die("No changes");
+
+       while (list) {
+               write_out_one_result(list);
+               list = list->next;
+       }
+}
+
+static struct cache_file cache_file;
+
 static int apply_patch(int fd)
 {
+       int newfd;
        unsigned long offset, size;
        char *buffer = read_patch_file(fd, &size);
        struct patch *list = NULL, **listp = &list;
@@ -1103,9 +1229,27 @@ static int apply_patch(int fd)
                size -= nr;
        }
 
+       newfd = -1;
+       write_index = check_index && apply;
+       if (write_index)
+               newfd = hold_index_file_for_update(&cache_file, get_index_file());
+       if (check_index) {
+               if (read_cache() < 0)
+                       die("unable to read index file");
+       }
+
        if ((check || apply) && check_patch_list(list) < 0)
                exit(1);
 
+       if (apply)
+               write_out_results(list);
+
+       if (write_index) {
+               if (write_cache(newfd, active_cache, active_nr) ||
+                   commit_index_file(&cache_file))
+                       die("Unable to write new cachefile");
+       }
+
        if (show_files)
                show_file_list(list);
 
@@ -1121,9 +1265,6 @@ int main(int argc, char **argv)
        int i;
        int read_stdin = 1;
 
-       if (read_cache() < 0)
-               die("unable to read index file");
-
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                int fd;