Merge branch 'dm/compat-s-ifmt-for-zos'
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Dec 2014 20:27:16 +0000 (12:27 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Dec 2014 20:27:16 +0000 (12:27 -0800)
Long overdue departure from the assumption that S_IFMT is shared by
everybody made in 2005.

* dm/compat-s-ifmt-for-zos:
compat: convert modes to use portable file type values

Makefile
cache.h
compat/stat.c [new file with mode: 0644]
configure.ac
git-compat-util.h
index 7482a4dbab458b1b82a7cb683ce7dc6f41fd4145..86bc0c2f04b8f3b45412a407a4e6124b16897867 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.
@@ -1230,6 +1234,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 22b7b8129072f3905c68f02fe19f463bdb738b9e..f704af5df0984e092fe318e535596921c4ea7122 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -65,13 +65,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 6af964797f7b0ee64deb34bdff40b2a17db067b6..5c1312f24a247fca9bdd7dc9d66aa05f8a7c60d5 100644 (file)
@@ -873,6 +873,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 cef2691276918c04a8a9a2b38f0dbcfd8113a4e0..b763a4e2693a5f08977132513196e78951868d5b 100644 (file)
@@ -475,6 +475,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))