fstatat.c raw

   1  #define _BSD_SOURCE
   2  #include <sys/stat.h>
   3  #include <string.h>
   4  #include <fcntl.h>
   5  #include <errno.h>
   6  #include <stdint.h>
   7  #include <sys/sysmacros.h>
   8  #include "syscall.h"
   9  #include "kstat.h"
  10  
  11  struct statx {
  12  	uint32_t stx_mask;
  13  	uint32_t stx_blksize;
  14  	uint64_t stx_attributes;
  15  	uint32_t stx_nlink;
  16  	uint32_t stx_uid;
  17  	uint32_t stx_gid;
  18  	uint16_t stx_mode;
  19  	uint16_t pad1;
  20  	uint64_t stx_ino;
  21  	uint64_t stx_size;
  22  	uint64_t stx_blocks;
  23  	uint64_t stx_attributes_mask;
  24  	struct {
  25  		int64_t tv_sec;
  26  		uint32_t tv_nsec;
  27  		int32_t pad;
  28  	} stx_atime, stx_btime, stx_ctime, stx_mtime;
  29  	uint32_t stx_rdev_major;
  30  	uint32_t stx_rdev_minor;
  31  	uint32_t stx_dev_major;
  32  	uint32_t stx_dev_minor;
  33  	uint64_t spare[14];
  34  };
  35  
  36  static int fstatat_statx(int fd, const char *restrict path, struct stat *restrict st, int flag)
  37  {
  38  	struct statx stx;
  39  
  40  	int ret = __syscall(SYS_statx, fd, path, flag, 0x7ff, &stx);
  41  	if (ret) return ret;
  42  
  43  	*st = (struct stat){
  44  		.st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor),
  45  		.st_ino = stx.stx_ino,
  46  		.st_mode = stx.stx_mode,
  47  		.st_nlink = stx.stx_nlink,
  48  		.st_uid = stx.stx_uid,
  49  		.st_gid = stx.stx_gid,
  50  		.st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor),
  51  		.st_size = stx.stx_size,
  52  		.st_blksize = stx.stx_blksize,
  53  		.st_blocks = stx.stx_blocks,
  54  		.st_atim.tv_sec = stx.stx_atime.tv_sec,
  55  		.st_atim.tv_nsec = stx.stx_atime.tv_nsec,
  56  		.st_mtim.tv_sec = stx.stx_mtime.tv_sec,
  57  		.st_mtim.tv_nsec = stx.stx_mtime.tv_nsec,
  58  		.st_ctim.tv_sec = stx.stx_ctime.tv_sec,
  59  		.st_ctim.tv_nsec = stx.stx_ctime.tv_nsec,
  60  #if _REDIR_TIME64
  61  		.__st_atim32.tv_sec = stx.stx_atime.tv_sec,
  62  		.__st_atim32.tv_nsec = stx.stx_atime.tv_nsec,
  63  		.__st_mtim32.tv_sec = stx.stx_mtime.tv_sec,
  64  		.__st_mtim32.tv_nsec = stx.stx_mtime.tv_nsec,
  65  		.__st_ctim32.tv_sec = stx.stx_ctime.tv_sec,
  66  		.__st_ctim32.tv_nsec = stx.stx_ctime.tv_nsec,
  67  #endif
  68  	};
  69  	return 0;
  70  }
  71  
  72  static int fstatat_kstat(int fd, const char *restrict path, struct stat *restrict st, int flag)
  73  {
  74  	int ret;
  75  	struct kstat kst;
  76  
  77  	if (flag==AT_EMPTY_PATH && fd>=0 && !*path) {
  78  		ret = __syscall(SYS_fstat, fd, &kst);
  79  		if (ret==-EBADF && __syscall(SYS_fcntl, fd, F_GETFD)>=0) {
  80  			ret = __syscall(SYS_fstatat, fd, path, &kst, flag);
  81  			if (ret==-EINVAL) {
  82  				char buf[15+3*sizeof(int)];
  83  				__procfdname(buf, fd);
  84  #ifdef SYS_stat
  85  				ret = __syscall(SYS_stat, buf, &kst);
  86  #else
  87  				ret = __syscall(SYS_fstatat, AT_FDCWD, buf, &kst, 0);
  88  #endif
  89  			}
  90  		}
  91  	}
  92  #ifdef SYS_lstat
  93  	else if ((fd == AT_FDCWD || *path=='/') && flag==AT_SYMLINK_NOFOLLOW)
  94  		ret = __syscall(SYS_lstat, path, &kst);
  95  #endif
  96  #ifdef SYS_stat
  97  	else if ((fd == AT_FDCWD || *path=='/') && !flag)
  98  		ret = __syscall(SYS_stat, path, &kst);
  99  #endif
 100  	else ret = __syscall(SYS_fstatat, fd, path, &kst, flag);
 101  
 102  	if (ret) return ret;
 103  
 104  	*st = (struct stat){
 105  		.st_dev = kst.st_dev,
 106  		.st_ino = kst.st_ino,
 107  		.st_mode = kst.st_mode,
 108  		.st_nlink = kst.st_nlink,
 109  		.st_uid = kst.st_uid,
 110  		.st_gid = kst.st_gid,
 111  		.st_rdev = kst.st_rdev,
 112  		.st_size = kst.st_size,
 113  		.st_blksize = kst.st_blksize,
 114  		.st_blocks = kst.st_blocks,
 115  		.st_atim.tv_sec = kst.st_atime_sec,
 116  		.st_atim.tv_nsec = kst.st_atime_nsec,
 117  		.st_mtim.tv_sec = kst.st_mtime_sec,
 118  		.st_mtim.tv_nsec = kst.st_mtime_nsec,
 119  		.st_ctim.tv_sec = kst.st_ctime_sec,
 120  		.st_ctim.tv_nsec = kst.st_ctime_nsec,
 121  #if _REDIR_TIME64
 122  		.__st_atim32.tv_sec = kst.st_atime_sec,
 123  		.__st_atim32.tv_nsec = kst.st_atime_nsec,
 124  		.__st_mtim32.tv_sec = kst.st_mtime_sec,
 125  		.__st_mtim32.tv_nsec = kst.st_mtime_nsec,
 126  		.__st_ctim32.tv_sec = kst.st_ctime_sec,
 127  		.__st_ctim32.tv_nsec = kst.st_ctime_nsec,
 128  #endif
 129  	};
 130  
 131  	return 0;
 132  }
 133  
 134  int fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag)
 135  {
 136  	int ret;
 137  	if (sizeof((struct kstat){0}.st_atime_sec) < sizeof(time_t)) {
 138  		ret = fstatat_statx(fd, path, st, flag);
 139  		if (ret!=-ENOSYS) return __syscall_ret(ret);
 140  	}
 141  	ret = fstatat_kstat(fd, path, st, flag);
 142  	return __syscall_ret(ret);
 143  }
 144  
 145  #if !_REDIR_TIME64
 146  weak_alias(fstatat, fstatat64);
 147  #endif
 148