Преглед изворни кода

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

/bin/cp will now copy the permission bits from source to destination. :^)
Andreas Kling пре 6 година
родитељ
комит
1b16a29044

+ 7 - 0
Kernel/FileDescriptor.cpp

@@ -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());

+ 2 - 0
Kernel/FileDescriptor.h

@@ -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&);
 

+ 8 - 0
Kernel/Process.cpp

@@ -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))

+ 1 - 0
Kernel/Process.h

@@ -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);

+ 2 - 0
Kernel/Syscall.cpp

@@ -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:

+ 1 - 0
Kernel/Syscall.h

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

+ 13 - 11
Kernel/VirtualFileSystem.cpp

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

+ 1 - 0
Kernel/VirtualFileSystem.h

@@ -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&);

+ 2 - 2
LibC/stat.cpp

@@ -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);
 }
 
 }

+ 16 - 0
Userland/cp.cpp

@@ -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;