summaryrefslogtreecommitdiff
path: root/update-cache.c
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2005-05-06 15:45:01 +0200
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-05-06 08:41:12 -0700
commitffbe1addd5a5b7b7c2f987625a5aa6c1d22e3705 (patch)
tree68127262b118858d0dc4d898a3b89d78be6180cf /update-cache.c
parent20d37ef67286e5131d2333d7b4662bc70f9d4937 (diff)
downloadgit-ffbe1addd5a5b7b7c2f987625a5aa6c1d22e3705.tar.gz
[PATCH] fix compare symlink against readlink not data
Fix update-cache to compare the blob of a symlink against the link-target and not the file it points to. Also ignore all permissions applied to links. Thanks to Greg for recognizing this while he added our list of symlinks back to the udev repository. Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'update-cache.c')
-rw-r--r--update-cache.c50
1 files changed, 45 insertions, 5 deletions
diff --git a/update-cache.c b/update-cache.c
index 893ba8679d..210c786af6 100644
--- a/update-cache.c
+++ b/update-cache.c
@@ -64,7 +64,7 @@ static int add_file_to_cache_1(char *path)
struct stat st;
int fd;
unsigned int len;
- char target[1024];
+ char *target;
if (lstat(path, &st) < 0) {
if (errno == ENOENT || errno == ENOTDIR) {
@@ -90,11 +90,14 @@ static int add_file_to_cache_1(char *path)
return -1;
break;
case S_IFLNK:
- len = readlink(path, target, sizeof(target));
- if (len == -1 || len+1 > sizeof(target))
+ target = xmalloc(st.st_size+1);
+ if (readlink(path, target, st.st_size+1) != st.st_size) {
+ free(target);
return -1;
- if (write_sha1_file(target, len, "blob", ce->sha1))
+ }
+ if (write_sha1_file(target, st.st_size, "blob", ce->sha1))
return -1;
+ free(target);
break;
default:
return -1;
@@ -163,6 +166,33 @@ static int compare_data(struct cache_entry *ce, unsigned long expected_size)
return match;
}
+static int 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;
+}
+
/*
* "refresh" does not calculate a new sha1 file or bring the
* cache up-to-date for mode/content changes. But what it
@@ -194,8 +224,18 @@ static struct cache_entry *refresh_entry(struct cache_entry *ce)
if (changed & (MODE_CHANGED | TYPE_CHANGED))
return ERR_PTR(-EINVAL);
- if (compare_data(ce, st.st_size))
+ switch (st.st_mode & S_IFMT) {
+ case S_IFREG:
+ if (compare_data(ce, st.st_size))
+ return ERR_PTR(-EINVAL);
+ break;
+ case S_IFLNK:
+ if (compare_link(ce, st.st_size))
+ return ERR_PTR(-EINVAL);
+ break;
+ default:
return ERR_PTR(-EINVAL);
+ }
cache_changed = 1;
size = ce_size(ce);