Implement Qualcomm Sahara VIP and fix a few bugs

* Qualcomm Sahara VIP
* Project Cleanup
* Allow unlocking an already unlocked phone
This commit is contained in:
Gustave Monce
2021-08-11 14:33:49 +02:00
parent 9f4c92f437
commit c5fcb1ec8d
72 changed files with 987 additions and 861 deletions
+18 -26
View File
@@ -61,7 +61,7 @@ namespace DiscUtils.Internal
/// <returns>The resultant array.</returns>
public static U[] Map<T, U>(IEnumerable<T> source, Func<T, U> func)
{
List<U> result = new List<U>();
List<U> result = new();
foreach (T sVal in source)
{
@@ -81,7 +81,7 @@ namespace DiscUtils.Internal
/// <returns>The new collection, containing all entries where the predicate returns <c>true</c>.</returns>
public static C Filter<C, T>(ICollection<T> source, Func<T, bool> predicate) where C : ICollection<T>, new()
{
C result = new C();
C result = new();
foreach (T val in source)
{
if (predicate(val))
@@ -268,7 +268,7 @@ namespace DiscUtils.Internal
/// <param name="relativePath">The relative path.</param>
/// <returns>The absolute path. If no <paramref name="basePath"/> is specified
/// then relativePath is returned as-is. If <paramref name="relativePath"/>
/// contains more '..' characters than the base path contains levels of
/// contains more '..' characters than the base path contains levels of
/// directory, the resultant string be the root drive followed by the file name.
/// If no the basePath starts with '\' (no drive specified) then the returned
/// path will also start with '\'.
@@ -306,9 +306,9 @@ namespace DiscUtils.Internal
public static string MakeRelativePath(string path, string basePath)
{
List<string> pathElements =
new List<string>(path.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries));
new(path.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries));
List<string> basePathElements =
new List<string>(basePath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries));
new(basePath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries));
if (!basePath.EndsWith("\\", StringComparison.Ordinal) && basePathElements.Count > 0)
{
@@ -319,7 +319,7 @@ namespace DiscUtils.Internal
int i = 0;
while (i < Math.Min(pathElements.Count - 1, basePathElements.Count))
{
if (pathElements[i].ToUpperInvariant() != basePathElements[i].ToUpperInvariant())
if (!string.Equals(pathElements[i], basePathElements[i], StringComparison.InvariantCultureIgnoreCase))
{
break;
}
@@ -328,7 +328,7 @@ namespace DiscUtils.Internal
}
// For each remaining part of the base path, insert '..'
StringBuilder result = new StringBuilder();
StringBuilder result = new();
if (i == basePathElements.Count)
{
result.Append(@".\");
@@ -348,7 +348,7 @@ namespace DiscUtils.Internal
result.Append(@"\");
}
result.Append(pathElements[pathElements.Count - 1]);
result.Append(pathElements[^1]);
// If the target was a directory, put the terminator back
if (path.EndsWith(@"\", StringComparison.Ordinal))
@@ -441,25 +441,17 @@ namespace DiscUtils.Internal
public static FileAttributes FileAttributesFromUnixFileType(UnixFileType fileType)
{
switch (fileType)
return fileType switch
{
case UnixFileType.Fifo:
return FileAttributes.Device | FileAttributes.System;
case UnixFileType.Character:
return FileAttributes.Device | FileAttributes.System;
case UnixFileType.Directory:
return FileAttributes.Directory;
case UnixFileType.Block:
return FileAttributes.Device | FileAttributes.System;
case UnixFileType.Regular:
return FileAttributes.Normal;
case UnixFileType.Link:
return FileAttributes.ReparsePoint;
case UnixFileType.Socket:
return FileAttributes.Device | FileAttributes.System;
default:
return 0;
}
UnixFileType.Fifo => FileAttributes.Device | FileAttributes.System,
UnixFileType.Character => FileAttributes.Device | FileAttributes.System,
UnixFileType.Directory => FileAttributes.Directory,
UnixFileType.Block => FileAttributes.Device | FileAttributes.System,
UnixFileType.Regular => FileAttributes.Normal,
UnixFileType.Link => FileAttributes.ReparsePoint,
UnixFileType.Socket => FileAttributes.Device | FileAttributes.System,
_ => 0,
};
}
#endregion
+3 -3
View File
@@ -62,7 +62,7 @@ namespace DiscUtils.Fat
"buffer is too small - cluster would overflow buffer");
}
uint firstSector = (uint)((cluster - 2) * _sectorsPerCluster + _firstDataSector);
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
_stream.Position = firstSector * _bytesPerSector;
StreamUtilities.ReadExact(_stream, buffer, offset, _clusterSize);
@@ -76,7 +76,7 @@ namespace DiscUtils.Fat
"buffer is too small - cluster would overflow buffer");
}
uint firstSector = (uint)((cluster - 2) * _sectorsPerCluster + _firstDataSector);
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
_stream.Position = firstSector * _bytesPerSector;
@@ -85,7 +85,7 @@ namespace DiscUtils.Fat
internal void WipeCluster(uint cluster)
{
uint firstSector = (uint)((cluster - 2) * _sectorsPerCluster + _firstDataSector);
uint firstSector = (uint)(((cluster - 2) * _sectorsPerCluster) + _firstDataSector);
_stream.Position = firstSector * _bytesPerSector;
+13 -20
View File
@@ -194,8 +194,7 @@ namespace DiscUtils.Fat
if (desiredNumClusters < actualNumClusters)
{
uint cluster;
if (!TryGetClusterByPosition(value, out cluster))
if (!TryGetClusterByPosition(value, out uint cluster))
{
throw new IOException("Internal state corrupt - unable to find cluster");
}
@@ -218,8 +217,7 @@ namespace DiscUtils.Fat
}
else if (desiredNumClusters > actualNumClusters)
{
uint cluster;
while (!TryGetClusterByPosition(value, out cluster))
while (!TryGetClusterByPosition(value, out uint cluster))
{
cluster = ExtendChain();
_reader.WipeCluster(cluster);
@@ -314,7 +312,7 @@ namespace DiscUtils.Fat
// Partial cluster, so need to read existing cluster data first
LoadCluster(cluster);
int copyLength = Math.Min(count, _reader.ClusterSize - pos % _reader.ClusterSize);
int copyLength = Math.Min(count, _reader.ClusterSize - (pos % _reader.ClusterSize));
Array.Copy(buffer, offset, _clusterBuffer, pos, copyLength);
WriteCurrentCluster();
@@ -331,13 +329,12 @@ namespace DiscUtils.Fat
private uint ExtendChain()
{
// Sanity check - make sure the final known cluster is the EOC marker
if (!_fat.IsEndOfChain(_knownClusters[_knownClusters.Count - 1]))
if (!_fat.IsEndOfChain(_knownClusters[^1]))
{
throw new IOException("Corrupt file system: final cluster isn't End-of-Chain");
}
uint cluster;
if (!_fat.TryGetFreeCluster(out cluster))
if (!_fat.TryGetFreeCluster(out uint cluster))
{
throw new IOException("Out of disk space");
}
@@ -349,10 +346,10 @@ namespace DiscUtils.Fat
}
else
{
_fat.SetNext(_knownClusters[_knownClusters.Count - 2], cluster);
_fat.SetNext(_knownClusters[^2], cluster);
}
_knownClusters[_knownClusters.Count - 1] = cluster;
_knownClusters[^1] = cluster;
_knownClusters.Add(_fat.GetNext(cluster));
return cluster;
@@ -373,8 +370,7 @@ namespace DiscUtils.Fat
private bool TryLoadClusterByPosition(long pos)
{
uint cluster;
if (!TryGetClusterByPosition(pos, out cluster))
if (!TryGetClusterByPosition(pos, out uint cluster))
{
return false;
}
@@ -408,13 +404,10 @@ namespace DiscUtils.Fat
{
int index = (int)(pos / _reader.ClusterSize);
if (_knownClusters.Count <= index)
if (_knownClusters.Count <= index && !TryPopulateKnownClusters(index))
{
if (!TryPopulateKnownClusters(index))
{
cluster = uint.MaxValue;
return false;
}
cluster = uint.MaxValue;
return false;
}
// Chain is shorter than the current stream position
@@ -438,7 +431,7 @@ namespace DiscUtils.Fat
private bool TryPopulateKnownClusters(int index)
{
uint lastKnown = _knownClusters[_knownClusters.Count - 1];
uint lastKnown = _knownClusters[^1];
while (!_fat.IsEndOfChain(lastKnown) && _knownClusters.Count <= index)
{
lastKnown = _fat.GetNext(lastKnown);
@@ -450,7 +443,7 @@ namespace DiscUtils.Fat
private uint DetectLength()
{
while (!_fat.IsEndOfChain(_knownClusters[_knownClusters.Count - 1]))
while (!_fat.IsEndOfChain(_knownClusters[^1]))
{
if (!TryPopulateKnownClusters(_knownClusters.Count))
{
+4 -7
View File
@@ -159,7 +159,7 @@ namespace DiscUtils.Fat
int day = date & 0x001F;
int hour = (time & 0xF800) >> 11;
int minute = (time & 0x07E0) >> 5;
int second = (time & 0x001F) * 2 + tenths / 100;
int second = ((time & 0x001F) * 2) + (tenths / 100);
int millis = tenths % 100 * 10;
return new DateTime(year, month, day, hour, minute, second, millis);
@@ -167,15 +167,12 @@ namespace DiscUtils.Fat
private static void DateTimeToFileTime(DateTime value, out ushort date)
{
byte tenths;
ushort time;
DateTimeToFileTime(value, out date, out time, out tenths);
DateTimeToFileTime(value, out date, out ushort time, out byte tenths);
}
private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time)
{
byte tenths;
DateTimeToFileTime(value, out date, out time, out tenths);
DateTimeToFileTime(value, out date, out time, out byte tenths);
}
private static void DateTimeToFileTime(DateTime value, out ushort date, out ushort time, out byte tenths)
@@ -189,7 +186,7 @@ namespace DiscUtils.Fat
(ushort)((((value.Year - 1980) << 9) & 0xFE00) | ((value.Month << 5) & 0x01E0) | (value.Day & 0x001F));
time =
(ushort)(((value.Hour << 11) & 0xF800) | ((value.Minute << 5) & 0x07E0) | ((value.Second / 2) & 0x001F));
tenths = (byte)(value.Second % 2 * 100 + value.Millisecond / 10);
tenths = (byte)((value.Second % 2 * 100) + (value.Millisecond / 10));
}
private void Load(byte[] data, int offset)
+25 -35
View File
@@ -71,15 +71,13 @@ namespace DiscUtils.Fat
{
get
{
switch (_type)
return _type switch
{
case FatType.Fat12:
return _buffer.Length / 3 * 2;
case FatType.Fat16:
return _buffer.Length / 2;
default: // FAT32
return _buffer.Length / 4;
}
FatType.Fat12 => _buffer.Length / 3 * 2,
FatType.Fat16 => _buffer.Length / 2,
// FAT32
_ => _buffer.Length / 4,
};
}
}
@@ -95,32 +93,24 @@ namespace DiscUtils.Fat
internal bool IsEndOfChain(uint val)
{
switch (_type)
return _type switch
{
case FatType.Fat12:
return (val & 0x0FFF) >= 0x0FF8;
case FatType.Fat16:
return (val & 0xFFFF) >= 0xFFF8;
case FatType.Fat32:
return (val & 0x0FFFFFF8) >= 0x0FFFFFF8;
default:
throw new ArgumentException("Unknown FAT type");
}
FatType.Fat12 => (val & 0x0FFF) >= 0x0FF8,
FatType.Fat16 => (val & 0xFFFF) >= 0xFFF8,
FatType.Fat32 => (val & 0x0FFFFFF8) >= 0x0FFFFFF8,
_ => throw new ArgumentException("Unknown FAT type"),
};
}
internal bool IsBadCluster(uint val)
{
switch (_type)
return _type switch
{
case FatType.Fat12:
return (val & 0x0FFF) == 0x0FF7;
case FatType.Fat16:
return (val & 0xFFFF) == 0xFFF7;
case FatType.Fat32:
return (val & 0x0FFFFFF8) == 0x0FFFFFF7;
default:
throw new ArgumentException("Unknown FAT type");
}
FatType.Fat12 => (val & 0x0FFF) == 0x0FF7,
FatType.Fat16 => (val & 0xFFFF) == 0xFFF7,
FatType.Fat32 => (val & 0x0FFFFFF8) == 0x0FFFFFF7,
_ => throw new ArgumentException("Unknown FAT type"),
};
}
internal uint GetNext(uint cluster)
@@ -138,9 +128,9 @@ namespace DiscUtils.Fat
if ((cluster & 1) != 0)
{
return
(uint)((EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster + cluster / 2)) >> 4) & 0x0FFF);
(uint)((EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster + (cluster / 2))) >> 4) & 0x0FFF);
}
return (uint)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster + cluster / 2)) & 0x0FFF);
return (uint)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)(cluster + (cluster / 2))) & 0x0FFF);
}
internal void SetEndOfChain(uint cluster)
@@ -179,19 +169,19 @@ namespace DiscUtils.Fat
}
else
{
uint offset = cluster + cluster / 2;
uint offset = cluster + (cluster / 2);
MarkDirty(offset);
MarkDirty(offset + 1); // On alternate sector boundaries, cluster info crosses two sectors
ushort maskedOldVal;
if ((cluster & 1) != 0)
{
next = next << 4;
next <<= 4;
maskedOldVal = (ushort)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)offset) & 0x000F);
}
else
{
next = next & 0x0FFF;
next &= 0x0FFF;
maskedOldVal = (ushort)(EndianUtilities.ToUInt16LittleEndian(_buffer, (int)offset) & 0xF000);
}
@@ -230,7 +220,7 @@ namespace DiscUtils.Fat
internal List<uint> GetChain(uint head)
{
List<uint> result = new List<uint>();
List<uint> result = new();
if (head != 0)
{
@@ -254,7 +244,7 @@ namespace DiscUtils.Fat
{
foreach (uint val in _dirtySectors.Values)
{
stream.Position = position + val * DirtyRegionSize;
stream.Position = position + (val * DirtyRegionSize);
stream.Write(_buffer, (int)(val * DirtyRegionSize), (int)DirtyRegionSize);
}
}
@@ -39,7 +39,7 @@ namespace DiscUtils.Fat
internal FatFileSystemOptions(FileSystemParameters parameters)
{
if (parameters != null && parameters.FileNameEncoding != null)
if (parameters?.FileNameEncoding != null)
{
FileNameEncoding = parameters.FileNameEncoding;
}
@@ -39,7 +39,7 @@ namespace DiscUtils.Fat
_firstFatSector = firstFatSector;
_numFats = numFats;
_stream.Position = (firstFatSector + fatSize * activeFat) * Sizes.Sector;
_stream.Position = (firstFatSector + (fatSize * activeFat)) * Sizes.Sector;
_buffer = new FatBuffer(type, StreamUtilities.ReadExact(_stream, (int)(fatSize * Sizes.Sector)));
}
@@ -82,7 +82,7 @@ namespace DiscUtils.Fat
{
for (int i = 0; i < _numFats; ++i)
{
_buffer.WriteDirtyRegions(_stream, _firstFatSector * Sizes.Sector + _buffer.Size * i);
_buffer.WriteDirtyRegions(_stream, (_firstFatSector * Sizes.Sector) + (_buffer.Size * i));
}
_buffer.ClearDirtyRegions();
+3 -3
View File
@@ -31,13 +31,13 @@ namespace DiscUtils.Fat
private const byte SpaceByte = 0x20;
public static readonly FileName SelfEntryName =
new FileName(new byte[] { 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
new(new byte[] { 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
public static readonly FileName ParentEntryName =
new FileName(new byte[] { 0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
new(new byte[] { 0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
public static readonly FileName Null =
new FileName(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0);
new(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0);
private static readonly byte[] InvalidBytes = { 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C };
+1 -1
View File
@@ -36,7 +36,7 @@ namespace DiscUtils.Fat
return new FileSystemInfo[] { new VfsFileSystemInfo("FAT", "Microsoft FAT", Open) };
}
return new FileSystemInfo[0];
return System.Array.Empty<FileSystemInfo>();
}
private DiscFileSystem Open(Stream stream, VolumeInfo volumeInfo, FileSystemParameters parameters)
+37 -43
View File
@@ -43,8 +43,8 @@ namespace DiscUtils.Fat
private DirectoryEntry _parentEntry;
private long _parentEntryLocation;
internal Dictionary<string, string> LongFileNames_ShortKey = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, string> LongFileNames_LongKey = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, string> LongFileNames_ShortKey = new(StringComparer.OrdinalIgnoreCase);
internal Dictionary<string, string> LongFileNames_LongKey = new(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Initializes a new instance of the Directory class. Use this constructor to represent non-root directories.
@@ -81,22 +81,22 @@ namespace DiscUtils.Fat
// see http://home.teleport.com/~brainy/lfn.htm
// NOTE: we assume ordinals are ok here.
char[] chars = new char[13];
chars[0] = (char)(256 * buffer[2] + buffer[1]);
chars[1] = (char)(256 * buffer[4] + buffer[3]);
chars[2] = (char)(256 * buffer[6] + buffer[5]);
chars[3] = (char)(256 * buffer[8] + buffer[7]);
chars[4] = (char)(256 * buffer[10] + buffer[9]);
chars[0] = (char)((256 * buffer[2]) + buffer[1]);
chars[1] = (char)((256 * buffer[4]) + buffer[3]);
chars[2] = (char)((256 * buffer[6]) + buffer[5]);
chars[3] = (char)((256 * buffer[8]) + buffer[7]);
chars[4] = (char)((256 * buffer[10]) + buffer[9]);
chars[5] = (char)(256 * buffer[15] + buffer[14]);
chars[6] = (char)(256 * buffer[17] + buffer[16]);
chars[7] = (char)(256 * buffer[19] + buffer[18]);
chars[8] = (char)(256 * buffer[21] + buffer[20]);
chars[9] = (char)(256 * buffer[23] + buffer[22]);
chars[10] = (char)(256 * buffer[25] + buffer[24]);
chars[5] = (char)((256 * buffer[15]) + buffer[14]);
chars[6] = (char)((256 * buffer[17]) + buffer[16]);
chars[7] = (char)((256 * buffer[19]) + buffer[18]);
chars[8] = (char)((256 * buffer[21]) + buffer[20]);
chars[9] = (char)((256 * buffer[23]) + buffer[22]);
chars[10] = (char)((256 * buffer[25]) + buffer[24]);
chars[11] = (char)(256 * buffer[29] + buffer[28]);
chars[12] = (char)(256 * buffer[31] + buffer[30]);
string chunk = new string(chars);
chars[11] = (char)((256 * buffer[29]) + buffer[28]);
chars[12] = (char)((256 * buffer[31]) + buffer[30]);
string chunk = new(chars);
int zero = chunk.IndexOf('\0');
return zero >= 0 ? chunk.Substring(0, zero) : chunk;
}
@@ -133,10 +133,7 @@ namespace DiscUtils.Fat
set
{
if (_parent != null)
{
_parent.UpdateEntry(_parentId, value);
}
_parent?.UpdateEntry(_parentId, value);
}
}
@@ -195,7 +192,7 @@ namespace DiscUtils.Fat
public DirectoryEntry[] GetDirectories()
{
List<DirectoryEntry> dirs = new List<DirectoryEntry>(_entries.Count);
List<DirectoryEntry> dirs = new(_entries.Count);
foreach (DirectoryEntry dirEntry in _entries.Values)
{
if ((dirEntry.Attributes & FatAttributes.Directory) != 0)
@@ -209,7 +206,7 @@ namespace DiscUtils.Fat
public DirectoryEntry[] GetFiles()
{
List<DirectoryEntry> files = new List<DirectoryEntry>(_entries.Count);
List<DirectoryEntry> files = new(_entries.Count);
foreach (DirectoryEntry dirEntry in _entries.Values)
{
if ((dirEntry.Attributes & (FatAttributes.Directory | FatAttributes.VolumeId)) == 0)
@@ -261,15 +258,14 @@ namespace DiscUtils.Fat
{
try
{
uint firstCluster;
if (!_fileSystem.Fat.TryGetFreeCluster(out firstCluster))
if (!_fileSystem.Fat.TryGetFreeCluster(out uint firstCluster))
{
throw new IOException("Failed to allocate first cluster for new directory");
}
_fileSystem.Fat.SetEndOfChain(firstCluster);
DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Directory, _fileSystem.FatVariant);
DirectoryEntry newEntry = new(_fileSystem.FatOptions, name, FatAttributes.Directory, _fileSystem.FatVariant);
newEntry.FirstCluster = firstCluster;
newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow);
newEntry.LastWriteTime = newEntry.CreationTime;
@@ -297,11 +293,11 @@ namespace DiscUtils.Fat
throw new IOException("Directory entry already exists");
}
DirectoryEntry newEntry = new DirectoryEntry(newChild.ParentsChildEntry);
DirectoryEntry newEntry = new(newChild.ParentsChildEntry);
newEntry.Name = name;
AddEntry(newEntry);
DirectoryEntry newParentEntry = new DirectoryEntry(SelfEntry);
DirectoryEntry newParentEntry = new(SelfEntry);
newParentEntry.Name = FileName.ParentEntryName;
newChild.ParentEntry = newParentEntry;
}
@@ -367,7 +363,7 @@ namespace DiscUtils.Fat
else if ((mode == FileMode.OpenOrCreate || mode == FileMode.CreateNew || mode == FileMode.Create) && !exists)
{
// Create new file
DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Archive, _fileSystem.FatVariant);
DirectoryEntry newEntry = new(_fileSystem.FatOptions, name, FatAttributes.Archive, _fileSystem.FatVariant);
newEntry.FirstCluster = 0; // i.e. Zero-length
newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow);
newEntry.LastWriteTime = newEntry.CreationTime;
@@ -421,7 +417,7 @@ namespace DiscUtils.Fat
{
DirectoryEntry entry = _entries[id];
DirectoryEntry copy = new DirectoryEntry(entry);
DirectoryEntry copy = new(entry);
copy.Name = entry.Name.Deleted();
_dirStream.Position = id;
copy.WriteTo(_dirStream);
@@ -466,7 +462,7 @@ namespace DiscUtils.Fat
while (_dirStream.Position < _dirStream.Length)
{
long streamPos = _dirStream.Position;
DirectoryEntry entry = new DirectoryEntry(_fileSystem.FatOptions, _dirStream, _fileSystem.FatVariant);
DirectoryEntry entry = new(_fileSystem.FatOptions, _dirStream, _fileSystem.FatVariant);
if (entry.Attributes == (FatAttributes.ReadOnly | FatAttributes.Hidden | FatAttributes.System | FatAttributes.VolumeId))
{
@@ -542,20 +538,18 @@ namespace DiscUtils.Fat
private void PopulateNewChildDirectory(DirectoryEntry newEntry)
{
// Populate new directory with initial (special) entries. First one is easy, just change the name!
using (ClusterStream stream = new ClusterStream(_fileSystem, FileAccess.Write, newEntry.FirstCluster, uint.MaxValue))
{
// First is the self-referencing entry...
DirectoryEntry selfEntry = new DirectoryEntry(newEntry);
selfEntry.Name = FileName.SelfEntryName;
selfEntry.WriteTo(stream);
using ClusterStream stream = new(_fileSystem, FileAccess.Write, newEntry.FirstCluster, uint.MaxValue);
// First is the self-referencing entry...
DirectoryEntry selfEntry = new(newEntry);
selfEntry.Name = FileName.SelfEntryName;
selfEntry.WriteTo(stream);
// Second is a clone of our self entry (i.e. parent) - though dates are odd...
DirectoryEntry parentEntry = new DirectoryEntry(SelfEntry);
parentEntry.Name = FileName.ParentEntryName;
parentEntry.CreationTime = newEntry.CreationTime;
parentEntry.LastWriteTime = newEntry.LastWriteTime;
parentEntry.WriteTo(stream);
}
// Second is a clone of our self entry (i.e. parent) - though dates are odd...
DirectoryEntry parentEntry = new(SelfEntry);
parentEntry.Name = FileName.ParentEntryName;
parentEntry.CreationTime = newEntry.CreationTime;
parentEntry.LastWriteTime = newEntry.LastWriteTime;
parentEntry.WriteTo(stream);
}
private void Dispose(bool disposing)
@@ -40,7 +40,7 @@ namespace DiscUtils.Fat
/// <summary>
/// The Epoch for FAT file systems (1st Jan, 1980).
/// </summary>
public static readonly DateTime Epoch = new DateTime(1980, 1, 1);
public static readonly DateTime Epoch = new(1980, 1, 1);
private TimeConverter _timeConverter;
private Stream _data;
@@ -158,7 +158,7 @@ namespace DiscUtils.Fat
{
_dirCache = new Dictionary<uint, Directory>();
if (parameters != null && parameters.TimeConverter != null)
if (parameters?.TimeConverter != null)
{
_timeConverter = parameters.TimeConverter;
}
@@ -196,13 +196,13 @@ namespace DiscUtils.Fat
{
get
{
switch (_type)
return _type switch
{
case FatType.Fat12: return "Microsoft FAT12";
case FatType.Fat16: return "Microsoft FAT16";
case FatType.Fat32: return "Microsoft FAT32";
default: return "Unknown FAT";
}
FatType.Fat12 => "Microsoft FAT12",
FatType.Fat16 => "Microsoft FAT16",
FatType.Fat32 => "Microsoft FAT32",
_ => "Unknown FAT",
};
}
}
@@ -463,14 +463,14 @@ namespace DiscUtils.Fat
// Write both FAT copies
uint fatSize = CalcFatSize(sectors, FatType.Fat12, 1);
byte[] fat = new byte[fatSize * Sizes.Sector];
FatBuffer fatBuffer = new FatBuffer(FatType.Fat12, fat);
FatBuffer fatBuffer = new(FatType.Fat12, fat);
fatBuffer.SetNext(0, 0xFFFFFFF0);
fatBuffer.SetEndOfChain(1);
stream.Write(fat, 0, fat.Length);
stream.Write(fat, 0, fat.Length);
// Write the (empty) root directory
uint rootDirSectors = ((224 * 32) + Sizes.Sector - 1) / Sizes.Sector;
const uint rootDirSectors = ((224 * 32) + Sizes.Sector - 1) / Sizes.Sector;
byte[] rootDir = new byte[rootDirSectors * Sizes.Sector];
stream.Write(rootDir, 0, rootDir.Length);
@@ -493,16 +493,14 @@ namespace DiscUtils.Fat
/// <returns>An object that provides access to the newly created partition file system.</returns>
public static FatFileSystem FormatPartition(VirtualDisk disk, int partitionIndex, string label)
{
using (Stream partitionStream = disk.Partitions[partitionIndex].Open())
{
return FormatPartition(
partitionStream,
label,
disk.Geometry,
(int)disk.Partitions[partitionIndex].FirstSector,
(int)(1 + disk.Partitions[partitionIndex].LastSector - disk.Partitions[partitionIndex].FirstSector),
0);
}
using Stream partitionStream = disk.Partitions[partitionIndex].Open();
return FormatPartition(
partitionStream,
label,
disk.Geometry,
(int)disk.Partitions[partitionIndex].FirstSector,
(int)(1 + disk.Partitions[partitionIndex].LastSector - disk.Partitions[partitionIndex].FirstSector),
0);
}
/// <summary>
@@ -612,7 +610,7 @@ namespace DiscUtils.Fat
*/
byte[] fat = new byte[CalcFatSize((uint)sectorCount, fatType, sectorsPerCluster) * Sizes.Sector];
FatBuffer fatBuffer = new FatBuffer(fatType, fat);
FatBuffer fatBuffer = new(fatType, fat);
fatBuffer.SetNext(0, 0xFFFFFFF8);
fatBuffer.SetEndOfChain(1);
if (fatType >= FatType.Fat32)
@@ -780,8 +778,7 @@ namespace DiscUtils.Fat
return;
}
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
DirectoryEntry dirEntry = parent.GetEntry(id);
FatAttributes newFatAttr = (FatAttributes)newValue;
@@ -836,7 +833,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.CreationTime = newTime; });
UpdateDirEntry(path, (e) => e.CreationTime = newTime);
}
/// <summary>
@@ -871,7 +868,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.CreationTime = ConvertFromUtc(newTime); });
UpdateDirEntry(path, (e) => e.CreationTime = ConvertFromUtc(newTime));
}
/// <summary>
@@ -906,7 +903,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastAccessTime = newTime; });
UpdateDirEntry(path, (e) => e.LastAccessTime = newTime);
}
/// <summary>
@@ -941,7 +938,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastAccessTime = ConvertFromUtc(newTime); });
UpdateDirEntry(path, (e) => e.LastAccessTime = ConvertFromUtc(newTime));
}
/// <summary>
@@ -976,7 +973,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastWriteTime = newTime; });
UpdateDirEntry(path, (e) => e.LastWriteTime = newTime);
}
/// <summary>
@@ -1011,7 +1008,7 @@ namespace DiscUtils.Fat
return;
}
UpdateDirEntry(path, (e) => { e.LastWriteTime = ConvertFromUtc(newTime); });
UpdateDirEntry(path, (e) => e.LastWriteTime = ConvertFromUtc(newTime));
}
/// <summary>
@@ -1032,8 +1029,7 @@ namespace DiscUtils.Fat
/// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
public override void CopyFile(string sourceFile, string destinationFile, bool overwrite)
{
Directory sourceDir;
long sourceEntryId = GetDirectoryEntry(sourceFile, out sourceDir);
long sourceEntryId = GetDirectoryEntry(sourceFile, out Directory sourceDir);
if (sourceDir == null || sourceEntryId < 0)
{
@@ -1047,12 +1043,11 @@ namespace DiscUtils.Fat
throw new IOException("The source file is a directory");
}
DirectoryEntry newEntry = new DirectoryEntry(sourceEntry);
DirectoryEntry newEntry = new(sourceEntry);
newEntry.Name = FileName.FromPath(destinationFile, FatOptions.FileNameEncoding);
newEntry.FirstCluster = 0;
Directory destDir;
long destEntryId = GetDirectoryEntry(destinationFile, out destDir);
long destEntryId = GetDirectoryEntry(destinationFile, out Directory destDir);
if (destDir == null)
{
@@ -1095,11 +1090,9 @@ namespace DiscUtils.Fat
destEntryId = destDir.AddEntry(newEntry);
// Copy the contents...
using (Stream sourceStream = new FatFileStream(this, sourceDir, sourceEntryId, FileAccess.Read),
destStream = new FatFileStream(this, destDir, destEntryId, FileAccess.Write))
{
StreamUtilities.PumpStreams(sourceStream, destStream);
}
using Stream sourceStream = new FatFileStream(this, sourceDir, sourceEntryId, FileAccess.Read),
destStream = new FatFileStream(this, destDir, destEntryId, FileAccess.Write);
StreamUtilities.PumpStreams(sourceStream, destStream);
}
/// <summary>
@@ -1151,8 +1144,7 @@ namespace DiscUtils.Fat
throw new IOException("Unable to delete non-empty directory");
}
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
if (parent == null && id == 0)
{
throw new IOException("Unable to delete root directory");
@@ -1175,8 +1167,7 @@ namespace DiscUtils.Fat
/// <param name="path">The path of the file to delete.</param>
public override void DeleteFile(string path)
{
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
if (parent == null || id < 0)
{
throw new FileNotFoundException("No such file", path);
@@ -1261,7 +1252,7 @@ namespace DiscUtils.Fat
}
DirectoryEntry[] entries = dir.GetDirectories();
List<string> dirs = new List<string>(entries.Length);
List<string> dirs = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
dirs.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
@@ -1282,7 +1273,7 @@ namespace DiscUtils.Fat
{
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
List<string> dirs = new List<string>();
List<string> dirs = new();
DoSearch(dirs, path, re, searchOption == SearchOption.AllDirectories, true, false);
return dirs.ToArray();
}
@@ -1297,7 +1288,7 @@ namespace DiscUtils.Fat
Directory dir = GetDirectory(path);
DirectoryEntry[] entries = dir.GetFiles();
List<string> files = new List<string>(entries.Length);
List<string> files = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
files.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
@@ -1318,7 +1309,7 @@ namespace DiscUtils.Fat
{
Regex re = Utilities.ConvertWildcardsToRegEx(searchPattern);
List<string> results = new List<string>();
List<string> results = new();
DoSearch(results, path, re, searchOption == SearchOption.AllDirectories, false, true);
return results.ToArray();
}
@@ -1333,7 +1324,7 @@ namespace DiscUtils.Fat
Directory dir = GetDirectory(path);
DirectoryEntry[] entries = dir.Entries;
List<string> result = new List<string>(entries.Length);
List<string> result = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
result.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
@@ -1356,7 +1347,7 @@ namespace DiscUtils.Fat
Directory dir = GetDirectory(path);
DirectoryEntry[] entries = dir.Entries;
List<string> result = new List<string>(entries.Length);
List<string> result = new(entries.Length);
foreach (DirectoryEntry dirEntry in entries)
{
if (re.IsMatch(dirEntry.Name.GetSearchName(FatOptions.FileNameEncoding)))
@@ -1387,8 +1378,7 @@ namespace DiscUtils.Fat
}
}
Directory destParent;
long destId = GetDirectoryEntry(destinationDirectoryName, out destParent);
long destId = GetDirectoryEntry(destinationDirectoryName, out Directory destParent);
if (destParent == null)
{
throw new DirectoryNotFoundException("Target directory doesn't exist");
@@ -1398,8 +1388,7 @@ namespace DiscUtils.Fat
throw new IOException("Target directory already exists");
}
Directory sourceParent;
long sourceId = GetDirectoryEntry(sourceDirectoryName, out sourceParent);
long sourceId = GetDirectoryEntry(sourceDirectoryName, out Directory sourceParent);
if (sourceParent == null || sourceId < 0)
{
throw new IOException("Source directory doesn't exist");
@@ -1417,8 +1406,7 @@ namespace DiscUtils.Fat
/// <param name="overwrite">Whether to permit a destination file to be overwritten.</param>
public override void MoveFile(string sourceName, string destinationName, bool overwrite)
{
Directory sourceDir;
long sourceEntryId = GetDirectoryEntry(sourceName, out sourceDir);
long sourceEntryId = GetDirectoryEntry(sourceName, out Directory sourceDir);
if (sourceDir == null || sourceEntryId < 0)
{
@@ -1432,11 +1420,10 @@ namespace DiscUtils.Fat
throw new IOException("The source file is a directory");
}
DirectoryEntry newEntry = new DirectoryEntry(sourceEntry);
DirectoryEntry newEntry = new(sourceEntry);
newEntry.Name = FileName.FromPath(destinationName, FatOptions.FileNameEncoding);
Directory destDir;
long destEntryId = GetDirectoryEntry(destinationName, out destDir);
long destEntryId = GetDirectoryEntry(destinationName, out Directory destDir);
if (destDir == null)
{
@@ -1492,14 +1479,13 @@ namespace DiscUtils.Fat
internal Directory GetDirectory(string path)
{
Directory parent;
if (string.IsNullOrEmpty(path) || path == "\\")
{
return _rootDir;
}
long id = GetDirectoryEntry(_rootDir, path, out parent);
long id = GetDirectoryEntry(_rootDir, path, out Directory parent);
if (id >= 0)
{
return GetDirectory(parent, id);
@@ -1524,8 +1510,7 @@ namespace DiscUtils.Fat
}
// If we have this one cached, return it
Directory result;
if (_dirCache.TryGetValue(dirEntry.FirstCluster, out result))
if (_dirCache.TryGetValue(dirEntry.FirstCluster, out Directory result))
{
return result;
}
@@ -1549,9 +1534,8 @@ namespace DiscUtils.Fat
internal DirectoryEntry GetDirectoryEntry(string path)
{
Directory parent;
long id = GetDirectoryEntry(_rootDir, path, out parent);
long id = GetDirectoryEntry(_rootDir, path, out Directory parent);
if (parent == null || id < 0)
{
return null;
@@ -1707,7 +1691,7 @@ namespace DiscUtils.Fat
private static uint CalcFatSize(uint sectors, FatType fatType, byte sectorsPerCluster)
{
uint numClusters = (uint)(sectors / sectorsPerCluster);
uint fatBytes = (numClusters * (ushort)fatType) / 8;
uint fatBytes = numClusters * (ushort)fatType / 8;
return (fatBytes + Sizes.Sector - 1) / Sizes.Sector;
}
@@ -1894,8 +1878,7 @@ namespace DiscUtils.Fat
else
{
// Long filename support - translate long filename lookup to short filename
string ShortName;
if (dir.LongFileNames_LongKey.TryGetValue(pathEntries[pathOffset], out ShortName))
if (dir.LongFileNames_LongKey.TryGetValue(pathEntries[pathOffset], out string ShortName))
pathEntries[pathOffset] = ShortName;
entryId = dir.FindEntry(new FileName(pathEntries[pathOffset], FatOptions.FileNameEncoding));
@@ -1955,8 +1938,7 @@ namespace DiscUtils.Fat
private void UpdateDirEntry(string path, EntryUpdateAction action)
{
Directory parent;
long id = GetDirectoryEntry(path, out parent);
long id = GetDirectoryEntry(path, out Directory parent);
DirectoryEntry entry = parent.GetEntry(id);
action(entry);
parent.UpdateEntry(id, entry);
@@ -1973,7 +1955,7 @@ namespace DiscUtils.Fat
/// <summary>
/// Size of the Filesystem in bytes
/// </summary>
public override long Size { get { return ((TotalSectors - ReservedSectorCount - (FatSize * FatCount)) * BytesPerSector); } }
public override long Size { get { return (TotalSectors - ReservedSectorCount - (FatSize * FatCount)) * BytesPerSector; } }
/// <summary>
/// Used space of the Filesystem in bytes
@@ -1991,7 +1973,7 @@ namespace DiscUtils.Fat
usedCluster++;
}
}
return (usedCluster * SectorsPerCluster * BytesPerSector);
return usedCluster * SectorsPerCluster * BytesPerSector;
}
}
@@ -2016,8 +1998,7 @@ namespace DiscUtils.Fat
if (dir == null)
return fileName;
string lfn;
if (dir.LongFileNames_ShortKey.TryGetValue(Path.GetFileName(shortFullPath), out lfn))
if (dir.LongFileNames_ShortKey.TryGetValue(Path.GetFileName(shortFullPath), out string lfn))
return lfn;
return fileName;