summaryrefslogtreecommitdiff
path: root/src/stat
diff options
context:
space:
mode:
Diffstat (limited to 'src/stat')
-rw-r--r--src/stat/__xstat.c7
-rw-r--r--src/stat/fchmodat.c19
-rw-r--r--src/stat/fstat.c18
-rw-r--r--src/stat/fstatat.c151
-rw-r--r--src/stat/lstat.c9
-rw-r--r--src/stat/stat.c9
-rw-r--r--src/stat/statvfs.c6
-rw-r--r--src/stat/utimensat.c43
8 files changed, 203 insertions, 59 deletions
diff --git a/src/stat/__xstat.c b/src/stat/__xstat.c
index f6303430..b4560df7 100644
--- a/src/stat/__xstat.c
+++ b/src/stat/__xstat.c
@@ -1,5 +1,7 @@
#include <sys/stat.h>
+#if !_REDIR_TIME64
+
int __fxstat(int ver, int fd, struct stat *buf)
{
return fstat(fd, buf);
@@ -20,10 +22,7 @@ int __xstat(int ver, const char *path, struct stat *buf)
return stat(path, buf);
}
-weak_alias(__fxstat, __fxstat64);
-weak_alias(__fxstatat, __fxstatat64);
-weak_alias(__lxstat, __lxstat64);
-weak_alias(__xstat, __xstat64);
+#endif
int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev)
{
diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
index be61bdf3..92c9d1b0 100644
--- a/src/stat/fchmodat.c
+++ b/src/stat/fchmodat.c
@@ -5,17 +5,20 @@
int fchmodat(int fd, const char *path, mode_t mode, int flag)
{
- if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag);
+ if (!flag) return syscall(SYS_fchmodat, fd, path, mode);
+
+ int ret = __syscall(SYS_fchmodat2, fd, path, mode, flag);
+ if (ret != -ENOSYS) return __syscall_ret(ret);
if (flag != AT_SYMLINK_NOFOLLOW)
return __syscall_ret(-EINVAL);
struct stat st;
- int ret, fd2;
+ int fd2;
char proc[15+3*sizeof(int)];
- if ((ret = __syscall(SYS_fstatat, fd, path, &st, flag)))
- return __syscall_ret(ret);
+ if (fstatat(fd, path, &st, flag))
+ return -1;
if (S_ISLNK(st.st_mode))
return __syscall_ret(-EOPNOTSUPP);
@@ -26,12 +29,12 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag)
}
__procfdname(proc, fd2);
- ret = __syscall(SYS_fstatat, AT_FDCWD, proc, &st, 0);
+ ret = stat(proc, &st);
if (!ret) {
- if (S_ISLNK(st.st_mode)) ret = -EOPNOTSUPP;
- else ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
+ if (S_ISLNK(st.st_mode)) ret = __syscall_ret(-EOPNOTSUPP);
+ else ret = syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
}
__syscall(SYS_close, fd2);
- return __syscall_ret(ret);
+ return ret;
}
diff --git a/src/stat/fstat.c b/src/stat/fstat.c
index 4f13f4f0..fd28b8ac 100644
--- a/src/stat/fstat.c
+++ b/src/stat/fstat.c
@@ -1,21 +1,13 @@
+#define _BSD_SOURCE
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include "syscall.h"
-int fstat(int fd, struct stat *st)
+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
+ if (fd<0) return __syscall_ret(-EBADF);
+ return __fstatat(fd, "", st, AT_EMPTY_PATH);
}
-weak_alias(fstat, fstat64);
+weak_alias(__fstat, fstat);
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index 582db442..9eed063b 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -1,9 +1,154 @@
+#define _BSD_SOURCE
#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/sysmacros.h>
#include "syscall.h"
-int fstatat(int fd, const char *restrict path, struct stat *restrict buf, int flag)
+struct statx {
+ uint32_t stx_mask;
+ uint32_t stx_blksize;
+ uint64_t stx_attributes;
+ uint32_t stx_nlink;
+ uint32_t stx_uid;
+ uint32_t stx_gid;
+ uint16_t stx_mode;
+ uint16_t pad1;
+ uint64_t stx_ino;
+ uint64_t stx_size;
+ uint64_t stx_blocks;
+ uint64_t stx_attributes_mask;
+ struct {
+ int64_t tv_sec;
+ uint32_t tv_nsec;
+ int32_t pad;
+ } stx_atime, stx_btime, stx_ctime, stx_mtime;
+ uint32_t stx_rdev_major;
+ uint32_t stx_rdev_minor;
+ uint32_t stx_dev_major;
+ uint32_t stx_dev_minor;
+ uint64_t spare[14];
+};
+
+static int fstatat_statx(int fd, const char *restrict path, struct stat *restrict st, int flag)
+{
+ struct statx stx;
+
+ flag |= AT_NO_AUTOMOUNT;
+ int ret = __syscall(SYS_statx, fd, path, flag, 0x7ff, &stx);
+ if (ret) return ret;
+
+ *st = (struct stat){
+ .st_dev = makedev(stx.stx_dev_major, stx.stx_dev_minor),
+ .st_ino = stx.stx_ino,
+ .st_mode = stx.stx_mode,
+ .st_nlink = stx.stx_nlink,
+ .st_uid = stx.stx_uid,
+ .st_gid = stx.stx_gid,
+ .st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor),
+ .st_size = stx.stx_size,
+ .st_blksize = stx.stx_blksize,
+ .st_blocks = stx.stx_blocks,
+ .st_atim.tv_sec = stx.stx_atime.tv_sec,
+ .st_atim.tv_nsec = stx.stx_atime.tv_nsec,
+ .st_mtim.tv_sec = stx.stx_mtime.tv_sec,
+ .st_mtim.tv_nsec = stx.stx_mtime.tv_nsec,
+ .st_ctim.tv_sec = stx.stx_ctime.tv_sec,
+ .st_ctim.tv_nsec = stx.stx_ctime.tv_nsec,
+#if _REDIR_TIME64
+ .__st_atim32.tv_sec = stx.stx_atime.tv_sec,
+ .__st_atim32.tv_nsec = stx.stx_atime.tv_nsec,
+ .__st_mtim32.tv_sec = stx.stx_mtime.tv_sec,
+ .__st_mtim32.tv_nsec = stx.stx_mtime.tv_nsec,
+ .__st_ctim32.tv_sec = stx.stx_ctime.tv_sec,
+ .__st_ctim32.tv_nsec = stx.stx_ctime.tv_nsec,
+#endif
+ };
+ return 0;
+}
+
+#ifdef SYS_fstatat
+
+#include "kstat.h"
+
+static int fstatat_kstat(int fd, const char *restrict path, struct stat *restrict st, int flag)
+{
+ int ret;
+ struct kstat kst;
+
+ if (flag==AT_EMPTY_PATH && fd>=0 && !*path) {
+ ret = __syscall(SYS_fstat, fd, &kst);
+ if (ret==-EBADF && __syscall(SYS_fcntl, fd, F_GETFD)>=0) {
+ ret = __syscall(SYS_fstatat, fd, path, &kst, flag);
+ if (ret==-EINVAL) {
+ char buf[15+3*sizeof(int)];
+ __procfdname(buf, fd);
+#ifdef SYS_stat
+ ret = __syscall(SYS_stat, buf, &kst);
+#else
+ ret = __syscall(SYS_fstatat, AT_FDCWD, buf, &kst, 0);
+#endif
+ }
+ }
+ }
+#ifdef SYS_lstat
+ else if ((fd == AT_FDCWD || *path=='/') && flag==AT_SYMLINK_NOFOLLOW)
+ ret = __syscall(SYS_lstat, path, &kst);
+#endif
+#ifdef SYS_stat
+ else if ((fd == AT_FDCWD || *path=='/') && !flag)
+ ret = __syscall(SYS_stat, path, &kst);
+#endif
+ else ret = __syscall(SYS_fstatat, fd, path, &kst, flag);
+
+ if (ret) return ret;
+
+ *st = (struct stat){
+ .st_dev = kst.st_dev,
+ .st_ino = kst.st_ino,
+ .st_mode = kst.st_mode,
+ .st_nlink = kst.st_nlink,
+ .st_uid = kst.st_uid,
+ .st_gid = kst.st_gid,
+ .st_rdev = kst.st_rdev,
+ .st_size = kst.st_size,
+ .st_blksize = kst.st_blksize,
+ .st_blocks = kst.st_blocks,
+ .st_atim.tv_sec = kst.st_atime_sec,
+ .st_atim.tv_nsec = kst.st_atime_nsec,
+ .st_mtim.tv_sec = kst.st_mtime_sec,
+ .st_mtim.tv_nsec = kst.st_mtime_nsec,
+ .st_ctim.tv_sec = kst.st_ctime_sec,
+ .st_ctim.tv_nsec = kst.st_ctime_nsec,
+#if _REDIR_TIME64
+ .__st_atim32.tv_sec = kst.st_atime_sec,
+ .__st_atim32.tv_nsec = kst.st_atime_nsec,
+ .__st_mtim32.tv_sec = kst.st_mtime_sec,
+ .__st_mtim32.tv_nsec = kst.st_mtime_nsec,
+ .__st_ctim32.tv_sec = kst.st_ctime_sec,
+ .__st_ctim32.tv_nsec = kst.st_ctime_nsec,
+#endif
+ };
+
+ return 0;
+}
+#endif
+
+int __fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag)
{
- return syscall(SYS_fstatat, fd, path, buf, flag);
+ int ret;
+#ifdef SYS_fstatat
+ if (sizeof((struct kstat){0}.st_atime_sec) < sizeof(time_t)) {
+ ret = fstatat_statx(fd, path, st, flag);
+ if (ret!=-ENOSYS) return __syscall_ret(ret);
+ }
+ ret = fstatat_kstat(fd, path, st, flag);
+#else
+ ret = fstatat_statx(fd, path, st, flag);
+#endif
+ return __syscall_ret(ret);
}
-weak_alias(fstatat, fstatat64);
+weak_alias(__fstatat, fstatat);
diff --git a/src/stat/lstat.c b/src/stat/lstat.c
index 5b89f290..6822fcae 100644
--- a/src/stat/lstat.c
+++ b/src/stat/lstat.c
@@ -1,14 +1,7 @@
#include <sys/stat.h>
#include <fcntl.h>
-#include "syscall.h"
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);
diff --git a/src/stat/stat.c b/src/stat/stat.c
index 0bec9d6f..23570e7a 100644
--- a/src/stat/stat.c
+++ b/src/stat/stat.c
@@ -1,14 +1,7 @@
#include <sys/stat.h>
#include <fcntl.h>
-#include "syscall.h"
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);
diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c
index f65d1b54..bc12da8b 100644
--- a/src/stat/statvfs.c
+++ b/src/stat/statvfs.c
@@ -39,6 +39,7 @@ static void fixup(struct statvfs *out, const struct statfs *in)
out->f_fsid = in->f_fsid.__val[0];
out->f_flag = in->f_flags;
out->f_namemax = in->f_namelen;
+ out->f_type = in->f_type;
}
int statvfs(const char *restrict path, struct statvfs *restrict buf)
@@ -56,8 +57,3 @@ int fstatvfs(int fd, struct statvfs *buf)
fixup(buf, &kbuf);
return 0;
}
-
-weak_alias(statvfs, statvfs64);
-weak_alias(statfs, statfs64);
-weak_alias(fstatvfs, fstatvfs64);
-weak_alias(fstatfs, fstatfs64);
diff --git a/src/stat/utimensat.c b/src/stat/utimensat.c
index 159c8be3..730723a9 100644
--- a/src/stat/utimensat.c
+++ b/src/stat/utimensat.c
@@ -4,28 +4,51 @@
#include <errno.h>
#include "syscall.h"
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define NS_SPECIAL(ns) ((ns)==UTIME_NOW || (ns)==UTIME_OMIT)
+
int utimensat(int fd, const char *path, const struct timespec times[2], int flags)
{
- int r = __syscall(SYS_utimensat, fd, path, times, flags);
+ int r;
+ if (times && times[0].tv_nsec==UTIME_NOW && times[1].tv_nsec==UTIME_NOW)
+ times = 0;
+#ifdef SYS_utimensat_time64
+ r = -ENOSYS;
+ time_t s0=0, s1=0;
+ long ns0=0, ns1=0;
+ if (times) {
+ ns0 = times[0].tv_nsec;
+ ns1 = times[1].tv_nsec;
+ if (!NS_SPECIAL(ns0)) s0 = times[0].tv_sec;
+ if (!NS_SPECIAL(ns1)) s1 = times[1].tv_sec;
+ }
+ if (SYS_utimensat == SYS_utimensat_time64 || !IS32BIT(s0) || !IS32BIT(s1))
+ r = __syscall(SYS_utimensat_time64, fd, path, times ?
+ ((long long[]){s0, ns0, s1, ns1}) : 0, flags);
+ if (SYS_utimensat == SYS_utimensat_time64 || r!=-ENOSYS)
+ return __syscall_ret(r);
+ if (!IS32BIT(s0) || !IS32BIT(s1))
+ return __syscall_ret(-ENOTSUP);
+ r = __syscall(SYS_utimensat, fd, path,
+ times ? ((long[]){s0, ns0, s1, ns1}) : 0, flags);
+#else
+ r = __syscall(SYS_utimensat, fd, path, times, flags);
+#endif
+
#ifdef SYS_futimesat
if (r != -ENOSYS || flags) return __syscall_ret(r);
- struct timeval *tv = 0, tmp[2];
+ long *tv=0, tmp[4];
if (times) {
int i;
tv = tmp;
for (i=0; i<2; i++) {
if (times[i].tv_nsec >= 1000000000ULL) {
- if (times[i].tv_nsec == UTIME_NOW &&
- times[1-i].tv_nsec == UTIME_NOW) {
- tv = 0;
- break;
- }
- if (times[i].tv_nsec == UTIME_OMIT)
+ if (NS_SPECIAL(times[i].tv_nsec))
return __syscall_ret(-ENOSYS);
return __syscall_ret(-EINVAL);
}
- tmp[i].tv_sec = times[i].tv_sec;
- tmp[i].tv_usec = times[i].tv_nsec / 1000;
+ tmp[2*i+0] = times[i].tv_sec;
+ tmp[2*i+1] = times[i].tv_nsec / 1000;
}
}