git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] fix compare symlink against readlink not data

From
KSKay Sievers <kay.sievers@vrfy.org>
Date
May 6, 2005, 13:45 UTC
Message-ID
<20050506134501.GA11430@vrfy.org>

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>
---
--- a/diff-files.c
+++ b/diff-files.c
@@ -111,7 +111,7 @@ int main(int argc, char **argv)
 			continue;
 		}
  
-		if (stat(ce->name, &st) < 0) {
+		if (lstat(ce->name, &st) < 0) {
 			if (errno != ENOENT) {
 				perror(ce->name);
 				continue;
--- a/read-cache.c
+++ b/read-cache.c
@@ -16,6 +16,9 @@ int cache_match_stat(struct cache_entry 
 	switch (ntohl(ce->ce_mode) & S_IFMT) {
 	case S_IFREG:
 		changed |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0;
+		/* We consider only the owner x bit to be relevant for "mode changes" */
+		if (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))
+			changed |= MODE_CHANGED;
 		break;
 	case S_IFLNK:
 		changed |= !S_ISLNK(st->st_mode) ? TYPE_CHANGED : 0;
@@ -43,9 +46,6 @@ int cache_match_stat(struct cache_entry 
 	if (ce->ce_uid != htonl(st->st_uid) ||
 	    ce->ce_gid != htonl(st->st_gid))
 		changed |= OWNER_CHANGED;
-	/* We consider only the owner x bit to be relevant for "mode changes" */
-	if (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))
-		changed |= MODE_CHANGED;
 	if (ce->ce_dev != htonl(st->st_dev) ||
 	    ce->ce_ino != htonl(st->st_ino))
 		changed |= INODE_CHANGED;
--- a/update-cache.c
+++ b/update-cache.c
@@ -64,7 +64,7 @@ static int add_file_to_cache_1(char *pat
 	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 *pat
 			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,32 @@ static int compare_data(struct cache_ent
 	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 +223,18 @@ static struct cache_entry *refresh_entry
 	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);
Next: Greg KH
Message 1 of 9 in “fix compare symlink against readlink not data”
  1. fix compare symlink against readlink not dataKay Sievers, May 6, 2005
  2. Greg KHMay 6, 2005
  3. Kay SieversMay 6, 2005
  4. Greg KHMay 6, 2005
  5. Kay SieversMay 6, 2005
  6. Linus TorvaldsMay 6, 2005
  7. Greg KHMay 6, 2005
  8. Junio C HamanoMay 6, 2005
  9. Greg KHMay 6, 2005

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.