diff --git a/src/build/libroot/fs_darwin.cpp b/src/build/libroot/fs_darwin.cpp index c5e9105d9e..c0bb8c1350 100644 --- a/src/build/libroot/fs_darwin.cpp +++ b/src/build/libroot/fs_darwin.cpp @@ -13,19 +13,67 @@ #include #include #include +#include #include +int +eaccess(const char* path, int accessMode) +{ + uid_t uid = geteuid(); + int fileMode = 0; + + struct stat st; + if (stat(path, &st) < 0) { + // failed to get stat information on path + return -1; + } + + if (uid == 0) { + // user is root + // root has always read/write permission, but at least one of the + // X bits must be set for execute permission + fileMode = R_OK | W_OK; + if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0) + fileMode |= X_OK; + } else if (st.st_uid == uid) { + // user is node owner + if ((st.st_mode & S_IRUSR) != 0) + fileMode |= R_OK; + if ((st.st_mode & S_IWUSR) != 0) + fileMode |= W_OK; + if ((st.st_mode & S_IXUSR) != 0) + fileMode |= X_OK; + } else if (st.st_gid == getegid()) { + // user is in owning group + if ((st.st_mode & S_IRGRP) != 0) + fileMode |= R_OK; + if ((st.st_mode & S_IWGRP) != 0) + fileMode |= W_OK; + if ((st.st_mode & S_IXGRP) != 0) + fileMode |= X_OK; + } else { + // user is one of the others + if ((st.st_mode & S_IROTH) != 0) + fileMode |= R_OK; + if ((st.st_mode & S_IWOTH) != 0) + fileMode |= W_OK; + if ((st.st_mode & S_IXOTH) != 0) + fileMode |= X_OK; + } + + if ((accessMode & ~fileMode) != 0) { + errno = EACCES; + return -1; + } + + return 0; +} + + int faccessat(int fd, const char* path, int accessMode, int flag) { - if ((flag & AT_EACCESS) == 0) { - // Perform access checks using the effective user and group IDs - // CURRENTLY UNSUPPORTED - errno = ENOTSUP; - return -1; - } - if ((flag & AT_SYMLINK_NOFOLLOW) == 0) { // do not dereference, instead return information about the link // itself @@ -36,7 +84,8 @@ faccessat(int fd, const char* path, int accessMode, int flag) if (path && path[0] == '/') { // path is absolute, call access() ignoring fd - return access(path, accessMode); + return (flag & AT_EACCESS) == 0 ? eaccess(path, accessMode) + : access(path, accessMode); } if (!fd) { @@ -47,16 +96,17 @@ faccessat(int fd, const char* path, int accessMode, int flag) if (fd == AT_FDCWD) { // fd is set to AT_FDCWD, call access() - return access(path, accessMode); + return (flag & AT_EACCESS) == 0 ? eaccess(path, accessMode) + : access(path, accessMode); } - struct stat mystat; - if (fstat(fd, &mystat) < 0) { - // failed to grab stat information, fstat sets errno + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno return -1; } - if ((mystat.st_mode & S_IFDIR) != 0) { + if ((dirst.st_mode & S_IFDIR) != 0) { // fd does not point to a directory errno = ENOTDIR; return -1; @@ -81,55 +131,370 @@ faccessat(int fd, const char* path, int accessMode, int flag) return -1; } - return access(dirpath, accessMode); + return (flag & AT_EACCESS) == 0 ? eaccess(path, accessMode) + : access(path, accessMode); } int fchmodat(int fd, const char* path, mode_t mode, int flag) { - errno = ENOSYS; - return -1; + if ((flag & AT_SYMLINK_NOFOLLOW) == 0) { + // do not dereference, instead return information about the link + // itself + // CURRENTLY UNSUPPORTED + errno = ENOTSUP; + return -1; + } else if (flag != 0) { + errno = EINVAL; + return -1; + } + + if (path && path[0] == '/') { + // path is absolute, call chmod() ignoring fd + return chmod(path, mode); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call chmod() + return chmod(path, mode); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return chmod(dirpath, mode); } int fchownat(int fd, const char* path, uid_t owner, gid_t group, int flag) { - errno = ENOSYS; - return -1; + if ((flag & AT_SYMLINK_NOFOLLOW) == 0) { + // do not dereference, instead return information about the link + // itself + // CURRENTLY UNSUPPORTED + errno = ENOTSUP; + return -1; + } else if (flag != 0) { + errno = EINVAL; + return -1; + } + + if (path && path[0] == '/') { + // path is absolute, call chown() ignoring fd + return chown(path, owner, group); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call access() + return chown(path, owner, group); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return chown(dirpath, owner, group); } int fstatat(int fd, const char *path, struct stat *st, int flag) { - errno = ENOSYS; - return -1; + if ((flag & AT_NO_AUTOMOUNT) == 0) { + // Don't automount the terminal ("basename") component of pathname if + // it is a directory that is an automount point. + // CURRENTLY UNSUPPORTED + errno = ENOTSUP; + return -1; + } + + if ((flag & AT_SYMLINK_NOFOLLOW) == 0) { + // do not dereference, instead return information about the link + // itself + // CURRENTLY UNSUPPORTED + errno = ENOTSUP; + return -1; + } + + if (path && path[0] == '/') { + // path is absolute, call stat() ignoring fd + return stat(path, st); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call stat() + return stat(path, st); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return stat(dirpath, st); } int mkdirat(int fd, const char *path, mode_t mode) { - errno = ENOSYS; - return -1; + if (path && path[0] == '/') { + // path is absolute, call mkdir() ignoring fd + return mkdir(path, mode); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call mkdir() + return mkdir(path, mode); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return mkdir(dirpath, mode); } int mkfifoat(int fd, const char *path, mode_t mode) { - errno = ENOSYS; - return -1; + if (path && path[0] == '/') { + // path is absolute, call mkfifo() ignoring fd + return mkfifo(path, mode); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call mkfifo() + return mkfifo(path, mode); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return mkfifo(dirpath, mode); } int -mknodat(int fd, const char *name, mode_t mode, dev_t dev) +mknodat(int fd, const char *path, mode_t mode, dev_t dev) { - errno = ENOSYS; - return -1; + if (path && path[0] == '/') { + // path is absolute, call mknod() ignoring fd + return mknod(path, mode, dev); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call mknod() + return mknod(path, mode, dev); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return mknod(dirpath, mode, dev); } @@ -176,6 +541,52 @@ linkat(int toFD, const char *toPath, int linkFD, const char *linkPath, int flag) int futimesat(int fd, const char *path, const struct timeval times[2]) { - errno = ENOSYS; - return -1; + if (path && path[0] == '/') { + // path is absolute, call utimes() ignoring fd + return utimes(path, times); + } + + if (!fd) { + // fd is not a valid file descriptor + errno = EBADF; + return -1; + } + + if (fd == AT_FDCWD) { + // fd is set to AT_FDCWD, call utimes() + return utimes(path, times); + } + + struct stat dirst; + if (fstat(fd, &dirst) < 0) { + // failed to grab stat information, fstat() sets errno + return -1; + } + + if ((dirst.st_mode & S_IFDIR) != 0) { + // fd does not point to a directory + errno = ENOTDIR; + return -1; + } + + char *dirpath; + dirpath = (char *)malloc(MAXPATHLEN); + if (dirpath == NULL) { + // ran out of memory allocating dirpath + errno = ENOMEM; + return -1; + } + + if (fcntl(fd, F_GETPATH, dirpath) < 0) { + // failed to get the path of fd, fcntl sets errno + return -1; + } + + if (strlcat(dirpath, path, MAXPATHLEN) > MAXPATHLEN) { + // full path is too long, set errno and return + errno = ENAMETOOLONG; + return -1; + } + + return utimes(dirpath, times); } diff --git a/src/build/libroot/fs_darwin.h b/src/build/libroot/fs_darwin.h index a6c731e0ce..c07fe4041e 100644 --- a/src/build/libroot/fs_darwin.h +++ b/src/build/libroot/fs_darwin.h @@ -13,7 +13,9 @@ #define AT_SYMLINK_FOLLOW 0x02 /* linkat() */ #define AT_REMOVEDIR 0x04 /* unlinkat() */ #define AT_EACCESS 0x08 /* faccessat() */ +#define AT_NO_AUTOMOUNT 0x10 /* fstatat */ +int eaccess(const char* path, int accessMode); int faccessat(int fd, const char* path, int accessMode, int flag); int fchmodat(int fd, const char* path, mode_t mode, int flag); int fchownat(int fd, const char* path, uid_t owner, gid_t group, int flag);