diff options
Diffstat (limited to 'read-cache.c')
-rw-r--r-- | read-cache.c | 375 |
1 files changed, 183 insertions, 192 deletions
diff --git a/read-cache.c b/read-cache.c index 1bbaf1c..274e54b 100644 --- a/read-cache.c +++ b/read-cache.c @@ -10,10 +10,10 @@ #include "dir.h" #include "tree.h" #include "commit.h" -#include "diff.h" -#include "diffcore.h" -#include "revision.h" #include "blob.h" +#include "resolve-undo.h" + +static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); /* Index extensions. * @@ -26,6 +26,7 @@ #define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) ) #define CACHE_EXT_TREE 0x54524545 /* "TREE" */ +#define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUC" */ struct index_state the_index; @@ -91,7 +92,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st) if (fd >= 0) { unsigned char sha1[20]; - if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name)) + if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0)) match = hashcmp(sha1, ce->sha1); /* index_fd() closed the file descriptor already */ } @@ -156,7 +157,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return 0; } -int is_empty_blob_sha1(const unsigned char *sha1) +static int is_empty_blob_sha1(const unsigned char *sha1) { static const unsigned char empty_blob_sha1[20] = { 0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b, @@ -259,12 +260,17 @@ int ie_match_stat(const struct index_state *istate, { unsigned int changed; int ignore_valid = options & CE_MATCH_IGNORE_VALID; + int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE; int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY; /* * If it's marked as always valid in the index, it's * valid whatever the checked-out copy says. + * + * skip-worktree has the same effect with higher precedence */ + if (!ignore_skip_worktree && ce_skip_worktree(ce)) + return 0; if (!ignore_valid && (ce->ce_flags & CE_VALID)) return 0; @@ -449,6 +455,7 @@ int remove_index_entry_at(struct index_state *istate, int pos) { struct cache_entry *ce = istate->cache[pos]; + record_resolve_undo(istate, ce); remove_name_hash(ce); istate->cache_changed = 1; istate->cache_nr--; @@ -564,7 +571,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, int size, namelen, was_same; mode_t st_mode = st->st_mode; struct cache_entry *ce, *alias; - unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY; + unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY; int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND); int pretend = flags & ADD_CACHE_PRETEND; int intent_only = flags & ADD_CACHE_INTENT; @@ -601,16 +608,40 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, ce->ce_mode = ce_mode_from_stat(ent, st_mode); } + /* When core.ignorecase=true, determine if a directory of the same name but differing + * case already exists within the Git repository. If it does, ensure the directory + * case of the file being added to the repository matches (is folded into) the existing + * entry's directory case. + */ + if (ignore_case) { + const char *startPtr = ce->name; + const char *ptr = startPtr; + while (*ptr) { + while (*ptr && *ptr != '/') + ++ptr; + if (*ptr == '/') { + struct cache_entry *foundce; + ++ptr; + foundce = index_name_exists(&the_index, ce->name, ptr - ce->name, ignore_case); + if (foundce) { + memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr); + startPtr = ptr; + } + } + } + } + alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case); if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) { /* Nothing changed, really */ free(ce); - ce_mark_uptodate(alias); + if (!S_ISGITLINK(alias->ce_mode)) + ce_mark_uptodate(alias); alias->ce_flags |= CE_ADDED; return 0; } if (!intent_only) { - if (index_path(ce->sha1, path, st, 1)) + if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT)) return error("unable to index file %s", path); } else record_intent_to_add(ce); @@ -675,30 +706,9 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b) return ce_namelen(b) == len && !memcmp(a->name, b->name, len); } -int ce_path_match(const struct cache_entry *ce, const char **pathspec) +int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec) { - const char *match, *name; - int len; - - if (!pathspec) - return 1; - - len = ce_namelen(ce); - name = ce->name; - while ((match = *pathspec++) != NULL) { - int matchlen = strlen(match); - if (matchlen > len) - continue; - if (memcmp(name, match, matchlen)) - continue; - if (matchlen && name[matchlen-1] == '/') - return 1; - if (name[matchlen] == '/' || !name[matchlen]) - return 1; - if (!matchlen) - return 1; - } - return 0; + return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL); } /* @@ -716,11 +726,12 @@ static int verify_dotfile(const char *rest) * has already been discarded, we now test * the rest. */ - switch (*rest) { + /* "." is not allowed */ - case '\0': case '/': + if (*rest == '\0' || is_dir_sep(*rest)) return 0; + switch (*rest) { /* * ".git" followed by NUL or slash is bad. This * shares the path end test with the ".." case. @@ -733,7 +744,7 @@ static int verify_dotfile(const char *rest) rest += 2; /* fallthrough */ case '.': - if (rest[1] == '\0' || rest[1] == '/') + if (rest[1] == '\0' || is_dir_sep(rest[1])) return 0; } return 1; @@ -743,23 +754,19 @@ int verify_path(const char *path) { char c; + if (has_dos_drive_prefix(path)) + return 0; + goto inside; for (;;) { if (!c) return 1; - if (c == '/') { + if (is_dir_sep(c)) { inside: c = *path++; - switch (c) { - default: - continue; - case '/': case '\0': - break; - case '.': - if (verify_dotfile(path)) - continue; - } - return 0; + if ((c == '.' && !verify_dotfile(path)) || + is_dir_sep(c) || c == '\0') + return 0; } c = *path++; } @@ -994,20 +1001,27 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti */ static struct cache_entry *refresh_cache_ent(struct index_state *istate, struct cache_entry *ce, - unsigned int options, int *err) + unsigned int options, int *err, + int *changed_ret) { struct stat st; struct cache_entry *updated; int changed, size; int ignore_valid = options & CE_MATCH_IGNORE_VALID; + int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE; if (ce_uptodate(ce)) return ce; /* - * CE_VALID means the user promised us that the change to - * the work tree does not matter and told us not to worry. + * CE_VALID or CE_SKIP_WORKTREE means the user promised us + * that the change to the work tree does not matter and told + * us not to worry. */ + if (!ignore_skip_worktree && ce_skip_worktree(ce)) { + ce_mark_uptodate(ce); + return ce; + } if (!ignore_valid && (ce->ce_flags & CE_VALID)) { ce_mark_uptodate(ce); return ce; @@ -1020,6 +1034,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, } changed = ie_match_stat(istate, ce, &st, options); + if (changed_ret) + *changed_ret = changed; if (!changed) { /* * The path is unchanged. If we were told to ignore @@ -1037,7 +1053,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, * because CE_UPTODATE flag is in-core only; * we are not going to write this change out. */ - ce_mark_uptodate(ce); + if (!S_ISGITLINK(ce->ce_mode)) + ce_mark_uptodate(ce); return ce; } } @@ -1066,17 +1083,17 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, } static void show_file(const char * fmt, const char * name, int in_porcelain, - int * first, char *header_msg) + int * first, const char *header_msg) { if (in_porcelain && *first && header_msg) { printf("%s\n", header_msg); - *first=0; + *first = 0; } printf(fmt, name); } int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, - char *seen, char *header_msg) + char *seen, const char *header_msg) { int i; int has_errors = 0; @@ -1088,19 +1105,31 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p int first = 1; int in_porcelain = (flags & REFRESH_IN_PORCELAIN); unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0; - const char *needs_update_fmt; - const char *needs_merge_fmt; - - needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n"); - needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n"); + const char *modified_fmt; + const char *deleted_fmt; + const char *typechange_fmt; + const char *added_fmt; + const char *unmerged_fmt; + + modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n"); + deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n"); + typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n"); + added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n"); + unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n"); for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce, *new; int cache_errno = 0; + int changed = 0; + int filtered = 0; ce = istate->cache[i]; if (ignore_submodules && S_ISGITLINK(ce->ce_mode)) continue; + if (pathspec && + !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen)) + filtered = 1; + if (ce_stage(ce)) { while ((i < istate->cache_nr) && ! strcmp(istate->cache[i]->name, ce->name)) @@ -1108,18 +1137,22 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p i--; if (allow_unmerged) continue; - show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg); + if (!filtered) + show_file(unmerged_fmt, ce->name, in_porcelain, + &first, header_msg); has_errors = 1; continue; } - if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen)) + if (filtered) continue; - new = refresh_cache_ent(istate, ce, options, &cache_errno); + new = refresh_cache_ent(istate, ce, options, &cache_errno, &changed); if (new == ce) continue; if (!new) { + const char *fmt; + if (not_new && cache_errno == ENOENT) continue; if (really && cache_errno == EINVAL) { @@ -1131,7 +1164,17 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p } if (quiet) continue; - show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg); + + if (cache_errno == ENOENT) + fmt = deleted_fmt; + else if (ce->ce_flags & CE_INTENT_TO_ADD) + fmt = added_fmt; /* must be before other checks */ + else if (changed & TYPE_CHANGED) + fmt = typechange_fmt; + else + fmt = modified_fmt; + show_file(fmt, + ce->name, in_porcelain, &first, header_msg); has_errors = 1; continue; } @@ -1141,9 +1184,9 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p return has_errors; } -struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) +static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) { - return refresh_cache_ent(&the_index, ce, really, NULL); + return refresh_cache_ent(&the_index, ce, really, NULL, NULL); } static int verify_hdr(struct cache_header *hdr, unsigned long size) @@ -1170,6 +1213,9 @@ static int read_index_extension(struct index_state *istate, case CACHE_EXT_TREE: istate->cache_tree = cache_tree_read(data, sz); break; + case CACHE_EXT_RESOLVE_UNDO: + istate->resolve_undo = resolve_undo_read(data, sz); + break; default: if (*ext < 'A' || 'Z' < *ext) return error("index uses %.4s extension, which we do not understand", @@ -1185,29 +1231,18 @@ int read_index(struct index_state *istate) return read_index_from(istate, get_index_file()); } -static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce) +static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk) { + struct cache_entry *ce; size_t len; const char *name; + unsigned int flags; - ce->ce_ctime.sec = ntohl(ondisk->ctime.sec); - ce->ce_mtime.sec = ntohl(ondisk->mtime.sec); - ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec); - ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec); - ce->ce_dev = ntohl(ondisk->dev); - ce->ce_ino = ntohl(ondisk->ino); - ce->ce_mode = ntohl(ondisk->mode); - ce->ce_uid = ntohl(ondisk->uid); - ce->ce_gid = ntohl(ondisk->gid); - ce->ce_size = ntohl(ondisk->size); /* On-disk flags are just 16 bits */ - ce->ce_flags = ntohs(ondisk->flags); - - hashcpy(ce->sha1, ondisk->sha1); + flags = ntohs(ondisk->flags); + len = flags & CE_NAMEMASK; - len = ce->ce_flags & CE_NAMEMASK; - - if (ce->ce_flags & CE_EXTENDED) { + if (flags & CE_EXTENDED) { struct ondisk_cache_entry_extended *ondisk2; int extended_flags; ondisk2 = (struct ondisk_cache_entry_extended *)ondisk; @@ -1215,7 +1250,7 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */ if (extended_flags & ~CE_EXTENDED_FLAGS) die("Unknown index entry format %08x", extended_flags); - ce->ce_flags |= extended_flags; + flags |= extended_flags; name = ondisk2->name; } else @@ -1223,25 +1258,26 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en if (len == CE_NAMEMASK) len = strlen(name); - /* - * NEEDSWORK: If the original index is crafted, this copy could - * go unchecked. - */ - memcpy(ce->name, name, len + 1); -} -static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries) -{ - long per_entry; + ce = xmalloc(cache_entry_size(len)); - per_entry = sizeof(struct cache_entry) - sizeof(struct ondisk_cache_entry); + ce->ce_ctime.sec = ntohl(ondisk->ctime.sec); + ce->ce_mtime.sec = ntohl(ondisk->mtime.sec); + ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec); + ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec); + ce->ce_dev = ntohl(ondisk->dev); + ce->ce_ino = ntohl(ondisk->ino); + ce->ce_mode = ntohl(ondisk->mode); + ce->ce_uid = ntohl(ondisk->uid); + ce->ce_gid = ntohl(ondisk->gid); + ce->ce_size = ntohl(ondisk->size); + ce->ce_flags = flags; - /* - * Alignment can cause differences. This should be "alignof", but - * since that's a gcc'ism, just use the size of a pointer. - */ - per_entry += sizeof(void *); - return ondisk_size + entries*per_entry; + hashcpy(ce->sha1, ondisk->sha1); + + memcpy(ce->name, name, len); + ce->name[len] = '\0'; + return ce; } /* remember to discard_cache() before reading a different cache! */ @@ -1249,7 +1285,7 @@ int read_index_from(struct index_state *istate, const char *path) { int fd, i; struct stat st; - unsigned long src_offset, dst_offset; + unsigned long src_offset; struct cache_header *hdr; void *mmap; size_t mmap_size; @@ -1288,29 +1324,18 @@ int read_index_from(struct index_state *istate, const char *path) istate->cache_nr = ntohl(hdr->hdr_entries); istate->cache_alloc = alloc_nr(istate->cache_nr); istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *)); - - /* - * The disk format is actually larger than the in-memory format, - * due to space for nsec etc, so even though the in-memory one - * has room for a few more flags, we can allocate using the same - * index size - */ - istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr)); istate->initialized = 1; src_offset = sizeof(*hdr); - dst_offset = 0; for (i = 0; i < istate->cache_nr; i++) { struct ondisk_cache_entry *disk_ce; struct cache_entry *ce; disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset); - ce = (struct cache_entry *)((char *)istate->alloc + dst_offset); - convert_from_disk(disk_ce, ce); + ce = create_from_disk(disk_ce); set_index_entry(istate, i, ce); src_offset += ondisk_ce_size(ce); - dst_offset += ce_size(ce); } istate->timestamp.sec = st.st_mtime; istate->timestamp.nsec = ST_MTIME_NSEC(st); @@ -1322,7 +1347,7 @@ int read_index_from(struct index_state *istate, const char *path) * extension name (4-byte) and section length * in 4-byte network byte order. */ - unsigned long extsize; + uint32_t extsize; memcpy(&extsize, (char *)mmap + src_offset + 4, 4); extsize = ntohl(extsize); if (read_index_extension(istate, @@ -1344,11 +1369,16 @@ unmap: int is_index_unborn(struct index_state *istate) { - return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec); + return (!istate->cache_nr && !istate->timestamp.sec); } int discard_index(struct index_state *istate) { + int i; + + for (i = 0; i < istate->cache_nr; i++) + free(istate->cache[i]); + resolve_undo_clear_index(istate); istate->cache_nr = 0; istate->cache_changed = 0; istate->timestamp.sec = 0; @@ -1356,8 +1386,6 @@ int discard_index(struct index_state *istate) istate->name_hash_initialized = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); - free(istate->alloc); - istate->alloc = NULL; istate->initialized = 0; /* no need to throw away allocated active_cache */ @@ -1497,6 +1525,7 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) int size = ondisk_ce_size(ce); struct ondisk_cache_entry *ondisk = xcalloc(1, size); char *name; + int result; ondisk->ctime.sec = htonl(ce->ce_ctime.sec); ondisk->mtime.sec = htonl(ce->ce_mtime.sec); @@ -1520,7 +1549,34 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) name = ondisk->name; memcpy(name, ce->name, ce_namelen(ce)); - return ce_write(c, fd, ondisk, size); + result = ce_write(c, fd, ondisk, size); + free(ondisk); + return result; +} + +static int has_racy_timestamp(struct index_state *istate) +{ + int entries = istate->cache_nr; + int i; + + for (i = 0; i < entries; i++) { + struct cache_entry *ce = istate->cache[i]; + if (is_racy_timestamp(istate, ce)) + return 1; + } + return 0; +} + +/* + * Opportunisticly update the index but do not complain if we can't + */ +void update_index_if_able(struct index_state *istate, struct lock_file *lockfile) +{ + if ((istate->cache_changed || has_racy_timestamp(istate)) && + !write_index(istate, lockfile->fd)) + commit_locked_index(lockfile); + else + rollback_lock_file(lockfile); } int write_index(struct index_state *istate, int newfd) @@ -1574,6 +1630,17 @@ int write_index(struct index_state *istate, int newfd) if (err) return -1; } + if (istate->resolve_undo) { + struct strbuf sb = STRBUF_INIT; + + resolve_undo_write(&sb, istate->resolve_undo); + err = write_index_ext_header(&c, newfd, CACHE_EXT_RESOLVE_UNDO, + sb.len) < 0 + || ce_write(&c, newfd, sb.buf, sb.len) < 0; + strbuf_release(&sb); + if (err) + return -1; + } if (ce_flush(&c, newfd) || fstat(newfd, &st)) return -1; @@ -1606,9 +1673,8 @@ int read_index_unmerged(struct index_state *istate) len = strlen(ce->name); size = cache_entry_size(len); new_ce = xcalloc(1, size); - hashcpy(new_ce->sha1, ce->sha1); memcpy(new_ce->name, ce->name, len); - new_ce->ce_flags = create_ce_flags(len, 0); + new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED; new_ce->ce_mode = ce->ce_mode; if (add_index_entry(istate, new_ce, 0)) return error("%s: cannot drop to stage #0", @@ -1618,81 +1684,6 @@ int read_index_unmerged(struct index_state *istate) return unmerged; } -struct update_callback_data -{ - int flags; - int add_errors; -}; - -static void update_callback(struct diff_queue_struct *q, - struct diff_options *opt, void *cbdata) -{ - int i; - struct update_callback_data *data = cbdata; - - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - const char *path = p->one->path; - switch (p->status) { - default: - die("unexpected diff status %c", p->status); - case DIFF_STATUS_UNMERGED: - /* - * ADD_CACHE_IGNORE_REMOVAL is unset if "git - * add -u" is calling us, In such a case, a - * missing work tree file needs to be removed - * if there is an unmerged entry at stage #2, - * but such a diff record is followed by - * another with DIFF_STATUS_DELETED (and if - * there is no stage #2, we won't see DELETED - * nor MODIFIED). We can simply continue - * either way. - */ - if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL)) - continue; - /* - * Otherwise, it is "git add path" is asking - * to explicitly add it; we fall through. A - * missing work tree file is an error and is - * caught by add_file_to_index() in such a - * case. - */ - case DIFF_STATUS_MODIFIED: - case DIFF_STATUS_TYPE_CHANGED: - if (add_file_to_index(&the_index, path, data->flags)) { - if (!(data->flags & ADD_CACHE_IGNORE_ERRORS)) - die("updating files failed"); - data->add_errors++; - } - break; - case DIFF_STATUS_DELETED: - if (data->flags & ADD_CACHE_IGNORE_REMOVAL) - break; - if (!(data->flags & ADD_CACHE_PRETEND)) - remove_file_from_index(&the_index, path); - if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE)) - printf("remove '%s'\n", path); - break; - } - } -} - -int add_files_to_cache(const char *prefix, const char **pathspec, int flags) -{ - struct update_callback_data data; - struct rev_info rev; - init_revisions(&rev, prefix); - setup_revisions(0, NULL, &rev, NULL); - rev.prune_data = pathspec; - rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = update_callback; - data.flags = flags; - data.add_errors = 0; - rev.diffopt.format_callback_data = &data; - run_diff_files(&rev, DIFF_RACY_IS_MODIFIED); - return !!data.add_errors; -} - /* * Returns 1 if the path is an "other" path with respect to * the index; that is, the path is not mentioned in the index at all, |