//
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;
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;
};
{ "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 },
*/
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;
}
{
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)
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;
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)
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;
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;
}
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)
}
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)
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) {
}
}
+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;
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);
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;