X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=apply.c;h=7d9059ba94aaa4c7f3dc2c8059acb4aca2c3277b;hb=218e441daf24b9c3be0f5ec423ace5185389ca61;hp=4f3ac90c94761ee3e49b22f66650e88a2b872781;hpb=30996652e752d5fdf18f6978a70905747d1fdabc;p=git.git diff --git a/apply.c b/apply.c index 4f3ac90c..7d9059ba 100644 --- 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,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"); + 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; } @@ -627,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; @@ -966,6 +975,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; } @@ -979,7 +992,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) @@ -990,6 +1003,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) @@ -1006,6 +1020,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) { @@ -1093,8 +1109,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; @@ -1118,9 +1232,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); @@ -1136,9 +1268,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;