fat32 rewrite and storage stability fixes
This commit is contained in:
+126
-7
File diff suppressed because it is too large
Load Diff
@@ -195,6 +195,7 @@ procedure do_refresh_load(state: PFileBrowserState); forward;
|
||||
procedure do_refresh_build(state: PFileBrowserState); forward;
|
||||
procedure schedule_refresh(state: PFileBrowserState); forward;
|
||||
procedure fb_refresh_poll_cb(tmr: Plv_timer); cdecl; forward;
|
||||
function fb_error_name(err : TError) : pchar; forward;
|
||||
procedure fb_collect_cb(key: pchar; data: void; ud: void); forward;
|
||||
procedure do_refresh(state: PFileBrowserState); forward;
|
||||
procedure navigate_to(state: PFileBrowserState; newDir: pchar); forward;
|
||||
@@ -582,6 +583,51 @@ begin
|
||||
puint32(@state^.refresh_pending)^ := 1;
|
||||
end;
|
||||
|
||||
function fb_error_name(err : TError) : pchar;
|
||||
begin
|
||||
case err of
|
||||
eNone: fb_error_name := 'eNone';
|
||||
eUnknown: fb_error_name := 'eUnknown';
|
||||
eNotSupported: fb_error_name := 'eNotSupported';
|
||||
eOutOfMemory: fb_error_name := 'eOutOfMemory';
|
||||
eInvalidArgument: fb_error_name := 'eInvalidArgument';
|
||||
eFileInUse: fb_error_name := 'eFileInUse';
|
||||
eFileDoesNotExist: fb_error_name := 'eFileDoesNotExist';
|
||||
eInvalidFileName: fb_error_name := 'eInvalidFileName';
|
||||
eInvalidFileExtension: fb_error_name := 'eInvalidFileExtension';
|
||||
eFilenameTooLong: fb_error_name := 'eFilenameTooLong';
|
||||
eDirectoryDoesNotExist: fb_error_name := 'eDirectoryDoesNotExist';
|
||||
eDirectoryAlreadyExists: fb_error_name := 'eDirectoryAlreadyExists';
|
||||
eDirectoryNotEmpty: fb_error_name := 'eDirectoryNotEmpty';
|
||||
eDirectoryFull: fb_error_name := 'eDirectoryFull';
|
||||
eNotADirectory: fb_error_name := 'eNotADirectory';
|
||||
eWriteOnly: fb_error_name := 'eWriteOnly';
|
||||
eReadOnly: fb_error_name := 'eReadOnly';
|
||||
ePermissionDenied: fb_error_name := 'ePermissionDenied';
|
||||
eInvalidPath: fb_error_name := 'eInvalidPath';
|
||||
eTooManyOpenFiles: fb_error_name := 'eTooManyOpenFiles';
|
||||
eInvalidHandle: fb_error_name := 'eInvalidHandle';
|
||||
eFileNotLoaded: fb_error_name := 'eFileNotLoaded';
|
||||
eAlreadyExists: fb_error_name := 'eAlreadyExists';
|
||||
eDiskFull: fb_error_name := 'eDiskFull';
|
||||
eIOError: fb_error_name := 'eIOError';
|
||||
eIOTimeout: fb_error_name := 'eIOTimeout';
|
||||
eIOCancelled: fb_error_name := 'eIOCancelled';
|
||||
eDeviceNotReady: fb_error_name := 'eDeviceNotReady';
|
||||
eDeviceRemoved: fb_error_name := 'eDeviceRemoved';
|
||||
eDeviceNotFound: fb_error_name := 'eDeviceNotFound';
|
||||
eQueueFull: fb_error_name := 'eQueueFull';
|
||||
eNoFreeSlot: fb_error_name := 'eNoFreeSlot';
|
||||
eCorruptFilesystem: fb_error_name := 'eCorruptFilesystem';
|
||||
eBadSector: fb_error_name := 'eBadSector';
|
||||
eAlreadyMounted: fb_error_name := 'eAlreadyMounted';
|
||||
eNotMounted: fb_error_name := 'eNotMounted';
|
||||
eUnsupportedFilesystem: fb_error_name := 'eUnsupportedFilesystem';
|
||||
eInvalidPartitionTable: fb_error_name := 'eInvalidPartitionTable';
|
||||
eVolumeNotFound: fb_error_name := 'eVolumeNotFound';
|
||||
end;
|
||||
end;
|
||||
|
||||
{ fb_refresh_poll_cb — 50ms LVGL poll timer; when rd_ready=1, build UI }
|
||||
procedure fb_refresh_poll_cb(tmr: Plv_timer); cdecl;
|
||||
var
|
||||
@@ -604,9 +650,12 @@ begin
|
||||
case state^.wop_kind of
|
||||
1: lv_msgbox_add_text(mbox, 'Could not create folder.');
|
||||
2: lv_msgbox_add_text(mbox, 'Could not rename item.');
|
||||
3: lv_msgbox_add_text(mbox, 'Could not create file.');
|
||||
4: lv_msgbox_add_text(mbox, 'Could not delete item.');
|
||||
else
|
||||
lv_msgbox_add_text(mbox, 'Operation failed.');
|
||||
end;
|
||||
lv_msgbox_add_text(mbox, fb_error_name(state^.wop_result));
|
||||
ok_b := lv_msgbox_add_footer_button(mbox, 'OK');
|
||||
lv_obj_add_event_cb(ok_b, @fb_mbox_close_cb, LV_EVENT_CLICKED, mbox);
|
||||
end;
|
||||
@@ -619,8 +668,8 @@ begin
|
||||
kfree(void(state^.wop_path2));
|
||||
state^.wop_path2 := nil;
|
||||
end;
|
||||
{ For rename, clear selection }
|
||||
if state^.wop_kind = 2 then
|
||||
{ For rename/delete, clear selection }
|
||||
if (state^.wop_kind = 2) or (state^.wop_kind = 4) then
|
||||
clear_selection(state);
|
||||
schedule_refresh(state);
|
||||
end;
|
||||
@@ -1591,15 +1640,16 @@ begin
|
||||
@fb_delete_done, state);
|
||||
end;
|
||||
|
||||
{ Async completion callback — runs in ISR/worker context, defer to LVGL }
|
||||
{ Async completion callback — runs outside the LVGL thread, so only set flags. }
|
||||
procedure fb_delete_done(error: TError; userdata: pointer);
|
||||
var
|
||||
state: PFileBrowserState;
|
||||
begin
|
||||
state := PFileBrowserState(userdata);
|
||||
if state = nil then exit;
|
||||
state^.op_err := error;
|
||||
lv_timer_create(@fb_delete_done_timer, 1, state);
|
||||
state^.wop_kind := 4;
|
||||
state^.wop_result := error;
|
||||
puint32(@state^.wop_done)^ := 1;
|
||||
end;
|
||||
|
||||
{ Deferred UI update after delete }
|
||||
@@ -1864,11 +1914,16 @@ begin
|
||||
end else begin
|
||||
if nfctx^.handle <> 0 then
|
||||
driver.storage.vfs.CloseFile(nfctx^.handle);
|
||||
lv_timer_create(@fb_newfile_done_timer, 1, nfctx);
|
||||
if nfctx^.state <> nil then begin
|
||||
nfctx^.state^.wop_kind := 3;
|
||||
nfctx^.state^.wop_result := nfctx^.err;
|
||||
puint32(@nfctx^.state^.wop_done)^ := 1;
|
||||
end;
|
||||
kfree(void(nfctx));
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Async step 2: write complete — close handle and schedule UI refresh }
|
||||
{ Async step 2: write complete — close handle and defer UI work via poll flags }
|
||||
procedure fb_newfile_written(error: TError; userdata: pointer);
|
||||
var
|
||||
nfctx : PNewFileCtx;
|
||||
@@ -1878,7 +1933,12 @@ begin
|
||||
if error <> eNone then nfctx^.err := error;
|
||||
if nfctx^.handle <> 0 then
|
||||
driver.storage.vfs.CloseFile(nfctx^.handle);
|
||||
lv_timer_create(@fb_newfile_done_timer, 1, nfctx);
|
||||
if nfctx^.state <> nil then begin
|
||||
nfctx^.state^.wop_kind := 3;
|
||||
nfctx^.state^.wop_result := nfctx^.err;
|
||||
puint32(@nfctx^.state^.wop_done)^ := 1;
|
||||
end;
|
||||
kfree(void(nfctx));
|
||||
end;
|
||||
|
||||
procedure fb_newfile_done_timer(tmr: Plv_timer); cdecl;
|
||||
|
||||
+433
-77
File diff suppressed because it is too large
Load Diff
@@ -336,18 +336,20 @@ end;
|
||||
|
||||
procedure write_mbr(device : PStorage_Device; mbr : PMaster_Boot_Record);
|
||||
var
|
||||
oldCache : pointer;
|
||||
cache : puint32;
|
||||
buf : puint32;
|
||||
begin
|
||||
push_trace('driver.storage.mgr.write_mbr');
|
||||
if (device = nil) or (mbr = nil) or (not device^.writable) then exit;
|
||||
{ Update cache }
|
||||
if device^.cachedMBR <> nil then
|
||||
kfree(device^.cachedMBR);
|
||||
oldCache := device^.cachedMBR;
|
||||
cache := puint32(kalloc(sizeof(TMaster_Boot_Record)));
|
||||
if cache <> nil then
|
||||
memcpy(uint32(mbr), uint32(cache), sizeof(TMaster_Boot_Record));
|
||||
device^.cachedMBR := pointer(cache);
|
||||
if oldCache <> nil then
|
||||
kfree(oldCache);
|
||||
|
||||
buf := alloc_mbr_io_buffer(device, mbr);
|
||||
if buf = nil then exit;
|
||||
@@ -364,6 +366,7 @@ end;
|
||||
procedure write_mbr_async(device : PStorage_Device; mbr : PMaster_Boot_Record;
|
||||
callback : TIOCallback; callbackData : pointer);
|
||||
var
|
||||
oldCache : pointer;
|
||||
cache : puint32;
|
||||
buf : puint32;
|
||||
ctx : PMBRWriteAsyncData;
|
||||
@@ -379,12 +382,13 @@ begin
|
||||
exit;
|
||||
end;
|
||||
{ Update cache }
|
||||
if device^.cachedMBR <> nil then
|
||||
kfree(device^.cachedMBR);
|
||||
oldCache := device^.cachedMBR;
|
||||
cache := puint32(kalloc(sizeof(TMaster_Boot_Record)));
|
||||
if cache <> nil then
|
||||
memcpy(uint32(mbr), uint32(cache), sizeof(TMaster_Boot_Record));
|
||||
device^.cachedMBR := pointer(cache);
|
||||
if oldCache <> nil then
|
||||
kfree(oldCache);
|
||||
|
||||
buf := alloc_mbr_io_buffer(device, mbr);
|
||||
if buf = nil then begin
|
||||
|
||||
@@ -134,7 +134,7 @@ procedure UnwatchDirectory(WatchID : uint32);
|
||||
{ Volume invalidation — must be called before freeing a volume.
|
||||
Closes all open FDs referencing the volume across all processes,
|
||||
evicts directory cache entries, and removes VFS mount points. }
|
||||
procedure InvalidateVolume(vol : PStorage_Volume);
|
||||
function InvalidateVolume(vol : PStorage_Volume) : boolean;
|
||||
|
||||
{ VFS Functions }
|
||||
function newVirtualDirectory(Path : pchar) : TError;
|
||||
@@ -149,6 +149,7 @@ implementation
|
||||
|
||||
uses
|
||||
driver.storage.fs.mgr,
|
||||
driver.storage.fs.fat32,
|
||||
proc.mgr,
|
||||
proc.types,
|
||||
io.stdio,
|
||||
@@ -508,7 +509,36 @@ end;
|
||||
function GetObjectFromPath(path : pchar) : PVFSObject; forward;
|
||||
function GetObjectFromPathEx(path : pchar; var volRelPath : pchar) : PVFSObject; forward;
|
||||
|
||||
procedure InvalidateVolume(vol : PStorage_Volume);
|
||||
function volumeHasAsyncHandles(vol : PStorage_Volume) : boolean;
|
||||
var
|
||||
pCount : uint32;
|
||||
pi : uint32;
|
||||
fi : uint32;
|
||||
pCtx : proc.types.PProcessContext;
|
||||
tbl : PFDTable;
|
||||
begin
|
||||
volumeHasAsyncHandles := false;
|
||||
if vol = nil then exit;
|
||||
|
||||
pCount := proc.mgr.processCount();
|
||||
if pCount = 0 then exit;
|
||||
|
||||
for pi := 0 to pCount - 1 do begin
|
||||
pCtx := proc.mgr.getProcessByIndex(pi);
|
||||
if pCtx = nil then continue;
|
||||
tbl := PFDTable(pCtx^.FDTable);
|
||||
if tbl = nil then continue;
|
||||
for fi := 0 to MAX_FDS - 1 do begin
|
||||
if tbl^.Entries[fi].InUse and (tbl^.Entries[fi].Volume = vol)
|
||||
and (tbl^.Entries[fi].AsyncRefs > 0) then begin
|
||||
volumeHasAsyncHandles := true;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function InvalidateVolume(vol : PStorage_Volume) : boolean;
|
||||
var
|
||||
pCount : uint32;
|
||||
pi : uint32;
|
||||
@@ -522,7 +552,12 @@ var
|
||||
child : PVFSObject;
|
||||
begin
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.enter');
|
||||
InvalidateVolume := false;
|
||||
if vol = nil then exit;
|
||||
if volumeHasAsyncHandles(vol) then begin
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.busy');
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ 1. Evict all directory cache entries for this volume }
|
||||
DirCache_Invalidate(vol, nil);
|
||||
@@ -575,6 +610,10 @@ begin
|
||||
kfree(void(bootObj));
|
||||
end;
|
||||
|
||||
if (vol^.filesystem <> nil) and (stringCompare(vol^.filesystem^.sName, 'FAT32') = 0) then
|
||||
FAT32ReleaseVolumeState(vol);
|
||||
|
||||
InvalidateVolume := true;
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.exit');
|
||||
end;
|
||||
|
||||
@@ -1313,6 +1352,17 @@ begin
|
||||
{ Cache per-file metadata and populate DataSize via FS open hook }
|
||||
if (vol^.filesystem <> nil) and (vol^.filesystem^.openFileCallback <> nil) then begin
|
||||
fd^.FSPrivate := vol^.filesystem^.openFileCallback(vol, dir, fname, fd^.DataSize);
|
||||
if fd^.FSPrivate = nil then begin
|
||||
if Error <> nil then begin
|
||||
if (OpenMode = omCreate) or (OpenMode = omWrite) then
|
||||
Error^ := eInvalidFileName
|
||||
else
|
||||
Error^ := eFileDoesNotExist;
|
||||
end;
|
||||
fd_close(tbl, slot);
|
||||
debug.tracer.push_trace('driver.storage.vfs.OpenFile.exit');
|
||||
exit;
|
||||
end;
|
||||
if vol^.filesystem^.closeFileCallback <> nil then
|
||||
fd^.FSCloseHook := pointer(vol^.filesystem^.closeFileCallback);
|
||||
if Error <> nil then Error^ := eNone;
|
||||
@@ -1599,6 +1649,19 @@ begin
|
||||
|
||||
if (vol^.filesystem <> nil) and (vol^.filesystem^.openFileCallback <> nil) then begin
|
||||
fd^.FSPrivate := vol^.filesystem^.openFileCallback(vol, dir, fname, fd^.DataSize);
|
||||
if fd^.FSPrivate = nil then begin
|
||||
if Error <> nil then begin
|
||||
if (OpenMode = omCreate) or (OpenMode = omWrite) then
|
||||
Error^ := eInvalidFileName
|
||||
else
|
||||
Error^ := eFileDoesNotExist;
|
||||
end;
|
||||
fd_close(tbl, slot);
|
||||
OutHandle := 0;
|
||||
if Callback <> nil then Callback(Error^, CallbackData);
|
||||
debug.tracer.push_trace('driver.storage.vfs.OpenFileAsync.exit');
|
||||
exit;
|
||||
end;
|
||||
if vol^.filesystem^.closeFileCallback <> nil then
|
||||
fd^.FSCloseHook := pointer(vol^.filesystem^.closeFileCallback);
|
||||
if Error <> nil then Error^ := eNone;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,7 @@ uses
|
||||
io.syslog,
|
||||
debug.tracer,
|
||||
core.util, arch.x86.util,
|
||||
driver.storage.vol.mbr,
|
||||
driver.storage.vol.mgr;
|
||||
|
||||
type
|
||||
@@ -763,13 +764,38 @@ end;
|
||||
|
||||
function identify_volume(volume : PStorage_Volume) : boolean;
|
||||
var
|
||||
buffer : puint32;
|
||||
bufSize : uint32;
|
||||
buffer : puint32;
|
||||
bufSize : uint32;
|
||||
mbr : PMaster_Boot_Record;
|
||||
freeMbr : boolean;
|
||||
slot : sint32;
|
||||
i : uint32;
|
||||
begin
|
||||
push_trace('driver.storage.fs.flatfs.identify_volume');
|
||||
identify_volume := false;
|
||||
if volume^.device^.dispatchRead = nil then exit;
|
||||
|
||||
mbr := driver.storage.mgr.get_cached_mbr(volume^.device);
|
||||
freeMbr := false;
|
||||
if mbr = nil then begin
|
||||
mbr := driver.storage.mgr.read_mbr(volume^.device);
|
||||
freeMbr := mbr <> nil;
|
||||
end;
|
||||
|
||||
slot := -1;
|
||||
if mbr <> nil then begin
|
||||
for i := 0 to 3 do begin
|
||||
if mbr^.partition[i].LBA_start = volume^.sectorStart then begin
|
||||
slot := sint32(i);
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if (slot >= 0) and (mbr^.partition[slot].system_id <> filesystem.system_id) then begin
|
||||
if freeMbr then kfree(void(mbr));
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
bufSize := volume^.device^.sectorSize;
|
||||
if bufSize < 512 then bufSize := 512;
|
||||
buffer := puint32(kalloc(bufSize));
|
||||
@@ -783,6 +809,7 @@ begin
|
||||
end;
|
||||
|
||||
kfree(buffer);
|
||||
if freeMbr then kfree(void(mbr));
|
||||
end;
|
||||
|
||||
function readDirectoryEntries(volume : PStorage_Volume; directory : pchar; status : PuInt32) : PLinkedListBase;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user