compat: convert modes to use portable file type values
authorDavid Michael <fedora.dm0@gmail.com>
Thu, 4 Dec 2014 02:24:17 +0000 (21:24 -0500)
committerJunio C Hamano <gitster@pobox.com>
Thu, 4 Dec 2014 19:58:36 +0000 (11:58 -0800)
This adds simple wrapper functions around calls to stat(), fstat(),
and lstat() that translate the operating system's native file type
bits to those used by most operating systems. It also rewrites the
S_IF* macros to the common values, so all file type processing is
performed using the translated modes. This makes projects portable
across operating systems that use different file type definitions.

Only the file type bits may be affected by these compatibility
functions; the file permission bits are assumed to be 07777 and are
passed through unchanged.

Signed-off-by: David Michael <fedora.dm0@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
cache.h
compat/stat.c [new file with mode: 0644]
configure.ac
git-compat-util.h
index 9f984a9e5561d6b67b453124a311963ae8845f6d..aa1812dc9d83dabe02fd079565a78b8710062520 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -191,6 +191,10 @@ all::
 # Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
 # the executable mode bit, but doesn't really do so.
 #
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values (e.g. z/OS defines I_SFMT to 0xFF000000 as opposed to the
+# usual 0xF000).
+#
 # Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
 #
 # Define NO_UNIX_SOCKETS if your system does not offer unix sockets.
@@ -1355,6 +1359,10 @@ endif
 ifdef NO_TRUSTABLE_FILEMODE
        BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
 endif
+ifdef NEEDS_MODE_TRANSLATION
+       COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
+       COMPAT_OBJS += compat/stat.o
+endif
 ifdef NO_IPV6
        BASIC_CFLAGS += -DNO_IPV6
 endif
diff --git a/cache.h b/cache.h
index dcf3a2afe9d782e4b2474d8834602f80610ba25f..a2911fa88cb3f02d0c4554224e168b1dfab18c19 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -64,13 +64,6 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
  *
  * The value 0160000 is not normally a valid mode, and
  * also just happens to be S_IFDIR + S_IFLNK
- *
- * NOTE! We *really* shouldn't depend on the S_IFxxx macros
- * always having the same values everywhere. We should use
- * our internal git values for these things, and then we can
- * translate that to the OS-specific value. It just so
- * happens that everybody shares the same bit representation
- * in the UNIX world (and apparently wider too..)
  */
 #define S_IFGITLINK    0160000
 #define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
diff --git a/compat/stat.c b/compat/stat.c
new file mode 100644 (file)
index 0000000..a2d3931
--- /dev/null
@@ -0,0 +1,48 @@
+#define _POSIX_C_SOURCE 200112L
+#include <sys/stat.h>  /* *stat, S_IS* */
+#include <sys/types.h> /* mode_t       */
+
+static inline mode_t mode_native_to_git(mode_t native_mode)
+{
+       mode_t perm_bits = native_mode & 07777;
+       if (S_ISREG(native_mode))
+               return 0100000 | perm_bits;
+       if (S_ISDIR(native_mode))
+               return 0040000 | perm_bits;
+       if (S_ISLNK(native_mode))
+               return 0120000 | perm_bits;
+       if (S_ISBLK(native_mode))
+               return 0060000 | perm_bits;
+       if (S_ISCHR(native_mode))
+               return 0020000 | perm_bits;
+       if (S_ISFIFO(native_mode))
+               return 0010000 | perm_bits;
+       if (S_ISSOCK(native_mode))
+               return 0140000 | perm_bits;
+       /* Non-standard type bits were given. */
+       return perm_bits;
+}
+
+int git_stat(const char *path, struct stat *buf)
+{
+       int rc = stat(path, buf);
+       if (rc == 0)
+               buf->st_mode = mode_native_to_git(buf->st_mode);
+       return rc;
+}
+
+int git_fstat(int fd, struct stat *buf)
+{
+       int rc = fstat(fd, buf);
+       if (rc == 0)
+               buf->st_mode = mode_native_to_git(buf->st_mode);
+       return rc;
+}
+
+int git_lstat(const char *path, struct stat *buf)
+{
+       int rc = lstat(path, buf);
+       if (rc == 0)
+               buf->st_mode = mode_native_to_git(buf->st_mode);
+       return rc;
+}
index 4b1ae7c3c9f5ff5080dc026a6eb835d579d29949..f75609e743517930738dc9eb2e919107c75e7440 100644 (file)
@@ -865,6 +865,29 @@ else
        SNPRINTF_RETURNS_BOGUS=
 fi
 GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
+#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values.
+AC_CACHE_CHECK([whether the platform uses typical file type bits],
+ [ac_cv_sane_mode_bits], [
+AC_EGREP_CPP(yippeeyeswehaveit,
+       AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+[#if S_IFMT == 0170000 && \
+       S_IFREG == 0100000 && S_IFDIR == 0040000 && S_IFLNK == 0120000 && \
+       S_IFBLK == 0060000 && S_IFCHR == 0020000 && \
+       S_IFIFO == 0010000 && S_IFSOCK == 0140000
+yippeeyeswehaveit
+#endif
+]),
+       [ac_cv_sane_mode_bits=yes],
+       [ac_cv_sane_mode_bits=no])
+])
+if test $ac_cv_sane_mode_bits = yes; then
+       NEEDS_MODE_TRANSLATION=
+else
+       NEEDS_MODE_TRANSLATION=UnfortunatelyYes
+fi
+GIT_CONF_SUBST([NEEDS_MODE_TRANSLATION])
 
 
 ## Checks for library functions.
index f587749b7cf6a74be376792eb0ad70b7e5e4f597..9dfefb2f4b969035def3abf6b688ff72222698c7 100644 (file)
@@ -455,6 +455,40 @@ extern int git_munmap(void *start, size_t length);
 #define on_disk_bytes(st) ((st).st_blocks * 512)
 #endif
 
+#ifdef NEEDS_MODE_TRANSLATION
+#undef S_IFMT
+#undef S_IFREG
+#undef S_IFDIR
+#undef S_IFLNK
+#undef S_IFBLK
+#undef S_IFCHR
+#undef S_IFIFO
+#undef S_IFSOCK
+#define S_IFMT   0170000
+#define S_IFREG  0100000
+#define S_IFDIR  0040000
+#define S_IFLNK  0120000
+#define S_IFBLK  0060000
+#define S_IFCHR  0020000
+#define S_IFIFO  0010000
+#define S_IFSOCK 0140000
+#ifdef stat
+#undef stat
+#endif
+#define stat(path, buf) git_stat(path, buf)
+extern int git_stat(const char *, struct stat *);
+#ifdef fstat
+#undef fstat
+#endif
+#define fstat(fd, buf) git_fstat(fd, buf)
+extern int git_fstat(int, struct stat *);
+#ifdef lstat
+#undef lstat
+#endif
+#define lstat(path, buf) git_lstat(path, buf)
+extern int git_lstat(const char *, struct stat *);
+#endif
+
 #define DEFAULT_PACKED_GIT_LIMIT \
        ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))