Kernel+Userland: Implement fchmod() syscall and use it to improve /bin/cp.

/bin/cp will now copy the permission bits from source to destination. :^)
This commit is contained in:
Andreas Kling 2019-03-01 10:39:19 +01:00
parent b5e5f26a82
commit 1b16a29044
Notes: sideshowbarker 2024-07-19 15:34:50 +09:00
10 changed files with 54 additions and 14 deletions

View File

@ -138,6 +138,13 @@ int FileDescriptor::fstat(stat* buffer)
return 0;
}
KResult FileDescriptor::fchmod(mode_t mode)
{
if (!m_inode)
return KResult(-EBADF);
return VFS::the().chmod(*m_inode, mode);
}
off_t FileDescriptor::seek(off_t offset, int whence)
{
ASSERT(!is_fifo());

View File

@ -34,6 +34,8 @@ public:
ssize_t write(Process&, const byte* data, ssize_t);
int fstat(stat*);
KResult fchmod(mode_t);
bool can_read(Process&);
bool can_write(Process&);

View File

@ -2177,6 +2177,14 @@ int Process::sys$chmod(const char* pathname, mode_t mode)
return VFS::the().chmod(String(pathname), mode, cwd_inode());
}
int Process::sys$fchmod(int fd, mode_t mode)
{
auto* descriptor = file_descriptor(fd);
if (!descriptor)
return -EBADF;
return descriptor->fchmod(mode);
}
int Process::sys$chown(const char* pathname, uid_t uid, gid_t gid)
{
if (!validate_read_str(pathname))

View File

@ -219,6 +219,7 @@ public:
int sys$rmdir(const char* pathname);
int sys$read_tsc(dword* lsw, dword* msw);
int sys$chmod(const char* pathname, mode_t);
int sys$fchmod(int fd, mode_t);
int sys$chown(const char* pathname, uid_t, gid_t);
int sys$socket(int domain, int type, int protocol);
int sys$bind(int sockfd, const sockaddr* addr, socklen_t);

View File

@ -199,6 +199,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
return current->sys$rmdir((const char*)arg1);
case Syscall::SC_chmod:
return current->sys$chmod((const char*)arg1, (mode_t)arg2);
case Syscall::SC_fchmod:
return current->sys$fchmod((int)arg1, (mode_t)arg2);
case Syscall::SC_socket:
return current->sys$socket((int)arg1, (int)arg2, (int)arg3);
case Syscall::SC_bind:

View File

@ -83,6 +83,7 @@
__ENUMERATE_SYSCALL(release_shared_buffer) \
__ENUMERATE_SYSCALL(link) \
__ENUMERATE_SYSCALL(chown) \
__ENUMERATE_SYSCALL(fchmod) \
namespace Syscall {

View File

@ -290,24 +290,26 @@ KResult VFS::access(const String& path, int mode, Inode& base)
return KSuccess;
}
KResult VFS::chmod(Inode& inode, mode_t mode)
{
if (inode.fs().is_readonly())
return KResult(-EROFS);
if (current->euid() != inode.metadata().uid && !current->is_superuser())
return KResult(-EPERM);
// Only change the permission bits.
mode = (inode.mode() & ~04777u) | (mode & 04777u);
return inode.chmod(mode);
}
KResult VFS::chmod(const String& path, mode_t mode, Inode& base)
{
auto inode_or_error = resolve_path_to_inode(path, base);
if (inode_or_error.is_error())
return inode_or_error.error();
auto inode = inode_or_error.value();
if (inode->fs().is_readonly())
return KResult(-EROFS);
if (current->euid() != inode->metadata().uid && !current->is_superuser())
return KResult(-EPERM);
// Only change the permission bits.
mode = (inode->mode() & ~04777) | (mode & 04777);
kprintf("VFS::chmod(): %u:%u mode %o\n", inode->fsid(), inode->index(), mode);
return inode->chmod(mode);
return chmod(*inode, mode);
}
KResult VFS::chown(const String& path, uid_t a_uid, gid_t a_gid, Inode& base)

View File

@ -70,6 +70,7 @@ public:
KResult unlink(const String& path, Inode& base);
KResult rmdir(const String& path, Inode& base);
KResult chmod(const String& path, mode_t, Inode& base);
KResult chmod(Inode&, mode_t);
KResult chown(const String& path, uid_t, gid_t, Inode& base);
KResult access(const String& path, int mode, Inode& base);
bool stat(const String& path, int& error, int options, Inode& base, struct stat&);

View File

@ -25,8 +25,8 @@ int chmod(const char* pathname, mode_t mode)
int fchmod(int fd, mode_t mode)
{
dbgprintf("FIXME(LibC): fchmod(%d, %o)\n", fd, mode);
ASSERT_NOT_REACHED();
int rc = syscall(SC_fchmod, fd, mode);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}

View File

@ -2,6 +2,7 @@
#include <fcntl.h>
#include <assert.h>
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char** argv)
{
@ -9,6 +10,7 @@ int main(int argc, char** argv)
printf("usage: cp <source> <destination>\n");
return 0;
}
int src_fd = open(argv[1], O_RDONLY);
if (src_fd < 0) {
perror("open src");
@ -20,6 +22,13 @@ int main(int argc, char** argv)
return 1;
}
struct stat src_stat;
int rc = fstat(src_fd, &src_stat);
if (rc < 0) {
perror("stat src");
return 1;
}
for (;;) {
char buffer[BUFSIZ];
ssize_t nread = read(src_fd, buffer, sizeof(buffer));
@ -42,6 +51,13 @@ int main(int argc, char** argv)
bufptr += nwritten;
}
}
rc = fchmod(dst_fd, src_stat.st_mode);
if (rc < 0) {
perror("fchmod dst");
return 1;
}
close(src_fd);
close(dst_fd);
return 0;