diff options
Diffstat (limited to 'ports')
-rw-r--r-- | ports/darwin/guts/open.c | 3 | ||||
-rw-r--r-- | ports/linux/guts/__xmknodat.c | 3 | ||||
-rw-r--r-- | ports/linux/guts/openat.c | 3 | ||||
-rw-r--r-- | ports/unix/guts/fchmodat.c | 26 | ||||
-rw-r--r-- | ports/unix/guts/mkdirat.c | 3 | ||||
-rw-r--r-- | ports/unix/guts/mknodat.c | 3 | ||||
-rw-r--r-- | ports/unix/guts/umask.c | 14 | ||||
-rw-r--r-- | ports/unix/wrapfuncs.in | 1 |
8 files changed, 53 insertions, 3 deletions
diff --git a/ports/darwin/guts/open.c b/ports/darwin/guts/open.c index c66cc15..520bb70 100644 --- a/ports/darwin/guts/open.c +++ b/ports/darwin/guts/open.c @@ -9,6 +9,9 @@ struct stat buf = { }; int existed = 1; int save_errno; + + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; #ifdef PSEUDO_FORCE_ASYNCH flags &= ~O_SYNC; #endif diff --git a/ports/linux/guts/__xmknodat.c b/ports/linux/guts/__xmknodat.c index 59b4f2f..0888b8a 100644 --- a/ports/linux/guts/__xmknodat.c +++ b/ports/linux/guts/__xmknodat.c @@ -9,6 +9,9 @@ pseudo_msg_t *msg; struct stat64 buf; + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + /* we don't use underlying call, so _ver is irrelevant to us */ (void) ver; diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c index 8460073..4053549 100644 --- a/ports/linux/guts/openat.c +++ b/ports/linux/guts/openat.c @@ -10,6 +10,9 @@ int existed = 1; int save_errno; + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { errno = ENOSYS; diff --git a/ports/unix/guts/fchmodat.c b/ports/unix/guts/fchmodat.c index 59a92ce..69a953c 100644 --- a/ports/unix/guts/fchmodat.c +++ b/ports/unix/guts/fchmodat.c @@ -8,6 +8,7 @@ */ PSEUDO_STATBUF buf; int save_errno = errno; + static int picky_fchmodat = 0; #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { @@ -15,6 +16,16 @@ return -1; } if (flags & AT_SYMLINK_NOFOLLOW) { + /* Linux, as of this writing, will always reject this. + * GNU tar relies on getting the rejection. To cut down + * on traffic, we check for the failure, and if we saw + * a failure previously, we reject it right away and tell + * the caller to retry. + */ + if (picky_fchmodat) { + errno = ENOTSUP; + return -1; + } rc = base_lstat(path, &buf); } else { rc = base_stat(path, &buf); @@ -50,13 +61,22 @@ /* user bits added so "root" can always access files. */ #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS - /* note: if path was a symlink, and AT_NOFOLLOW_SYMLINKS was + /* note: if path was a symlink, and AT_SYMLINK_NOFOLLOW was * specified, we already bailed previously. */ real_chmod(path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode))); #else - real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode)), flags); + rc = real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode, S_ISDIR(buf.st_mode)), flags); + /* AT_SYMLINK_NOFOLLOW isn't supported by fchmodat. GNU tar + * tries to use it anyway, figuring it can just retry if that + * fails. So we want to report that *particular* failure instead + * of doing the fallback. + */ + if (rc == -1 && errno == ENOTSUP && (flags & AT_SYMLINK_NOFOLLOW)) { + picky_fchmodat = 1; + return -1; + } #endif - /* we ignore a failure from underlying fchmod, because pseudo + /* we otherwise ignore failures from underlying fchmod, because pseudo * may believe you are permitted to change modes that the filesystem * doesn't. Note that we also don't need to know whether the * file might be a (pseudo) block device or some such; pseudo diff --git a/ports/unix/guts/mkdirat.c b/ports/unix/guts/mkdirat.c index e846b70..e0b6af9 100644 --- a/ports/unix/guts/mkdirat.c +++ b/ports/unix/guts/mkdirat.c @@ -6,11 +6,14 @@ * wrap_mkdirat(int dirfd, const char *path, mode_t mode) { * int rc = -1; */ + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { errno = ENOSYS; return -1; } + rc = real_mkdir(path, PSEUDO_FS_MODE(mode, 1)); #else rc = real_mkdirat(dirfd, path, PSEUDO_FS_MODE(mode, 1)); diff --git a/ports/unix/guts/mknodat.c b/ports/unix/guts/mknodat.c index 6fd5b42..5d8d47c 100644 --- a/ports/unix/guts/mknodat.c +++ b/ports/unix/guts/mknodat.c @@ -10,6 +10,9 @@ PSEUDO_STATBUF buf; int save_errno = errno; + /* mask out mode bits appropriately */ + mode = mode & ~pseudo_umask; + #ifdef PSEUDO_NO_REAL_AT_FUNCTIONS if (dirfd != AT_FDCWD) { errno = ENOSYS; diff --git a/ports/unix/guts/umask.c b/ports/unix/guts/umask.c new file mode 100644 index 0000000..6b060d3 --- /dev/null +++ b/ports/unix/guts/umask.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2014 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * mode_t umask(mode_t mask) + * mode_t rc = 0; + */ + + pseudo_umask = mask; + rc = real_umask(mask); + +/* return rc; + * } + */ diff --git a/ports/unix/wrapfuncs.in b/ports/unix/wrapfuncs.in index 8460a65..e0e9739 100644 --- a/ports/unix/wrapfuncs.in +++ b/ports/unix/wrapfuncs.in @@ -67,3 +67,4 @@ void sync(void); /* async_skip= */ int syncfs(int fd); /* async_skip=0 */ int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags); /* async_skip=0 */ int msync(void *addr, size_t length, int flags); /* async_skip=0 */ +mode_t umask(mode_t mask); |