7fa12df7 overlooked the fact that we use `first_cluster == 0` to
represent root directories in addition to clusterless entries. This
patch makes compute_cluster_list return a cluster list that actually
contains cluster #0 if we're dealing with the root directory (like it
used to), but retains the new behavior for all other entries.
Instead, this patch makes it get all the information it needs directly
from the inode object or the filesystem. This also inlines the
cluster-freeing mechanism in remove_child_impl since we can no longer
use compute_cluster_list there.
This isn't a valid scenario, and we don't really guard against malformed
filesystems in most places, but this becomes somewhat relevant in the
next commit.
Since the VFS renaming refactor, this function has only been used for
hardlinking, which isn't possible on FATFS since there's no real concept
of inodes or anything comparable to those.
Now we no longer compute the cluster list at the exact moment when an
in-memory inode is created, but rather defer doing that until we
actually need the cluster list. This distinction is important when
traversing directories, as we *are* interested in the inode, but not
really in its contents (though now we do have to resort to using the
file size to approximate the amount of allocated blocks, but this
shouldn't be an issue when working with well-formed filesystems.)
Plain resizes (that increase file size) are now much faster, as the
zeroing is now done in a more efficient way (rather than just looping
over `write_bytes_locked`.) Writes should also be faster, since we no
longer zero out the underlying bytes if we are going to write something
in that very same location anyway.
Previously, the VFS layer would try to handle renames more-or-less by
itself, which really only worked for ext2, and even that was only due to
the replace_child kludge existing specifically for this purpose. This
never worked properly for FATFS, since the VFS layer effectively
depended on filesystems having some kind of reference-counting for
inodes, which is something that simply doesn't exist on any FAT variant
we support.
To resolve various issues with the existing scheme, this commit makes
filesystem implementations themselves responsible for the actual rename
operation, while keeping all the existing validation inside the VFS
layer. The only intended behavior change here is that rename operations
should actually properly work on FATFS.
There were two separate issues at play which made this work incorrectly.
The first was that the newly allocated block was incorrectly computed,
because it was assumed that the cached block list was updated when a new
cluster was allocated. The second issue was that there was an off-by-one
in the loop that collected the newly allocated entries, which meant that
the resulting list had an entry less than what was requested.
The old overload still depended on m_entry being initialized, which
meant that (due to where this method is used) all inodes ended up
getting the same index.
This is a large commit because it implements a lot of stuff to make
add_child simpler to get working. This allows us to create new files
on a FAT partition.
This is the first part of write support, it allows for full file
modification, but no creating or removing files yet.
Co-Authored-By: implicitfield <114500360+implicitfield@users.noreply.github.com>
Caching the cluster list allows us to fill the two fields in the
InodeMetadata. While at it, don't cache the metadata as when we
have write support having to keep both InodeMetadata and FATEntry
correct is going to get very annoying.
This never was a logical block size, it always was a device specific
block size. Ideally the block size would change in accordance to
whatever the driver wants to use, but that is a change for the future.
For now, let's get rid of this confusing naming.