pluto icon indicating copy to clipboard operation
pluto copied to clipboard

VFS file and directory deletion

Open SamTebbs33 opened this issue 4 years ago • 7 comments

The virtual filesystem should support deleting of files and directories (which should only be deletable if it has no children).

SamTebbs33 avatar Jul 21 '20 17:07 SamTebbs33

How will this work? Should initrd support file deletion? Or should an Unimplemented error be added to vfs.Error?

iamgweej avatar Aug 08 '20 11:08 iamgweej

My opinion is that whether deletion is implemented shouldn't be a concern for the code attempting to delete a file, so I don't think it should throw an error. I think it would be fine to just do nothing and perhaps log that an unsupported operation was attempted. As the implementer, @DrDeano may have some input.

SamTebbs33 avatar Aug 08 '20 15:08 SamTebbs33

For the initrd, this isn't a "real" file system, so probrably just log something at the most, but will just do nothing. As the user won't be interacting with the initrd anyway, there won't be any code that trys to delete a file from the initrd.

DrDeano avatar Aug 08 '20 20:08 DrDeano

I've been looking a bit into old linux kernels to see how to implement their VFS, and it seems to look something like this:

struct file_operations {
	int (*lseek) (struct inode *, struct file *, off_t, int);
	int (*read) (struct inode *, struct file *, char *, int);
	int (*write) (struct inode *, struct file *, const char *, int);
	int (*readdir) (struct inode *, struct file *, void *, filldir_t);
	int (*select) (struct inode *, struct file *, int, select_table *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	void (*release) (struct inode *, struct file *);
	int (*fsync) (struct inode *, struct file *);
	int (*fasync) (struct inode *, struct file *, int);
	int (*check_media_change) (kdev_t dev);
	int (*revalidate) (kdev_t dev);
};

and:

struct inode_operations {
	struct file_operations * default_file_ops;
	int (*create) (struct inode *,const char *,int,int,struct inode **);
	int (*lookup) (struct inode *,const char *,int,struct inode **);
	int (*link) (struct inode *,struct inode *,const char *,int);
	int (*unlink) (struct inode *,const char *,int);
	int (*symlink) (struct inode *,const char *,int,const char *);
	int (*mkdir) (struct inode *,const char *,int,int);
	int (*rmdir) (struct inode *,const char *,int);
	int (*mknod) (struct inode *,const char *,int,int,int);
	int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
	int (*readlink) (struct inode *,char *,int);
	int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
	int (*readpage) (struct inode *, struct page *);
	int (*writepage) (struct inode *, struct page *);
	int (*bmap) (struct inode *,int);
	void (*truncate) (struct inode *);
	int (*permission) (struct inode *, int);
	int (*smap) (struct inode *,int);
};

I don't think we should feel obligated to follow their implementation, but I think it gives a rough idea what our VFS should support and in what fashion.

iamgweej avatar Aug 29 '20 12:08 iamgweej

It looks like their implementation (linux 2.0) supports deleting a file from a directory, as an operation on the directory taking the file basename as a parameter.

I've also checked in a newer kernel (v5.9-rc2) and it seems that there it is also an operation on the directory containing the file: https://www.kernel.org/doc/htmldocs/filesystems/API-vfs-unlink.html and https://elixir.bootlin.com/linux/v5.9-rc2/source/fs/namei.c#L3812

iamgweej avatar Aug 29 '20 12:08 iamgweej

Maybe something like this?

    ///
    /// Delete a member of this filesystem.
    ///
    /// Arguments:
    ///     IN self: *const FileSystem - The filesystem in question being operated on
    ///     IN node: *const DirNode - The directory to delete a file/directory from
    ///     IN name: []const u8 - The name of the file/directory to delete
    ///
    /// Error: Allocator.Error || Error
    ///     Allocator.Error.OutOfMemory - There wasn't enough memory to fulfill the request
    ///     Error.NoSuchFileOrDir - The file/dir by that name doesn't exist.
    ///     Error.NonemptyDir - The directory by that name is not empty, and therefore it can't be deleted.
    ///
    const Delete = fn (self: *const Self, node: *const DirNode, name: []const u8) (Allocator.Error || Error)!void;

iamgweej avatar Aug 29 '20 13:08 iamgweej

That looks good to me! It's nice that it is similar to open. Taking the name to represent the file/dir being deleted rather than a node is a good idea since it shouldn't have to be necessary to open a file/dir in order to delete it.

SamTebbs33 avatar Aug 29 '20 14:08 SamTebbs33