Compare commits

...
Author SHA1 Message Date
Aaron c8c7c2983d vfs: symlink support in file picker, test cleanup, boot mount fix
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
- File picker (app.filepicker.pas): add otSYMLINK to directory case in
  fp_collect_cb so symlinks like /sys appear as navigable directories
- VFS: add RemoveVirtualTree() to recursively free vdir/symlink trees
- VFS UnitTest: clean up /utest_vfs tree after all tests
- STORTEST: clean up /st_test tree after tests, fix listing leak in
  cmd_stortest (GetDirectoryListingFrom result was never freed)
- Boot mount: auto-mount boot drive at /boot via mountVolume() instead
  of symlink; remove /boot and /cfg from init() vdirs
- mount.asr: remove boot line (now only 'mnt {device}/sys /sys')
2026-03-08 19:00:47 +00:00
Aaron 91bc0e5ea2 vfs: consolidate scattered type/const/var sections into single blocks 2026-03-08 18:07:44 +00:00
Aaron 2cf879c4b9 vfs: replace asr.mnt with mount.asr declarative boot mounts
- Add mount.asr parser in auto_mount_volumes: reads MOUNT.ASR from boot
  volume root, parses 'mnt {device}<src> <target>' lines, expands {device}
  to the boot volume's /disk/volN path, creates symlinks for each entry
- Remove old asr.mnt persistent mount logic from auto_mount_volumes
- Remove persistent mount write ([p] flag) from MOUNT shell command
- Remove hardcoded /boot mount for boot volumes (now driven by mount.asr)
- Add iso/mount.asr with default /boot and /sys symlinks
- Update doc/vfs.md with mount.asr documentation
2026-03-08 18:07:44 +00:00
Aaron fcc9809248 vfs: major overhaul — device nodes, stream I/O, mode simplification
- 5-phase VFS architecture overhaul (path resolution, dir cache, watch/notify,
  symlinks, async API)
- Add character/block device node layer with /dev/null and /dev/zero built-ins
- RegisterDevice() API for custom device nodes with read/write/size callbacks
- Merge TOpenMode + TWriteMode into single TOpenMode enum
  (omRead, omWrite, omCreate, omReadWrite, omStream)
- Add stream write support: WriteFile/WriteFileAsync now accept omStream handles
  with auto-advancing offset for both device and volume FDs
- Add PPWriteOffsetHook type and writeOffsetCallback field to TFilesystem
- Add PPReadOffsetHook-based streaming reads for FAT32 and ISO9660
- Update all callers (notepad, edit, inio, wasm runner, filepicker, filedispatch,
  vterminal, stdio) to new 2-param OpenFile API
- 77 unit tests (0 failures) covering path ops, dir cache, symlinks, watch,
  device nodes, and stream read/write
