aboutsummaryrefslogtreecommitdiffstats
path: root/ports
diff options
context:
space:
mode:
Diffstat (limited to 'ports')
-rw-r--r--ports/linux/guts/close_range.c20
-rw-r--r--ports/linux/guts/closefrom.c16
-rw-r--r--ports/linux/guts/fcntl.c26
-rw-r--r--ports/linux/guts/fcntl64.c99
-rw-r--r--ports/linux/guts/fstatat.c15
-rw-r--r--ports/linux/guts/fstatat64.c15
-rw-r--r--ports/linux/guts/lchmod.c14
-rw-r--r--ports/linux/guts/mkostemp64.c53
-rw-r--r--ports/linux/guts/mkstemp64.c37
-rw-r--r--ports/linux/guts/openat.c26
-rw-r--r--ports/linux/nostatx/portdefs.h38
-rw-r--r--ports/linux/portdefs.h21
-rw-r--r--ports/linux/pseudo_wrappers.c58
-rw-r--r--ports/linux/statvfs/guts/statvfs64.c15
-rw-r--r--ports/linux/statvfs/wrapfuncs.in1
-rw-r--r--ports/linux/statx/guts/statx.c42
-rw-r--r--ports/linux/statx/portdefs.h6
-rw-r--r--ports/linux/statx/wrapfuncs.in1
-rwxr-xr-xports/linux/subports20
-rw-r--r--ports/linux/wrapfuncs.in28
-rw-r--r--ports/linux/xattr/portdefs.h6
-rw-r--r--ports/linux/xattr/pseudo_wrappers.c8
-rw-r--r--ports/linux/xattr/wrapfuncs.in24
-rw-r--r--ports/unix/guts/access.c2
-rw-r--r--ports/unix/guts/faccessat.c15
-rw-r--r--ports/unix/guts/faccessat2.c46
-rw-r--r--ports/unix/guts/fchmodat.c15
-rw-r--r--ports/unix/guts/linkat.c1
-rw-r--r--ports/unix/guts/realpath.c9
-rw-r--r--ports/unix/guts/rename.c49
-rw-r--r--ports/unix/guts/renameat.c48
-rwxr-xr-xports/unix/subports2
-rw-r--r--ports/unix/wrapfuncs.in24
33 files changed, 670 insertions, 130 deletions
diff --git a/ports/linux/guts/close_range.c b/ports/linux/guts/close_range.c
new file mode 100644
index 0000000..4bd2fe1
--- /dev/null
+++ b/ports/linux/guts/close_range.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021 Richard Purdie
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int close_range(unsigned int lowfd, unsigned int maxfd, int flags)
+ * int rc = -1;
+ */
+
+ (void) lowfd;
+ (void) maxfd;
+ (void) flags;
+ /* for now pretend the kernel doesn't support it regardless
+ which users are supposed to be able to handle */
+ errno = ENOSYS;
+ rc = -1;
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/guts/closefrom.c b/ports/linux/guts/closefrom.c
new file mode 100644
index 0000000..1350506
--- /dev/null
+++ b/ports/linux/guts/closefrom.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021 Richard Purdie
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * void closefrom(int fd)
+ */
+ pseudo_msg_t *msg;
+ /* this cleans up internal tables, and shouldn't make it to the server. Avoids pseudo's internal fds */
+ msg = pseudo_client_op(OP_CLOSEFROM, 0, fd, -1, 0, 0);
+ /* fds between fd and msg->fd are closed within the above function avoiding pseudo's own fds */
+ real_closefrom(msg->fd);
+
+/* return;
+ * }
+ */
diff --git a/ports/linux/guts/fcntl.c b/ports/linux/guts/fcntl.c
index 4dd9796..ffb50be 100644
--- a/ports/linux/guts/fcntl.c
+++ b/ports/linux/guts/fcntl.c
@@ -8,6 +8,22 @@
* wrap_fcntl(int fd, int cmd, ...struct flock *lock) {
* int rc = -1;
*/
+#if !defined(F_GETPIPE_SZ)
+#define F_GETPIPE_SZ (1032)
+#endif
+
+#if F_GETPIPE_SZ != 1032
+#error System F_GETPIPE_SZ has unexpected value
+#endif
+
+#if !defined(F_SETPIPE_SZ)
+#define F_SETPIPE_SZ (1031)
+#endif
+
+#if F_SETPIPE_SZ != 1031
+#error System F_SETPIPE_SZ has unexpected value
+#endif
+
long arg;
int save_errno;
@@ -31,12 +47,17 @@
}
errno = save_errno;
break;
+ case F_SETPIPE_SZ:
+ /* actually do something */
+ rc = real_fcntl(fd, cmd, arg);
+ break;
/* no argument: */
case F_GETFD:
case F_GETFL:
case F_GETOWN:
case F_GETSIG:
case F_GETLEASE:
+ case F_GETPIPE_SZ:
rc = real_fcntl(fd, cmd);
break;
/* long argument */
@@ -52,6 +73,11 @@
case F_GETLK:
case F_SETLK:
case F_SETLKW:
+#ifdef F_OFD_GETLK
+ case F_OFD_GETLK:
+ case F_OFD_SETLK:
+ case F_OFD_SETLKW:
+#endif
rc = real_fcntl(fd, cmd, lock);
break;
#if defined(F_GETLK64) && (F_GETLK64 != F_GETLK)
diff --git a/ports/linux/guts/fcntl64.c b/ports/linux/guts/fcntl64.c
new file mode 100644
index 0000000..99de43d
--- /dev/null
+++ b/ports/linux/guts/fcntl64.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2008-2010 Wind River Systems; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * wrap_fcntl64(int fd, int cmd, ...struct flock *lock) {
+ * int rc = -1;
+ */
+#if !defined(F_GETPIPE_SZ)
+#define F_GETPIPE_SZ (1032)
+#endif
+
+#if F_GETPIPE_SZ != 1032
+#error System F_GETPIPE_SZ has unexpected value
+#endif
+
+#if !defined(F_SETPIPE_SZ)
+#define F_SETPIPE_SZ (1031)
+#endif
+
+#if F_SETPIPE_SZ != 1031
+#error System F_SETPIPE_SZ has unexpected value
+#endif
+
+ long arg;
+ int save_errno;
+
+ /* we don't know whether we need lock or arg; grab both, which
+ * should be safe enough on Linuxy systems. */
+ va_start(ap, cmd);
+ arg = va_arg(ap, long);
+ va_end(ap);
+
+ switch (cmd) {
+ case F_DUPFD:
+#ifdef F_DUPFD_CLOEXEC
+ case F_DUPFD_CLOEXEC:
+#endif
+ /* actually do something */
+ rc = real_fcntl64(fd, cmd, arg);
+ save_errno = errno;
+ if (rc != -1) {
+ pseudo_debug(PDBGF_OP, "fcntl64_dup: %d->%d\n", fd, rc);
+ pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0);
+ }
+ errno = save_errno;
+ break;
+ case F_SETPIPE_SZ:
+ /* actually do something */
+ rc = real_fcntl64(fd, cmd, arg);
+ break;
+ /* no argument: */
+ case F_GETFD:
+ case F_GETFL:
+ case F_GETOWN:
+ case F_GETSIG:
+ case F_GETLEASE:
+ case F_GETPIPE_SZ:
+ rc = real_fcntl64(fd, cmd);
+ break;
+ /* long argument */
+ case F_SETFD:
+ case F_SETFL:
+ case F_SETOWN:
+ case F_SETSIG:
+ case F_SETLEASE:
+ case F_NOTIFY:
+ rc = real_fcntl64(fd, cmd, arg);
+ break;
+ /* struct flock * argument */
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+#ifdef F_OFD_GETLK
+ case F_OFD_GETLK:
+ case F_OFD_SETLK:
+ case F_OFD_SETLKW:
+#endif
+ rc = real_fcntl64(fd, cmd, lock);
+ break;
+#if defined(F_GETLK64) && (F_GETLK64 != F_GETLK)
+ /* the cast is safe, all struct pointers must smell the same */
+ case F_GETLK64:
+ case F_SETLK64:
+ case F_SETLKW64:
+ rc = real_fcntl64(fd, cmd, (struct flock64 *) lock);
+ break;
+#endif
+ default:
+ pseudo_diag("unknown fcntl64 argument %d, assuming long argument.\n",
+ cmd);
+ rc = real_fcntl64(fd, cmd, arg);
+ break;
+ }
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/guts/fstatat.c b/ports/linux/guts/fstatat.c
new file mode 100644
index 0000000..3267641
--- /dev/null
+++ b/ports/linux/guts/fstatat.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021 Linux Foundation; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int fstatat(int dirfd, const char *path, struct stat *buf, int flags)
+ * int rc = -1;
+ */
+
+ rc = wrap___fxstatat(_STAT_VER, dirfd, path, buf, flags);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/guts/fstatat64.c b/ports/linux/guts/fstatat64.c
new file mode 100644
index 0000000..c981e14
--- /dev/null
+++ b/ports/linux/guts/fstatat64.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021 Linux Foundation; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int fstatat64(int dirfd, const char *path, struct stat64 *buf, int flags)
+ * int rc = -1;
+ */
+
+ rc = wrap___fxstatat64(_STAT_VER, dirfd, path, buf, flags);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/guts/lchmod.c b/ports/linux/guts/lchmod.c
new file mode 100644
index 0000000..da330a7
--- /dev/null
+++ b/ports/linux/guts/lchmod.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021 Linux Foundation
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * wrap_lchmod(const char *path, mode_t mode) {
+ */
+
+ rc = wrap_fchmodat(AT_FDCWD, path, mode, AT_SYMLINK_NOFOLLOW);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/guts/mkostemp64.c b/ports/linux/guts/mkostemp64.c
new file mode 100644
index 0000000..502211b
--- /dev/null
+++ b/ports/linux/guts/mkostemp64.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010 Wind River Systems; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * wrap_mkstemp64(char *template, int oflags) {
+ * int rc = -1;
+ */
+ struct stat64 buf;
+ int save_errno;
+ size_t len;
+ char *tmp_template;
+
+ if (!template) {
+ errno = EFAULT;
+ return 0;
+ }
+
+ len = strlen(template);
+ tmp_template = PSEUDO_ROOT_PATH(AT_FDCWD, template, AT_SYMLINK_NOFOLLOW);
+
+ if (!tmp_template) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* mkstemp64 wrapper uses this code and mkostemp64 not present in some glibc versions */
+ if (oflags == 0)
+ rc = real_mkstemp64(tmp_template);
+ else
+ rc = real_mkostemp64(tmp_template, oflags);
+
+ if (rc != -1) {
+ save_errno = errno;
+
+ if (real___fxstat64(_STAT_VER, rc, &buf) != -1) {
+ real_fchmod(rc, PSEUDO_FS_MODE(0600, 0));
+ pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf);
+ pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, &buf);
+ } else {
+ pseudo_debug(PDBGF_CONSISTENCY, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n",
+ rc, strerror(errno));
+ pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, 0);
+ }
+ errno = save_errno;
+ }
+ /* mkstemp only changes the XXXXXX at the end. */
+ memcpy(template + len - 6, tmp_template + strlen(tmp_template) - 6, 6);
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/guts/mkstemp64.c b/ports/linux/guts/mkstemp64.c
index aa7bb58..487f256 100644
--- a/ports/linux/guts/mkstemp64.c
+++ b/ports/linux/guts/mkstemp64.c
@@ -8,42 +8,9 @@
* wrap_mkstemp64(char *template) {
* int rc = -1;
*/
- struct stat64 buf;
- int save_errno;
- size_t len;
- char *tmp_template;
+ /* mkstemp64() is just like mkostemp64() with no flags */
+ rc = wrap_mkostemp64(template, 0);
- if (!template) {
- errno = EFAULT;
- return 0;
- }
-
- len = strlen(template);
- tmp_template = PSEUDO_ROOT_PATH(AT_FDCWD, template, AT_SYMLINK_NOFOLLOW);
-
- if (!tmp_template) {
- errno = ENOENT;
- return -1;
- }
-
- rc = real_mkstemp64(tmp_template);
-
- if (rc != -1) {
- save_errno = errno;
-
- if (real___fxstat64(_STAT_VER, rc, &buf) != -1) {
- real_fchmod(rc, PSEUDO_FS_MODE(0600, 0));
- pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf);
- pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, &buf);
- } else {
- pseudo_debug(PDBGF_CONSISTENCY, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n",
- rc, strerror(errno));
- pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, 0);
- }
- errno = save_errno;
- }
- /* mkstemp only changes the XXXXXX at the end. */
- memcpy(template + len - 6, tmp_template + strlen(tmp_template) - 6, 6);
/* return rc;
* }
*/
diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c
index 673ea6e..656ac2b 100644
--- a/ports/linux/guts/openat.c
+++ b/ports/linux/guts/openat.c
@@ -55,9 +55,13 @@
if (flags & O_CREAT) {
save_errno = errno;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
- rc = real___xstat64(_STAT_VER, path, &buf);
+ if (flags & O_NOFOLLOW) {
+ rc = real___lxstat64(_STAT_VER, path, &buf);
+ } else {
+ rc = real___xstat64(_STAT_VER, path, &buf);
+ }
#else
- rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0);
+ rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
#endif
existed = (rc != -1);
if (!existed)
@@ -72,9 +76,13 @@
if (!(flags & O_NONBLOCK) && ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_RDWR)) {
save_errno = errno;
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
- rc = real___xstat64(_STAT_VER, path, &buf);
+ if (flags & O_NOFOLLOW) {
+ rc = real___lxstat64(_STAT_VER, path, &buf);
+ } else {
+ rc = real___xstat64(_STAT_VER, path, &buf);
+ }
#else
- rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0);
+ rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
#endif
if (rc != -1 && S_ISFIFO(buf.st_mode)) {
overly_magic_nonblocking = 1;
@@ -126,11 +134,17 @@
}
#endif
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
- stat_rc = real___xstat64(_STAT_VER, path, &buf);
+ if (flags & O_NOFOLLOW) {
+ stat_rc = real___lxstat64(_STAT_VER, path, &buf);
+ } else {
+ stat_rc = real___xstat64(_STAT_VER, path, &buf);
+ }
#else
- stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0);
+ stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0);
#endif
+ pseudo_debug(PDBGF_FILE, "openat(path %s), flags %o, stat rc %d, stat mode %o\n",
+ path, flags, stat_rc, buf.st_mode);
if (stat_rc != -1) {
buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode);
if (!existed) {
diff --git a/ports/linux/nostatx/portdefs.h b/ports/linux/nostatx/portdefs.h
new file mode 100644
index 0000000..ded8ff9
--- /dev/null
+++ b/ports/linux/nostatx/portdefs.h
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Copy of the statx struct to allow a pseudo built on a system without
+ * statx to work on one with statx and hence work with OE's uninative
+ */
+
+struct statx_timestamp
+{
+ __int64_t tv_sec;
+ __uint32_t tv_nsec;
+ __int32_t __statx_timestamp_pad1[1];
+};
+
+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 __statx_pad1[1];
+ __uint64_t stx_ino;
+ __uint64_t stx_size;
+ __uint64_t stx_blocks;
+ __uint64_t stx_attributes_mask;
+ struct statx_timestamp stx_atime;
+ struct statx_timestamp stx_btime;
+ struct statx_timestamp stx_ctime;
+ struct statx_timestamp stx_mtime;
+ __uint32_t stx_rdev_major;
+ __uint32_t stx_rdev_minor;
+ __uint32_t stx_dev_major;
+ __uint32_t stx_dev_minor;
+ __uint64_t __statx_pad2[14];
+};
diff --git a/ports/linux/portdefs.h b/ports/linux/portdefs.h
index d419365..9545550 100644
--- a/ports/linux/portdefs.h
+++ b/ports/linux/portdefs.h
@@ -32,3 +32,24 @@ GLIBC_COMPAT_SYMBOL(memcpy,2.0);
#include <linux/capability.h>
#include <sys/syscall.h>
+#include <sys/prctl.h>
+#include <linux/seccomp.h>
+
+#ifndef _STAT_VER
+#if defined (__aarch64__)
+#define _STAT_VER 0
+#elif defined (__x86_64__)
+#define _STAT_VER 1
+#else
+#define _STAT_VER 3
+#endif
+#endif
+#ifndef _MKNOD_VER
+#if defined (__aarch64__)
+#define _MKNOD_VER 0
+#elif defined (__x86_64__)
+#define _MKNOD_VER 0
+#else
+#define _MKNOD_VER 1
+#endif
+#endif
diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c
index cd7e173..7659897 100644
--- a/ports/linux/pseudo_wrappers.c
+++ b/ports/linux/pseudo_wrappers.c
@@ -57,6 +57,7 @@ int pseudo_capset(cap_user_header_t hdrp, const cap_user_data_t datap) {
long
syscall(long number, ...) {
long rc = -1;
+ va_list ap;
if (!pseudo_check_wrappers() || !real_syscall) {
/* rc was initialized to the "failure" value */
@@ -77,11 +78,25 @@ syscall(long number, ...) {
(void) number;
#endif
+#ifdef SYS_seccomp
+ /* pseudo and seccomp are incompatible as pseudo uses different syscalls
+ * so pretend to enable seccomp but really do nothing */
+ if (number == SYS_seccomp) {
+ unsigned long cmd;
+ va_start(ap, number);
+ cmd = va_arg(ap, unsigned long);
+ va_end(ap);
+ if (cmd == SECCOMP_SET_MODE_FILTER) {
+ return 0;
+ }
+ }
+#endif
+
/* gcc magic to attempt to just pass these args to syscall. we have to
* guess about the number of args; the docs discuss calling conventions
* up to 7, so let's try that?
*/
- void *res = __builtin_apply((void (*)()) real_syscall, __builtin_apply_args(), sizeof(long) * 7);
+ void *res = __builtin_apply((void (*)(void)) real_syscall, __builtin_apply_args(), sizeof(long) * 7);
__builtin_return(res);
}
@@ -92,3 +107,44 @@ static long wrap_syscall(long nr, va_list ap) {
(void) ap;
return -1;
}
+
+int
+prctl(int option, ...) {
+ int rc = -1;
+ va_list ap;
+
+ if (!pseudo_check_wrappers() || !real_prctl) {
+ /* rc was initialized to the "failure" value */
+ pseudo_enosys("prctl");
+ return rc;
+ }
+
+#ifdef SECCOMP_SET_MODE_FILTER
+ /* pseudo and seccomp are incompatible as pseudo uses different syscalls
+ * so pretend to enable seccomp but really do nothing */
+ if (option == PR_SET_SECCOMP) {
+ unsigned long cmd;
+ va_start(ap, option);
+ cmd = va_arg(ap, unsigned long);
+ va_end(ap);
+ if (cmd == SECCOMP_SET_MODE_FILTER) {
+ return 0;
+ }
+ }
+#endif
+
+ /* gcc magic to attempt to just pass these args to prctl. we have to
+ * guess about the number of args; the docs discuss calling conventions
+ * up to 5, so let's try that?
+ */
+ void *res = __builtin_apply((void (*)(void)) real_prctl, __builtin_apply_args(), sizeof(long) * 5);
+ __builtin_return(res);
+}
+
+/* unused.
+ */
+static int wrap_prctl(int option, va_list ap) {
+ (void) option;
+ (void) ap;
+ return -1;
+}
diff --git a/ports/linux/statvfs/guts/statvfs64.c b/ports/linux/statvfs/guts/statvfs64.c
new file mode 100644
index 0000000..856d3db
--- /dev/null
+++ b/ports/linux/statvfs/guts/statvfs64.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018 Wind River Systems; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int statvfs64(const char *path, struct statvfs64 *buf)
+ * int rc = -1;
+ */
+
+ rc = real_statvfs64(path, buf);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/statvfs/wrapfuncs.in b/ports/linux/statvfs/wrapfuncs.in
index 1afb64d..6a59660 100644
--- a/ports/linux/statvfs/wrapfuncs.in
+++ b/ports/linux/statvfs/wrapfuncs.in
@@ -1 +1,2 @@
int statvfs(const char *path, struct statvfs *buf);
+int statvfs64(const char *path, struct statvfs64 *buf);
diff --git a/ports/linux/statx/guts/statx.c b/ports/linux/statx/guts/statx.c
new file mode 100644
index 0000000..42aebe5
--- /dev/null
+++ b/ports/linux/statx/guts/statx.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Linux Foundation
+ * Author: Richard Purdie
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * int
+ * statx(int dirfd, const char *path, int flags, unsigned int mask, struct statx *statxbuf) {
+ * int rc = -1;
+ */
+ pseudo_msg_t *msg;
+ PSEUDO_STATBUF buf;
+ int save_errno;
+
+ rc = real_statx(dirfd, path, flags, mask, statxbuf);
+ save_errno = errno;
+ if (rc == -1) {
+ return rc;
+ }
+
+ buf.st_uid = statxbuf->stx_uid;
+ buf.st_gid = statxbuf->stx_gid;
+ buf.st_dev = makedev(statxbuf->stx_dev_major, statxbuf->stx_dev_minor);
+ buf.st_ino = statxbuf->stx_ino;
+ buf.st_mode = statxbuf->stx_mode;
+ buf.st_rdev = makedev(statxbuf->stx_rdev_major, statxbuf->stx_rdev_minor);
+ buf.st_nlink = statxbuf->stx_nlink;
+ msg = pseudo_client_op(OP_STAT, 0, -1, dirfd, path, &buf);
+ if (msg && msg->result == RESULT_SUCCEED) {
+ pseudo_debug(PDBGF_FILE, "statx(path %s), flags %o, stat rc %d, stat uid %o\n", path, flags, rc, statxbuf->stx_uid);
+ statxbuf->stx_uid = msg->uid;
+ statxbuf->stx_gid = msg->gid;
+ statxbuf->stx_mode = msg->mode;
+ statxbuf->stx_rdev_major = major(msg->rdev);
+ statxbuf->stx_rdev_minor = minor(msg->rdev);
+ } else {
+ pseudo_debug(PDBGF_FILE, "statx(path %s) failed, flags %o, stat rc %d, stat uid %o\n", path, flags, rc, statxbuf->stx_uid);
+ }
+ errno = save_errno;
+/* return rc;
+ * }
+ */
diff --git a/ports/linux/statx/portdefs.h b/ports/linux/statx/portdefs.h
new file mode 100644
index 0000000..bf934dc
--- /dev/null
+++ b/ports/linux/statx/portdefs.h
@@ -0,0 +1,6 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
diff --git a/ports/linux/statx/wrapfuncs.in b/ports/linux/statx/wrapfuncs.in
new file mode 100644
index 0000000..168234f
--- /dev/null
+++ b/ports/linux/statx/wrapfuncs.in
@@ -0,0 +1 @@
+int statx(int dirfd, const char *path, int flags, unsigned int mask, struct statx *statxbuf);
diff --git a/ports/linux/subports b/ports/linux/subports
index a29044a..099ea59 100755
--- a/ports/linux/subports
+++ b/ports/linux/subports
@@ -29,11 +29,12 @@ fi
if $port_xattr; then
cat > dummy.c <<EOF
#include <sys/types.h>
-#include <attr/xattr.h>
+#include <sys/xattr.h>
+#include <attr/attributes.h>
int i;
EOF
if ! ${CC} -c -o dummy.o dummy.c >/dev/null 2>&1; then
- echo >&2 "Warning: Can't compile trivial program using <attr/xattr.h>".
+ echo >&2 "Warning: Can't compile trivial program using <attr/attributes.h>".
echo >&2 " xattr support will require that header."
fi
echo "linux/xattr"
@@ -54,3 +55,18 @@ else
fi
rm -f dummy.c dummy.o
+# For statx, we want a pseudo which can work with OE's uninative, i.e. build on a system without
+# statx but work on one with it. We have a header in nostatx to allow this.
+cat > dummy.c <<EOF
+#define _GNU_SOURCE
+#include <sys/stat.h>
+struct statx x;
+EOF
+if ${CC} -c -o dummy.o dummy.c >/dev/null 2>&1; then
+ echo "linux/statx"
+else
+ echo "linux/nostatx"
+ echo "linux/statx"
+fi
+rm -f dummy.c dummy.o
+
diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in
index 4cdbc9c..97b16c2 100644
--- a/ports/linux/wrapfuncs.in
+++ b/ports/linux/wrapfuncs.in
@@ -1,41 +1,46 @@
-int open(const char *path, int flags, ...{mode_t mode}); /* flags=flags|O_NOFOLLOW */
+int open(const char *path, int flags, ...{mode_t mode}); /* flags=flags&O_NOFOLLOW, noignore_path=1 */
char *get_current_dir_name(void);
int __xstat(int ver, const char *path, struct stat *buf);
int __lxstat(int ver, const char *path, struct stat *buf); /* flags=AT_SYMLINK_NOFOLLOW */
int __fxstat(int ver, int fd, struct stat *buf);
+int lchmod(const char *path, mode_t mode); /* flags=AT_SYMLINK_NOFOLLOW */
int lchown(const char *path, uid_t owner, gid_t group); /* flags=AT_SYMLINK_NOFOLLOW */
int __fxstatat(int ver, int dirfd, const char *path, struct stat *buf, int flags);
-int openat(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=flags|O_NOFOLLOW */
-int __openat_2(int dirfd, const char *path, int flags); /* flags=flags|O_NOFOLLOW */
+int openat(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=flags&O_NOFOLLOW, noignore_path=1 */
+int __openat_2(int dirfd, const char *path, int flags); /* flags=flags&O_NOFOLLOW, noignore_path=1 */
int mknod(const char *path, mode_t mode, dev_t dev); /* real_func=pseudo_mknod */
int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev); /* real_func=pseudo_mknodat */
int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev); /* flags=AT_SYMLINK_NOFOLLOW */
int __xmknodat(int ver, int dirfd, const char *path, mode_t mode, dev_t *dev); /* flags=AT_SYMLINK_NOFOLLOW */
-int fcntl(int fd, int cmd, ...{struct flock *lock});
+int fcntl(int fd, int cmd, ...{struct flock *lock}); /* noignore_path=1 */
+int fcntl64(int fd, int cmd, ...{struct flock *lock}); /* noignore_path=1 */
# just so we know the inums of symlinks
char *canonicalize_file_name(const char *filename);
int eaccess(const char *path, int mode);
-int open64(const char *path, int flags, ...{mode_t mode}); /* flags=flags|O_NOFOLLOW */
-int openat64(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=flags|O_NOFOLLOW */
-int __openat64_2(int dirfd, const char *path, int flags); /* flags=flags|O_NOFOLLOW */
+int open64(const char *path, int flags, ...{mode_t mode}); /* flags=flags&O_NOFOLLOW, noignore_path=1 */
+int openat64(int dirfd, const char *path, int flags, ...{mode_t mode}); /* flags=flags&O_NOFOLLOW, noignore_path=1 */
+int __openat64_2(int dirfd, const char *path, int flags); /* flags=flags&O_NOFOLLOW, noignore_path=1 */
int creat64(const char *path, mode_t mode);
int stat(const char *path, struct stat *buf); /* real_func=pseudo_stat */
int lstat(const char *path, struct stat *buf); /* real_func=pseudo_lstat, flags=AT_SYMLINK_NOFOLLOW */
int fstat(int fd, struct stat *buf); /* real_func=pseudo_fstat */
+int fstatat(int dirfd, const char *path, struct stat *buf, int flags);
int stat64(const char *path, struct stat64 *buf); /* real_func=pseudo_stat64 */
int lstat64(const char *path, struct stat64 *buf); /* real_func=pseudo_lstat64, flags=AT_SYMLINK_NOFOLLOW */
int fstat64(int fd, struct stat64 *buf); /* real_func=pseudo_fstat64 */
+int fstatat64(int dirfd, const char *path, struct stat64 *buf, int flags);
int __xstat64(int ver, const char *path, struct stat64 *buf);
int __lxstat64(int ver, const char *path, struct stat64 *buf); /* flags=AT_SYMLINK_NOFOLLOW */
int __fxstat64(int ver, int fd, struct stat64 *buf);
int __fxstatat64(int ver, int dirfd, const char *path, struct stat64 *buf, int flags);
-FILE *fopen64(const char *path, const char *mode);
-int nftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int, struct FTW *), int nopenfd, int flag);
-FILE *freopen64(const char *path, const char *mode, FILE *stream);
+FILE *fopen64(const char *path, const char *mode); /* noignore_path=1 */
+int nftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int, struct FTW *), int nopenfd, int flag); /* noignore_path=1 */
+FILE *freopen64(const char *path, const char *mode, FILE *stream); /* noignore_path=1 */
int ftw64(const char *path, int (*fn)(const char *, const struct stat64 *, int), int nopenfd);
int glob64(const char *pattern, int flags, int (*errfunc)(const char *, int), glob64_t *pglob);
int scandir64(const char *path, struct dirent64 ***namelist, int (*filter)(const struct dirent64 *), int (*compar)());
int truncate64(const char *path, off64_t length);
+int mkostemp64(char *template, int oflags); /* flags=AT_SYMLINK_NOFOLLOW */
int mkstemp64(char *template); /* flags=AT_SYMLINK_NOFOLLOW */
int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
int setgroups(size_t size, const gid_t *list);
@@ -56,3 +61,6 @@ int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbuf
int capset(cap_user_header_t hdrp, const cap_user_data_t datap); /* real_func=pseudo_capset */
long syscall(long nr, ...); /* hand_wrapped=1 */
int renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags); /* flags=AT_SYMLINK_NOFOLLOW */
+int prctl(int option, ...); /* hand_wrapped=1 */
+int close_range(unsigned int lowfd, unsigned int maxfd, int flags);
+void closefrom(int fd);
diff --git a/ports/linux/xattr/portdefs.h b/ports/linux/xattr/portdefs.h
index 56cd3ca..beab7d0 100644
--- a/ports/linux/xattr/portdefs.h
+++ b/ports/linux/xattr/portdefs.h
@@ -2,5 +2,9 @@
* SPDX-License-Identifier: LGPL-2.1-only
*
*/
-#include <attr/xattr.h>
+#include <sys/xattr.h>
#include <stdint.h>
+
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
diff --git a/ports/linux/xattr/pseudo_wrappers.c b/ports/linux/xattr/pseudo_wrappers.c
index 590af30..0b65920 100644
--- a/ports/linux/xattr/pseudo_wrappers.c
+++ b/ports/linux/xattr/pseudo_wrappers.c
@@ -134,7 +134,7 @@ static ssize_t shared_getxattr(const char *path, int fd, const char *name, void
pseudo_debug(PDBGF_XATTR, "getxattr(%s [fd %d], %s)\n",
path ? path : "<no path>", fd, name);
pseudo_msg_t *result = pseudo_client_op(OP_GET_XATTR, 0, fd, -1, path, &buf, name);
- if (result->result != RESULT_SUCCEED) {
+ if (!result || result->result != RESULT_SUCCEED) {
errno = ENOATTR;
return -1;
}
@@ -197,7 +197,7 @@ static int shared_setxattr(const char *path, int fd, const char *name, const voi
mode |= get_special_bits(path, fd);
pseudo_debug(PDBGF_XATTR, "posix_acl_access translated to mode %04o. Remaining attribute(s): %d.\n",
mode, extra);
- buf.st_mode = mode;
+
/* we want to actually issue a corresponding chmod,
* as well, or else the file ends up 0600 on the
* host. Using the slightly-less-efficient wrap_chmod
@@ -254,7 +254,7 @@ static int shared_setxattr(const char *path, int fd, const char *name, const voi
static ssize_t shared_listxattr(const char *path, int fd, char *list, size_t size) {
RC_AND_BUF
pseudo_msg_t *result = pseudo_client_op(OP_LIST_XATTR, 0, fd, -1, path, &buf);
- if (result->result != RESULT_SUCCEED) {
+ if (!result || result->result != RESULT_SUCCEED) {
pseudo_debug(PDBGF_XATTR, "listxattr: no success.\n");
errno = ENOATTR;
return -1;
@@ -276,7 +276,7 @@ static int shared_removexattr(const char *path, int fd, const char *name) {
RC_AND_BUF
pseudo_msg_t *result = pseudo_client_op(OP_REMOVE_XATTR, 0, fd, -1, path, &buf, name);
- if (result->result != RESULT_SUCCEED) {
+ if (!result || result->result != RESULT_SUCCEED) {
/* docs say ENOATTR, but I don't have one */
errno = ENOENT;
return -1;
diff --git a/ports/linux/xattr/wrapfuncs.in b/ports/linux/xattr/wrapfuncs.in
index c37f78a..09eba23 100644
--- a/ports/linux/xattr/wrapfuncs.in
+++ b/ports/linux/xattr/wrapfuncs.in
@@ -1,12 +1,12 @@
-ssize_t getxattr(const char *path, const char *name, void *value, size_t size); /* flags=0 */
-ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size); /* flags=AT_SYMLINK_NOFOLLOW */
-ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size);
-int setxattr(const char *path, const char *name, const void *value, size_t size, int xflags); /* flags=0 */
-int lsetxattr(const char *path, const char *name, const void *value, size_t size, int xflags); /* flags=AT_SYMLINK_NOFOLLOW */
-int fsetxattr(int filedes, const char *name, const void *value, size_t size, int xflags);
-ssize_t listxattr(const char *path, char *list, size_t size); /* flags=0 */
-ssize_t llistxattr(const char *path, char *list, size_t size); /* flags=AT_SYMLINK_NOFOLLOW */
-ssize_t flistxattr(int filedes, char *list, size_t size);
-int removexattr(const char *path, const char *name); /* flags=0 */
-int lremovexattr(const char *path, const char *name); /* flags=AT_SYMLINK_NOFOLLOW */
-int fremovexattr(int filedes, const char *name);
+ssize_t getxattr(const char *path, const char *name, void *value, size_t size); /* flags=0, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size); /* flags=AT_SYMLINK_NOFOLLOW, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size); /* version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+int setxattr(const char *path, const char *name, const void *value, size_t size, int xflags); /* flags=0, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+int lsetxattr(const char *path, const char *name, const void *value, size_t size, int xflags); /* flags=AT_SYMLINK_NOFOLLOW, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+int fsetxattr(int filedes, const char *name, const void *value, size_t size, int xflags); /* version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+ssize_t listxattr(const char *path, char *list, size_t size); /* flags=0, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+ssize_t llistxattr(const char *path, char *list, size_t size); /* flags=AT_SYMLINK_NOFOLLOW, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+ssize_t flistxattr(int filedes, char *list, size_t size); /* version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+int removexattr(const char *path, const char *name); /* flags=0, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+int lremovexattr(const char *path, const char *name); /* flags=AT_SYMLINK_NOFOLLOW, version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
+int fremovexattr(int filedes, const char *name); /* version="GLIBC_2.3", version-aarch64="GLIBC_2.17" */
diff --git a/ports/unix/guts/access.c b/ports/unix/guts/access.c
index 1cc8d58..4725f49 100644
--- a/ports/unix/guts/access.c
+++ b/ports/unix/guts/access.c
@@ -21,7 +21,7 @@
if (buf.st_mode & 0111) {
return 0;
} else {
- errno = EPERM;
+ errno = EACCES;
return -1;
}
} else {
diff --git a/ports/unix/guts/faccessat.c b/ports/unix/guts/faccessat.c
new file mode 100644
index 0000000..02515ee
--- /dev/null
+++ b/ports/unix/guts/faccessat.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Linux Foundation; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * wrap_fsaccessat(int dirfd, const char *path, int mode, int flags) {
+ * int rc = -1;
+ */
+ rc = wrap_faccessat2(dirfd, path, mode, flags);
+
+/* return rc;
+ * }
+ */
diff --git a/ports/unix/guts/faccessat2.c b/ports/unix/guts/faccessat2.c
new file mode 100644
index 0000000..1283cc6
--- /dev/null
+++ b/ports/unix/guts/faccessat2.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, Linux Foundation; see
+ * guts/COPYRIGHT for information.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * wrap_fsaccessat2(int dirfd, const char *path, int mode, int flags) {
+ * int rc = -1;
+ */
+ PSEUDO_STATBUF buf;
+
+#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
+ if (dirfd != AT_FDCWD) {
+ errno = ENOSYS;
+ return -1;
+ }
+ if (flags & AT_SYMLINK_NOFOLLOW) {
+ rc = base_lstat(path, &buf);
+ } else {
+ rc = base_stat(path, &buf);
+ }
+#else
+ rc = base_fstatat(dirfd, path, &buf, flags & AT_SYMLINK_NOFOLLOW);
+#endif
+ if (rc == -1)
+ return rc;
+
+ /* note: no attempt to handle the case where user isn't
+ * root.
+ */
+
+ if (mode & X_OK) {
+ if (buf.st_mode & 0111) {
+ return 0;
+ } else {
+ errno = EACCES;
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+
+/* return rc;
+ * }
+ */
diff --git a/ports/unix/guts/fchmodat.c b/ports/unix/guts/fchmodat.c
index 55dbd35..5a31151 100644
--- a/ports/unix/guts/fchmodat.c
+++ b/ports/unix/guts/fchmodat.c
@@ -11,16 +11,16 @@
PSEUDO_STATBUF buf;
int save_errno = errno;
- if (flags & AT_SYMLINK_NOFOLLOW) {
- errno = ENOTSUP;
- return -1;
- }
#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS
if (dirfd != AT_FDCWD) {
errno = ENOSYS;
return -1;
}
- rc = base_stat(path, &buf);
+ if (flags & AT_SYMLINK_NOFOLLOW) {
+ rc = base_lstat(path, &buf);
+ } else {
+ rc = base_stat(path, &buf);
+ }
#else
rc = base_fstatat(dirfd, path, &buf, flags);
#endif
@@ -28,9 +28,8 @@
return rc;
}
if (S_ISLNK(buf.st_mode)) {
- /* we don't really support chmod of a symlink */
- errno = ENOSYS;
- return -1;
+ /* according to docs, "chmod on a symbolic link always succeeds and has no effect" */
+ return 0;
}
save_errno = errno;
diff --git a/ports/unix/guts/linkat.c b/ports/unix/guts/linkat.c
index 381f9d0..7d8dff4 100644
--- a/ports/unix/guts/linkat.c
+++ b/ports/unix/guts/linkat.c
@@ -116,6 +116,7 @@
* if the thing linked is a symlink.
*/
pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &buf);
+ pseudo_client_linked_paths(oldpath, newpath);
errno = save_errno;
diff --git a/ports/unix/guts/realpath.c b/ports/unix/guts/realpath.c
index 085d2cb..8d8118b 100644
--- a/ports/unix/guts/realpath.c
+++ b/ports/unix/guts/realpath.c
@@ -14,7 +14,14 @@
errno = ENAMETOOLONG;
return NULL;
}
- if ((len = strlen(rname)) >= pseudo_sys_path_max()) {
+ len = strlen(rname);
+ char *ep = rname + len - 1;
+ while (ep > rname && *ep == '/') {
+ --len;
+ *(ep--) = '\0';
+ }
+
+ if (len >= pseudo_sys_path_max()) {
errno = ENAMETOOLONG;
return NULL;
}
diff --git a/ports/unix/guts/rename.c b/ports/unix/guts/rename.c
index 5073c71..80bbf41 100644
--- a/ports/unix/guts/rename.c
+++ b/ports/unix/guts/rename.c
@@ -13,7 +13,8 @@
int oldrc, newrc;
int save_errno;
int old_db_entry = 0;
- int may_unlinked = 0;
+ int may_unlink_new = 0;
+ int may_unlink_old = 0;
pseudo_debug(PDBGF_OP, "rename: %s->%s\n",
oldpath ? oldpath : "<nil>",
@@ -29,41 +30,51 @@
newrc = base_lstat(newpath, &newbuf);
oldrc = base_lstat(oldpath, &oldbuf);
+ /* nothing to do for a "rename" of a link to itself */
+ if (newrc != -1 && oldrc != -1 &&
+ newbuf.st_dev == oldbuf.st_dev &&
+ newbuf.st_ino == oldbuf.st_ino) {
+ pseudo_debug(PDBGF_OP, "rename: paths are the same\n");
+ return real_rename(oldpath, newpath);
+ }
+
errno = save_errno;
/* newpath must be removed. */
/* as with unlink, we have to mark that the file may get deleted */
msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, -1, newpath, newrc ? NULL : &newbuf);
if (msg && msg->result == RESULT_SUCCEED)
- may_unlinked = 1;
+ may_unlink_new = 1;
+ /* oldpath is also likely to disappear. Something could call stat() after
+ real_rename so we need to mark as MAY_UNLINK too */
+ msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, -1, oldpath, oldrc ? NULL : &oldbuf);
+ if (msg && msg->result == RESULT_SUCCEED)
+ may_unlink_old = 1;
+
msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, oldrc ? NULL : &oldbuf);
if (msg && msg->result == RESULT_SUCCEED)
old_db_entry = 1;
rc = real_rename(oldpath, newpath);
save_errno = errno;
- if (may_unlinked) {
- if (rc == -1) {
- /* since we failed, that wasn't really unlinked -- put
- * it back.
- */
- pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, newpath, &newbuf);
- } else {
- /* confirm that the file was removed */
- pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, newpath, &newbuf);
- }
- }
+
if (rc == -1) {
+ /* since we failed, that wasn't really unlinked -- put
+ * it back.
+ */
+ if (may_unlink_new)
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, newpath, &newbuf);
+ if (may_unlink_old)
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, -1, oldpath, &oldbuf);
/* and we're done. */
errno = save_errno;
return rc;
}
+
+ /* confirm that the file was removed */
+ if (may_unlink_new)
+ pseudo_client_op(OP_DID_UNLINK, 0, -1, -1, newpath, &newbuf);
+ /* OP_DID_UNLINK for oldpath is handled by the server */
save_errno = errno;
- /* nothing to do for a "rename" of a link to itself */
- if (newrc != -1 && oldrc != -1 &&
- newbuf.st_dev == oldbuf.st_dev &&
- newbuf.st_ino == oldbuf.st_ino) {
- return rc;
- }
/* rename(3) is not mv(1). rename(file, dir) fails; you must provide
* the corrected path yourself. You can rename over a directory only
diff --git a/ports/unix/guts/renameat.c b/ports/unix/guts/renameat.c
index 735a60a..5ac63f9 100644
--- a/ports/unix/guts/renameat.c
+++ b/ports/unix/guts/renameat.c
@@ -13,7 +13,8 @@
int oldrc, newrc;
int save_errno;
int old_db_entry = 0;
- int may_unlinked = 0;
+ int may_unlink_new = 0;
+ int may_unlink_old = 0;
pseudo_debug(PDBGF_FILE, "renameat: %d,%s->%d,%s\n",
olddirfd, oldpath ? oldpath : "<nil>",
@@ -41,42 +42,51 @@
newrc = base_fstatat(newdirfd, newpath, &newbuf, AT_SYMLINK_NOFOLLOW);
#endif
+ /* nothing to do for a "rename" of a link to itself */
+ if (newrc != -1 && oldrc != -1 &&
+ newbuf.st_dev == oldbuf.st_dev &&
+ newbuf.st_ino == oldbuf.st_ino) {
+ pseudo_debug(PDBGF_OP, "renameat: paths are the same\n");
+ return real_renameat(olddirfd, oldpath, newdirfd, newpath);
+ }
+
errno = save_errno;
/* newpath must be removed. */
/* as with unlink, we have to mark that the file may get deleted */
msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, newdirfd, newpath, newrc ? NULL : &newbuf);
if (msg && msg->result == RESULT_SUCCEED)
- may_unlinked = 1;
+ may_unlink_new = 1;
+ /* oldpath is also likely to disappear. Something could call stat() after
+ real_rename so we need to mark as MAY_UNLINK too */
+ msg = pseudo_client_op(OP_MAY_UNLINK, 0, -1, olddirfd, oldpath, oldrc ? NULL : &oldbuf);
+ if (msg && msg->result == RESULT_SUCCEED)
+ may_unlink_old = 1;
+
msg = pseudo_client_op(OP_STAT, 0, -1, olddirfd, oldpath, oldrc ? NULL : &oldbuf);
if (msg && msg->result == RESULT_SUCCEED)
old_db_entry = 1;
rc = real_renameat(olddirfd, oldpath, newdirfd, newpath);
save_errno = errno;
- if (may_unlinked) {
- if (rc == -1) {
- /* since we failed, that wasn't really unlinked -- put
- * it back.
- */
- pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, newdirfd, newpath, &newbuf);
- } else {
- /* confirm that the file was removed */
- pseudo_client_op(OP_DID_UNLINK, 0, -1, newdirfd, newpath, &newbuf);
- }
- }
if (rc == -1) {
+ /* since we failed, that wasn't really unlinked -- put
+ * it back.
+ */
+ if (may_unlink_new)
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, newdirfd, newpath, &newbuf);
+ if (may_unlink_old)
+ pseudo_client_op(OP_CANCEL_UNLINK, 0, -1, olddirfd, oldpath, &oldbuf);
/* and we're done. */
errno = save_errno;
return rc;
}
+
+ /* confirm that the file was removed */
+ if (may_unlink_new)
+ pseudo_client_op(OP_DID_UNLINK, 0, -1, newdirfd, newpath, &newbuf);
+ /* OP_DID_UNLINK for oldpath is handled by the server */
save_errno = errno;
- /* nothing to do for a "rename" of a link to itself */
- if (newrc != -1 && oldrc != -1 &&
- newbuf.st_dev == oldbuf.st_dev &&
- newbuf.st_ino == oldbuf.st_ino) {
- return rc;
- }
/* rename(3) is not mv(1). rename(file, dir) fails; you must provide
* the corrected path yourself. You can rename over a directory only
diff --git a/ports/unix/subports b/ports/unix/subports
index e41b036..bd5a2f6 100755
--- a/ports/unix/subports
+++ b/ports/unix/subports
@@ -1,11 +1,13 @@
#!/bin/sh
cat > dummy.c <<EOF
+#define _GNU_SOURCE
#include <unistd.h>
int main(void) {
syncfs(0);
return 0;
}
EOF
+
if ${CC} -o dummy dummy.c > /dev/null 2>&1; then
echo "unix/syncfs"
fi
diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in
index 3910fae..7724fc7 100644
--- a/ports/unix/wrapfuncs.in
+++ b/ports/unix/wrapfuncs.in
@@ -1,15 +1,17 @@
int creat(const char *path, mode_t mode);
char *getcwd(char *buf, size_t size);
char *getwd(char *buf);
-int close(int fd);
+int close(int fd); /* noignore_path=1 */
int fchmod(int fd, mode_t mode);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group); /* flags=AT_SYMLINK_NOFOLLOW */
-int dup2(int oldfd, int newfd);
-int dup(int fd);
-int chdir(const char *path);
-int fchdir(int dirfd);
+int dup2(int oldfd, int newfd); /* noignore_path=1 */
+int dup(int fd); /* noignore_path=1 */
+int chdir(const char *path); /* noignore_path=1 */
+int fchdir(int dirfd); /* noignore_path=1 */
int access(const char *path, int mode);
+int faccessat(int dirfd, const char *path, int mode, int flags);
+int faccessat2(int dirfd, const char *path, int mode, int flags);
FTS *fts_open(char * const *path_argv, int options, int (*compar)(const FTSENT **, const FTSENT **)); /* inode64=1 */
int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int nopenfd);
int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int nopenfd, int flag);
@@ -20,18 +22,18 @@ char *mktemp(char *template);
long pathconf(const char *path, int name);
char *realpath(const char *name, char *resolved_name); /* version="GLIBC_2.3" */
int remove(const char *path); /* flags=AT_SYMLINK_NOFOLLOW */
-DIR *opendir(const char *path);
-int closedir(DIR *dirp);
+DIR *opendir(const char *path); /* noignore_path=1 */
+int closedir(DIR *dirp); /* noignore_path=1 */
char *tempnam(const char *template, const char *pfx);
char *tmpnam(char *s);
int truncate(const char *path, off_t length);
int utime(const char *path, const struct utimbuf *buf);
int utimes(const char *path, const struct timeval *times);
# needed because libc stdio does horrible things with inline asm syscalls
-FILE *fopen(const char *path, const char *mode);
-int fclose(FILE *fp);
-FILE *freopen(const char *path, const char *mode, FILE *stream);
-int chroot(const char *path);
+FILE *fopen(const char *path, const char *mode); /* noignore_path=1 */
+int fclose(FILE *fp); /* noignore_path=1 */
+FILE *freopen(const char *path, const char *mode, FILE *stream); /* noignore_path=1 */
+int chroot(const char *path); /* noignore_path=1 */
int acct(const char *path);
int chmod(const char *path, mode_t mode);
int chown(const char *path, uid_t owner, gid_t group);