-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow clearing FAT dirty flag. #66
base: master
Are you sure you want to change the base?
Conversation
src/fs.rs
Outdated
@@ -604,6 +608,15 @@ impl<IO: Read + Write + Seek, TP, OCC> FileSystem<IO, TP, OCC> { | |||
Ok(()) | |||
} | |||
|
|||
pub fn set_fat_dirty_flag(&self, dirty: bool) -> Result<(), Error<IO::Error>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think handling it when filesystem is mounted would be better. Fail by default if dirty flag is set + add option in FsOptions
to allow mounting a dirty FS (and clear the flag during mounting - this probably deserves another option). Also handle dirty flag from BSP. I don't like showing in user-facing API those weird and legacy things from FAT like doubled dirty flags by making two setters and getters.
Of course it is still a bad to work with a dirty FS. Proper solution would be to add some filesystem checking functionality but that's probably a ton of work...
c57fad8
to
9bbab4f
Compare
@rafalh, I have moved the check and added an option to ignore/clear the flag when mounting the file system. |
4971e1c
to
d05dca7
Compare
@rafalh, can you review this again? Thanks. |
@rafalh, ping. |
@rafalh, could you have another look here? Thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you mixed in too many things here. Dirty bit handling is a very important thing and can result in undetected filesystem corruption if not handled with care. I don't like changes to it being mixed with some refactors like const
functions or some weird changes to errors in DiskSlice
.
Please split this into smaller PRs that are easy to review.
let status_flags = fs.read_status_flags().unwrap(); | ||
assert_eq!(status_flags.dirty(), true); | ||
assert_eq!(status_flags.dirty(), false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also add one more remount step to make sure dirty flag is cleared on the disk (it is cached so such test makes sense)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added another remount step.
val |= FAT32_IO_ERROR_BIT; | ||
} | ||
|
||
Fat32::set(fat, 1, FatValue::Data(!val)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to keep it more explicit than using bit-wise negation here like that.
Also it's not really a "data" so it makes more sense to use set_raw
function
src/fs.rs
Outdated
} | ||
|
||
fn unmount_internal(&self) -> Result<(), Error<IO::Error>> { | ||
pub fn flush(&mut self) -> Result<(), Error<IO::Error>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, at first I through it's a bad idea to allow clearing the dirty flag like that, but it makes sense because dirty flag is set after first write, not at mount. If I understand correctly &mut
will require all files to be closed, so it should be okay.
But if this was to be public it must be documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the &mut
is the important part here. This is basically the same as unmount
without actually dropping the IO
object.
if bpb.status_flags().dirty { | ||
if bpb_status_flags.dirty() { | ||
if options.ignore_dirty_flag { | ||
warn!("BPB is dirty, clearing dirty flag."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not BPB being dirty, it's entire filesystem. Please change it, e.g. "Filesystem is dirty (BPB), clearing..."
let mut fat_status_flags = read_fat_flags(&mut fat_slice::<&mut IO, IO::Error, IO>(&mut disk, &bpb), fat_type)?; | ||
if fat_status_flags.dirty() { | ||
if options.ignore_dirty_flag { | ||
warn!("FAT is dirty, clearing dirty flag."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not BPB being dirty, it's entire filesystem. Please change it, e.g. "Filesystem is dirty (FAT), clearing..."
@@ -512,7 +552,7 @@ impl<IO: Read + Write + Seek, TP, OCC> FileSystem<IO, TP, OCC> { | |||
/// | |||
/// `Error::Io` will be returned if the underlying storage object returned an I/O error. | |||
pub fn read_status_flags(&self) -> Result<FsStatusFlags, Error<IO::Error>> { | |||
let bpb_status = self.bpb.status_flags(); | |||
let bpb_status = self.current_status_flags.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function allowed to check if dirty flag was set before filesystem was opened. current_status_flags
will never have this flag set, even if ignore_dirty_flag
is set. I would rather keep the old behavior for now because new one makes it impossible to mount a dirty volume and still get information about it being dirty.
src/fs.rs
Outdated
disk.write_u8(encoded)?; | ||
self.current_status_flags.set(flags); | ||
Ok(()) | ||
set_dirty_flag(&mut *disk, self.fat_type(), &self.current_status_flags, dirty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why adding this new free set_dirty_flag
function? AFAIK it is used only in this place.
@@ -695,12 +716,12 @@ pub(crate) struct FsIoAdapter<'a, IO: ReadWriteSeek, TP, OCC> { | |||
} | |||
|
|||
impl<IO: ReadWriteSeek, TP, OCC> IoBase for FsIoAdapter<'_, IO, TP, OCC> { | |||
type Error = IO::Error; | |||
type Error = Error<IO::Error>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this change? I see some more changes to error handling but I don't understand how it is related to clearing dirty flags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite remember exactly. Somewhere the errors types were not compatible during propagation.
dfb1181
to
e8f9663
Compare
e8f9663
to
8e79f69
Compare
8e79f69
to
6ec1aa4
Compare
@rafalh, can you take a look here? You should review my other PRs first so I can rebase this one for easier review. |
When the FAT dirty flag is set (which happens after ejecting an SD card without unmounting first on macOS), creating directories does not work as expected afterwards: When remounting the SD card after creating directories, these directories will be files instead.
If the dirty flag is cleared before creating the directories, mounting the SD card again under macOS works as expected, i.e. the directories are accessible as normal.
I have added a
set_fat_dirty_flag
method to clear the flag, but I am not sure when clearing this flag should be done.When the dirty flag is set, this should result in an error when creating the
FileSystem
(or when trying to write to it).Alternatively, the flag should ideally be cleared automatically when mounting after the filesystem has been checked somehow.
Closes #64.