refactor all stat functions in terms of fstatat
authorRich Felker <dalias@aerifal.cx>
Thu, 18 Jul 2019 19:16:20 +0000 (15:16 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 18 Jul 2019 23:36:23 +0000 (19:36 -0400)
equivalent logic for fstat+O_PATH fallback and direct use of
stat/lstat syscalls where appropriate is kept, now in the fstatat
function. this change both improves functionality (now, fstatat forms
equivalent to fstat/lstat/stat will work even on kernels too old to
have the at functions) and localizes direct interfacing with the
kernel stat structure to one file.

src/stat/fstat.c
src/stat/fstatat.c
src/stat/lstat.c
src/stat/stat.c

index 4f13f4f..d2a828f 100644 (file)
@@ -1,3 +1,4 @@
+#define _BSD_SOURCE
 #include <sys/stat.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -5,17 +6,7 @@
 
 int fstat(int fd, struct stat *st)
 {
-       int ret = __syscall(SYS_fstat, fd, st);
-       if (ret != -EBADF || __syscall(SYS_fcntl, fd, F_GETFD) < 0)
-               return __syscall_ret(ret);
-
-       char buf[15+3*sizeof(int)];
-       __procfdname(buf, fd);
-#ifdef SYS_stat
-       return syscall(SYS_stat, buf, st);
-#else
-       return syscall(SYS_fstatat, AT_FDCWD, buf, st, 0);
-#endif
+       return fstatat(fd, "", st, AT_EMPTY_PATH);
 }
 
 weak_alias(fstat, fstat64);
index 582db44..f5bc368 100644 (file)
@@ -1,9 +1,40 @@
+#define _BSD_SOURCE
 #include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
 #include "syscall.h"
 
-int fstatat(int fd, const char *restrict path, struct stat *restrict buf, int flag)
+int fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag)
 {
-       return syscall(SYS_fstatat, fd, path, buf, flag);
+       int ret;
+
+       if (flag==AT_EMPTY_PATH && fd>=0 && !*path) {
+               ret = __syscall(SYS_fstat, fd, st);
+               if (ret==-EBADF && __syscall(SYS_fcntl, fd, F_GETFD)>=0) {
+                       ret = __syscall(SYS_fstatat, fd, path, st, flag);
+                       if (ret==-EINVAL) {
+                               char buf[15+3*sizeof(int)];
+                               __procfdname(buf, fd);
+#ifdef SYS_stat
+                               ret = __syscall(SYS_stat, buf, st);
+#else
+                               ret = __syscall(SYS_fstatat, AT_FDCWD, buf, st, 0);
+#endif
+                       }
+               }
+       }
+#ifdef SYS_lstat
+       else if ((fd == AT_FDCWD || *path=='/') && flag==AT_SYMLINK_NOFOLLOW)
+               ret = __syscall(SYS_lstat, path, st);
+#endif
+#ifdef SYS_stat
+       else if ((fd == AT_FDCWD || *path=='/') && !flag)
+               ret = __syscall(SYS_stat, path, st);
+#endif
+       else ret = __syscall(SYS_fstatat, fd, path, st, flag);
+
+       return __syscall_ret(ret);
 }
 
 weak_alias(fstatat, fstatat64);
index 5b89f29..8b365ba 100644 (file)
@@ -4,11 +4,7 @@
 
 int lstat(const char *restrict path, struct stat *restrict buf)
 {
-#ifdef SYS_lstat
-       return syscall(SYS_lstat, path, buf);
-#else
-       return syscall(SYS_fstatat, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
-#endif
+       return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
 }
 
 weak_alias(lstat, lstat64);
index 0bec9d6..b4e6279 100644 (file)
@@ -4,11 +4,7 @@
 
 int stat(const char *restrict path, struct stat *restrict buf)
 {
-#ifdef SYS_stat
-       return syscall(SYS_stat, path, buf);
-#else
-       return syscall(SYS_fstatat, AT_FDCWD, path, buf, 0);
-#endif
+       return fstatat(AT_FDCWD, path, buf, 0);
 }
 
 weak_alias(stat, stat64);