X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=read-cache.c;h=2eb81a66b941325dc339d61a0ab804a60cbb8be2;hb=f5833f0110119fc17973835cc0042e76e3375ccd;hp=2a280b83ccc559d2e9e1ade9f4b76e77b380112f;hpb=b005d550f87fdb56406120a35fa218d869cdde3a;p=platform%2Fupstream%2Fgit.git diff --git a/read-cache.c b/read-cache.c index 2a280b8..2eb81a6 100644 --- a/read-cache.c +++ b/read-cache.c @@ -19,6 +19,7 @@ #include "varint.h" #include "split-index.h" #include "utf8.h" +#include "fsmonitor.h" /* Mask for the name length in ce_flags in the on-disk index */ @@ -38,11 +39,12 @@ #define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUC" */ #define CACHE_EXT_LINK 0x6c696e6b /* "link" */ #define CACHE_EXT_UNTRACKED 0x554E5452 /* "UNTR" */ +#define CACHE_EXT_FSMONITOR 0x46534D4E /* "FSMN" */ /* changes that can be kept in $GIT_DIR/index (basically all extensions) */ #define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \ CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \ - SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED) + SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED | FSMONITOR_CHANGED) struct index_state the_index; static const char *alternate_index_output; @@ -62,6 +64,7 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache free(old); set_index_entry(istate, nr, ce); ce->ce_flags |= CE_UPDATE_IN_BASE; + mark_fsmonitor_invalid(istate, ce); istate->cache_changed |= CE_ENTRY_CHANGED; } @@ -150,8 +153,10 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) if (assume_unchanged) ce->ce_flags |= CE_VALID; - if (S_ISREG(st->st_mode)) + if (S_ISREG(st->st_mode)) { ce_mark_uptodate(ce); + mark_fsmonitor_valid(ce); + } } static int ce_compare_data(const struct cache_entry *ce, struct stat *st) @@ -191,7 +196,7 @@ static int ce_compare_link(const struct cache_entry *ce, size_t expected_size) static int ce_compare_gitlink(const struct cache_entry *ce) { - unsigned char sha1[20]; + struct object_id oid; /* * We don't actually require that the .git directory @@ -201,9 +206,9 @@ static int ce_compare_gitlink(const struct cache_entry *ce) * * If so, we consider it always to match. */ - if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0) + if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0) return 0; - return hashcmp(sha1, ce->oid.hash); + return oidcmp(&oid, &ce->oid); } static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st) @@ -301,7 +306,7 @@ int match_stat_data_racy(const struct index_state *istate, return match_stat_data(sd, st); } -int ie_match_stat(const struct index_state *istate, +int ie_match_stat(struct index_state *istate, const struct cache_entry *ce, struct stat *st, unsigned int options) { @@ -309,7 +314,10 @@ int ie_match_stat(const struct index_state *istate, 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; + int ignore_fsmonitor = options & CE_MATCH_IGNORE_FSMONITOR; + if (!ignore_fsmonitor) + refresh_fsmonitor(istate); /* * If it's marked as always valid in the index, it's * valid whatever the checked-out copy says. @@ -320,6 +328,8 @@ int ie_match_stat(const struct index_state *istate, return 0; if (!ignore_valid && (ce->ce_flags & CE_VALID)) return 0; + if (!ignore_fsmonitor && (ce->ce_flags & CE_FSMONITOR_VALID)) + return 0; /* * Intent-to-add entries have not been added, so the index entry @@ -357,7 +367,7 @@ int ie_match_stat(const struct index_state *istate, return changed; } -int ie_modified(const struct index_state *istate, +int ie_modified(struct index_state *istate, const struct cache_entry *ce, struct stat *st, unsigned int options) { @@ -631,13 +641,17 @@ 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; + struct cache_entry *ce, *alias = NULL; 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; int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE| (intent_only ? ADD_CACHE_NEW_ONLY : 0)); + int newflags = HASH_WRITE_OBJECT; + + if (flags & HASH_RENORMALIZE) + newflags |= HASH_RENORMALIZE; if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode)) return error("%s: can only add regular files, symbolic links or git-directories", path); @@ -678,19 +692,23 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, if (ignore_case) { adjust_dirname_case(istate, ce->name); } + if (!(flags & HASH_RENORMALIZE)) { + alias = index_file_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 */ + if (!S_ISGITLINK(alias->ce_mode)) + ce_mark_uptodate(alias); + alias->ce_flags |= CE_ADDED; - alias = index_file_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 */ - if (!S_ISGITLINK(alias->ce_mode)) - ce_mark_uptodate(alias); - alias->ce_flags |= CE_ADDED; - - free(ce); - return 0; + free(ce); + return 0; + } } if (!intent_only) { - if (index_path(&ce->oid, path, st, HASH_WRITE_OBJECT)) { + if (index_path(&ce->oid, path, st, newflags)) { free(ce); return error("unable to index file %s", path); } @@ -733,7 +751,7 @@ struct cache_entry *make_cache_entry(unsigned int mode, int size, len; struct cache_entry *ce, *ret; - if (!verify_path(path, mode)) { + if (!verify_path(path)) { error("Invalid path '%s'", path); return NULL; } @@ -778,6 +796,7 @@ int chmod_index_entry(struct index_state *istate, struct cache_entry *ce, } cache_tree_invalidate_path(istate, ce->name); ce->ce_flags |= CE_UPDATE_IN_BASE; + mark_fsmonitor_invalid(istate, ce); istate->cache_changed |= CE_ENTRY_CHANGED; return 0; @@ -797,7 +816,7 @@ int ce_same_name(const struct cache_entry *a, const struct cache_entry *b) * Also, we don't want double slashes or slashes at the * end that can make pathnames ambiguous. */ -static int verify_dotfile(const char *rest, unsigned mode) +static int verify_dotfile(const char *rest) { /* * The first character was '.', but that @@ -811,13 +830,8 @@ static int verify_dotfile(const char *rest, unsigned mode) switch (*rest) { /* - * ".git" followed by NUL or slash is bad. Note that we match - * case-insensitively here, even if ignore_case is not set. - * This outlaws ".GIT" everywhere out of an abundance of caution, - * since there's really no good reason to allow it. - * - * Once we've seen ".git", we can also find ".gitmodules", etc (also - * case-insensitively). + * ".git" followed by NUL or slash is bad. This + * shares the path end test with the ".." case. */ case 'g': case 'G': @@ -825,15 +839,8 @@ static int verify_dotfile(const char *rest, unsigned mode) break; if (rest[2] != 't' && rest[2] != 'T') break; - if (rest[3] == '\0' || is_dir_sep(rest[3])) - return 0; - if (S_ISLNK(mode)) { - rest += 3; - if (skip_iprefix(rest, "modules", &rest) && - (*rest == '\0' || is_dir_sep(*rest))) - return 0; - } - break; + rest += 2; + /* fallthrough */ case '.': if (rest[1] == '\0' || is_dir_sep(rest[1])) return 0; @@ -841,52 +848,28 @@ static int verify_dotfile(const char *rest, unsigned mode) return 1; } -int verify_path(const char *path, unsigned mode) +int verify_path(const char *path) { char c; if (has_dos_drive_prefix(path)) return 0; - if (!is_valid_path(path)) - return 0; - goto inside; for (;;) { if (!c) return 1; if (is_dir_sep(c)) { inside: - if (protect_hfs) { - if (is_hfs_dotgit(path)) - return 0; - if (S_ISLNK(mode)) { - if (is_hfs_dotgitmodules(path)) - return 0; - } - } - if (protect_ntfs) { - if (is_ntfs_dotgit(path)) - return 0; - if (S_ISLNK(mode)) { - if (is_ntfs_dotgitmodules(path)) - return 0; - } - } - + if (protect_hfs && is_hfs_dotgit(path)) + return 0; + if (protect_ntfs && is_ntfs_dotgit(path)) + return 0; c = *path++; - if ((c == '.' && !verify_dotfile(path, mode)) || + if ((c == '.' && !verify_dotfile(path)) || is_dir_sep(c) || c == '\0') return 0; - } else if (c == '\\' && protect_ntfs) { - if (is_ntfs_dotgit(path)) - return 0; - if (S_ISLNK(mode)) { - if (is_ntfs_dotgitmodules(path)) - return 0; - } } - c = *path++; } } @@ -1200,7 +1183,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e if (!ok_to_add) return -1; - if (!verify_path(ce->name, ce->ce_mode)) + if (!verify_path(ce->name)) return error("Invalid path '%s'", ce->name); if (!skip_df_check && @@ -1265,10 +1248,13 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, int ignore_valid = options & CE_MATCH_IGNORE_VALID; int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE; int ignore_missing = options & CE_MATCH_IGNORE_MISSING; + int ignore_fsmonitor = options & CE_MATCH_IGNORE_FSMONITOR; if (!refresh || ce_uptodate(ce)) return ce; + if (!ignore_fsmonitor) + refresh_fsmonitor(istate); /* * CE_VALID or CE_SKIP_WORKTREE means the user promised us * that the change to the work tree does not matter and told @@ -1282,6 +1268,10 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, ce_mark_uptodate(ce); return ce; } + if (!ignore_fsmonitor && (ce->ce_flags & CE_FSMONITOR_VALID)) { + ce_mark_uptodate(ce); + return ce; + } if (has_symlink_leading_path(ce->name, ce_namelen(ce))) { if (ignore_missing) @@ -1319,8 +1309,10 @@ 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. */ - if (!S_ISGITLINK(ce->ce_mode)) + if (!S_ISGITLINK(ce->ce_mode)) { ce_mark_uptodate(ce); + mark_fsmonitor_valid(ce); + } return ce; } } @@ -1428,6 +1420,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, */ ce->ce_flags &= ~CE_VALID; ce->ce_flags |= CE_UPDATE_IN_BASE; + mark_fsmonitor_invalid(istate, ce); istate->cache_changed |= CE_ENTRY_CHANGED; } if (quiet) @@ -1547,6 +1540,9 @@ struct ondisk_cache_entry_extended { /* Allow fsck to force verification of the index checksum. */ int verify_index_checksum; +/* Allow fsck to force verification of the cache entry order. */ +int verify_ce_order; + static int verify_hdr(struct cache_header *hdr, unsigned long size) { git_SHA_CTX c; @@ -1587,6 +1583,9 @@ static int read_index_extension(struct index_state *istate, case CACHE_EXT_UNTRACKED: istate->untracked = read_untracked_extension(data, sz); break; + case CACHE_EXT_FSMONITOR: + read_fsmonitor_extension(istate, data, sz); + break; default: if (*ext < 'A' || 'Z' < *ext) return error("index uses %.4s extension, which we do not understand", @@ -1704,6 +1703,9 @@ static void check_ce_order(struct index_state *istate) { unsigned int i; + if (!verify_ce_order) + return; + for (i = 1; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i - 1]; struct cache_entry *next_ce = istate->cache[i]; @@ -1759,6 +1761,7 @@ static void post_read_index_from(struct index_state *istate) check_ce_order(istate); tweak_untracked_cache(istate); tweak_split_index(istate); + tweak_fsmonitor(istate); } /* remember to discard_cache() before reading a different cache! */ @@ -2212,17 +2215,22 @@ static int has_racy_timestamp(struct index_state *istate) return 0; } -/* - * Opportunistically 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)) && - verify_index(istate) && - write_locked_index(istate, lockfile, COMMIT_LOCK)) + verify_index(istate)) + write_locked_index(istate, lockfile, COMMIT_LOCK); + else rollback_lock_file(lockfile); } +/* + * On success, `tempfile` is closed. If it is the temporary file + * of a `struct lock_file`, we will therefore effectively perform + * a 'close_lock_file_gently()`. Since that is an implementation + * detail of lockfiles, callers of `do_write_index()` should not + * rely on it. + */ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, int strip_extensions) { @@ -2345,12 +2353,21 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile, if (err) return -1; } + if (!strip_extensions && istate->fsmonitor_last_update) { + struct strbuf sb = STRBUF_INIT; + + write_fsmonitor_extension(&sb, istate); + err = write_index_ext_header(&c, newfd, CACHE_EXT_FSMONITOR, sb.len) < 0 + || ce_write(&c, newfd, sb.buf, sb.len) < 0; + strbuf_release(&sb); + if (err) + return -1; + } if (ce_flush(&c, newfd, istate->sha1)) return -1; if (close_tempfile_gently(tempfile)) { error(_("could not close '%s'"), tempfile->filename.buf); - delete_tempfile(&tempfile); return -1; } if (stat(tempfile->filename.buf, &st)) @@ -2379,14 +2396,9 @@ static int do_write_locked_index(struct index_state *istate, struct lock_file *l int ret = do_write_index(istate, lock->tempfile, 0); if (ret) return ret; - assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) != - (COMMIT_LOCK | CLOSE_LOCK)); if (flags & COMMIT_LOCK) return commit_locked_index(lock); - else if (flags & CLOSE_LOCK) - return close_lock_file_gently(lock); - else - return ret; + return close_lock_file_gently(lock); } static int write_split_index(struct index_state *istate, @@ -2531,11 +2543,15 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, int new_shared_index, ret; struct split_index *si = istate->split_index; + if (istate->fsmonitor_last_update) + fill_fsmonitor_bitmap(istate); + if (!si || alternate_index_output || (istate->cache_changed & ~EXTMASK)) { if (si) hashclr(si->base_sha1); - return do_write_locked_index(istate, lock, flags); + ret = do_write_locked_index(istate, lock, flags); + goto out; } if (getenv("GIT_TEST_SPLIT_INDEX")) { @@ -2551,7 +2567,7 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, if (new_shared_index) { ret = write_shared_index(istate, lock, flags); if (ret) - return ret; + goto out; } ret = write_split_index(istate, lock, flags); @@ -2560,6 +2576,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock, if (!ret && !new_shared_index) freshen_shared_index(sha1_to_hex(si->base_sha1), 1); +out: + if (flags & COMMIT_LOCK) + rollback_lock_file(lock); return ret; }