mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
REFACTOR: Final cleanup of DiscImageChef.Filesystems.
This commit is contained in:
@@ -132,7 +132,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
byte[] readSector =
|
||||
device.ReadSector((ulong)((int)partition.Start + p / sectorMask.Length * sectorMask.Length +
|
||||
sectorMask[p % sectorMask.Length]));
|
||||
if(workingDefinition.complement) for(int b = 0; b < readSector.Length; b++) readSector[b] = (byte)(~readSector[b] & 0xFF);
|
||||
if(workingDefinition.complement)
|
||||
for(int b = 0; b < readSector.Length; b++) readSector[b] = (byte)(~readSector[b] & 0xFF);
|
||||
|
||||
deinterleavedSectors.Add((ulong)p, readSector);
|
||||
}
|
||||
@@ -213,13 +214,14 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// For each directory entry
|
||||
for(int dOff = 0; dOff < directory.Length; dOff += 32)
|
||||
// Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries
|
||||
// Describes a file (does not support PDOS entries with user >= 16, because they're identical to password entries
|
||||
if((directory[dOff] & 0x7F) < 0x10)
|
||||
if(allocationBlocks.Count > 256)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
DirectoryEntry16 entry = (DirectoryEntry16)Marshal.PtrToStructure(dirPtr, typeof(DirectoryEntry16));
|
||||
DirectoryEntry16 entry =
|
||||
(DirectoryEntry16)Marshal.PtrToStructure(dirPtr, typeof(DirectoryEntry16));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
bool hidden = (entry.statusUser & 0x80) == 0x80;
|
||||
@@ -254,11 +256,11 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// Do we have a stat for the file already?
|
||||
if(statCache.TryGetValue(filename, out FileEntryInfo fInfo)) statCache.Remove(filename);
|
||||
else
|
||||
{ fInfo = new FileEntryInfo {Attributes = new FileAttributes()}; }
|
||||
else fInfo = new FileEntryInfo {Attributes = new FileAttributes()};
|
||||
|
||||
// And any extent?
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks)) fileExtents.Remove(filename);
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks))
|
||||
fileExtents.Remove(filename);
|
||||
else extentBlocks = new Dictionary<int, List<ushort>>();
|
||||
|
||||
// Do we already have this extent? Should never happen
|
||||
@@ -275,7 +277,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
// because that's where the directory resides.
|
||||
// There is also a field telling how many bytes are used in the last block, but its meaning is non-standard so
|
||||
// we must ignore it.
|
||||
foreach(ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0)) blocks.Add(blk);
|
||||
foreach(ushort blk in entry.allocations.Where(blk => !blocks.Contains(blk) && blk != 0))
|
||||
blocks.Add(blk);
|
||||
|
||||
// Save the file
|
||||
fInfo.UID = (ulong)user;
|
||||
@@ -341,11 +344,11 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
|
||||
// Do we have a stat for the file already?
|
||||
if(statCache.TryGetValue(filename, out FileEntryInfo fInfo)) statCache.Remove(filename);
|
||||
else
|
||||
{ fInfo = new FileEntryInfo {Attributes = new FileAttributes()}; }
|
||||
else fInfo = new FileEntryInfo {Attributes = new FileAttributes()};
|
||||
|
||||
// And any extent?
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks)) fileExtents.Remove(filename);
|
||||
if(fileExtents.TryGetValue(filename, out Dictionary<int, List<ushort>> extentBlocks))
|
||||
fileExtents.Remove(filename);
|
||||
else extentBlocks = new Dictionary<int, List<ushort>>();
|
||||
|
||||
// Do we already have this extent? Should never happen
|
||||
@@ -362,7 +365,8 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
// because that's where the directory resides.
|
||||
// There is also a field telling how many bytes are used in the last block, but its meaning is non-standard so
|
||||
// we must ignore it.
|
||||
foreach(ushort blk in entry.allocations.Cast<ushort>().Where(blk => !blocks.Contains(blk) && blk != 0)) blocks.Add(blk);
|
||||
foreach(ushort blk in entry.allocations.Cast<ushort>()
|
||||
.Where(blk => !blocks.Contains(blk) && blk != 0)) blocks.Add(blk);
|
||||
|
||||
// Save the file
|
||||
fInfo.UID = (ulong)user;
|
||||
@@ -434,161 +438,164 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
dirCnt++;
|
||||
}
|
||||
// Volume label and password entry. Volume password is ignored.
|
||||
else switch(directory[dOff] & 0x7F) {
|
||||
case 0x20:
|
||||
LabelEntry labelEntry;
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
labelEntry = (LabelEntry)Marshal.PtrToStructure(dirPtr, typeof(LabelEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
else
|
||||
switch(directory[dOff] & 0x7F)
|
||||
{
|
||||
case 0x20:
|
||||
LabelEntry labelEntry;
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
labelEntry = (LabelEntry)Marshal.PtrToStructure(dirPtr, typeof(LabelEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
// The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an access time
|
||||
atime |= (labelEntry.flags & 0x40) == 0x40;
|
||||
// The volume label defines if one of the fields in CP/M 3 timestamp is a creation or an access time
|
||||
atime |= (labelEntry.flags & 0x40) == 0x40;
|
||||
|
||||
label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim();
|
||||
labelCreationDate = new byte[4];
|
||||
labelUpdateDate = new byte[4];
|
||||
Array.Copy(directory, dOff + 24, labelCreationDate, 0, 4);
|
||||
Array.Copy(directory, dOff + 28, labelUpdateDate, 0, 4);
|
||||
label = Encoding.ASCII.GetString(directory, dOff + 1, 11).Trim();
|
||||
labelCreationDate = new byte[4];
|
||||
labelUpdateDate = new byte[4];
|
||||
Array.Copy(directory, dOff + 24, labelCreationDate, 0, 4);
|
||||
Array.Copy(directory, dOff + 28, labelUpdateDate, 0, 4);
|
||||
|
||||
// Count entries 3 by 3 for timestamps
|
||||
switch(dirCnt % 3)
|
||||
{
|
||||
case 0:
|
||||
file1 = null;
|
||||
break;
|
||||
case 1:
|
||||
file2 = null;
|
||||
break;
|
||||
case 2:
|
||||
file3 = null;
|
||||
break;
|
||||
}
|
||||
|
||||
dirCnt++;
|
||||
break;
|
||||
case 0x21:
|
||||
if(directory[dOff + 10] == 0x00 && directory[dOff + 20] == 0x00 &&
|
||||
directory[dOff + 30] == 0x00 && directory[dOff + 31] == 0x00)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
DateEntry dateEntry = (DateEntry)Marshal.PtrToStructure(dirPtr, typeof(DateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4);
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file3, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
// Count entries 3 by 3 for timestamps
|
||||
switch(dirCnt % 3)
|
||||
{
|
||||
case 0:
|
||||
file1 = null;
|
||||
break;
|
||||
case 1:
|
||||
file2 = null;
|
||||
break;
|
||||
case 2:
|
||||
file3 = null;
|
||||
break;
|
||||
}
|
||||
|
||||
dirCnt++;
|
||||
break;
|
||||
case 0x21:
|
||||
if(directory[dOff + 10] == 0x00 && directory[dOff + 20] == 0x00 && directory[dOff + 30] == 0x00 &&
|
||||
directory[dOff + 31] == 0x00)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
DateEntry dateEntry = (DateEntry)Marshal.PtrToStructure(dirPtr, typeof(DateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date1);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date2);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
dirCnt = 0;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
// However, if this byte is 0, timestamp is in Z80DOS or DOS+ format
|
||||
else if(directory[dOff + 1] == 0x00)
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
TrdPartyDateEntry trdPartyDateEntry =
|
||||
(TrdPartyDateEntry)Marshal.PtrToStructure(dirPtr, typeof(TrdPartyDateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date3);
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date4);
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create1[0];
|
||||
ctime[1] = trdPartyDateEntry.create1[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create2[0];
|
||||
ctime[1] = trdPartyDateEntry.create2[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2);
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create3[0];
|
||||
ctime[1] = trdPartyDateEntry.create3[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
file1 = null;
|
||||
file2 = null;
|
||||
file3 = null;
|
||||
dirCnt = 0;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file3, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
if(atime) fInfo.AccessTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
else fInfo.CreationTime = DateHandlers.CpmToDateTime(dateEntry.date5);
|
||||
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(dateEntry.date6);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
file1 = null;
|
||||
file2 = null;
|
||||
file3 = null;
|
||||
dirCnt = 0;
|
||||
}
|
||||
// However, if this byte is 0, timestamp is in Z80DOS or DOS+ format
|
||||
else if(directory[dOff + 1] == 0x00)
|
||||
{
|
||||
dirPtr = Marshal.AllocHGlobal(32);
|
||||
Marshal.Copy(directory, dOff, dirPtr, 32);
|
||||
TrdPartyDateEntry trdPartyDateEntry = (TrdPartyDateEntry)Marshal.PtrToStructure(dirPtr, typeof(TrdPartyDateEntry));
|
||||
Marshal.FreeHGlobal(dirPtr);
|
||||
|
||||
FileEntryInfo fInfo;
|
||||
|
||||
// Entry contains timestamps for last 3 entries, whatever the kind they are.
|
||||
if(!string.IsNullOrEmpty(file1))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file1);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create1[0];
|
||||
ctime[1] = trdPartyDateEntry.create1[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access1);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify1);
|
||||
|
||||
statCache.Add(file1, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file2))
|
||||
{
|
||||
if(statCache.TryGetValue(file2, out fInfo)) statCache.Remove(file2);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create2[0];
|
||||
ctime[1] = trdPartyDateEntry.create2[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access2);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify2);
|
||||
|
||||
statCache.Add(file2, fInfo);
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(file3))
|
||||
{
|
||||
if(statCache.TryGetValue(file1, out fInfo)) statCache.Remove(file3);
|
||||
else fInfo = new FileEntryInfo();
|
||||
|
||||
byte[] ctime = new byte[4];
|
||||
ctime[0] = trdPartyDateEntry.create3[0];
|
||||
ctime[1] = trdPartyDateEntry.create3[1];
|
||||
|
||||
fInfo.AccessTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.access3);
|
||||
fInfo.CreationTime = DateHandlers.CpmToDateTime(ctime);
|
||||
fInfo.LastWriteTime = DateHandlers.CpmToDateTime(trdPartyDateEntry.modify3);
|
||||
|
||||
statCache.Add(file3, fInfo);
|
||||
}
|
||||
|
||||
file1 = null;
|
||||
file2 = null;
|
||||
file3 = null;
|
||||
dirCnt = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Cache all files. As CP/M maximum volume size is 8 Mib
|
||||
// this should not be a problem
|
||||
@@ -675,7 +682,7 @@ namespace DiscImageChef.Filesystems.CPM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the mounted volume.
|
||||
/// Gets information about the mounted volume.
|
||||
/// </summary>
|
||||
/// <param name="stat">Information about the mounted volume.</param>
|
||||
public override Errno StatFs(ref FileSystemInfo stat)
|
||||
|
||||
Reference in New Issue
Block a user