feat: fix file rename implementation
This commit is contained in:
@@ -81,6 +81,10 @@ namespace Montauk {
|
|||||||
return Fs::Vfs::VfsMkdir(path);
|
return Fs::Vfs::VfsMkdir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Sys_FRename(const char* oldPath, const char* newPath) {
|
||||||
|
return Fs::Vfs::VfsRename(oldPath, newPath);
|
||||||
|
}
|
||||||
|
|
||||||
static int Sys_DriveList(int* outDrives, int maxEntries) {
|
static int Sys_DriveList(int* outDrives, int maxEntries) {
|
||||||
return Fs::Vfs::VfsDriveList(outDrives, maxEntries);
|
return Fs::Vfs::VfsDriveList(outDrives, maxEntries);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,6 +200,10 @@ namespace Montauk {
|
|||||||
case SYS_FMKDIR:
|
case SYS_FMKDIR:
|
||||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||||
return (int64_t)Sys_FMkdir((const char*)frame->arg1);
|
return (int64_t)Sys_FMkdir((const char*)frame->arg1);
|
||||||
|
case SYS_FRENAME:
|
||||||
|
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||||
|
if (!ValidUserPtr(frame->arg2)) return -1;
|
||||||
|
return (int64_t)Sys_FRename((const char*)frame->arg1, (const char*)frame->arg2);
|
||||||
case SYS_DRIVELIST:
|
case SYS_DRIVELIST:
|
||||||
if (!ValidUserPtr(frame->arg1)) return -1;
|
if (!ValidUserPtr(frame->arg1)) return -1;
|
||||||
return (int64_t)Sys_DriveList((int*)frame->arg1, (int)frame->arg2);
|
return (int64_t)Sys_DriveList((int*)frame->arg1, (int)frame->arg2);
|
||||||
|
|||||||
@@ -182,6 +182,9 @@ namespace Montauk {
|
|||||||
static constexpr uint64_t SYS_SETUSER = 92;
|
static constexpr uint64_t SYS_SETUSER = 92;
|
||||||
static constexpr uint64_t SYS_GETUSER = 93;
|
static constexpr uint64_t SYS_GETUSER = 93;
|
||||||
|
|
||||||
|
/* Filesystem.hpp */
|
||||||
|
static constexpr uint64_t SYS_FRENAME = 94;
|
||||||
|
|
||||||
static constexpr int SOCK_TCP = 1;
|
static constexpr int SOCK_TCP = 1;
|
||||||
static constexpr int SOCK_UDP = 2;
|
static constexpr int SOCK_UDP = 2;
|
||||||
|
|
||||||
|
|||||||
@@ -1437,6 +1437,109 @@ namespace Fs::Ext2 {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Rename — move a directory entry (inode stays the same)
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
static int RenameImpl(int inst, const char* oldPath, const char* newPath) {
|
||||||
|
if (inst < 0 || inst >= g_instanceCount || !g_instances[inst].active) return -1;
|
||||||
|
auto& self = g_instances[inst];
|
||||||
|
|
||||||
|
// Split old path
|
||||||
|
char oldParentPath[MaxNameLen];
|
||||||
|
char oldFileName[MaxNameLen];
|
||||||
|
SplitPath(oldPath, oldParentPath, MaxNameLen, oldFileName, MaxNameLen);
|
||||||
|
if (oldFileName[0] == '\0') return -1;
|
||||||
|
|
||||||
|
// Split new path
|
||||||
|
char newParentPath[MaxNameLen];
|
||||||
|
char newFileName[MaxNameLen];
|
||||||
|
SplitPath(newPath, newParentPath, MaxNameLen, newFileName, MaxNameLen);
|
||||||
|
if (newFileName[0] == '\0') return -1;
|
||||||
|
|
||||||
|
// Find old entry
|
||||||
|
uint32_t oldParentInodeNum;
|
||||||
|
Inode oldParentInode;
|
||||||
|
if (!TraversePath(self, oldParentPath, &oldParentInodeNum, &oldParentInode)) return -1;
|
||||||
|
if ((oldParentInode.i_mode & IMODE_TYPE_MASK) != IMODE_DIR) return -1;
|
||||||
|
|
||||||
|
ParsedEntry oldEntry;
|
||||||
|
if (!FindInDirectory(self, oldParentInode, oldFileName, &oldEntry)) return -1;
|
||||||
|
|
||||||
|
// Find new parent
|
||||||
|
uint32_t newParentInodeNum;
|
||||||
|
Inode newParentInode;
|
||||||
|
if (!TraversePath(self, newParentPath, &newParentInodeNum, &newParentInode)) return -1;
|
||||||
|
if ((newParentInode.i_mode & IMODE_TYPE_MASK) != IMODE_DIR) return -1;
|
||||||
|
|
||||||
|
// If destination already exists, delete it
|
||||||
|
ParsedEntry destEntry;
|
||||||
|
if (FindInDirectory(self, newParentInode, newFileName, &destEntry)) {
|
||||||
|
Inode destInode;
|
||||||
|
if (!ReadInode(self, destEntry.inodeNum, &destInode)) return -1;
|
||||||
|
|
||||||
|
bool destIsDir = (destInode.i_mode & IMODE_TYPE_MASK) == IMODE_DIR;
|
||||||
|
if (destIsDir) {
|
||||||
|
ParsedEntry children[1];
|
||||||
|
int childCount = ReadDirectoryEntries(self, destInode, children, 1);
|
||||||
|
if (childCount > 0) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!RemoveDirEntry(self, newParentInode, newFileName)) return -1;
|
||||||
|
|
||||||
|
if (destIsDir) {
|
||||||
|
newParentInode.i_links_count--;
|
||||||
|
WriteInode(self, newParentInodeNum, &newParentInode);
|
||||||
|
}
|
||||||
|
|
||||||
|
destInode.i_links_count--;
|
||||||
|
if (destIsDir) destInode.i_links_count--;
|
||||||
|
if (destInode.i_links_count <= 0) {
|
||||||
|
FreeInodeBlocks(self, destInode);
|
||||||
|
destInode.i_mode = 0;
|
||||||
|
WriteInode(self, destEntry.inodeNum, &destInode);
|
||||||
|
FreeInode(self, destEntry.inodeNum);
|
||||||
|
} else {
|
||||||
|
WriteInode(self, destEntry.inodeNum, &destInode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-read new parent inode since RemoveDirEntry may have modified it
|
||||||
|
ReadInode(self, newParentInodeNum, &newParentInode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove old directory entry (does not touch the inode)
|
||||||
|
// Re-read old parent in case it's the same dir and was modified above
|
||||||
|
ReadInode(self, oldParentInodeNum, &oldParentInode);
|
||||||
|
if (!RemoveDirEntry(self, oldParentInode, oldFileName)) return -1;
|
||||||
|
|
||||||
|
// Add new directory entry pointing to the same inode
|
||||||
|
if (!AddDirEntry(self, newParentInodeNum, newParentInode,
|
||||||
|
oldEntry.inodeNum, newFileName, oldEntry.fileType)) {
|
||||||
|
// Failed to add — try to restore old entry
|
||||||
|
ReadInode(self, oldParentInodeNum, &oldParentInode);
|
||||||
|
AddDirEntry(self, oldParentInodeNum, oldParentInode,
|
||||||
|
oldEntry.inodeNum, oldFileName, oldEntry.fileType);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If moving a directory across parents, update ".." entry and link counts
|
||||||
|
bool isDir = oldEntry.fileType == EXT2_FT_DIR;
|
||||||
|
if (isDir && oldParentInodeNum != newParentInodeNum) {
|
||||||
|
// Decrement old parent link count, increment new parent
|
||||||
|
ReadInode(self, oldParentInodeNum, &oldParentInode);
|
||||||
|
oldParentInode.i_links_count--;
|
||||||
|
WriteInode(self, oldParentInodeNum, &oldParentInode);
|
||||||
|
|
||||||
|
ReadInode(self, newParentInodeNum, &newParentInode);
|
||||||
|
newParentInode.i_links_count++;
|
||||||
|
WriteInode(self, newParentInodeNum, &newParentInode);
|
||||||
|
|
||||||
|
// TODO: update ".." entry inside the moved directory to point to new parent
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Template thunks — generate unique function pointers per instance
|
// Template thunks — generate unique function pointers per instance
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -1451,6 +1554,7 @@ namespace Fs::Ext2 {
|
|||||||
static int Create(const char* p) { return CreateImpl(N, p); }
|
static int Create(const char* p) { return CreateImpl(N, p); }
|
||||||
static int Delete(const char* p) { return DeleteImpl(N, p); }
|
static int Delete(const char* p) { return DeleteImpl(N, p); }
|
||||||
static int Mkdir(const char* p) { return MkdirImpl(N, p); }
|
static int Mkdir(const char* p) { return MkdirImpl(N, p); }
|
||||||
|
static int Rename(const char* o, const char* n) { return RenameImpl(N, o, n); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int N>
|
template<int N>
|
||||||
@@ -1465,6 +1569,7 @@ namespace Fs::Ext2 {
|
|||||||
Thunks<N>::Create,
|
Thunks<N>::Create,
|
||||||
Thunks<N>::Delete,
|
Thunks<N>::Delete,
|
||||||
Thunks<N>::Mkdir,
|
Thunks<N>::Mkdir,
|
||||||
|
Thunks<N>::Rename,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1469,6 +1469,220 @@ namespace Fs::Fat32 {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Rename — atomic directory entry move
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
static int RenameImpl(int inst, const char* oldPath, const char* newPath) {
|
||||||
|
if (inst < 0 || inst >= g_instanceCount || !g_instances[inst].active) return -1;
|
||||||
|
auto& self = g_instances[inst];
|
||||||
|
|
||||||
|
// Split old path
|
||||||
|
char oldParentPath[MaxNameLen];
|
||||||
|
char oldFileName[MaxNameLen];
|
||||||
|
SplitPath(oldPath, oldParentPath, MaxNameLen, oldFileName, MaxNameLen);
|
||||||
|
if (oldFileName[0] == '\0') return -1;
|
||||||
|
|
||||||
|
// Split new path
|
||||||
|
char newParentPath[MaxNameLen];
|
||||||
|
char newFileName[MaxNameLen];
|
||||||
|
SplitPath(newPath, newParentPath, MaxNameLen, newFileName, MaxNameLen);
|
||||||
|
if (newFileName[0] == '\0') return -1;
|
||||||
|
|
||||||
|
// Traverse to old parent directory
|
||||||
|
ParsedEntry oldParent;
|
||||||
|
if (!TraversePath(inst, oldParentPath, &oldParent)) return -1;
|
||||||
|
if (!(oldParent.attributes & ATTR_DIRECTORY)) return -1;
|
||||||
|
|
||||||
|
// Find old entry
|
||||||
|
ParsedEntry oldEntry;
|
||||||
|
if (!FindInDirectory(inst, oldParent.firstCluster, oldFileName, &oldEntry)) return -1;
|
||||||
|
|
||||||
|
// Save the data we need from the old entry before deleting it
|
||||||
|
uint32_t savedFirstCluster = oldEntry.firstCluster;
|
||||||
|
uint32_t savedFileSize = oldEntry.fileSize;
|
||||||
|
uint8_t savedAttributes = oldEntry.attributes;
|
||||||
|
|
||||||
|
// Traverse to new parent directory
|
||||||
|
ParsedEntry newParent;
|
||||||
|
if (!TraversePath(inst, newParentPath, &newParent)) return -1;
|
||||||
|
if (!(newParent.attributes & ATTR_DIRECTORY)) return -1;
|
||||||
|
|
||||||
|
// If destination already exists, delete it (including its cluster chain)
|
||||||
|
ParsedEntry destEntry;
|
||||||
|
if (FindInDirectory(inst, newParent.firstCluster, newFileName, &destEntry)) {
|
||||||
|
// Don't allow overwriting a non-empty directory
|
||||||
|
if (destEntry.attributes & ATTR_DIRECTORY) {
|
||||||
|
ParsedEntry children[1];
|
||||||
|
int childCount = ReadDirectory(inst, destEntry.firstCluster, children, 1);
|
||||||
|
if (childCount > 0) return -1;
|
||||||
|
}
|
||||||
|
// Free destination cluster chain
|
||||||
|
uint32_t cl = destEntry.firstCluster;
|
||||||
|
while (!IsEndOfChain(cl) && cl >= 2) {
|
||||||
|
uint32_t next = GetNextCluster(self, cl);
|
||||||
|
WriteFatEntry(self, cl, CLUSTER_FREE);
|
||||||
|
cl = next;
|
||||||
|
}
|
||||||
|
// Mark destination directory entries as deleted
|
||||||
|
// (reuse the delete-entry-marking logic inline)
|
||||||
|
uint32_t cluster = newParent.firstCluster;
|
||||||
|
while (!IsEndOfChain(cluster)) {
|
||||||
|
if (!ReadCluster(self, cluster)) return -1;
|
||||||
|
int perCluster = (int)(self.clusterSize / 32);
|
||||||
|
bool modified = false;
|
||||||
|
for (int i = 0; i < perCluster; i++) {
|
||||||
|
uint8_t* e = self.clusterBuf + i * 32;
|
||||||
|
if (e[0] == 0x00) break;
|
||||||
|
if (e[0] == 0xE5) continue;
|
||||||
|
uint64_t clusterPartSec = ClusterToPartSector(self, cluster);
|
||||||
|
uint32_t byteOff = i * 32;
|
||||||
|
uint64_t entrySec = clusterPartSec + (byteOff / self.bytesPerSector);
|
||||||
|
uint32_t entryOff = byteOff % self.bytesPerSector;
|
||||||
|
if (entrySec == destEntry.sfnPartSector &&
|
||||||
|
entryOff == destEntry.sfnOffInSector) {
|
||||||
|
e[0] = 0xE5;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modified) WriteClusterData(self, cluster, self.clusterBuf);
|
||||||
|
cluster = GetNextCluster(self, cluster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark old directory entries as deleted (but DO NOT free the cluster chain)
|
||||||
|
{
|
||||||
|
uint32_t cluster = oldParent.firstCluster;
|
||||||
|
bool inLfnRun = false;
|
||||||
|
|
||||||
|
while (!IsEndOfChain(cluster)) {
|
||||||
|
if (!ReadCluster(self, cluster)) return -1;
|
||||||
|
int perCluster = (int)(self.clusterSize / 32);
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < perCluster; i++) {
|
||||||
|
uint8_t* e = self.clusterBuf + i * 32;
|
||||||
|
if (e[0] == 0x00) goto old_write_back;
|
||||||
|
if (e[0] == 0xE5) { inLfnRun = false; continue; }
|
||||||
|
|
||||||
|
uint8_t attr = e[11];
|
||||||
|
if (attr == ATTR_LFN) {
|
||||||
|
uint8_t seq = e[0];
|
||||||
|
if (seq & 0x40) {
|
||||||
|
inLfnRun = false;
|
||||||
|
int lfnCount = seq & 0x1F;
|
||||||
|
int sfnIdx = i + lfnCount;
|
||||||
|
if (sfnIdx < perCluster) {
|
||||||
|
uint64_t clusterPartSec = ClusterToPartSector(self, cluster);
|
||||||
|
uint32_t byteOff = sfnIdx * 32;
|
||||||
|
uint64_t sfnSec = clusterPartSec + (byteOff / self.bytesPerSector);
|
||||||
|
uint32_t sfnOff = byteOff % self.bytesPerSector;
|
||||||
|
if (sfnSec == oldEntry.sfnPartSector &&
|
||||||
|
sfnOff == oldEntry.sfnOffInSector) {
|
||||||
|
inLfnRun = true;
|
||||||
|
e[0] = 0xE5;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (inLfnRun) {
|
||||||
|
e[0] = 0xE5;
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t clusterPartSec = ClusterToPartSector(self, cluster);
|
||||||
|
uint32_t byteOff = i * 32;
|
||||||
|
uint64_t entrySec = clusterPartSec + (byteOff / self.bytesPerSector);
|
||||||
|
uint32_t entryOff = byteOff % self.bytesPerSector;
|
||||||
|
if (entrySec == oldEntry.sfnPartSector &&
|
||||||
|
entryOff == oldEntry.sfnOffInSector) {
|
||||||
|
e[0] = 0xE5;
|
||||||
|
modified = true;
|
||||||
|
inLfnRun = false;
|
||||||
|
goto old_write_back;
|
||||||
|
}
|
||||||
|
inLfnRun = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_write_back:
|
||||||
|
if (modified) WriteClusterData(self, cluster, self.clusterBuf);
|
||||||
|
{
|
||||||
|
uint64_t clusterPartSec = ClusterToPartSector(self, cluster);
|
||||||
|
uint64_t clusterEndSec = clusterPartSec + self.sectorsPerCluster;
|
||||||
|
if (oldEntry.sfnPartSector >= clusterPartSec &&
|
||||||
|
oldEntry.sfnPartSector < clusterEndSec) {
|
||||||
|
break; // done removing old entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cluster = GetNextCluster(self, cluster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new directory entry with the saved cluster chain and size
|
||||||
|
char shortName[11];
|
||||||
|
GenerateShortName(newFileName, shortName);
|
||||||
|
MakeShortNameUnique(inst, newParent.firstCluster, shortName);
|
||||||
|
|
||||||
|
uint8_t lfnEntries[20 * 32];
|
||||||
|
int lfnCount = 0;
|
||||||
|
bool needsLfn = NeedsLfn(newFileName, shortName);
|
||||||
|
if (needsLfn) {
|
||||||
|
uint8_t checksum = LfnChecksum(shortName);
|
||||||
|
lfnCount = BuildLfnEntries(newFileName, checksum, lfnEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalSlots = lfnCount + 1;
|
||||||
|
DirSlotPos pos = FindFreeDirSlots(inst, newParent.firstCluster, totalSlots);
|
||||||
|
if (!pos.found) return -1;
|
||||||
|
|
||||||
|
// Build all entries (LFN + SFN) contiguously
|
||||||
|
uint8_t allEntries[21 * 32];
|
||||||
|
if (lfnCount > 0) {
|
||||||
|
memcpy(allEntries, lfnEntries, lfnCount * 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the SFN entry with preserved cluster/size
|
||||||
|
uint8_t* sfn = allEntries + lfnCount * 32;
|
||||||
|
memset(sfn, 0, 32);
|
||||||
|
memcpy(sfn, shortName, 11);
|
||||||
|
sfn[11] = savedAttributes;
|
||||||
|
|
||||||
|
uint16_t clHi = (uint16_t)(savedFirstCluster >> 16);
|
||||||
|
uint16_t clLo = (uint16_t)(savedFirstCluster & 0xFFFF);
|
||||||
|
memcpy(sfn + 20, &clHi, 2);
|
||||||
|
memcpy(sfn + 26, &clLo, 2);
|
||||||
|
memcpy(sfn + 28, &savedFileSize, 4);
|
||||||
|
|
||||||
|
// Write entries to disk, handling sector boundaries
|
||||||
|
uint64_t curSector = pos.partSector;
|
||||||
|
uint32_t curOff = pos.offsetInSec;
|
||||||
|
uint8_t sectorBuf[512];
|
||||||
|
|
||||||
|
if (!ReadPartSectors(self, curSector, 1, sectorBuf)) return -1;
|
||||||
|
|
||||||
|
int bytesTotal = totalSlots * 32;
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
while (written < bytesTotal) {
|
||||||
|
int space = (int)self.bytesPerSector - (int)curOff;
|
||||||
|
int chunk = bytesTotal - written;
|
||||||
|
if (chunk > space) chunk = space;
|
||||||
|
|
||||||
|
memcpy(sectorBuf + curOff, allEntries + written, chunk);
|
||||||
|
written += chunk;
|
||||||
|
|
||||||
|
if (!WritePartSectors(self, curSector, 1, sectorBuf)) return -1;
|
||||||
|
if (written < bytesTotal) {
|
||||||
|
curSector++;
|
||||||
|
curOff = 0;
|
||||||
|
if (!ReadPartSectors(self, curSector, 1, sectorBuf)) return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Template thunks — generate unique function pointers per instance
|
// Template thunks — generate unique function pointers per instance
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -1483,6 +1697,7 @@ namespace Fs::Fat32 {
|
|||||||
static int Create(const char* p) { return CreateImpl(N, p); }
|
static int Create(const char* p) { return CreateImpl(N, p); }
|
||||||
static int Delete(const char* p) { return DeleteImpl(N, p); }
|
static int Delete(const char* p) { return DeleteImpl(N, p); }
|
||||||
static int Mkdir(const char* p) { return MkdirImpl(N, p); }
|
static int Mkdir(const char* p) { return MkdirImpl(N, p); }
|
||||||
|
static int Rename(const char* o, const char* n) { return RenameImpl(N, o, n); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int N>
|
template<int N>
|
||||||
@@ -1497,6 +1712,7 @@ namespace Fs::Fat32 {
|
|||||||
Thunks<N>::Create,
|
Thunks<N>::Create,
|
||||||
Thunks<N>::Delete,
|
Thunks<N>::Delete,
|
||||||
Thunks<N>::Mkdir,
|
Thunks<N>::Mkdir,
|
||||||
|
Thunks<N>::Rename,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -211,6 +211,25 @@ namespace Fs::Vfs {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VfsRename(const char* oldPath, const char* newPath) {
|
||||||
|
int oldDrive, newDrive;
|
||||||
|
const char* oldLocal;
|
||||||
|
const char* newLocal;
|
||||||
|
|
||||||
|
if (!ParsePath(oldPath, oldDrive, oldLocal)) return -1;
|
||||||
|
if (!ParsePath(newPath, newDrive, newLocal)) return -1;
|
||||||
|
|
||||||
|
// Cross-drive rename not supported
|
||||||
|
if (oldDrive != newDrive) return -1;
|
||||||
|
if (oldDrive < 0 || oldDrive >= MaxDrives || driveTable[oldDrive] == nullptr) return -1;
|
||||||
|
if (driveTable[oldDrive]->Rename == nullptr) return -1;
|
||||||
|
|
||||||
|
vfsLock.Acquire();
|
||||||
|
int result = driveTable[oldDrive]->Rename(oldLocal, newLocal);
|
||||||
|
vfsLock.Release();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int VfsReadDir(const char* path, const char** outNames, int maxEntries) {
|
int VfsReadDir(const char* path, const char** outNames, int maxEntries) {
|
||||||
int drive;
|
int drive;
|
||||||
const char* localPath;
|
const char* localPath;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace Fs::Vfs {
|
|||||||
int (*Create)(const char* path);
|
int (*Create)(const char* path);
|
||||||
int (*Delete)(const char* path);
|
int (*Delete)(const char* path);
|
||||||
int (*Mkdir)(const char* path);
|
int (*Mkdir)(const char* path);
|
||||||
|
int (*Rename)(const char* oldPath, const char* newPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
@@ -37,6 +38,7 @@ namespace Fs::Vfs {
|
|||||||
void VfsClose(int handle);
|
void VfsClose(int handle);
|
||||||
int VfsReadDir(const char* path, const char** outNames, int maxEntries);
|
int VfsReadDir(const char* path, const char** outNames, int maxEntries);
|
||||||
int VfsMkdir(const char* path);
|
int VfsMkdir(const char* path);
|
||||||
|
int VfsRename(const char* oldPath, const char* newPath);
|
||||||
|
|
||||||
// Returns number of registered drives, fills outDrives[] with their indices
|
// Returns number of registered drives, fills outDrives[] with their indices
|
||||||
int VfsDriveList(int* outDrives, int maxEntries);
|
int VfsDriveList(int* outDrives, int maxEntries);
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ extern "C" {
|
|||||||
#define MTK_SYS_WINSETCURSOR 68
|
#define MTK_SYS_WINSETCURSOR 68
|
||||||
#define MTK_SYS_FDELETE 77
|
#define MTK_SYS_FDELETE 77
|
||||||
#define MTK_SYS_FMKDIR 78
|
#define MTK_SYS_FMKDIR 78
|
||||||
|
#define MTK_SYS_FRENAME 94
|
||||||
#define MTK_SYS_DRIVELIST 79
|
#define MTK_SYS_DRIVELIST 79
|
||||||
#define MTK_SYS_AUDIOOPEN 80
|
#define MTK_SYS_AUDIOOPEN 80
|
||||||
#define MTK_SYS_AUDIOCLOSE 81
|
#define MTK_SYS_AUDIOCLOSE 81
|
||||||
@@ -377,6 +378,10 @@ static inline int mtk_mkdir(const char *path) {
|
|||||||
return (int)_mtk_syscall1(MTK_SYS_FMKDIR, (long)path);
|
return (int)_mtk_syscall1(MTK_SYS_FMKDIR, (long)path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int mtk_rename(const char *oldpath, const char *newpath) {
|
||||||
|
return (int)_mtk_syscall2(MTK_SYS_FRENAME, (long)oldpath, (long)newpath);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int mtk_readdir(const char *path, const char **names, int max) {
|
static inline int mtk_readdir(const char *path, const char **names, int max) {
|
||||||
return (int)_mtk_syscall3(MTK_SYS_READDIR, (long)path, (long)names, (long)max);
|
return (int)_mtk_syscall3(MTK_SYS_READDIR, (long)path, (long)names, (long)max);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) {
|
|||||||
#define SYS_FCREATE 42
|
#define SYS_FCREATE 42
|
||||||
#define SYS_FDELETE 77
|
#define SYS_FDELETE 77
|
||||||
#define SYS_FMKDIR 78
|
#define SYS_FMKDIR 78
|
||||||
|
#define SYS_FRENAME 94
|
||||||
|
|
||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
errno
|
errno
|
||||||
@@ -1217,40 +1218,8 @@ int remove(const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int rename(const char *oldpath, const char *newpath) {
|
int rename(const char *oldpath, const char *newpath) {
|
||||||
/* No atomic rename syscall -- copy + delete */
|
|
||||||
if (oldpath == NULL || newpath == NULL) return -1;
|
if (oldpath == NULL || newpath == NULL) return -1;
|
||||||
|
return (int)_zos_syscall2(SYS_FRENAME, (long)oldpath, (long)newpath);
|
||||||
int src = (int)_zos_syscall1(SYS_OPEN, (long)oldpath);
|
|
||||||
if (src < 0) return -1;
|
|
||||||
|
|
||||||
unsigned long sz = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)src);
|
|
||||||
|
|
||||||
/* Create destination */
|
|
||||||
_zos_syscall1(SYS_FDELETE, (long)newpath);
|
|
||||||
int dst = (int)_zos_syscall1(SYS_FCREATE, (long)newpath);
|
|
||||||
if (dst < 0) {
|
|
||||||
_zos_syscall1(SYS_CLOSE, (long)src);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy in chunks */
|
|
||||||
char copybuf[4096];
|
|
||||||
unsigned long off = 0;
|
|
||||||
while (off < sz) {
|
|
||||||
unsigned long chunk = sz - off;
|
|
||||||
if (chunk > sizeof(copybuf)) chunk = sizeof(copybuf);
|
|
||||||
int r = (int)_zos_syscall4(SYS_READ, (long)src,
|
|
||||||
(long)copybuf, (long)off, (long)chunk);
|
|
||||||
if (r <= 0) break;
|
|
||||||
_zos_syscall4(SYS_FWRITE, (long)dst,
|
|
||||||
(long)copybuf, (long)off, (long)r);
|
|
||||||
off += (unsigned long)r;
|
|
||||||
}
|
|
||||||
|
|
||||||
_zos_syscall1(SYS_CLOSE, (long)src);
|
|
||||||
_zos_syscall1(SYS_CLOSE, (long)dst);
|
|
||||||
_zos_syscall1(SYS_FDELETE, (long)oldpath);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void perror(const char *s) {
|
void perror(const char *s) {
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user