[PATCH 0/5] Be careful about lstat()-vs-readlink()
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: 2016-06-15 22:45:47
Subsystem:
the rest · Maintainer:
Linus Torvalds
This series of five patches makes us a lot more careful about readlink(), and in particular it avoids the code that depends on doing an lstat(), and then using st_size as the length of the link. That's what POSIX says _should_ happen, but Ramon Tayag reported git failing on NTFS under Linux because st_size doesn't match readlink() return value. It doesn't seem to be unknown elsewhere either, since coreutils (through gnulib's areadlink_with_size) also has a big compatibility layer around readlink(). This series has been 'tested' by running it with the appended totally hacky patch that fakes out the lstat() st_size values for symlinks, so it has actually had some testing. The complete series does: Linus Torvalds (5): Add generic 'strbuf_readlink()' helper function Make 'ce_compare_link()' use the new 'strbuf_readlink()' Make 'index_path()' use 'strbuf_readlink()' Make 'diff_populate_filespec()' use the new 'strbuf_readlink()' Make 'prepare_temp_file()' ignore st_size for symlinks builtin-apply.c | 6 ++---- diff.c | 25 +++++++++++-------------- read-cache.c | 22 ++++++++-------------- sha1_file.c | 14 +++++--------- strbuf.c | 28 ++++++++++++++++++++++++++++ strbuf.h | 1 + 6 files changed, 55 insertions(+), 41 deletions(-) and the hacky test-patch (which is obviously _not_ meant to be applied) is as follows... Linus ---
diff --git a/cache.h b/cache.h
index 231c06d..2d85fca 100644
--- a/cache.h
+++ b/cache.h@@ -943,4 +943,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix); char *alias_lookup(const char *alias); int split_cmdline(char *cmdline, const char ***argv); +extern int gitlstat(const char *, struct stat *); +#define lstat gitlstat + #endif /* CACHE_H */
diff --git a/read-cache.c b/read-cache.c
index b1475ff..defbb20 100644
--- a/read-cache.c
+++ b/read-cache.c@@ -15,6 +15,16 @@ #include "revision.h" #include "blob.h" +#undef lstat +int gitlstat(const char *path, struct stat *buf) +{ + int retval = lstat(path, buf); + if (!retval && S_ISLNK(buf->st_mode)) + buf->st_size = 1; + return retval; +} +#define lstat gitlstat + /* Index extensions. * * The first letter should be 'A'..'Z' for extensions that are not