summaryrefslogtreecommitdiff
path: root/read-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'read-cache.c')
-rw-r--r--read-cache.c85
1 files changed, 67 insertions, 18 deletions
diff --git a/read-cache.c b/read-cache.c
index 940ec76fdf..3f587110cb 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -67,8 +67,10 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
*/
void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
{
- ce->ce_ctime = st->st_ctime;
- ce->ce_mtime = st->st_mtime;
+ ce->ce_ctime.sec = (unsigned int)st->st_ctime;
+ ce->ce_mtime.sec = (unsigned int)st->st_mtime;
+ ce->ce_ctime.nsec = ST_CTIME_NSEC(*st);
+ ce->ce_mtime.nsec = ST_MTIME_NSEC(*st);
ce->ce_dev = st->st_dev;
ce->ce_ino = st->st_ino;
ce->ce_uid = st->st_uid;
@@ -196,11 +198,18 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
default:
die("internal error: ce_mode is %o", ce->ce_mode);
}
- if (ce->ce_mtime != (unsigned int) st->st_mtime)
+ if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
changed |= MTIME_CHANGED;
- if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)
+ if (trust_ctime && ce->ce_ctime.sec != (unsigned int)st->st_ctime)
changed |= CTIME_CHANGED;
+#ifdef USE_NSEC
+ if (ce->ce_mtime.nsec != ST_MTIME_NSEC(*st))
+ changed |= MTIME_CHANGED;
+ if (trust_ctime && ce->ce_ctime.nsec != ST_CTIME_NSEC(*st))
+ changed |= CTIME_CHANGED;
+#endif
+
if (ce->ce_uid != (unsigned int) st->st_uid ||
ce->ce_gid != (unsigned int) st->st_gid)
changed |= OWNER_CHANGED;
@@ -232,8 +241,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
{
return (!S_ISGITLINK(ce->ce_mode) &&
- istate->timestamp &&
- ((unsigned int)istate->timestamp) <= ce->ce_mtime);
+ istate->timestamp.sec &&
+#ifdef USE_NSEC
+ /* nanosecond timestamped files can also be racy! */
+ (istate->timestamp.sec < ce->ce_mtime.sec ||
+ (istate->timestamp.sec == ce->ce_mtime.sec &&
+ istate->timestamp.nsec <= ce->ce_mtime.nsec))
+#else
+ istate->timestamp.sec <= ce->ce_mtime.sec
+#endif
+ );
}
int ie_match_stat(const struct index_state *istate,
@@ -443,6 +460,26 @@ int remove_index_entry_at(struct index_state *istate, int pos)
return 1;
}
+/*
+ * Remove all cache ententries marked for removal, that is where
+ * CE_REMOVE is set in ce_flags. This is much more effective than
+ * calling remove_index_entry_at() for each entry to be removed.
+ */
+void remove_marked_cache_entries(struct index_state *istate)
+{
+ struct cache_entry **ce_array = istate->cache;
+ unsigned int i, j;
+
+ for (i = j = 0; i < istate->cache_nr; i++) {
+ if (ce_array[i]->ce_flags & CE_REMOVE)
+ remove_name_hash(ce_array[i]);
+ else
+ ce_array[j++] = ce_array[i];
+ }
+ istate->cache_changed = 1;
+ istate->cache_nr = j;
+}
+
int remove_file_from_index(struct index_state *istate, const char *path)
{
int pos = index_name_pos(istate, path, strlen(path));
@@ -1139,8 +1176,10 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
size_t len;
const char *name;
- ce->ce_ctime = ntohl(ondisk->ctime.sec);
- ce->ce_mtime = ntohl(ondisk->mtime.sec);
+ 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);
@@ -1206,7 +1245,8 @@ int read_index_from(struct index_state *istate, const char *path)
return istate->cache_nr;
errno = ENOENT;
- istate->timestamp = 0;
+ istate->timestamp.sec = 0;
+ istate->timestamp.nsec = 0;
fd = open(path, O_RDONLY);
if (fd < 0) {
if (errno == ENOENT)
@@ -1258,7 +1298,9 @@ int read_index_from(struct index_state *istate, const char *path)
src_offset += ondisk_ce_size(ce);
dst_offset += ce_size(ce);
}
- istate->timestamp = st.st_mtime;
+ istate->timestamp.sec = st.st_mtime;
+ istate->timestamp.nsec = ST_MTIME_NSEC(st);
+
while (src_offset <= mmap_size - 20 - 8) {
/* After an array of active_nr index entries,
* there can be arbitrary number of extended
@@ -1288,14 +1330,15 @@ unmap:
int is_index_unborn(struct index_state *istate)
{
- return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
+ return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);
}
int discard_index(struct index_state *istate)
{
istate->cache_nr = 0;
istate->cache_changed = 0;
- istate->timestamp = 0;
+ istate->timestamp.sec = 0;
+ istate->timestamp.nsec = 0;
istate->name_hash_initialized = 0;
free_hash(&istate->name_hash);
cache_tree_free(&(istate->cache_tree));
@@ -1441,10 +1484,10 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
struct ondisk_cache_entry *ondisk = xcalloc(1, size);
char *name;
- ondisk->ctime.sec = htonl(ce->ce_ctime);
- ondisk->ctime.nsec = 0;
- ondisk->mtime.sec = htonl(ce->ce_mtime);
- ondisk->mtime.nsec = 0;
+ ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
+ ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
+ ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
+ ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
ondisk->dev = htonl(ce->ce_dev);
ondisk->ino = htonl(ce->ce_ino);
ondisk->mode = htonl(ce->ce_mode);
@@ -1466,13 +1509,14 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
return ce_write(c, fd, ondisk, size);
}
-int write_index(const struct index_state *istate, int newfd)
+int write_index(struct index_state *istate, int newfd)
{
git_SHA_CTX c;
struct cache_header hdr;
int i, err, removed, extended;
struct cache_entry **cache = istate->cache;
int entries = istate->cache_nr;
+ struct stat st;
for (i = removed = extended = 0; i < entries; i++) {
if (cache[i]->ce_flags & CE_REMOVE)
@@ -1516,7 +1560,12 @@ int write_index(const struct index_state *istate, int newfd)
if (err)
return -1;
}
- return ce_flush(&c, newfd);
+
+ if (ce_flush(&c, newfd) || fstat(newfd, &st))
+ return -1;
+ istate->timestamp.sec = (unsigned int)st.st_mtime;
+ istate->timestamp.nsec = ST_MTIME_NSEC(st);
+ return 0;
}
/*