mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 04:57:44 +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
16 changed files with 142 additions and 6 deletions
|
@ -2009,3 +2009,13 @@ Inode* Process::cwd_inode()
|
||||||
m_cwd = VFS::the().root_inode();
|
m_cwd = VFS::the().root_inode();
|
||||||
return m_cwd.ptr();
|
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);
|
int sys$mkdir(const char* pathname, mode_t mode);
|
||||||
Unix::clock_t sys$times(Unix::tms*);
|
Unix::clock_t sys$times(Unix::tms*);
|
||||||
int sys$utime(const char* pathname, const struct Unix::utimbuf*);
|
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$create_window(const GUI_WindowParameters*);
|
||||||
int gui$destroy_window(int window_id);
|
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);
|
return current->sys$utime((const char*)arg1, (const Unix::utimbuf*)arg2);
|
||||||
case Syscall::SC_sync:
|
case Syscall::SC_sync:
|
||||||
return sync();
|
return sync();
|
||||||
|
case Syscall::SC_unlink:
|
||||||
|
return current->sys$unlink((const char*)arg1);
|
||||||
case Syscall::SC_gui_create_window:
|
case Syscall::SC_gui_create_window:
|
||||||
return current->gui$create_window((const GUI_WindowParameters*)arg1);
|
return current->gui$create_window((const GUI_WindowParameters*)arg1);
|
||||||
case Syscall::SC_gui_destroy_window:
|
case Syscall::SC_gui_destroy_window:
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
__ENUMERATE_SYSCALL(select) \
|
__ENUMERATE_SYSCALL(select) \
|
||||||
__ENUMERATE_SYSCALL(gui_get_window_parameters) \
|
__ENUMERATE_SYSCALL(gui_get_window_parameters) \
|
||||||
__ENUMERATE_SYSCALL(gui_set_window_parameters) \
|
__ENUMERATE_SYSCALL(gui_set_window_parameters) \
|
||||||
|
__ENUMERATE_SYSCALL(unlink) \
|
||||||
|
|
||||||
|
|
||||||
struct fd_set;
|
struct fd_set;
|
||||||
|
|
|
@ -42,6 +42,7 @@ cp -v ../Userland/mkdir mnt/bin/mkdir
|
||||||
cp -v ../Userland/touch mnt/bin/touch
|
cp -v ../Userland/touch mnt/bin/touch
|
||||||
cp -v ../Userland/sync mnt/bin/sync
|
cp -v ../Userland/sync mnt/bin/sync
|
||||||
cp -v ../Userland/more mnt/bin/more
|
cp -v ../Userland/more mnt/bin/more
|
||||||
|
cp -v ../Userland/rm mnt/bin/rm
|
||||||
cp -v ../Userland/guitest mnt/bin/guitest
|
cp -v ../Userland/guitest mnt/bin/guitest
|
||||||
cp -v ../Userland/guitest2 mnt/bin/guitest2
|
cp -v ../Userland/guitest2 mnt/bin/guitest2
|
||||||
cp -v ../Userland/sysctl mnt/bin/sysctl
|
cp -v ../Userland/sysctl mnt/bin/sysctl
|
||||||
|
|
|
@ -199,9 +199,10 @@ int link(const char*, const char*)
|
||||||
assert(false);
|
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)
|
int isatty(int fd)
|
||||||
|
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
|
@ -24,3 +24,4 @@ more
|
||||||
guitest
|
guitest
|
||||||
guitest2
|
guitest2
|
||||||
sysctl
|
sysctl
|
||||||
|
rm
|
||||||
|
|
|
@ -21,7 +21,8 @@ OBJS = \
|
||||||
more.o \
|
more.o \
|
||||||
guitest.o \
|
guitest.o \
|
||||||
guitest2.o \
|
guitest2.o \
|
||||||
sysctl.o
|
sysctl.o \
|
||||||
|
rm.o
|
||||||
|
|
||||||
APPS = \
|
APPS = \
|
||||||
id \
|
id \
|
||||||
|
@ -47,7 +48,8 @@ APPS = \
|
||||||
more \
|
more \
|
||||||
guitest \
|
guitest \
|
||||||
guitest2 \
|
guitest2 \
|
||||||
sysctl
|
sysctl \
|
||||||
|
rm
|
||||||
|
|
||||||
ARCH_FLAGS =
|
ARCH_FLAGS =
|
||||||
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
|
STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib -nostdinc
|
||||||
|
@ -139,6 +141,9 @@ guitest2: guitest2.o
|
||||||
sysctl: sysctl.o
|
sysctl: sysctl.o
|
||||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||||
|
|
||||||
|
rm: rm.o
|
||||||
|
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||||
|
|
||||||
.cpp.o:
|
.cpp.o:
|
||||||
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
@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()
|
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
|
InodeMetadata Ext2FSInode::metadata() const
|
||||||
|
@ -443,6 +448,50 @@ bool Ext2FSInode::add_child(InodeIdentifier child_id, const String& name, byte f
|
||||||
return success;
|
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)
|
bool Ext2FS::write_directory_inode(unsigned directoryInode, Vector<DirectoryEntry>&& entries)
|
||||||
{
|
{
|
||||||
dbgprintf("Ext2FS: New directory inode %u contents to write:\n", directoryInode);
|
dbgprintf("Ext2FS: New directory inode %u contents to write:\n", directoryInode);
|
||||||
|
@ -1050,7 +1099,16 @@ int Ext2FSInode::decrement_link_count()
|
||||||
{
|
{
|
||||||
if (fs().is_readonly())
|
if (fs().is_readonly())
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
ASSERT(m_raw_inode.i_links_count);
|
||||||
--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);
|
set_metadata_dirty(true);
|
||||||
return 0;
|
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 void flush_metadata() override;
|
||||||
virtual bool write(const ByteBuffer&) 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 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 RetainPtr<Inode> parent() const override;
|
||||||
virtual int set_atime(Unix::time_t) override;
|
virtual int set_atime(Unix::time_t) override;
|
||||||
virtual int set_ctime(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_inode_allocation_state(unsigned inode, bool);
|
||||||
bool set_block_allocation_state(GroupIndex, BlockIndex, bool);
|
bool set_block_allocation_state(GroupIndex, BlockIndex, bool);
|
||||||
|
|
||||||
|
void uncache_inode(InodeIndex);
|
||||||
|
|
||||||
unsigned m_blockGroupCount { 0 };
|
unsigned m_blockGroupCount { 0 };
|
||||||
|
|
||||||
mutable ByteBuffer m_cached_super_block;
|
mutable ByteBuffer m_cached_super_block;
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
virtual String reverse_lookup(InodeIdentifier) = 0;
|
virtual String reverse_lookup(InodeIdentifier) = 0;
|
||||||
virtual bool write(const ByteBuffer&) = 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 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;
|
virtual RetainPtr<Inode> parent() const = 0;
|
||||||
|
|
||||||
bool is_metadata_dirty() const { return m_metadata_dirty; }
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SynthFSInode::remove_child(const String& name, int& error)
|
||||||
|
{
|
||||||
|
(void) name;
|
||||||
|
(void) error;
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
SynthFSInodeCustomData::~SynthFSInodeCustomData()
|
SynthFSInodeCustomData::~SynthFSInodeCustomData()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ private:
|
||||||
virtual void flush_metadata() override;
|
virtual void flush_metadata() override;
|
||||||
virtual bool write(const ByteBuffer&) 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 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 RetainPtr<Inode> parent() const override;
|
||||||
|
|
||||||
SynthFS& fs();
|
SynthFS& fs();
|
||||||
|
|
|
@ -222,6 +222,32 @@ bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& erro
|
||||||
return false;
|
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)
|
InodeIdentifier VFS::resolve_symbolic_link(InodeIdentifier base, Inode& symlink_inode, int& error)
|
||||||
{
|
{
|
||||||
auto symlink_contents = symlink_inode.read_entire();
|
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> 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);
|
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 mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
||||||
|
bool unlink(const String& path, Inode& base, int& error);
|
||||||
bool touch(const String&path);
|
|
||||||
|
|
||||||
void register_character_device(CharacterDevice&);
|
void register_character_device(CharacterDevice&);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue