mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
Add unlink() syscall and /bin/rm.
This patch adds most of the plumbing for working file deletion in Ext2FS. Directory entries are removed and inode link counts updated. We don't yet update the inode or block bitmaps, I will do that separately.
This commit is contained in:
parent
2f2f28f212
commit
bda0c935c2
Notes:
sideshowbarker
2024-07-19 15:58:59 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/bda0c935c26
16 changed files with 142 additions and 6 deletions
|
@ -2009,3 +2009,13 @@ Inode* Process::cwd_inode()
|
|||
m_cwd = VFS::the().root_inode();
|
||||
return m_cwd.ptr();
|
||||
}
|
||||
|
||||
int Process::sys$unlink(const char* pathname)
|
||||
{
|
||||
if (!validate_read_str(pathname))
|
||||
return -EFAULT;
|
||||
int error;
|
||||
if (!VFS::the().unlink(String(pathname), *cwd_inode(), error))
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -191,6 +191,7 @@ public:
|
|||
int sys$mkdir(const char* pathname, mode_t mode);
|
||||
Unix::clock_t sys$times(Unix::tms*);
|
||||
int sys$utime(const char* pathname, const struct Unix::utimbuf*);
|
||||
int sys$unlink(const char* pathname);
|
||||
|
||||
int gui$create_window(const GUI_WindowParameters*);
|
||||
int gui$destroy_window(int window_id);
|
||||
|
|
|
@ -191,6 +191,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
|||
return current->sys$utime((const char*)arg1, (const Unix::utimbuf*)arg2);
|
||||
case Syscall::SC_sync:
|
||||
return sync();
|
||||
case Syscall::SC_unlink:
|
||||
return current->sys$unlink((const char*)arg1);
|
||||
case Syscall::SC_gui_create_window:
|
||||
return current->gui$create_window((const GUI_WindowParameters*)arg1);
|
||||
case Syscall::SC_gui_destroy_window:
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
__ENUMERATE_SYSCALL(select) \
|
||||
__ENUMERATE_SYSCALL(gui_get_window_parameters) \
|
||||
__ENUMERATE_SYSCALL(gui_set_window_parameters) \
|
||||
__ENUMERATE_SYSCALL(unlink) \
|
||||
|
||||
|
||||
struct fd_set;
|
||||
|
|
|
@ -42,6 +42,7 @@ cp -v ../Userland/mkdir mnt/bin/mkdir
|
|||
cp -v ../Userland/touch mnt/bin/touch
|
||||
cp -v ../Userland/sync mnt/bin/sync
|
||||
cp -v ../Userland/more mnt/bin/more
|
||||
cp -v ../Userland/rm mnt/bin/rm
|
||||
cp -v ../Userland/guitest mnt/bin/guitest
|
||||
cp -v ../Userland/guitest2 mnt/bin/guitest2
|
||||
cp -v ../Userland/sysctl mnt/bin/sysctl
|
||||
|
|
|
@ -199,9 +199,10 @@ int link(const char*, const char*)
|
|||
assert(false);
|
||||
}
|
||||
|
||||
int unlink(const char*)
|
||||
int unlink(const char* pathname)
|
||||
{
|
||||
assert(false);
|
||||
int rc = syscall(SC_unlink, pathname);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int isatty(int fd)
|
||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -24,3 +24,4 @@ more
|
|||
guitest
|
||||
guitest2
|
||||
sysctl
|
||||
rm
|
||||
|
|
|
@ -21,7 +21,8 @@ OBJS = \
|
|||
more.o \
|
||||
guitest.o \
|
||||
guitest2.o \
|
||||
sysctl.o
|
||||
sysctl.o \
|
||||
rm.o
|
||||
|
||||
APPS = \
|
||||
id \
|
||||
|
@ -47,7 +48,8 @@ APPS = \
|
|||
more \
|
||||
guitest \
|
||||
guitest2 \
|
||||
sysctl
|
||||
sysctl \
|
||||
rm
|
||||
|
||||
ARCH_FLAGS =
|
||||
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
|
||||
|
@ -139,6 +141,9 @@ guitest2: guitest2.o
|
|||
sysctl: sysctl.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||
|
||||
rm: rm.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||
|
||||
.cpp.o:
|
||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
|
|
18
Userland/rm.cpp
Normal file
18
Userland/rm.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: rm <path>\n");
|
||||
return 1;
|
||||
}
|
||||
int rc = unlink(argv[1]);
|
||||
if (rc < 0) {
|
||||
perror("unlink");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -219,6 +219,11 @@ Ext2FSInode::Ext2FSInode(Ext2FS& fs, unsigned index, const ext2_inode& raw_inode
|
|||
|
||||
Ext2FSInode::~Ext2FSInode()
|
||||
{
|
||||
if (m_raw_inode.i_links_count == 0) {
|
||||
dbgprintf("Ext2FS: inode %u has no more links, time to delete!\n", index());
|
||||
// FIXME: Implement!
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
InodeMetadata Ext2FSInode::metadata() const
|
||||
|
@ -443,6 +448,50 @@ bool Ext2FSInode::add_child(InodeIdentifier child_id, const String& name, byte f
|
|||
return success;
|
||||
}
|
||||
|
||||
bool Ext2FSInode::remove_child(const String& name, int& error)
|
||||
{
|
||||
ASSERT(is_directory());
|
||||
|
||||
unsigned child_inode_index;
|
||||
{
|
||||
LOCKER(m_lock);
|
||||
auto it = m_lookup_cache.find(name);
|
||||
if (it == m_lookup_cache.end()) {
|
||||
error = -ENOENT;
|
||||
return false;
|
||||
}
|
||||
child_inode_index = (*it).value;
|
||||
}
|
||||
InodeIdentifier child_id { fsid(), child_inode_index };
|
||||
|
||||
//#ifdef EXT2_DEBUG
|
||||
dbgprintf("Ext2FS: Removing '%s' in directory %u\n", name.characters(), index());
|
||||
//#endif
|
||||
|
||||
Vector<FS::DirectoryEntry> entries;
|
||||
traverse_as_directory([&] (auto& entry) {
|
||||
if (entry.inode != child_id)
|
||||
entries.append(entry);
|
||||
return true;
|
||||
});
|
||||
|
||||
bool success = fs().write_directory_inode(index(), move(entries));
|
||||
if (!success) {
|
||||
// FIXME: Plumb error from write_directory_inode().
|
||||
error = -EIO;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
LOCKER(m_lock);
|
||||
m_lookup_cache.remove(name);
|
||||
}
|
||||
|
||||
auto child_inode = fs().get_inode(child_id);
|
||||
child_inode->decrement_link_count();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Ext2FS::write_directory_inode(unsigned directoryInode, Vector<DirectoryEntry>&& entries)
|
||||
{
|
||||
dbgprintf("Ext2FS: New directory inode %u contents to write:\n", directoryInode);
|
||||
|
@ -1050,7 +1099,16 @@ int Ext2FSInode::decrement_link_count()
|
|||
{
|
||||
if (fs().is_readonly())
|
||||
return -EROFS;
|
||||
ASSERT(m_raw_inode.i_links_count);
|
||||
--m_raw_inode.i_links_count;
|
||||
if (m_raw_inode.i_links_count == 0)
|
||||
fs().uncache_inode(index());
|
||||
set_metadata_dirty(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Ext2FS::uncache_inode(InodeIndex index)
|
||||
{
|
||||
LOCKER(m_inode_cache_lock);
|
||||
m_inode_cache.remove(index);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ private:
|
|||
virtual void flush_metadata() override;
|
||||
virtual bool write(const ByteBuffer&) override;
|
||||
virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) override;
|
||||
virtual bool remove_child(const String& name, int& error) override;
|
||||
virtual RetainPtr<Inode> parent() const override;
|
||||
virtual int set_atime(Unix::time_t) override;
|
||||
virtual int set_ctime(Unix::time_t) override;
|
||||
|
@ -105,6 +106,8 @@ private:
|
|||
bool set_inode_allocation_state(unsigned inode, bool);
|
||||
bool set_block_allocation_state(GroupIndex, BlockIndex, bool);
|
||||
|
||||
void uncache_inode(InodeIndex);
|
||||
|
||||
unsigned m_blockGroupCount { 0 };
|
||||
|
||||
mutable ByteBuffer m_cached_super_block;
|
||||
|
|
|
@ -85,6 +85,7 @@ public:
|
|||
virtual String reverse_lookup(InodeIdentifier) = 0;
|
||||
virtual bool write(const ByteBuffer&) = 0;
|
||||
virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) = 0;
|
||||
virtual bool remove_child(const String& name, int& error) = 0;
|
||||
virtual RetainPtr<Inode> parent() const = 0;
|
||||
|
||||
bool is_metadata_dirty() const { return m_metadata_dirty; }
|
||||
|
|
|
@ -290,6 +290,14 @@ bool SynthFSInode::add_child(InodeIdentifier child_id, const String& name, byte
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SynthFSInode::remove_child(const String& name, int& error)
|
||||
{
|
||||
(void) name;
|
||||
(void) error;
|
||||
ASSERT_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
SynthFSInodeCustomData::~SynthFSInodeCustomData()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ private:
|
|||
virtual void flush_metadata() override;
|
||||
virtual bool write(const ByteBuffer&) override;
|
||||
virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) override;
|
||||
virtual bool remove_child(const String& name, int& error) override;
|
||||
virtual RetainPtr<Inode> parent() const override;
|
||||
|
||||
SynthFS& fs();
|
||||
|
|
|
@ -222,6 +222,32 @@ bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& erro
|
|||
return false;
|
||||
}
|
||||
|
||||
bool VFS::unlink(const String& path, Inode& base, int& error)
|
||||
{
|
||||
error = -EWHYTHO;
|
||||
// FIXME: This won't work nicely across mount boundaries.
|
||||
FileSystemPath p(path);
|
||||
if (!p.is_valid()) {
|
||||
error = -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
InodeIdentifier parent_dir;
|
||||
auto inode_id = resolve_path(path, base.identifier(), error, 0, &parent_dir);
|
||||
if (!inode_id.is_valid()) {
|
||||
error = -ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto parent_inode = get_inode(parent_dir);
|
||||
// FIXME: The reverse_lookup here can definitely be avoided.
|
||||
if (!parent_inode->remove_child(parent_inode->reverse_lookup(inode_id), error))
|
||||
return false;
|
||||
|
||||
error = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
InodeIdentifier VFS::resolve_symbolic_link(InodeIdentifier base, Inode& symlink_inode, int& error)
|
||||
{
|
||||
auto symlink_contents = symlink_inode.read_entire();
|
||||
|
|
|
@ -67,8 +67,7 @@ public:
|
|||
RetainPtr<FileDescriptor> open(const String& path, int& error, int options, mode_t mode, InodeIdentifier base = InodeIdentifier());
|
||||
RetainPtr<FileDescriptor> create(const String& path, int& error, int options, mode_t mode, InodeIdentifier base);
|
||||
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
||||
|
||||
bool touch(const String&path);
|
||||
bool unlink(const String& path, Inode& base, int& error);
|
||||
|
||||
void register_character_device(CharacterDevice&);
|
||||
|
||||
|
|
Loading…
Reference in a new issue