From c396c39fc59a5d89612e2af3238153e208da72de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 10 May 2004 14:33:17 +0000 Subject: [PATCH] Changed the "stat" related syscalls to have an additional parameter that specified the size of the stat structure to allow extensions of that structure. Renamed those syscalls to the new naming scheme. Updated the syscalls to support stat extensions. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7494 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/core/fs/fd.c | 70 ++++++++++++++++++++++++++++---------- src/kernel/core/fs/vfs.cpp | 66 ++++++++++++++++++++++++++++------- src/kernel/core/syscalls.c | 8 ++--- 3 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/kernel/core/fs/fd.c b/src/kernel/core/fs/fd.c index bb0d604450..a1219efa90 100644 --- a/src/kernel/core/fs/fd.c +++ b/src/kernel/core/fs/fd.c @@ -448,12 +448,15 @@ user_rewind_dir(int fd) } -int -user_read_stat(int fd, struct stat *userStat) +status_t +_user_read_stat(int fd, struct stat *userStat, size_t statSize) { struct file_descriptor *descriptor; status_t status; + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + /* This is a user_function, so abort if we have a kernel address */ CHECK_USER_ADDR(userStat) @@ -461,7 +464,7 @@ user_read_stat(int fd, struct stat *userStat) if (descriptor == NULL) return B_FILE_ERROR; - TRACE(("user_read_stat(descriptor = %p)\n", descriptor)); + TRACE(("_user_read_stat(descriptor = %p)\n", descriptor)); if (descriptor->ops->fd_read_stat) { // we're using the stat buffer on the stack to not have to @@ -470,7 +473,7 @@ user_read_stat(int fd, struct stat *userStat) status = descriptor->ops->fd_read_stat(descriptor, &stat); if (status >= 0) - status = user_memcpy(userStat, &stat, sizeof(stat)); + status = user_memcpy(userStat, &stat, statSize); } else status = EOPNOTSUPP; @@ -479,25 +482,31 @@ user_read_stat(int fd, struct stat *userStat) } -int -user_write_stat(int fd, const struct stat *userStat, int statMask) +status_t +_user_write_stat(int fd, const struct stat *userStat, size_t statSize, int statMask) { struct file_descriptor *descriptor; status_t status; + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + CHECK_USER_ADDR(userStat) descriptor = get_fd(get_current_io_context(false), fd); if (descriptor == NULL) return B_FILE_ERROR; - TRACE(("user_write_stat(descriptor = %p)\n", descriptor)); + TRACE(("_user_write_stat(descriptor = %p)\n", descriptor)); if (descriptor->ops->fd_write_stat) { // we're using the stat buffer on the stack to not have to // lock the given stat buffer in memory struct stat stat; - status = user_memcpy(&stat, userStat, sizeof(stat)); + if (sizeof(struct stat) != statSize) + memset((uint8 *)&stat + statSize, 0, sizeof(struct stat) - statSize); + + status = user_memcpy(&stat, userStat, statSize); if (status == B_OK) status = descriptor->ops->fd_write_stat(descriptor, &stat, statMask); } else @@ -678,21 +687,35 @@ sys_rewind_dir(int fd) } -int -sys_read_stat(int fd, struct stat *stat) +status_t +_kern_read_stat(int fd, struct stat *stat, size_t statSize) { struct file_descriptor *descriptor; status_t status; + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + descriptor = get_fd(get_current_io_context(true), fd); if (descriptor == NULL) return B_FILE_ERROR; - TRACE(("sys_read_stat(descriptor = %p)\n", descriptor)); + TRACE(("_kern_read_stat(descriptor = %p)\n", descriptor)); - if (descriptor->ops->fd_read_stat) + if (descriptor->ops->fd_read_stat) { + // this supports different stat extensions + struct stat completeStat; + struct stat *originalStat = NULL; + + if (statSize < sizeof(struct stat)) { + originalStat = stat; + stat = &completeStat; + } status = descriptor->ops->fd_read_stat(descriptor, stat); - else + + if (originalStat != NULL) + memcpy(originalStat, stat, statSize); + } else status = EOPNOTSUPP; put_fd(descriptor); @@ -700,21 +723,32 @@ sys_read_stat(int fd, struct stat *stat) } -int -sys_write_stat(int fd, const struct stat *stat, int statMask) +status_t +_kern_write_stat(int fd, const struct stat *stat, size_t statSize, int statMask) { struct file_descriptor *descriptor; status_t status; + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + descriptor = get_fd(get_current_io_context(true), fd); if (descriptor == NULL) return B_FILE_ERROR; - TRACE(("sys_write_stat(descriptor = %p)\n", descriptor)); + TRACE(("_kern_write_stat(descriptor = %p)\n", descriptor)); - if (descriptor->ops->fd_write_stat) + if (descriptor->ops->fd_write_stat) { + // this supports different stat extensions + struct stat completeStat; + + if (statSize < sizeof(struct stat)) { + memset((uint8 *)&completeStat + statSize, 0, sizeof(struct stat) - statSize); + memcpy(&completeStat, stat, statSize); + stat = &completeStat; + } status = descriptor->ops->fd_write_stat(descriptor, stat, statMask); - else + } else status = EOPNOTSUPP; put_fd(descriptor); diff --git a/src/kernel/core/fs/vfs.cpp b/src/kernel/core/fs/vfs.cpp index 78d72f971d..4e55b23876 100755 --- a/src/kernel/core/fs/vfs.cpp +++ b/src/kernel/core/fs/vfs.cpp @@ -3731,22 +3731,52 @@ sys_access(const char *path, int mode) } -int -sys_read_path_stat(const char *path, bool traverseLeafLink, struct stat *stat) +status_t +_kern_read_path_stat(const char *path, bool traverseLeafLink, struct stat *stat, size_t statSize) { + struct stat completeStat; + struct stat *originalStat = NULL; char pathBuffer[SYS_MAX_PATH_LEN + 1]; + status_t status; + + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1); - return common_path_read_stat(pathBuffer, traverseLeafLink, stat, true); + // this supports different stat extensions + if (statSize < sizeof(struct stat)) { + originalStat = stat; + stat = &completeStat; + } + + status = common_path_read_stat(pathBuffer, traverseLeafLink, stat, true); + if (status == B_OK && originalStat != NULL) + memcpy(originalStat, stat, statSize); + + return status; } -int -sys_write_path_stat(const char *path, bool traverseLeafLink, const struct stat *stat, int statMask) +status_t +_kern_write_path_stat(const char *path, bool traverseLeafLink, const struct stat *stat, size_t statSize, int statMask) { + struct stat completeStat; char pathBuffer[SYS_MAX_PATH_LEN + 1]; + + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + strlcpy(pathBuffer, path, SYS_MAX_PATH_LEN - 1); + // this supports different stat extensions + + if (statSize < sizeof(struct stat)) { + memset((uint8 *)&completeStat + statSize, 0, sizeof(struct stat) - statSize); + memcpy(&completeStat, stat, statSize); + stat = &completeStat; + } + return common_path_write_stat(pathBuffer, traverseLeafLink, stat, statMask, true); } @@ -4281,38 +4311,50 @@ user_access(const char *userPath, int mode) } -int -user_read_path_stat(const char *userPath, bool traverseLink, struct stat *userStat) +status_t +_user_read_path_stat(const char *userPath, bool traverseLink, struct stat *userStat, + size_t statSize) { char path[SYS_MAX_PATH_LEN + 1]; struct stat stat; int status; + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + if (!IS_USER_ADDRESS(userPath) || !IS_USER_ADDRESS(userStat) || user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK) return B_BAD_ADDRESS; status = common_path_read_stat(path, traverseLink, &stat, false); - if (status < 0) + if (status < B_OK) return status; - return user_memcpy(userStat, &stat, sizeof(struct stat)); + return user_memcpy(userStat, &stat, statSize); } -int -user_write_path_stat(const char *userPath, bool traverseLeafLink, const struct stat *userStat, int statMask) +status_t +_user_write_path_stat(const char *userPath, bool traverseLeafLink, const struct stat *userStat, + size_t statSize, int statMask) { char path[SYS_MAX_PATH_LEN + 1]; struct stat stat; + if (statSize > sizeof(struct stat)) + return B_BAD_VALUE; + if (!IS_USER_ADDRESS(userStat) || !IS_USER_ADDRESS(userPath) || user_strlcpy(path, userPath, SYS_MAX_PATH_LEN) < B_OK - || user_memcpy(&stat, userStat, sizeof(struct stat)) < B_OK) + || user_memcpy(&stat, userStat, statSize) < B_OK) return B_BAD_ADDRESS; + // clear additional stat fields + if (statSize < sizeof(struct stat)) + memset((uint8 *)&stat + statSize, 0, sizeof(struct stat) - statSize); + return common_path_write_stat(path, traverseLeafLink, &stat, statMask, false); } diff --git a/src/kernel/core/syscalls.c b/src/kernel/core/syscalls.c index 0e2f3e6e97..818372e0fd 100644 --- a/src/kernel/core/syscalls.c +++ b/src/kernel/core/syscalls.c @@ -140,16 +140,16 @@ syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_ret) *call_ret = user_rename((const char *)arg0, (const char *)arg1); break; case SYSCALL_READ_PATH_STAT: - *call_ret = user_read_path_stat((const char *)arg0, (bool)arg1, (struct stat *)arg2); + *call_ret = _user_read_path_stat((const char *)arg0, (bool)arg1, (struct stat *)arg2, (size_t)arg3); break; case SYSCALL_WRITE_PATH_STAT: - *call_ret = user_write_path_stat((const char *)arg0, (bool)arg1, (const struct stat *)arg2, (int)arg3); + *call_ret = _user_write_path_stat((const char *)arg0, (bool)arg1, (const struct stat *)arg2, (size_t)arg3, (int)arg4); break; case SYSCALL_READ_STAT: - *call_ret = user_read_stat((int)arg0, (struct stat*)arg1); + *call_ret = _user_read_stat((int)arg0, (struct stat *)arg1, (size_t)arg2); break; case SYSCALL_WRITE_STAT: - *call_ret = user_write_stat((int)arg0, (const struct stat *)arg1, (int)arg2); + *call_ret = _user_write_stat((int)arg0, (const struct stat *)arg1, (size_t)arg2, (int)arg3); break; case SYSCALL_ACCESS: *call_ret = user_access((const char *)arg0, (int)arg1);