Jelajahi Sumber

Kernel+Userland: Add the rename() syscall along with a basic /bin/mv.

Andreas Kling 6 tahun lalu
induk
melakukan
37ae00a4dd

+ 44 - 0
Kernel/FileSystem/VirtualFileSystem.cpp

@@ -312,6 +312,50 @@ KResult VFS::chmod(const String& path, mode_t mode, Inode& base)
     return chmod(*inode, mode);
 }
 
+KResult VFS::rename(const String& old_path, const String& new_path, Inode& base)
+{
+    RetainPtr<Inode> old_parent_inode;
+    auto old_inode_or_error = resolve_path_to_inode(old_path, base, &old_parent_inode);
+    if (old_inode_or_error.is_error())
+        return old_inode_or_error.error();
+    auto old_inode = old_inode_or_error.value();
+
+    RetainPtr<Inode> new_parent_inode;
+    auto new_inode_or_error = resolve_path_to_inode(new_path, base, &new_parent_inode);
+    if (new_inode_or_error.is_error()) {
+        if (new_inode_or_error.error() != -ENOENT)
+            return new_inode_or_error.error();
+    }
+
+    if (!new_parent_inode->metadata().may_write(current->process()))
+        return KResult(-EACCES);
+
+    if (!old_parent_inode->metadata().may_write(current->process()))
+        return KResult(-EACCES);
+
+    if (!new_inode_or_error.is_error()) {
+        auto new_inode = new_inode_or_error.value();
+        // FIXME: Is this really correct? Check what other systems do.
+        if (new_inode.ptr() == old_inode.ptr())
+            return KSuccess;
+        if (new_inode->is_directory() && !old_inode->is_directory())
+            return KResult(-EISDIR);
+        auto result = new_parent_inode->remove_child(new_parent_inode->reverse_lookup(new_inode->identifier()));
+        if (result.is_error())
+            return result;
+    }
+
+    auto result = new_parent_inode->add_child(old_inode->identifier(), FileSystemPath(new_path).basename(), 0 /* FIXME: file type? */);
+    if (result.is_error())
+        return result;
+
+    result = old_parent_inode->remove_child(old_parent_inode->reverse_lookup(old_inode->identifier()));
+    if (result.is_error())
+        return result;
+
+    return KSuccess;
+}
+
 KResult VFS::chown(const String& path, uid_t a_uid, gid_t a_gid, Inode& base)
 {
     auto inode_or_error = resolve_path_to_inode(path, base);

+ 1 - 0
Kernel/FileSystem/VirtualFileSystem.h

@@ -75,6 +75,7 @@ public:
     KResult access(const String& path, int mode, Inode& base);
     KResult stat(const String& path, int options, Inode& base, struct stat&);
     KResult utime(const String& path, Inode& base, time_t atime, time_t mtime);
+    KResult rename(const String& oldpath, const String& newpath, Inode& base);
     KResultOr<Retained<Inode>> open_directory(const String& path, Inode& base);
 
     void register_device(Device&);

+ 9 - 0
Kernel/Process.cpp

@@ -2445,3 +2445,12 @@ int Process::sys$donate(int tid)
     Scheduler::donate_to(beneficiary, "sys$donate");
     return 0;
 }
+
+int Process::sys$rename(const char* oldpath, const char* newpath)
+{
+    if (!validate_read_str(oldpath))
+        return -EFAULT;
+    if (!validate_read_str(newpath))
+        return -EFAULT;
+    return VFS::the().rename(String(oldpath), String(newpath), cwd_inode());
+}

+ 1 - 0
Kernel/Process.h

@@ -180,6 +180,7 @@ public:
     int sys$setsockopt(const Syscall::SC_setsockopt_params*);
     int sys$restore_signal_mask(dword mask);
     int sys$create_thread(int(*)(void*), void*);
+    int sys$rename(const char* oldpath, const char* newpath);
 
     int sys$create_shared_buffer(pid_t peer_pid, int, void** buffer);
     void* sys$get_shared_buffer(int shared_buffer_id);

+ 2 - 0
Kernel/Syscall.cpp

@@ -241,6 +241,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
         return current->process().sys$setsockopt((const SC_setsockopt_params*)arg1);
     case Syscall::SC_create_thread:
         return current->process().sys$create_thread((int(*)(void*))arg1, (void*)arg2);
+    case Syscall::SC_rename:
+        return current->process().sys$rename((const char*)arg1, (const char*)arg2);
     default:
         kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
         break;

+ 1 - 0
Kernel/Syscall.h

@@ -95,6 +95,7 @@
     __ENUMERATE_SYSCALL(create_thread) \
     __ENUMERATE_SYSCALL(gettid) \
     __ENUMERATE_SYSCALL(donate) \
+    __ENUMERATE_SYSCALL(rename) \
 
 
 namespace Syscall {

+ 1 - 0
Kernel/sync.sh

@@ -79,6 +79,7 @@ cp -v ../Userland/uc mnt/bin/uc
 cp -v ../Userland/tc mnt/bin/tc
 cp -v ../Userland/host mnt/bin/host
 cp -v ../Userland/qs mnt/bin/qs
+cp -v ../Userland/mv mnt/bin/mv
 chmod 4755 mnt/bin/su
 cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal
 cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor

+ 2 - 2
LibC/stdio.cpp

@@ -418,8 +418,8 @@ int fclose(FILE* stream)
 
 int rename(const char* oldpath, const char* newpath)
 {
-    dbgprintf("FIXME(LibC): rename(%s, %s)\n", oldpath, newpath);
-    ASSERT_NOT_REACHED();
+    int rc = syscall(SC_rename, oldpath, newpath);
+    __RETURN_WITH_ERRNO(rc, rc, -1);
 }
 
 char* tmpnam(char*)

+ 1 - 0
Userland/.gitignore

@@ -42,3 +42,4 @@ uc
 tc
 host
 qs
+mv

+ 5 - 0
Userland/Makefile

@@ -38,6 +38,7 @@ OBJS = \
        tc.o \
        host.o \
        qs.o \
+       mv.o \
        rm.o
 
 APPS = \
@@ -81,6 +82,7 @@ APPS = \
        tc \
        host \
        qs \
+       mv \
        rm
 
 ARCH_FLAGS =
@@ -223,6 +225,9 @@ host: host.o
 qs: qs.o
 	$(LD) -o $@ $(LDFLAGS) -L../LibGUI $< -lgui -lc
 
+mv: mv.o
+	$(LD) -o $@ $(LDFLAGS) -L../LibGUI $< -lgui -lc
+
 .cpp.o:
 	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
 

+ 32 - 0
Userland/mv.cpp

@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <AK/AKString.h>
+#include <AK/FileSystemPath.h>
+
+int main(int argc, char** argv)
+{
+    if (argc != 3) {
+        printf("usage: mv <old-path> <new-path>\n");
+        return 1;
+    }
+
+    String old_path = argv[1];
+    String new_path = argv[2];
+
+    struct stat st;
+    int rc = lstat(new_path.characters(), &st);
+    if (rc == 0) {
+        if (S_ISDIR(st.st_mode)) {
+            auto old_basename = FileSystemPath(old_path).basename();
+            new_path = String::format("%s/%s", new_path.characters(), old_basename.characters());
+        }
+    }
+
+    rc = rename(old_path.characters(), new_path.characters());
+    if (rc < 0) {
+        perror("rename");
+        return 1;
+    }
+    return 0;
+}