Skip to content

Commit d543d9c

Browse files
dm0-gitster
authored andcommitted
compat: convert modes to use portable file type values
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>
1 parent 7fa1365 commit d543d9c

5 files changed

Lines changed: 113 additions & 7 deletions

File tree

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ all::
191191
# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
192192
# the executable mode bit, but doesn't really do so.
193193
#
194+
# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
195+
# bits in mode values (e.g. z/OS defines I_SFMT to 0xFF000000 as opposed to the
196+
# usual 0xF000).
197+
#
194198
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
195199
#
196200
# Define NO_UNIX_SOCKETS if your system does not offer unix sockets.
@@ -1355,6 +1359,10 @@ endif
13551359
ifdef NO_TRUSTABLE_FILEMODE
13561360
BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
13571361
endif
1362+
ifdef NEEDS_MODE_TRANSLATION
1363+
COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
1364+
COMPAT_OBJS += compat/stat.o
1365+
endif
13581366
ifdef NO_IPV6
13591367
BASIC_CFLAGS += -DNO_IPV6
13601368
endif

cache.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
6464
*
6565
* The value 0160000 is not normally a valid mode, and
6666
* also just happens to be S_IFDIR + S_IFLNK
67-
*
68-
* NOTE! We *really* shouldn't depend on the S_IFxxx macros
69-
* always having the same values everywhere. We should use
70-
* our internal git values for these things, and then we can
71-
* translate that to the OS-specific value. It just so
72-
* happens that everybody shares the same bit representation
73-
* in the UNIX world (and apparently wider too..)
7467
*/
7568
#define S_IFGITLINK 0160000
7669
#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)

compat/stat.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#define _POSIX_C_SOURCE 200112L
2+
#include <sys/stat.h> /* *stat, S_IS* */
3+
#include <sys/types.h> /* mode_t */
4+
5+
static inline mode_t mode_native_to_git(mode_t native_mode)
6+
{
7+
mode_t perm_bits = native_mode & 07777;
8+
if (S_ISREG(native_mode))
9+
return 0100000 | perm_bits;
10+
if (S_ISDIR(native_mode))
11+
return 0040000 | perm_bits;
12+
if (S_ISLNK(native_mode))
13+
return 0120000 | perm_bits;
14+
if (S_ISBLK(native_mode))
15+
return 0060000 | perm_bits;
16+
if (S_ISCHR(native_mode))
17+
return 0020000 | perm_bits;
18+
if (S_ISFIFO(native_mode))
19+
return 0010000 | perm_bits;
20+
if (S_ISSOCK(native_mode))
21+
return 0140000 | perm_bits;
22+
/* Non-standard type bits were given. */
23+
return perm_bits;
24+
}
25+
26+
int git_stat(const char *path, struct stat *buf)
27+
{
28+
int rc = stat(path, buf);
29+
if (rc == 0)
30+
buf->st_mode = mode_native_to_git(buf->st_mode);
31+
return rc;
32+
}
33+
34+
int git_fstat(int fd, struct stat *buf)
35+
{
36+
int rc = fstat(fd, buf);
37+
if (rc == 0)
38+
buf->st_mode = mode_native_to_git(buf->st_mode);
39+
return rc;
40+
}
41+
42+
int git_lstat(const char *path, struct stat *buf)
43+
{
44+
int rc = lstat(path, buf);
45+
if (rc == 0)
46+
buf->st_mode = mode_native_to_git(buf->st_mode);
47+
return rc;
48+
}

configure.ac

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,29 @@ else
865865
SNPRINTF_RETURNS_BOGUS=
866866
fi
867867
GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
868+
#
869+
# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
870+
# bits in mode values.
871+
AC_CACHE_CHECK([whether the platform uses typical file type bits],
872+
[ac_cv_sane_mode_bits], [
873+
AC_EGREP_CPP(yippeeyeswehaveit,
874+
AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
875+
[#if S_IFMT == 0170000 && \
876+
S_IFREG == 0100000 && S_IFDIR == 0040000 && S_IFLNK == 0120000 && \
877+
S_IFBLK == 0060000 && S_IFCHR == 0020000 && \
878+
S_IFIFO == 0010000 && S_IFSOCK == 0140000
879+
yippeeyeswehaveit
880+
#endif
881+
]),
882+
[ac_cv_sane_mode_bits=yes],
883+
[ac_cv_sane_mode_bits=no])
884+
])
885+
if test $ac_cv_sane_mode_bits = yes; then
886+
NEEDS_MODE_TRANSLATION=
887+
else
888+
NEEDS_MODE_TRANSLATION=UnfortunatelyYes
889+
fi
890+
GIT_CONF_SUBST([NEEDS_MODE_TRANSLATION])
868891

869892

870893
## Checks for library functions.

git-compat-util.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,40 @@ extern int git_munmap(void *start, size_t length);
455455
#define on_disk_bytes(st) ((st).st_blocks * 512)
456456
#endif
457457

458+
#ifdef NEEDS_MODE_TRANSLATION
459+
#undef S_IFMT
460+
#undef S_IFREG
461+
#undef S_IFDIR
462+
#undef S_IFLNK
463+
#undef S_IFBLK
464+
#undef S_IFCHR
465+
#undef S_IFIFO
466+
#undef S_IFSOCK
467+
#define S_IFMT 0170000
468+
#define S_IFREG 0100000
469+
#define S_IFDIR 0040000
470+
#define S_IFLNK 0120000
471+
#define S_IFBLK 0060000
472+
#define S_IFCHR 0020000
473+
#define S_IFIFO 0010000
474+
#define S_IFSOCK 0140000
475+
#ifdef stat
476+
#undef stat
477+
#endif
478+
#define stat(path, buf) git_stat(path, buf)
479+
extern int git_stat(const char *, struct stat *);
480+
#ifdef fstat
481+
#undef fstat
482+
#endif
483+
#define fstat(fd, buf) git_fstat(fd, buf)
484+
extern int git_fstat(int, struct stat *);
485+
#ifdef lstat
486+
#undef lstat
487+
#endif
488+
#define lstat(path, buf) git_lstat(path, buf)
489+
extern int git_lstat(const char *, struct stat *);
490+
#endif
491+
458492
#define DEFAULT_PACKED_GIT_LIMIT \
459493
((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
460494

0 commit comments

Comments
 (0)