github.com/afumu/libc@v0.0.6/musl/src/stat/fstatat.c (about)

     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