diff options
author | Junio C Hamano <junkio@cox.net> | 2005-09-19 15:11:15 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2005-09-20 15:07:53 -0700 |
commit | b0391890d25d9e7ca8f7df2199292df68ead8093 (patch) | |
tree | 9562d2c1387af4afb6f72317e8e1155b4b7fca48 /read-cache.c | |
parent | 1991b223c05d45d2a915842990b2a7c4819dcbcf (diff) | |
download | git-b0391890d25d9e7ca8f7df2199292df68ead8093.tar.gz |
Show modified files in git-ls-files
Add -m/--modified to show files that have been modified wrt. the index.
[jc: The original came from Brian Gerst on Sep 1st but it only checked
if the paths were cache dirty without actually checking the files were
modified. I also added the usage string and a new test.]
Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'read-cache.c')
-rw-r--r-- | read-cache.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/read-cache.c b/read-cache.c index 6eff4c8401..ef6fd79e20 100644 --- a/read-cache.c +++ b/read-cache.c @@ -83,6 +83,83 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st) return changed; } +static int ce_compare_data(struct cache_entry *ce, struct stat *st) +{ + int match = -1; + int fd = open(ce->name, O_RDONLY); + + if (fd >= 0) { + unsigned char sha1[20]; + if (!index_fd(sha1, fd, st, 0, NULL)) + match = memcmp(sha1, ce->sha1, 20); + close(fd); + } + return match; +} + +static int ce_compare_link(struct cache_entry *ce, unsigned long expected_size) +{ + int match = -1; + char *target; + void *buffer; + unsigned long size; + char type[10]; + int len; + + target = xmalloc(expected_size); + len = readlink(ce->name, target, expected_size); + if (len != expected_size) { + free(target); + return -1; + } + buffer = read_sha1_file(ce->sha1, type, &size); + if (!buffer) { + free(target); + return -1; + } + if (size == expected_size) + match = memcmp(buffer, target, size); + free(buffer); + free(target); + return match; +} + +int ce_modified(struct cache_entry *ce, struct stat *st) +{ + int changed; + changed = ce_match_stat(ce, st); + if (!changed) + return 0; + + /* + * If the mode or type has changed, there's no point in trying + * to refresh the entry - it's not going to match + */ + if (changed & (MODE_CHANGED | TYPE_CHANGED)) + return changed; + + /* Immediately after read-tree or update-index --cacheinfo, + * the length field is zero. For other cases the ce_size + * should match the SHA1 recorded in the index entry. + */ + if ((changed & DATA_CHANGED) && ce->ce_size != htonl(0)) + return changed; + + switch (st->st_mode & S_IFMT) { + case S_IFREG: + if (ce_compare_data(ce, st)) + return changed | DATA_CHANGED; + break; + case S_IFLNK: + if (ce_compare_link(ce, st->st_size)) + return changed | DATA_CHANGED; + break; + default: + return changed | TYPE_CHANGED; + } + return 0; +} + int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2) { |