REFACTOR: Final cleanup of DiscImageChef.Filesystems.

This commit is contained in:
2017-12-24 02:37:41 +00:00
parent ec73a6cdc3
commit 4115698ac8
94 changed files with 5196 additions and 5116 deletions

View File

@@ -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)