- Add doc/vfs.md — comprehensive public VFS API documentation
2026-03-08 18:07:44 +00:00
admin 63b67f5878 Merge pull request 'feature: add architecture-agnostic kernel panic (BSOD) engine' (#57) from feature/panic into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #57
Reviewed-by: Aaron Hance <[email protected]>
2026-03-08 17:21:41 +00:00
admin 521633c9a4 Merge pull request 'feature/bloom_filter' (#55) from feature/bloom_filter into develop
continuous-integration/drone/push Build is passing
Reviewed-on: #55
Reviewed-by: admin <[email protected]>
2026-03-08 14:24:43 +00:00
Aaron 0cd32a0f64 Fixed file header
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2026-03-08 14:04:48 +00:00
Aaron f2e5f3535a perf(ds): replace MD5 key hash in hashmap with FNV-1a32
continuous-integration/drone/push Build is passing
Removes per-lookup heap allocation (MD5Buffer/kfree) in favour of a
single zero-allocation FNV-1a32 pass. Drops core.enc.md5 dependency
from core.ds.hashmap.
2026-03-08 13:59:56 +00:00
Aaron 2159578bdf feat(ds/enc): add bloom filter, FNV-1a and DJB2 hash units
continuous-integration/drone/push Build is passing
- core.enc.fnv1a: FNV-1a 32/64-bit non-cryptographic hash with UnitTest
- core.enc.djb2: DJB2 XOR/Add 32/64-bit hash variants with UnitTest
- core.ds.bloom: probabilistic bloom filter (Bloom_New/Add/Test/Clear/Free)
  using double hashing (FNV-1a32 + DJB2_32) with UnitTest
- core.ds.types: add TBloomFilter / PBloomFilter record
- asuro.pas: wire all three UnitTests into boot test suite
2026-03-08 13:58:33 +00:00
24 changed files with 3932 additions and 603 deletions
+587
View File
File diff suppressed because it is too large Load Diff
Generated
+1
View File
@@ -0,0 +1 @@
mnt {device}/sys /sys
+3 -3
View File
@@ -138,7 +138,7 @@ begin
{ Open for writing }
debug.tracer.push_trace('edit.SaveFile.openRW');
fHandle := driver.storage.vfs.OpenFile(FilePath, omReadWrite, wmRewrite, @fError);
fHandle := driver.storage.vfs.OpenFile(FilePath, omReadWrite, @fError);
if fHandle <> 0 then begin
debug.tracer.push_trace('edit.SaveFile.writeFile');
driver.storage.vfs.WriteFile(fHandle, 0, puint8(buf), totalLen);
@@ -149,7 +149,7 @@ begin
end else begin
{ Try write-only for new file }
debug.tracer.push_trace('edit.SaveFile.openWO');
fHandle := driver.storage.vfs.OpenFile(FilePath, omWriteOnly, wmNew, @fError);
fHandle := driver.storage.vfs.OpenFile(FilePath, omCreate, @fError);
if fHandle <> 0 then begin
debug.tracer.push_trace('edit.SaveFile.writeFileNew');
driver.storage.vfs.WriteFile(fHandle, 0, puint8(buf), totalLen);
@@ -181,7 +181,7 @@ begin
if FilePath = nil then exit;
debug.tracer.push_trace('edit.LoadFile.openFile');
fHandle := driver.storage.vfs.OpenFile(FilePath, omReadOnly, wmRewrite, @fError);
fHandle := driver.storage.vfs.OpenFile(FilePath, omRead, @fError);
debug.tracer.push_trace('edit.LoadFile.openFile.done');
if (fHandle = 0) or (fError <> eNone) then begin
io.syslog.writestringln('New file.');
+40 -5
View File
@@ -77,12 +77,15 @@ type
{ Flat name buffer — heap-alloc'd in do_refresh to avoid stack bloat }
TNameBuf = array[0..ENTRY_MAX - 1] of pchar;
PNameBuf = ^TNameBuf;
TSizeBuf = array[0..ENTRY_MAX - 1] of uint32;
PSizeBuf = ^TSizeBuf;
{ Per-call context passed to the forEach collect callback }
PFPCollectCtx = ^TFPCollectCtx;
TFPCollectCtx = record
dir_names : PNameBuf;
file_names : PNameBuf;
file_sizes : PSizeBuf;
dir_count : uint32;
file_count : uint32;
filter : pchar;
@@ -350,6 +353,28 @@ begin
end;
end;
{ Insertion sort on name array, swapping a parallel size array in lockstep }
procedure sortNamesWithSizes(var names: array of pchar; var sizes: array of uint32; n: uint32);
var
i, j : uint32;
tmpN : pchar;
tmpS : uint32;
begin
if n < 2 then exit;
for i := 1 to n - 1 do begin
tmpN := names[i];
tmpS := sizes[i];
j := i;
while (j > 0) and strLess(tmpN, names[j - 1]) do begin
names[j] := names[j - 1];
sizes[j] := sizes[j - 1];
j := j - 1;
end;
names[j] := tmpN;
sizes[j] := tmpS;
end;
end;
{ ============================================================
fp_collect_cb
core.ds.hashmap.forEach callback: classifies each VFS entry as dir or file
@@ -364,7 +389,7 @@ begin
obj := PVFSObject(data);
if (ctx = nil) or (obj = nil) then exit;
case obj^.ObjectType of
otVDIRECTORY, otDRIVE, otDIRECTORY, otMOUNT:
otVDIRECTORY, otDRIVE, otDIRECTORY, otMOUNT, otSYMLINK:
if ctx^.dir_count < ENTRY_MAX then begin
ctx^.dir_names^[ctx^.dir_count] := key;
ctx^.dir_count := ctx^.dir_count + 1;
@@ -373,6 +398,7 @@ begin
if matchesFilter(key, ctx^.filter) then
if ctx^.file_count < ENTRY_MAX then begin
ctx^.file_names^[ctx^.file_count] := key;
ctx^.file_sizes^[ctx^.file_count] := obj^.FileSize;
ctx^.file_count := ctx^.file_count + 1;
end;
end;
@@ -390,12 +416,14 @@ var
ctx : TFPCollectCtx;
dir_names : PNameBuf; { heap-alloc'd to avoid blowing the core.version stack }
file_names : PNameBuf;
file_sizes : PSizeBuf;
dir_count : uint32;
file_count : uint32;
i : uint32;
row, name_lbl, size_lbl : Plv_obj;
sep : pchar;
copy : pchar;
szStr : pchar;
s1, s2, s3 : pchar;
begin
debug.tracer.push_trace('filepicker.do_refresh');
@@ -408,8 +436,10 @@ begin
io.syslog.logln('FPCIK', 'do_refresh: kalloc name bufs');
dir_names := PNameBuf(kalloc(sizeof(TNameBuf)));
file_names := PNameBuf(kalloc(sizeof(TNameBuf)));
file_sizes := PSizeBuf(kalloc(sizeof(TSizeBuf)));
memset(uint32(dir_names), 0, sizeof(TNameBuf));
memset(uint32(file_names), 0, sizeof(TNameBuf));
memset(uint32(file_sizes), 0, sizeof(TSizeBuf));
{ Sync path bar }
if p^.path_bar <> nil then
@@ -429,6 +459,7 @@ begin
lv_label_set_text(p^.status_label, 'Could not read directory');
kfree(void(dir_names));
kfree(void(file_names));
kfree(void(file_sizes));
debug.tracer.pop_trace;
exit;
end;
@@ -437,6 +468,7 @@ begin
driver.storage.vfs.FreeDirectoryListing(Map);
kfree(void(dir_names));
kfree(void(file_names));
kfree(void(file_sizes));
debug.tracer.pop_trace;
exit;
end;
@@ -444,6 +476,7 @@ begin
ctx.dir_names := dir_names;
ctx.file_names := file_names;
ctx.file_sizes := file_sizes;
ctx.dir_count := 0;
ctx.file_count := 0;
ctx.filter := p^.filter;
@@ -455,7 +488,7 @@ begin
{ --- Sort both collections alphabetically --- }
if dir_count > 0 then sortNames(dir_names^, dir_count);
if file_count > 0 then sortNames(file_names^, file_count);
if file_count > 0 then sortNamesWithSizes(file_names^, file_sizes^, file_count);
{ --- Build directory rows --- }
if dir_count > 0 then
@@ -524,10 +557,11 @@ begin
lv_obj_set_style_text_color(name_lbl, lv_color_make(210, 215, 230), 0);
lv_obj_set_style_text_font(name_lbl, @lv_font_montserrat_14, 0);
{ File size column: skipped here to avoid blocking disk I/O
inside the LVGL timer callback context. }
{ File size column: use metadata from directory listing }
size_lbl := lv_label_create(row);
lv_label_set_text(size_lbl, '--');
szStr := fmtFileSize(file_sizes^[i]);
lv_label_set_text(size_lbl, szStr);
kfree(void(szStr));
lv_obj_set_width(size_lbl, 70);
lv_obj_set_style_text_color(size_lbl, lv_color_make(100, 110, 130), 0);
lv_obj_set_style_text_font(size_lbl, @lv_font_montserrat_14, 0);
@@ -543,6 +577,7 @@ begin
kfree(void(dir_names));
kfree(void(file_names));
kfree(void(file_sizes));
{ Update status label: "X dirs, Y files" }
if p^.status_label <> nil then begin
+3 -3
View File
@@ -65,7 +65,7 @@ begin
{ ---- READ ---- }
if op[0] = '<' then begin
fHandle := driver.storage.vfs.OpenFile(absPath, omReadOnly, wmRewrite, @fError);
fHandle := driver.storage.vfs.OpenFile(absPath, omRead, @fError);
if (fHandle = 0) or (fError <> eNone) then begin
io.syslog.writestringln('Error: cannot open file for reading.');
kfree(void(absPath));
@@ -112,10 +112,10 @@ begin
contentLen := stringSize(content);
{ Try read-write rewrite first (existing file) }
fHandle := driver.storage.vfs.OpenFile(absPath, omReadWrite, wmRewrite, @fError);
fHandle := driver.storage.vfs.OpenFile(absPath, omReadWrite, @fError);
if (fHandle = 0) or (fError <> eNone) then begin
{ Try creating new file }
fHandle := driver.storage.vfs.OpenFile(absPath, omWriteOnly, wmNew, @fError);
fHandle := driver.storage.vfs.OpenFile(absPath, omCreate, @fError);
end;
if (fHandle = 0) or (fError <> eNone) then begin
+3 -3
View File
@@ -372,9 +372,9 @@ begin
buf := pchar(kalloc(FILE_BUF_SIZE));
memset(uint32(buf), 0, FILE_BUF_SIZE);
memcpy(uint32(txt), uint32(buf), len);
fHandle := driver.storage.vfs.OpenFile(state^.currentPath, omReadWrite, wmRewrite, @fError);
fHandle := driver.storage.vfs.OpenFile(state^.currentPath, omReadWrite, @fError);
if fHandle = 0 then
fHandle := driver.storage.vfs.OpenFile(state^.currentPath, omWriteOnly, wmNew, @fError);
fHandle := driver.storage.vfs.OpenFile(state^.currentPath, omCreate, @fError);
if fHandle = 0 then begin
kfree(void(buf));
io.syslog.logln('NOTEPAD', 'saveFile: OpenFile failed');
@@ -413,7 +413,7 @@ var
buf : pchar;
begin
debug.tracer.push_trace('notepad.loadFile');
fHandle := driver.storage.vfs.OpenFile(path, omReadOnly, wmRewrite, @fError);
fHandle := driver.storage.vfs.OpenFile(path, omRead, @fError);
if (fHandle = 0) or (fError <> eNone) then begin
io.syslog.logln('NOTEPAD', 'loadFile: could not open file');
showErrorMsgbox('Open Failed', 'Could not open file for reading.');
+3 -3
View File
@@ -343,7 +343,7 @@ begin
end;
end;
{ Resolve relative to per-terminal cwd }
Validity := driver.storage.vfs.changeDirectoryFrom(Path, state^.cwd, NewDir);
Validity := driver.storage.vfs.ChangeDirectoryFrom(Path, state^.cwd, NewDir);
case Validity of
pvDirectory: begin
kfree(void(state^.cwd));
@@ -410,7 +410,7 @@ var
begin
if STRLL_Size(state^.dir_stack) > 0 then begin
wd := STRLL_Get(state^.dir_stack, STRLL_Size(state^.dir_stack) - 1);
Validity := driver.storage.vfs.changeDirectoryFrom(wd, state^.cwd, NewDir);
Validity := driver.storage.vfs.ChangeDirectoryFrom(wd, state^.cwd, NewDir);
if Validity = pvDirectory then begin
kfree(void(state^.cwd));
state^.cwd := NewDir;
@@ -696,7 +696,7 @@ begin
end;
end else begin
{ No built-in command found — try file dispatch }
absPath := driver.storage.vfs.makeAbsolutePathFrom(params^.Param, state^.cwd);
absPath := driver.storage.vfs.MakeAbsolutePathFrom(params^.Param, state^.cwd);
if absPath <> nil then begin
if is_bg then begin
{ Background file dispatch }
+13 -14
View File
@@ -152,36 +152,35 @@ var
fh : TFileHandle;
err : TError;
fsize : uint32;
errb : uint8;
bytesRead : uint32;
processCtx : PProcessContext;
begin
debug.tracer.push_trace('wasmrunner.handler');
wasm_file_handler := 0;
{ 1. Get file size }
errb := 0;
fsize := driver.storage.vfs.FileSize(path, @errb);
if (fsize = 0) or (errb <> 0) then begin
io.stdio.bufWriteStrLn(stderr_buf, 'WASM: cannot determine file size');
{ 1. Open file once — omRead pre-loads the data and gives us the size }
err := eNone;
fh := driver.storage.vfs.OpenFile(path, omRead, @err);
if (fh = 0) or (err <> eNone) then begin
io.stdio.bufWriteStrLn(stderr_buf, 'WASM: cannot open file');
exit;
end;
fsize := driver.storage.vfs.FileSizeFromHandle(fh);
if fsize = 0 then begin
driver.storage.vfs.CloseFile(fh);
io.stdio.bufWriteStrLn(stderr_buf, 'WASM: file is empty or cannot determine size');
exit;
end;
{ 2. Allocate buffer and read file }
buf := puint8(kalloc(fsize));
if buf = nil then begin
driver.storage.vfs.CloseFile(fh);
io.stdio.bufWriteStrLn(stderr_buf, 'WASM: out of memory');
exit;
end;
err := eNone;
fh := driver.storage.vfs.OpenFile(path, omReadOnly, wmRewrite, @err);
if fh = 0 then begin
kfree(void(buf));
io.stdio.bufWriteStrLn(stderr_buf, 'WASM: cannot open file');
exit;
end;
bytesRead := driver.storage.vfs.ReadFile(fh, 0, buf, fsize);
driver.storage.vfs.CloseFile(fh);
+6
View File
@@ -106,6 +106,9 @@ uses
driver.storage.vfs,
driver.video,
arch.x86.memory.virtual,
core.enc.fnv1a,
core.enc.djb2,
core.ds.bloom,
app.volcmd,
driver.storage.vol.mgr,
app.vterminal,
@@ -349,6 +352,9 @@ begin
core.ds.prio.UnitTest;
driver.storage.vfs.UnitTest;
driver.storage.test.UnitTest;
core.enc.fnv1a.UnitTest;
core.enc.djb2.UnitTest;
core.ds.bloom.UnitTest;
{ Initialize driver.video.desktop environment }
boot.splash.update(100, 'Booting desktop...');
File diff suppressed because it is too large Load Diff
+3 -13
View File
@@ -16,6 +16,7 @@
Include->Hashmap - Basic Hashmap Implementation.
@author(Kieron Morris <[email protected]>)
@author(Aaron Hance <[email protected]>)
}
unit core.ds.hashmap;
@@ -23,7 +24,7 @@ interface
uses
memory.heap,
core.enc.md5,
core.enc.fnv1a,
core.strings,
io.syslog,
debug.tracer,
@@ -64,19 +65,8 @@ procedure forEach(map : PHashMap; cb : THashForEachCb; ud : void);
implementation
function KeyHash(key : pchar) : uint32;
var
KeyLength : uint32;
MD5_Hash : PMD5Digest;
Hash128 : puint128;
Hash32 : uint32;
begin
KeyLength:= StringSize(key);
MD5_Hash:= MD5Buffer(puint8(key), KeyLength);
Hash128:= puint128(MD5_Hash);
Hash32:= MD5To32(Hash128);
KeyHash:= Hash32;
kfree(void(MD5_Hash));
KeyHash := Hash_FNV1a32(void(uint32(key)), StringSize(key));
end;
function hashIndex(size : uint32; hash : uint32) : uint32;
+26
View File
@@ -195,6 +195,32 @@ type
IsMinHeap : boolean;
end;
{ ------ Bloom Filter ------ }
{**
@abstract Pointer to a bloom filter.
**}
PBloomFilter = ^TBloomFilter;
{**
@abstract Probabilistic set-membership filter using double hashing.
@discussion The bit array is a flat kalloc'd byte buffer of
ceil(BitCount / 8) bytes. Membership tests use k independent
hash positions derived from two base hashes (FNV-1a + DJB2)
via double hashing: h_i(x) = (h1(x) + i * h2(x)) mod BitCount.
False positives are possible; false negatives are not.
@field Bits Pointer to the flat bit-array buffer.
@field BitCount Total number of bits in the filter (m).
@field HashCount Number of hash functions applied per element (k).
@field Count Number of elements inserted.
**}
TBloomFilter = record
Bits : void;
BitCount : uint32;
HashCount : uint32;
Count : uint32;
end;
implementation
end.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -148,6 +148,10 @@ begin
entry := PDirectory_Entry(LL_Add(dirList));
entry^.fileName := stringCopy(Files[i].Name);
entry^.entryType := fileEntry;
entry^.fileSize := Files[i].Size;
entry^.modifiedDate := 0;
entry^.modifiedTime := 0;
entry^.attributes := 0;
end;
end;
if status <> nil then status^ := 0;
@@ -41,11 +41,12 @@ type
Directory : pchar; { directory path within the volume }
FileName : pchar; { filename within that directory }
OpenMode : uint8; { TOpenMode ordinal — avoids VFS type dependency }
WriteMode : uint8; { TWriteMode ordinal }
DataBuffer : puint32; { pre-loaded data for small files, nil otherwise }
DataSize : uint32; { size of pre-loaded data in bytes }
Loaded : boolean; { true if pre-loaded into DataBuffer }
StreamOff : uint32; { current byte offset for streaming / on-demand reads }
DeviceOps : pointer; { PVFSDeviceOps — non-nil for device FDs }
DeviceData : pointer; { opaque data passed to device callbacks }
end;
PFDTable = ^TFDTable;
@@ -113,6 +114,8 @@ begin
entry^.Loaded := false;
entry^.DataSize := 0;
entry^.StreamOff := 0;
entry^.DeviceOps := nil;
entry^.DeviceData := nil;
end;
procedure fd_table_free(table : PFDTable);
@@ -133,9 +133,10 @@ begin
validity := driver.storage.vfs.PathValid(absPath);
if validity <> pvFile then exit;
{ 2. Open the file and read the header bytes }
{ 2. Open the file in stream mode only reads the bytes we ask for,
avoids pre-loading the entire file just to check a few magic bytes. }
err := eNone;
fh := driver.storage.vfs.OpenFile(absPath, omReadOnly, wmRewrite, @err);
fh := driver.storage.vfs.OpenFile(absPath, omStream, @err);
if fh = 0 then exit;
memset(uint32(@headerBuf[0]), 0, MAX_MAGIC_LEN);
File diff suppressed because it is too large Load Diff
+17 -2
View File
@@ -90,6 +90,8 @@ type
eTooManyOpenFiles, { per-process FD table full }
eInvalidHandle, { TFileHandle does not refer to an open FD }
eNotStreamMode, { SeekFile called on a non-omStream handle }
eFileNotLoaded, { ReadFile on a pre-load handle whose data is not yet loaded }
eAlreadyExists, { generic: target name already exists (symlink, file, etc.) }
{ Disk / capacity errors }
eDiskFull, { FS reports no free clusters/blocks }
@@ -148,11 +150,17 @@ type
PPDeleteFileHook = procedure(volume : PStorage_Volume; filePath : pchar; status : puint32);
PPDeleteDirHook = procedure(volume : PStorage_Volume; path : pchar; status : puint32);
PPIdentifyHook = function(volume : PStorage_Volume) : boolean;
PPRenameFileHook = procedure(volume : PStorage_Volume; filePath : pchar; newName : pchar; status : puint32);
{ Offset-based read: reads byteCount bytes starting at byte offset into the file.
Returns the number of bytes actually read.
Filesystems that do not implement this leave the field nil and VFS falls back
to the load-all readCallback behaviour. }
PPReadOffsetHook = function(volume : PStorage_Volume; directory : pchar; fileName : pchar; offset : uint32; buffer : puint32; byteCount : uint32) : uint32;
{ Offset-based write: writes byteCount bytes starting at byte offset into the file.
Returns the number of bytes actually written.
Filesystems that do not implement this leave the field nil; VFS returns 0
for stream-mode writes on volume FDs. }
PPWriteOffsetHook = function(volume : PStorage_Volume; directory : pchar; fileName : pchar; offset : uint32; buffer : puint32; byteCount : uint32) : uint32;
{ === Async filesystem hook core.types ===
Each mirrors the corresponding sync hook but receives a TIOCallback + callbackData.
@@ -227,6 +235,8 @@ type
identifyCallback : PPIdentifyHook;
{ Offset-based read for streaming mode — nil if not implemented }
readOffsetCallback : PPReadOffsetHook;
{ Offset-based write for streaming mode — nil if not implemented }
writeOffsetCallback : PPWriteOffsetHook;
{ Async format — nil if FS only supports synchronous create }
createAsyncCallback : PPCreateAsyncHook;
{ Async variants of the main I/O hooks nil if FS only supports sync.
@@ -237,6 +247,7 @@ type
readDirAsyncCallback : PPReadDirAsyncHook;
deleteFileAsyncCallback : PPDeleteFileAsyncHook;
deleteDirAsyncCallback : PPDeleteDirAsyncHook;
renameFileCallback : PPRenameFileHook;
end;
{ Generic storage volume }
@@ -253,8 +264,12 @@ type
{ Generic directory entry }
TDirectory_Entry = record
fileName : pchar;
entryType : TDirectory_Entry_Type;
fileName : pchar;
entryType : TDirectory_Entry_Type;
fileSize : uint32;
modifiedDate : uint16; { FAT-style: bits 15-9=year-1980, 8-5=month, 4-0=day }
modifiedTime : uint16; { FAT-style: bits 15-11=hour, 10-5=min, 4-0=sec/2 }
attributes : uint8; { FS-specific attribute bits }
end;
TDrive_Error = record
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More