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

This commit is contained in:
Andreas Kling 2019-04-07 23:35:26 +02:00
parent 71b6436552
commit 37ae00a4dd
Notes: sideshowbarker 2024-07-19 14:47:42 +09:00
11 changed files with 99 additions and 2 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
Userland/.gitignore vendored
View file

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

View file

@ -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
Userland/mv.cpp Normal file
View file

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