feat: support for USB mass storage devices, hotplugging
This commit is contained in:
+126
-40
@@ -13,6 +13,8 @@ namespace Fs::FsProbe {
|
||||
|
||||
static ProbeFn g_probes[MaxProbes] = {};
|
||||
static int g_probeCount = 0;
|
||||
static bool g_mounted[Drivers::Storage::Gpt::MaxPartitions] = {};
|
||||
static int g_driveForPart[Drivers::Storage::Gpt::MaxPartitions] = {};
|
||||
|
||||
void Register(ProbeFn fn) {
|
||||
if (g_probeCount < MaxProbes && fn) {
|
||||
@@ -27,56 +29,93 @@ namespace Fs::FsProbe {
|
||||
memcmp(a.Data4, b.Data4, 8) == 0;
|
||||
}
|
||||
|
||||
static int TryMountPartitionAtLowestDrive(int partIndex, int firstDrive, bool efiLog) {
|
||||
if (!Vfs::IsInitialized()) return 0;
|
||||
if (partIndex < 0 || partIndex >= Drivers::Storage::Gpt::MaxPartitions) return 0;
|
||||
if (g_mounted[partIndex]) return 0;
|
||||
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(partIndex);
|
||||
if (!part) return 0;
|
||||
|
||||
int driveNum = Vfs::FindLowestAvailableDrive(firstDrive);
|
||||
if (driveNum < 0) {
|
||||
Kt::KernelLogStream(Kt::WARNING, "FsProbe") << "No free drive slot for partition "
|
||||
<< partIndex;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int p = 0; p < g_probeCount; p++) {
|
||||
Vfs::FsDriver* driver = g_probes[p](
|
||||
part->BlockDevIndex, part->StartLba, part->SectorCount);
|
||||
|
||||
if (!driver) continue;
|
||||
|
||||
if (Vfs::RegisterDrive(driveNum, driver) == 0) {
|
||||
g_mounted[partIndex] = true;
|
||||
g_driveForPart[partIndex] = driveNum;
|
||||
Kt::KernelLogStream(Kt::OK, "FsProbe")
|
||||
<< (efiLog ? "Mounted EFI partition " : "Mounted partition ")
|
||||
<< partIndex << " as drive " << driveNum;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Kt::KernelLogStream(Kt::INFO, "FsProbe") << "No filesystem recognized on partition "
|
||||
<< partIndex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MountPartitions(int firstDrive) {
|
||||
int partCount = Drivers::Storage::Gpt::GetPartitionCount();
|
||||
if (partCount == 0 || g_probeCount == 0) return;
|
||||
|
||||
int driveNum = firstDrive;
|
||||
|
||||
// First pass: mount non-EFI partitions so they get lower drive numbers
|
||||
for (int i = 0; i < partCount && driveNum < Vfs::MaxDrives; i++) {
|
||||
// First pass: mount non-EFI partitions so they get lower drive numbers.
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(i);
|
||||
if (!part) continue;
|
||||
if (IsEfiPartition(part)) continue;
|
||||
|
||||
for (int p = 0; p < g_probeCount; p++) {
|
||||
Vfs::FsDriver* driver = g_probes[p](
|
||||
part->BlockDevIndex, part->StartLba, part->SectorCount);
|
||||
|
||||
if (driver) {
|
||||
Vfs::RegisterDrive(driveNum, driver);
|
||||
Kt::KernelLogStream(Kt::OK, "FsProbe") << "Mounted partition "
|
||||
<< i << " as drive " << driveNum;
|
||||
driveNum++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!part || IsEfiPartition(part)) continue;
|
||||
TryMountPartitionAtLowestDrive(i, firstDrive, false);
|
||||
}
|
||||
|
||||
// Second pass: mount EFI system partitions after all others
|
||||
for (int i = 0; i < partCount && driveNum < Vfs::MaxDrives; i++) {
|
||||
// Second pass: mount EFI system partitions after all others.
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(i);
|
||||
if (!part) continue;
|
||||
if (!IsEfiPartition(part)) continue;
|
||||
|
||||
for (int p = 0; p < g_probeCount; p++) {
|
||||
Vfs::FsDriver* driver = g_probes[p](
|
||||
part->BlockDevIndex, part->StartLba, part->SectorCount);
|
||||
|
||||
if (driver) {
|
||||
Vfs::RegisterDrive(driveNum, driver);
|
||||
Kt::KernelLogStream(Kt::OK, "FsProbe") << "Mounted EFI partition "
|
||||
<< i << " as drive " << driveNum;
|
||||
driveNum++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!part || !IsEfiPartition(part)) continue;
|
||||
TryMountPartitionAtLowestDrive(i, firstDrive, true);
|
||||
}
|
||||
}
|
||||
|
||||
int MountPartitionsForBlockDevice(int blockDevIndex, int firstDrive) {
|
||||
if (!Vfs::IsInitialized() || g_probeCount == 0) return 0;
|
||||
|
||||
int partCount = Drivers::Storage::Gpt::GetPartitionCount();
|
||||
int mounted = 0;
|
||||
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(i);
|
||||
if (!part || part->BlockDevIndex != blockDevIndex || IsEfiPartition(part)) continue;
|
||||
|
||||
int result = TryMountPartitionAtLowestDrive(i, firstDrive, false);
|
||||
if (result > 0) mounted += result;
|
||||
}
|
||||
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(i);
|
||||
if (!part || part->BlockDevIndex != blockDevIndex || !IsEfiPartition(part)) continue;
|
||||
|
||||
int result = TryMountPartitionAtLowestDrive(i, firstDrive, true);
|
||||
if (result > 0) mounted += result;
|
||||
}
|
||||
|
||||
return mounted;
|
||||
}
|
||||
|
||||
int MountPartition(int partIndex, int driveNum) {
|
||||
if (driveNum < 0 || driveNum >= Vfs::MaxDrives) return -1;
|
||||
if (g_probeCount == 0) return -1;
|
||||
if (partIndex >= 0 && partIndex < Drivers::Storage::Gpt::MaxPartitions && g_mounted[partIndex]) return -1;
|
||||
if (Vfs::IsDriveRegistered(driveNum)) return -1;
|
||||
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(partIndex);
|
||||
if (!part) return -1;
|
||||
@@ -86,10 +125,16 @@ namespace Fs::FsProbe {
|
||||
part->BlockDevIndex, part->StartLba, part->SectorCount);
|
||||
|
||||
if (driver) {
|
||||
Vfs::RegisterDrive(driveNum, driver);
|
||||
Kt::KernelLogStream(Kt::OK, "FsProbe") << "Mounted partition "
|
||||
<< partIndex << " as drive " << driveNum;
|
||||
return 0;
|
||||
if (Vfs::RegisterDrive(driveNum, driver) == 0) {
|
||||
if (partIndex >= 0 && partIndex < Drivers::Storage::Gpt::MaxPartitions) {
|
||||
g_mounted[partIndex] = true;
|
||||
g_driveForPart[partIndex] = driveNum;
|
||||
}
|
||||
Kt::KernelLogStream(Kt::OK, "FsProbe") << "Mounted partition "
|
||||
<< partIndex << " as drive " << driveNum;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +142,45 @@ namespace Fs::FsProbe {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int UnmountPartitionsForBlockDevice(int blockDevIndex) {
|
||||
int partCount = Drivers::Storage::Gpt::GetPartitionCount();
|
||||
int unmounted = 0;
|
||||
int dst = 0;
|
||||
|
||||
for (int src = 0; src < partCount; src++) {
|
||||
auto* part = Drivers::Storage::Gpt::GetPartition(src);
|
||||
bool remove = part && part->BlockDevIndex == blockDevIndex;
|
||||
|
||||
if (remove) {
|
||||
if (src < Drivers::Storage::Gpt::MaxPartitions &&
|
||||
g_mounted[src] && g_driveForPart[src] >= 0) {
|
||||
if (Vfs::UnregisterDrive(g_driveForPart[src]) == 0) {
|
||||
unmounted++;
|
||||
}
|
||||
}
|
||||
if (src < Drivers::Storage::Gpt::MaxPartitions) {
|
||||
g_mounted[src] = false;
|
||||
g_driveForPart[src] = -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (src < Drivers::Storage::Gpt::MaxPartitions &&
|
||||
dst < Drivers::Storage::Gpt::MaxPartitions) {
|
||||
if (dst != src) {
|
||||
g_mounted[dst] = g_mounted[src];
|
||||
g_driveForPart[dst] = g_driveForPart[src];
|
||||
}
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = dst; i < partCount && i < Drivers::Storage::Gpt::MaxPartitions; i++) {
|
||||
g_mounted[i] = false;
|
||||
g_driveForPart[i] = -1;
|
||||
}
|
||||
|
||||
return unmounted;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -18,12 +18,20 @@ namespace Fs::FsProbe {
|
||||
// Register a filesystem probe function (called once per FS driver at init).
|
||||
void Register(ProbeFn fn);
|
||||
|
||||
// Probe all discovered GPT partitions and auto-mount recognized filesystems.
|
||||
// Assigns VFS drive numbers starting from firstDrive.
|
||||
// Probe all discovered storage partitions and auto-mount recognized filesystems.
|
||||
// Assigns each partition the lowest available VFS drive number at or above firstDrive.
|
||||
void MountPartitions(int firstDrive = 1);
|
||||
|
||||
// Probe discovered partitions for a single block device and mount recognized
|
||||
// filesystems at the lowest currently available VFS drive numbers.
|
||||
int MountPartitionsForBlockDevice(int blockDevIndex, int firstDrive = 0);
|
||||
|
||||
// Try to mount a single partition (by global partition index) as the given VFS drive.
|
||||
// Returns 0 on success, -1 if no probe recognized the filesystem.
|
||||
int MountPartition(int partIndex, int driveNum);
|
||||
|
||||
// Unmount every VFS drive backed by partitions on a block device and compact
|
||||
// mount bookkeeping to match Gpt::RemovePartitionsForBlockDevice().
|
||||
int UnmountPartitionsForBlockDevice(int blockDevIndex);
|
||||
|
||||
};
|
||||
|
||||
+146
-29
@@ -11,10 +11,12 @@
|
||||
namespace Fs::Vfs {
|
||||
|
||||
static FsDriver* driveTable[MaxDrives];
|
||||
static bool driveActive[MaxDrives];
|
||||
static uint32_t driveGeneration[MaxDrives];
|
||||
static bool initialized = false;
|
||||
|
||||
// Protects handle table and driver dispatch from concurrent CPU access.
|
||||
// Uses Mutex (not Spinlock) so interrupts stay enabled while held --
|
||||
// VFS is never called from interrupt context.
|
||||
// Protects driver dispatch from concurrent CPU access. Hot-unplug only
|
||||
// flips driveActive so an interrupted dispatch never sees a null driver.
|
||||
static kcp::Mutex vfsLock;
|
||||
|
||||
// Parse "N:/path" into drive number and local path.
|
||||
@@ -42,106 +44,202 @@ namespace Fs::Vfs {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void BumpDriveGeneration(int driveNumber) {
|
||||
driveGeneration[driveNumber]++;
|
||||
if (driveGeneration[driveNumber] == 0) {
|
||||
driveGeneration[driveNumber] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
for (int i = 0; i < MaxDrives; i++) {
|
||||
driveTable[i] = nullptr;
|
||||
driveActive[i] = false;
|
||||
driveGeneration[i] = 1;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
Kt::KernelLogStream(Kt::OK, "VFS") << "Initialized (" << MaxDrives << " drives)";
|
||||
}
|
||||
|
||||
bool IsInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
int RegisterDrive(int driveNumber, FsDriver* driver) {
|
||||
if (driveNumber < 0 || driveNumber >= MaxDrives) return -1;
|
||||
if (driver == nullptr) return -1;
|
||||
if (!initialized) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
if (driveActive[driveNumber]) {
|
||||
vfsLock.Release();
|
||||
return -1;
|
||||
}
|
||||
driveTable[driveNumber] = driver;
|
||||
BumpDriveGeneration(driveNumber);
|
||||
driveActive[driveNumber] = true;
|
||||
vfsLock.Release();
|
||||
|
||||
Kt::KernelLogStream(Kt::OK, "VFS") << "Registered drive " << driveNumber;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UnregisterDrive(int driveNumber) {
|
||||
if (!initialized) return -1;
|
||||
if (driveNumber < 0 || driveNumber >= MaxDrives) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
if (!driveActive[driveNumber]) {
|
||||
vfsLock.Release();
|
||||
return -1;
|
||||
}
|
||||
driveActive[driveNumber] = false;
|
||||
BumpDriveGeneration(driveNumber);
|
||||
vfsLock.Release();
|
||||
|
||||
Kt::KernelLogStream(Kt::OK, "VFS") << "Unregistered drive " << driveNumber;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IsDriveRegistered(int driveNumber) {
|
||||
if (driveNumber < 0 || driveNumber >= MaxDrives) return false;
|
||||
vfsLock.Acquire();
|
||||
bool registered = driveActive[driveNumber];
|
||||
vfsLock.Release();
|
||||
return registered;
|
||||
}
|
||||
|
||||
int FindLowestAvailableDrive(int firstDrive) {
|
||||
if (!initialized) return -1;
|
||||
if (firstDrive < 0) firstDrive = 0;
|
||||
|
||||
vfsLock.Acquire();
|
||||
for (int i = firstDrive; i < MaxDrives; i++) {
|
||||
if (!driveActive[i]) {
|
||||
vfsLock.Release();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
vfsLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int OpenBackendFile(const char* path, BackendFile& outFile) {
|
||||
outFile.driveNumber = -1;
|
||||
outFile.localHandle = -1;
|
||||
outFile.generation = 0;
|
||||
|
||||
int drive;
|
||||
const char* localPath;
|
||||
|
||||
if (!ParsePath(path, drive, localPath)) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || driveTable[drive] == nullptr) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || !driveActive[drive] || driveTable[drive] == nullptr) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
int localHandle = driveTable[drive]->Open(localPath);
|
||||
FsDriver* driver = driveTable[drive];
|
||||
uint32_t generation = driveGeneration[drive];
|
||||
int localHandle = (driveActive[drive] && driver) ? driver->Open(localPath) : -1;
|
||||
vfsLock.Release();
|
||||
if (localHandle < 0) return -1;
|
||||
|
||||
outFile.driveNumber = drive;
|
||||
outFile.localHandle = localHandle;
|
||||
outFile.generation = generation;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReadBackendFile(const BackendFile& file, uint8_t* buffer, uint64_t offset, uint64_t size) {
|
||||
vfsLock.Acquire();
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || driveTable[file.driveNumber] == nullptr ||
|
||||
FsDriver* driver = (file.driveNumber >= 0 && file.driveNumber < MaxDrives)
|
||||
? driveTable[file.driveNumber]
|
||||
: nullptr;
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || !driveActive[file.driveNumber] ||
|
||||
driver == nullptr ||
|
||||
file.generation != driveGeneration[file.driveNumber] ||
|
||||
file.localHandle < 0) {
|
||||
vfsLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = driveTable[file.driveNumber]->Read(file.localHandle, buffer, offset, size);
|
||||
int result = driver->Read(file.localHandle, buffer, offset, size);
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetBackendFileSize(const BackendFile& file) {
|
||||
vfsLock.Acquire();
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || driveTable[file.driveNumber] == nullptr ||
|
||||
FsDriver* driver = (file.driveNumber >= 0 && file.driveNumber < MaxDrives)
|
||||
? driveTable[file.driveNumber]
|
||||
: nullptr;
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || !driveActive[file.driveNumber] ||
|
||||
driver == nullptr ||
|
||||
file.generation != driveGeneration[file.driveNumber] ||
|
||||
file.localHandle < 0) {
|
||||
vfsLock.Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t result = driveTable[file.driveNumber]->GetSize(file.localHandle);
|
||||
uint64_t result = driver->GetSize(file.localHandle);
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BackendFileCanWrite(const BackendFile& file) {
|
||||
vfsLock.Acquire();
|
||||
FsDriver* driver = (file.driveNumber >= 0 && file.driveNumber < MaxDrives)
|
||||
? driveTable[file.driveNumber]
|
||||
: nullptr;
|
||||
bool canWrite = file.driveNumber >= 0 && file.driveNumber < MaxDrives &&
|
||||
driveTable[file.driveNumber] != nullptr &&
|
||||
driveActive[file.driveNumber] &&
|
||||
driver != nullptr &&
|
||||
file.generation == driveGeneration[file.driveNumber] &&
|
||||
file.localHandle >= 0 &&
|
||||
driveTable[file.driveNumber]->Write != nullptr;
|
||||
driver->Write != nullptr;
|
||||
vfsLock.Release();
|
||||
return canWrite;
|
||||
}
|
||||
|
||||
void CloseBackendFile(BackendFile& file) {
|
||||
vfsLock.Acquire();
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || driveTable[file.driveNumber] == nullptr ||
|
||||
FsDriver* driver = (file.driveNumber >= 0 && file.driveNumber < MaxDrives)
|
||||
? driveTable[file.driveNumber]
|
||||
: nullptr;
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || !driveActive[file.driveNumber] ||
|
||||
driver == nullptr ||
|
||||
file.generation != driveGeneration[file.driveNumber] ||
|
||||
file.localHandle < 0) {
|
||||
vfsLock.Release();
|
||||
file.driveNumber = -1;
|
||||
file.localHandle = -1;
|
||||
file.generation = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
driveTable[file.driveNumber]->Close(file.localHandle);
|
||||
driver->Close(file.localHandle);
|
||||
vfsLock.Release();
|
||||
|
||||
file.driveNumber = -1;
|
||||
file.localHandle = -1;
|
||||
file.generation = 0;
|
||||
}
|
||||
|
||||
int WriteBackendFile(const BackendFile& file, const uint8_t* buffer, uint64_t offset, uint64_t size) {
|
||||
vfsLock.Acquire();
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || driveTable[file.driveNumber] == nullptr ||
|
||||
FsDriver* driver = (file.driveNumber >= 0 && file.driveNumber < MaxDrives)
|
||||
? driveTable[file.driveNumber]
|
||||
: nullptr;
|
||||
if (file.driveNumber < 0 || file.driveNumber >= MaxDrives || !driveActive[file.driveNumber] ||
|
||||
driver == nullptr ||
|
||||
file.generation != driveGeneration[file.driveNumber] ||
|
||||
file.localHandle < 0) {
|
||||
vfsLock.Release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (driveTable[file.driveNumber]->Write == nullptr) { vfsLock.Release(); return -1; }
|
||||
int result = driveTable[file.driveNumber]->Write(file.localHandle, buffer, offset, size);
|
||||
if (driver->Write == nullptr) { vfsLock.Release(); return -1; }
|
||||
int result = driver->Write(file.localHandle, buffer, offset, size);
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
@@ -149,22 +247,27 @@ namespace Fs::Vfs {
|
||||
int CreateBackendFile(const char* path, BackendFile& outFile) {
|
||||
outFile.driveNumber = -1;
|
||||
outFile.localHandle = -1;
|
||||
outFile.generation = 0;
|
||||
|
||||
int drive;
|
||||
const char* localPath;
|
||||
|
||||
if (!ParsePath(path, drive, localPath)) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || driveTable[drive] == nullptr) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || !driveActive[drive] || driveTable[drive] == nullptr) return -1;
|
||||
if (driveTable[drive]->Create == nullptr) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
|
||||
int localHandle = driveTable[drive]->Create(localPath);
|
||||
FsDriver* driver = driveTable[drive];
|
||||
uint32_t generation = driveGeneration[drive];
|
||||
int localHandle = (driveActive[drive] && driver && driver->Create)
|
||||
? driver->Create(localPath)
|
||||
: -1;
|
||||
vfsLock.Release();
|
||||
if (localHandle < 0) return -1;
|
||||
|
||||
outFile.driveNumber = drive;
|
||||
outFile.localHandle = localHandle;
|
||||
outFile.generation = generation;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -173,11 +276,14 @@ namespace Fs::Vfs {
|
||||
const char* localPath;
|
||||
|
||||
if (!ParsePath(path, drive, localPath)) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || driveTable[drive] == nullptr) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || !driveActive[drive] || driveTable[drive] == nullptr) return -1;
|
||||
if (driveTable[drive]->Delete == nullptr) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
int result = driveTable[drive]->Delete(localPath);
|
||||
FsDriver* driver = driveTable[drive];
|
||||
int result = (driveActive[drive] && driver && driver->Delete)
|
||||
? driver->Delete(localPath)
|
||||
: -1;
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
@@ -187,11 +293,14 @@ namespace Fs::Vfs {
|
||||
const char* localPath;
|
||||
|
||||
if (!ParsePath(path, drive, localPath)) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || driveTable[drive] == nullptr) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || !driveActive[drive] || driveTable[drive] == nullptr) return -1;
|
||||
if (driveTable[drive]->Mkdir == nullptr) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
int result = driveTable[drive]->Mkdir(localPath);
|
||||
FsDriver* driver = driveTable[drive];
|
||||
int result = (driveActive[drive] && driver && driver->Mkdir)
|
||||
? driver->Mkdir(localPath)
|
||||
: -1;
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
@@ -200,7 +309,7 @@ namespace Fs::Vfs {
|
||||
vfsLock.Acquire();
|
||||
int count = 0;
|
||||
for (int i = 0; i < MaxDrives && count < maxEntries; i++) {
|
||||
if (driveTable[i] != nullptr) {
|
||||
if (driveActive[i]) {
|
||||
outDrives[count++] = i;
|
||||
}
|
||||
}
|
||||
@@ -213,7 +322,8 @@ namespace Fs::Vfs {
|
||||
outLabel[0] = '\0';
|
||||
|
||||
vfsLock.Acquire();
|
||||
if (driveNumber < 0 || driveNumber >= MaxDrives || driveTable[driveNumber] == nullptr) {
|
||||
if (driveNumber < 0 || driveNumber >= MaxDrives || !driveActive[driveNumber] ||
|
||||
driveTable[driveNumber] == nullptr) {
|
||||
vfsLock.Release();
|
||||
return -1;
|
||||
}
|
||||
@@ -250,11 +360,15 @@ namespace Fs::Vfs {
|
||||
|
||||
// Cross-drive rename not supported
|
||||
if (oldDrive != newDrive) return -1;
|
||||
if (oldDrive < 0 || oldDrive >= MaxDrives || driveTable[oldDrive] == nullptr) return -1;
|
||||
if (oldDrive < 0 || oldDrive >= MaxDrives || !driveActive[oldDrive] ||
|
||||
driveTable[oldDrive] == nullptr) return -1;
|
||||
if (driveTable[oldDrive]->Rename == nullptr) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
int result = driveTable[oldDrive]->Rename(oldLocal, newLocal);
|
||||
FsDriver* driver = driveTable[oldDrive];
|
||||
int result = (driveActive[oldDrive] && driver && driver->Rename)
|
||||
? driver->Rename(oldLocal, newLocal)
|
||||
: -1;
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
@@ -264,10 +378,13 @@ namespace Fs::Vfs {
|
||||
const char* localPath;
|
||||
|
||||
if (!ParsePath(path, drive, localPath)) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || driveTable[drive] == nullptr) return -1;
|
||||
if (drive < 0 || drive >= MaxDrives || !driveActive[drive] || driveTable[drive] == nullptr) return -1;
|
||||
|
||||
vfsLock.Acquire();
|
||||
int result = driveTable[drive]->ReadDir(localPath, outNames, maxEntries);
|
||||
FsDriver* driver = driveTable[drive];
|
||||
int result = (driveActive[drive] && driver && driver->ReadDir)
|
||||
? driver->ReadDir(localPath, outNames, maxEntries)
|
||||
: -1;
|
||||
vfsLock.Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Fs::Vfs {
|
||||
struct BackendFile {
|
||||
int driveNumber;
|
||||
int localHandle;
|
||||
uint32_t generation;
|
||||
};
|
||||
|
||||
struct FsDriver {
|
||||
@@ -32,7 +33,11 @@ namespace Fs::Vfs {
|
||||
};
|
||||
|
||||
void Initialize();
|
||||
bool IsInitialized();
|
||||
int RegisterDrive(int driveNumber, FsDriver* driver);
|
||||
int UnregisterDrive(int driveNumber);
|
||||
bool IsDriveRegistered(int driveNumber);
|
||||
int FindLowestAvailableDrive(int firstDrive = 0);
|
||||
|
||||
int OpenBackendFile(const char* path, BackendFile& outFile);
|
||||
int CreateBackendFile(const char* path, BackendFile& outFile);
|
||||
|
||||
Reference in New Issue
Block a user