public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aName, ulong aFirstCluster) : base(aFileSystem, aParent, aName, 0, DirectoryEntryTypeEnum.Directory) { if (aFileSystem == null) { throw new ArgumentNullException("aFileSystem"); } if (aName == null) { throw new ArgumentNullException("aName"); } if (aFirstCluster < 2) { throw new ArgumentOutOfRangeException("aFirstCluster"); } mFileSystem = aFileSystem; mParent = aParent; mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = 0; //FatHelpers.Debug( // "-- FatDirectoryEntry.ctor : " + "aParent.Name = " + aParent?.mName + ", aName = " + aName // + ", aFirstCluster = " + aFirstCluster + " --"); }
public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aName, ulong aFirstCluster) : base(aFileSystem, aParent, aName, 0, DirectoryEntryTypeEnum.Directory) { if (aFileSystem == null) { Global.mFileSystemDebugger.SendInternal($"FatDirectoryEntry.ctor : aFileSystem is null."); throw new ArgumentNullException(nameof(aFileSystem)); } if (aName == null) { Global.mFileSystemDebugger.SendInternal($"FatDirectoryEntry.ctor : aName is null."); throw new ArgumentNullException(nameof(aName)); } if (aFirstCluster < 2) { Global.mFileSystemDebugger.SendInternal($"FatDirectoryEntry.ctor : aFirstCluster is out of range."); throw new ArgumentOutOfRangeException(nameof(aFirstCluster)); } Global.mFileSystemDebugger.SendInternal($"FatDirectoryEntry.ctor : aParent.Name = {aParent?.mName}, aName = {aName}, aFirstCluster = {aFirstCluster}"); mFileSystem = aFileSystem; mParent = aParent; mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = 0; }
public FatDirectoryEntry AddDirectoryEntry(string aName, DirectoryEntryTypeEnum aType) { Global.mFileSystemDebugger.SendInternal("-- FatDirectoryEntry.AddDirectoryEntry --"); Global.mFileSystemDebugger.SendInternal("aName ="); Global.mFileSystemDebugger.SendInternal(aName); Global.mFileSystemDebugger.SendInternal("aType ="); Global.mFileSystemDebugger.SendInternal((uint)aType); if ((aType == DirectoryEntryTypeEnum.Directory) || (aType == DirectoryEntryTypeEnum.File)) { string xFullPath = Path.Combine(mFullPath, aName); uint xFirstCluster = ((FatFileSystem)mFileSystem).GetFat(0).GetNextUnallocatedFatEntry(); uint xEntryHeaderDataOffset = GetNextUnallocatedDirectoryEntry(); Global.mFileSystemDebugger.SendInternal("xFullPath ="); Global.mFileSystemDebugger.SendInternal(xFullPath); Global.mFileSystemDebugger.SendInternal("xFirstCluster ="); Global.mFileSystemDebugger.SendInternal(xFirstCluster); Global.mFileSystemDebugger.SendInternal("xEntryHeaderDataOffset ="); Global.mFileSystemDebugger.SendInternal(xEntryHeaderDataOffset); var xNewEntry = new FatDirectoryEntry((FatFileSystem)mFileSystem, this, xFullPath, aName, 0, xFirstCluster, xEntryHeaderDataOffset, aType); xNewEntry.AllocateDirectoryEntry(); return(xNewEntry); } throw new ArgumentOutOfRangeException(nameof(aType), "Unknown directory entry type."); }
public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aName, ulong aFirstCluster) : base(aFileSystem, aParent, aName, 0, DirectoryEntryTypeEnum.Directory) { if (aFileSystem == null) { FileSystemHelpers.Debug("FatDirectoryEntry.ctor", "aFileSystem is null."); throw new ArgumentNullException(nameof(aFileSystem)); } if (aName == null) { FileSystemHelpers.Debug("FatDirectoryEntry.ctor", "aName is null."); throw new ArgumentNullException(nameof(aName)); } if (aFirstCluster < 2) { FileSystemHelpers.Debug("FatDirectoryEntry.ctor", "aFirstCluster is out of range."); throw new ArgumentOutOfRangeException(nameof(aFirstCluster)); } FileSystemHelpers.Debug("FatDirectoryEntry.ctor", "aParent.Name =", aParent?.mName, ", aName =", aName, ", aFirstCluster =", aFirstCluster); mFileSystem = aFileSystem; mParent = aParent; mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = 0; }
// Size is UInt32 because FAT doesn't support bigger. // Don't change to UInt64 public FatDirectoryEntry(FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aName, uint aSize, ulong aFirstClusterNum, uint aEntryHeaderDataOffset, DirectoryEntryTypeEnum aEntryType) : base(aFileSystem, aParent, aName, aSize, aEntryType) { FileSystem = aFileSystem; Parent = aParent; FirstClusterNum = aFirstClusterNum; EntryHeaderDataOffset = aEntryHeaderDataOffset; }
public FatStream(FatDirectoryEntry aEntry) { mDirectoryEntry = aEntry; mFS = mDirectoryEntry.GetFileSystem(); mSize = mDirectoryEntry.mSize; if (mDirectoryEntry.mSize > 0) { mFatTable = mDirectoryEntry.GetFatTable(); } }
public FatStream(FatDirectoryEntry aFile) { mDirectoryEntry = aFile; mFS = mDirectoryEntry.FileSystem; mReadBuffer = mDirectoryEntry.FileSystem.NewClusterArray(); mSize = this.mDirectoryEntry.Size; if (mDirectoryEntry.Size > 0) { mFatTable = mDirectoryEntry.GetFatTable(); } }
public FatStream(FatDirectoryEntry aEntry) { Global.mFileSystemDebugger.SendInternal("FatStream with entry " + aEntry); mDirectoryEntry = aEntry; mFS = mDirectoryEntry.GetFileSystem(); mSize = mDirectoryEntry.mSize; if (mDirectoryEntry.mSize > 0) { mFatTable = mDirectoryEntry.GetFatTable(); } }
public FatDirectoryEntry AddDirectoryEntry(string aName, DirectoryEntryTypeEnum aType) { Global.mFileSystemDebugger.SendInternal($"FatDirectoryEntry.AddDirectoryEntry : aName = {aName}, aType = {aType}"); if ((aType == DirectoryEntryTypeEnum.Directory) || (aType == DirectoryEntryTypeEnum.File)) { uint xFirstCluster = mFileSystem.GetFat(0).GetNextUnallocatedFatEntry(); uint xEntryHeaderDataOffset = GetNextUnallocatedEntry(); var xNewEntry = new FatDirectoryEntry(mFileSystem, this, aName, 0, xFirstCluster, xEntryHeaderDataOffset, aType); xNewEntry.AllocateDirectoryEntry(); return(xNewEntry); } throw new ArgumentOutOfRangeException("aType", "Unknown directory entry type."); }
public FatDirectoryEntry FindVolumeId() { if (!IsRootDirectory()) { throw new Exception("VolumeId can be found only in Root Directory"); } Global.mFileSystemDebugger.SendInternal("-- FatDirectoryEntry.FindVolumeId --"); var xData = GetDirectoryEntryData(); FatDirectoryEntry xParent = this; FatDirectoryEntry xResult = null; for (uint i = 0; i < xData.Length; i = i + 32) { byte xAttrib = xData[i + 11]; //if ((xAttrib & FatDirectoryEntryAttributeConsts.VolumeID) != FatDirectoryEntryAttributeConsts.VolumeID) if (xAttrib != FatDirectoryEntryAttributeConsts.VolumeID) { continue; } Global.mFileSystemDebugger.SendInternal("VolumeID Found"); /* The Label in FAT could be only a shortName (limited to 11 characters) so it is more easy */ string xName = Encoding.ASCII.GetString(xData, (int)i, 11); xName = xName.TrimEnd(); string xFullPath = Path.Combine(mFullPath, xName); /* Probably can be OK to hardcode 0 here */ uint xSize = BitConverter.ToUInt32(xData, (int)i + 28); //uint xFirstCluster = (uint)(xData.ToUInt16(i + 20) << 16 | xData.ToUInt16(i + 26)); uint xFirstCluster = xParent.mFirstClusterNum; Global.mFileSystemDebugger.SendInternal($"VolumeID Found xName {xName} xFullPath {xFullPath} xSize {xSize} xFirstCluster {xFirstCluster}"); xResult = new FatDirectoryEntry(((FatFileSystem)mFileSystem), xParent, xFullPath, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.File); break; } if (xResult == null) { Global.mFileSystemDebugger.SendInternal($"VolumeID not found, returning null"); } return(xResult); }
public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aFullPath, string aName, ulong aFirstCluster) : base(aFileSystem, aParent, aFullPath, aName, 0, DirectoryEntryTypeEnum.Directory) { if (aFirstCluster < aFileSystem.RootCluster) { throw new ArgumentOutOfRangeException(nameof(aFirstCluster)); } mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = 0; }
public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aFullPath, string aName, uint aFirstCluster) : base(aFileSystem, aParent, aFullPath, aName, 0, DirectoryEntryTypeEnum.Directory) { if (aFirstCluster < aFileSystem.RootCluster) { throw new ArgumentOutOfRangeException(nameof(aFirstCluster)); } mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = 0; }
public FatStream(FatDirectoryEntry aEntry) { if (aEntry == null) { throw new ArgumentNullException(nameof(aEntry)); } mDirectoryEntry = aEntry; mFS = aEntry.GetFileSystem(); mFatTable = aEntry.GetFatTable(); mSize = aEntry.mSize; if (mFatTable == null) { throw new Exception("The fat chain returned for the directory entry was null."); } }
public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aFullPath, string aName, ulong aFirstCluster) : base(aFileSystem, aParent, aFullPath, aName, 0, DirectoryEntryTypeEnum.Directory) { Global.mFileSystemDebugger.SendInternal("FatDirectoryEntry.ctor"); if (aFirstCluster < 2) { Global.mFileSystemDebugger.SendInternal("aFirstCluster is out of range."); throw new ArgumentOutOfRangeException(nameof(aFirstCluster)); } mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = 0; }
public FatStream(FatDirectoryEntry aEntry) { Global.mFileSystemDebugger.SendInternal($"FatStream with entry {aEntry}"); mDirectoryEntry = aEntry; mFS = mDirectoryEntry.GetFileSystem(); mSize = mDirectoryEntry.mSize; Global.mFileSystemDebugger.SendInternal("FatStream with mSize {mSize}"); Global.mFileSystemDebugger.SendInternal("Getting FatTable"); // We get always the FatTable if the file is empty too mFatTable = mDirectoryEntry.GetFatTable(); // What to do if this should happen? Throw exception? if (mFatTable == null) { Global.mFileSystemDebugger.SendInternal("FatTable got but it is null!"); } }
// Size is UInt32 because FAT doesn't support bigger. // Don't change to UInt64 public FatDirectoryEntry( FatFileSystem aFileSystem, FatDirectoryEntry aParent, string aFullPath, string aName, long aSize, uint aFirstCluster, uint aEntryHeaderDataOffset, DirectoryEntryTypeEnum aEntryType) : base(aFileSystem, aParent, aFullPath, aName, aSize, aEntryType) { if (aFirstCluster < aFileSystem.RootCluster) { Global.mFileSystemDebugger.SendInternal($"aFirstCluster {aFirstCluster} < aFileSystem.RootCluster {aFileSystem.RootCluster}"); throw new ArgumentOutOfRangeException(nameof(aFirstCluster)); } mFirstClusterNum = aFirstCluster; mEntryHeaderDataOffset = aEntryHeaderDataOffset; }
public List<FatDirectoryEntry> ReadDirectoryContents() { Global.mFileSystemDebugger.SendInternal("-- FatDirectoryEntry.ReadDirectoryContents --"); var xData = GetDirectoryEntryData(); var xResult = new List<FatDirectoryEntry>(); FatDirectoryEntry xParent = (FatDirectoryEntry)(mParent ?? mFileSystem.GetRootDirectory()); //TODO: Change xLongName to StringBuilder string xLongName = ""; string xName = ""; for (uint i = 0; i < xData.Length; i = i + 32) { byte xAttrib = xData[i + 11]; byte xStatus = xData[i]; if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { byte xType = xData[i + 12]; byte xOrd = xData[i]; if (xOrd == 0xE5) { Global.mFileSystemDebugger.SendInternal("<DELETED> : Attrib = " + xAttrib + ", Status = " + xStatus); continue; } if (xType == 0) { if ((xOrd & 0x40) > 0) { xLongName = ""; } //TODO: Check LDIR_Ord for ordering and throw exception // if entries are found out of order. // Also save buffer and only copy name if a end Ord marker is found. string xLongPart = xData.GetUtf16String(i + 1, 5); // We have to check the length because 0xFFFF is a valid Unicode codepoint. // So we only want to stop if the 0xFFFF is AFTER a 0x0000. We can determin // this by also looking at the length. Since we short circuit the or, the length // is rarely evaluated. if (xData.ToUInt16(i + 14) != 0xFFFF || xLongPart.Length == 5) { xLongPart = xLongPart + xData.GetUtf16String(i + 14, 6); if (xData.ToUInt16(i + 28) != 0xFFFF || xLongPart.Length == 11) { xLongPart = xLongPart + xData.GetUtf16String(i + 28, 2); } } xLongName = xLongPart + xLongName; xLongPart = null; //TODO: LDIR_Chksum } } else { xName = xLongName; if (xStatus == 0x00) { Global.mFileSystemDebugger.SendInternal("<EOF> : Attrib = " + xAttrib + ", Status = " + xStatus); break; } switch (xStatus) { case 0x05: // Japanese characters - We dont handle these break; case 0xE5: // Empty slot, skip it break; default: if (xStatus >= 0x20) { if (xLongName.Length > 0) { // Leading and trailing spaces are to be ignored according to spec. // Many programs (including Windows) pad trailing spaces although it // it is not required for long names. // As per spec, ignore trailing periods xName = xLongName.Trim(); //If there are trailing periods int nameIndex = xName.Length - 1; if (xName[nameIndex] == '.') { //Search backwards till we find the first non-period character for (; nameIndex > 0; nameIndex--) { if (xName[nameIndex] != '.') { break; } } //Substring to remove the periods xName = xName.Substring(0, nameIndex + 1); } xLongName = ""; } else { string xEntry = xData.GetAsciiString(i, 11); xName = xEntry.Substring(0, 8).TrimEnd(); string xExt = xEntry.Substring(8, 3).TrimEnd(); if (xExt.Length > 0) { xName = xName + "." + xExt; } } } break; } } uint xFirstCluster = (uint)(xData.ToUInt16(i + 20) << 16 | xData.ToUInt16(i + 26)); int xTest = xAttrib & (FatDirectoryEntryAttributeConsts.Directory | FatDirectoryEntryAttributeConsts.VolumeID); if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { // skip adding, as it's a LongFileName entry, meaning the next normal entry is the item with the name. //Global.mFileSystemDebugger.SendInternal($"Entry was a Long FileName entry. Current LongName = '{xLongName}'"); } else if (xTest == 0) { uint xSize = xData.ToUInt32(i + 28); if (xSize == 0 && xName.Length == 0) { continue; } string xFullPath = Path.Combine(mFullPath, xName); var xEntry = new FatDirectoryEntry(((FatFileSystem)mFileSystem), xParent, xFullPath, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.File); xResult.Add(xEntry); Global.mFileSystemDebugger.SendInternal(xEntry.mName + " - " + xEntry.mSize + " bytes"); } else if (xTest == FatDirectoryEntryAttributeConsts.Directory) { string xFullPath = Path.Combine(mFullPath, xName); uint xSize = xData.ToUInt32(i + 28); var xEntry = new FatDirectoryEntry(((FatFileSystem)mFileSystem), xParent, xFullPath, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.Directory); Global.mFileSystemDebugger.SendInternal(xEntry.mName + " <DIR> " + xEntry.mSize + " bytes : Attrib = " + xAttrib + ", Status = " + xStatus); xResult.Add(xEntry); } else if (xTest == FatDirectoryEntryAttributeConsts.VolumeID) { Global.mFileSystemDebugger.SendInternal("<VOLUME ID> : Attrib = " + xAttrib + ", Status = " + xStatus); } else { Global.mFileSystemDebugger.SendInternal("<INVALID ENTRY> : Attrib = " + xAttrib + ", Status = " + xStatus); } } return xResult; }
public FatDirectoryEntry AddDirectoryEntry(string aName, DirectoryEntryTypeEnum aType) { Global.mFileSystemDebugger.SendInternal("-- FatDirectoryEntry.AddDirectoryEntry --"); Global.mFileSystemDebugger.SendInternal("aName ="); Global.mFileSystemDebugger.SendInternal(aName); Global.mFileSystemDebugger.SendInternal("aType ="); Global.mFileSystemDebugger.SendInternal((uint)aType); if ((aType == DirectoryEntryTypeEnum.Directory) || (aType == DirectoryEntryTypeEnum.File)) { string xFullPath = Path.Combine(mFullPath, aName); uint xFirstCluster = ((FatFileSystem)mFileSystem).GetFat(0).GetNextUnallocatedFatEntry(); uint xEntryHeaderDataOffset = GetNextUnallocatedDirectoryEntry(); Global.mFileSystemDebugger.SendInternal("xFullPath ="); Global.mFileSystemDebugger.SendInternal(xFullPath); Global.mFileSystemDebugger.SendInternal("xFirstCluster ="); Global.mFileSystemDebugger.SendInternal(xFirstCluster); Global.mFileSystemDebugger.SendInternal("xEntryHeaderDataOffset ="); Global.mFileSystemDebugger.SendInternal(xEntryHeaderDataOffset); var xNewEntry = new FatDirectoryEntry((FatFileSystem)mFileSystem, this, xFullPath, aName, 0, xFirstCluster, xEntryHeaderDataOffset, aType); xNewEntry.AllocateDirectoryEntry(); return xNewEntry; } throw new ArgumentOutOfRangeException(nameof(aType), "Unknown directory entry type."); }
/// <summary> /// Retrieves a <see cref="List{T}"/> of <see cref="FatDirectoryEntry"/> objects that represent the Directory Entries inside this Directory /// </summary> /// <returns>Returns a <see cref="List{T}"/> of the Directory Entries inside this Directory</returns> public List<FatDirectoryEntry> ReadDirectoryContents(bool aReturnShortFilenames = false) { Global.mFileSystemDebugger.SendInternal("-- FatDirectoryEntry.ReadDirectoryContents --"); var xData = GetDirectoryEntryData(); var xResult = new List<FatDirectoryEntry>(); FatDirectoryEntry xParent = this; //TODO: Change xLongName to StringBuilder string xLongName = ""; string xName = ""; for (uint i = 0; i < xData.Length; i = i + 32) { byte xAttrib = xData[i + 11]; byte xStatus = xData[i]; if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { byte xType = xData[i + 12]; if (aReturnShortFilenames) { continue; } if (xStatus == FatDirectoryEntryAttributeConsts.UnusedOrDeletedEntry) { Global.mFileSystemDebugger.SendInternal("<DELETED> : Attrib = " + xAttrib + ", Status = " + xStatus); continue; } if (xType == 0) { if ((xStatus & 0x40) > 0) { xLongName = ""; } //TODO: Check LDIR_Ord for ordering and throw exception // if entries are found out of order. // Also save buffer and only copy name if a end Ord marker is found. string xLongPart = xData.GetUtf16String(i + 1, 5); // We have to check the length because 0xFFFF is a valid Unicode codepoint. // So we only want to stop if the 0xFFFF is AFTER a 0x0000. We can determin // this by also looking at the length. Since we short circuit the or, the length // is rarely evaluated. if (xData.ToUInt16(i + 14) != 0xFFFF || xLongPart.Length == 5) { xLongPart = xLongPart + xData.GetUtf16String(i + 14, 6); if (xData.ToUInt16(i + 28) != 0xFFFF || xLongPart.Length == 11) { xLongPart = xLongPart + xData.GetUtf16String(i + 28, 2); } } xLongName = xLongPart + xLongName; xLongPart = null; //TODO: LDIR_Chksum } } else { xName = xLongName; if (xStatus == 0x00) { Global.mFileSystemDebugger.SendInternal("<EOF> : Attrib = " + xAttrib + ", Status = " + xStatus); break; } switch (xStatus) { case 0x05: // Japanese characters - We dont handle these break; case 0x2E: // Dot entry continue; case FatDirectoryEntryAttributeConsts.UnusedOrDeletedEntry: // Empty slot, skip it continue; default: int xTest = xAttrib & (FatDirectoryEntryAttributeConsts.Directory | FatDirectoryEntryAttributeConsts.VolumeID); if (xStatus >= 0x20) { if (xLongName.Length > 0) { // Leading and trailing spaces are to be ignored according to spec. // Many programs (including Windows) pad trailing spaces although it // it is not required for long names. // As per spec, ignore trailing periods xName = xLongName.Trim(); //If there are trailing periods int nameIndex = xName.Length - 1; if (xName[nameIndex] == '.') { //Search backwards till we find the first non-period character for (; nameIndex > 0; nameIndex--) { if (xName[nameIndex] != '.') { break; } } //Substring to remove the periods xName = xName.Substring(0, nameIndex + 1); } xLongName = ""; } else { if (xTest == 0) { string xEntry = xData.GetAsciiString(i, 11); xName = xEntry.Substring(0, 8).TrimEnd(); string xExt = xEntry.Substring(8, 3).TrimEnd(); if (xExt.Length > 0) { xName = xName + "." + xExt; } } else { xName = xData.GetAsciiString(i, 11).TrimEnd(); } } } uint xFirstCluster = (uint)(xData.ToUInt16(i + 20) << 16 | xData.ToUInt16(i + 26)); if (xTest == 0) { uint xSize = xData.ToUInt32(i + 28); if (xSize == 0 && xName.Length == 0) { continue; } string xFullPath = Path.Combine(mFullPath, xName); var xEntry = new FatDirectoryEntry(((FatFileSystem)mFileSystem), xParent, xFullPath, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.File); xResult.Add(xEntry); Global.mFileSystemDebugger.SendInternal(xEntry.mName + " - " + xEntry.mSize + " bytes"); } else if (xTest == FatDirectoryEntryAttributeConsts.Directory) { string xFullPath = Path.Combine(mFullPath, xName); uint xSize = xData.ToUInt32(i + 28); var xEntry = new FatDirectoryEntry(((FatFileSystem)mFileSystem), xParent, xFullPath, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.Directory); Global.mFileSystemDebugger.SendInternal(xEntry.mName + " <DIR> " + xEntry.mSize + " bytes : Attrib = " + xAttrib + ", Status = " + xStatus); xResult.Add(xEntry); } else if (xTest == FatDirectoryEntryAttributeConsts.VolumeID) { Global.mFileSystemDebugger.SendInternal("<VOLUME ID> : Attrib = " + xAttrib + ", Status = " + xStatus); } else { Global.mFileSystemDebugger.SendInternal("<INVALID ENTRY> : Attrib = " + xAttrib + ", Status = " + xStatus); } break; } } } return xResult; }
public FatDirectoryEntry AddDirectoryEntry(string aName, DirectoryEntryTypeEnum aEntryType) { Global.mFileSystemDebugger.SendInternal("-- FatDirectoryEntry.AddDirectoryEntry --"); Global.mFileSystemDebugger.SendInternal("aName ="); Global.mFileSystemDebugger.SendInternal(aName); Global.mFileSystemDebugger.SendInternal("aEntryType ="); Global.mFileSystemDebugger.SendInternal((uint)aEntryType); if ((aEntryType == DirectoryEntryTypeEnum.Directory) || (aEntryType == DirectoryEntryTypeEnum.File)) { string xShortName = aName; uint[] xDirectoryEntriesToAllocate = null; //Stack corruption, just delete everything from this until commented if when it's fixed var x1 = aEntryType == DirectoryEntryTypeEnum.File; var x2 = aName.Contains("."); var x3 = x2 ? aName.Substring(0, aName.LastIndexOf('.')).Contains(".") : false; var x4 = x2 ? aName.Substring(0, aName.IndexOf('.')).Length > 8 : false; var x5 = x2 ? aName.Substring(aName.IndexOf('.') + 1).Length > 3 : false; var x6 = aEntryType == DirectoryEntryTypeEnum.Directory; var x7 = aName.Length > 11; var x8 = (x3 || (x4 || x5)); var x9 = (x2 && x8); var x10 = (x1 && x9) || (x6 && x7); //if ((aEntryType == DirectoryEntryTypeEnum.File && (aName.Contains(".") && (aName.Substring(0, aName.LastIndexOf('.')).Contains(".") || (aName.Substring(0, aName.IndexOf('.')).Length > 8 || aName.Substring(aName.IndexOf('.') + 1).Length > 3)))) || // (aEntryType == DirectoryEntryTypeEnum.Directory && aName.Length > 11)) if (x10) { string xLongName = aName; char[] xInvalidShortNameChars = new char[] { '"', '*', '+', ',', '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '|' }; int xLastPeriodPosition = aName.LastIndexOf('.'); string xExt = ""; if (xLastPeriodPosition + 1 > 0 && xLastPeriodPosition + 1 < aName.Length) { xExt = xShortName.Substring(xLastPeriodPosition + 1); } for (int i = xShortName.Length - 1; i > 0; i--) { char xChar = xShortName[i]; if (char.IsWhiteSpace(xChar) || (xChar == '.' && i != xLastPeriodPosition)) { xShortName.Remove(i, 1); } } foreach (char xInvalidChar in xInvalidShortNameChars) { xShortName.Replace(xInvalidChar, '_'); } int n = 1; List<FatDirectoryEntry> xDirectoryEntries = ReadDirectoryContents(true); string[] xShortFilenames = new string[xDirectoryEntries.Count]; for (int i = 0; i < xDirectoryEntries.Count; i++) { xShortFilenames[i] = xDirectoryEntries[i].mName; } string xNameTry = ""; bool xTest = false; do { xNameTry = (xShortName.Substring(0, 7 - n.ToString().Length) + "~" + n).ToUpperInvariant(); if (!string.IsNullOrEmpty(xExt)) { xNameTry += '.' + xExt.ToUpperInvariant(); } n++; xTest = false; foreach (string name in xShortFilenames) { if (name == xNameTry) { xTest = true; break; } } } //TODO: Array.TrySZIndexOf plug is not being recognized; to use the generic version of IndexOf, just remove the cast to Array //while (Array.IndexOf((Array)xShortFilenames, xNameTry) != -1); while (xTest); xShortName = xNameTry; uint xChecksum = CalculateChecksum(GetShortName(xShortName)); int xNumEntries = (int)Math.Ceiling((double)xLongName.Length / (double)13); char[] xLongNameWithPad = new char[xNumEntries * 13]; xLongNameWithPad[xLongNameWithPad.Length - 1] = (char)0xFFFF; Array.Copy(xLongName.ToCharArray(), xLongNameWithPad, xLongName.Length); xDirectoryEntriesToAllocate = GetNextUnallocatedDirectoryEntries(xNumEntries + 1); for (int i = xNumEntries - 1; i >= 0; i--) { uint xEntry = xDirectoryEntriesToAllocate[xNumEntries - i - 1]; SetLongFilenameEntryMetadataValue(xEntry, FatDirectoryEntryMetadata.LongFilenameEntryMetadata.SequenceNumberAndAllocationStatus, (i + 1) | (i == xNumEntries - 1 ? (1 << 6) : 0)); SetLongFilenameEntryMetadataValue(xEntry, FatDirectoryEntryMetadata.LongFilenameEntryMetadata.Attributes, FatDirectoryEntryAttributeConsts.LongName); SetLongFilenameEntryMetadataValue(xEntry, FatDirectoryEntryMetadata.LongFilenameEntryMetadata.Checksum, xChecksum); SetLongFilenameEntryMetadataValue(xEntry, FatDirectoryEntryMetadata.LongFilenameEntryMetadata.LongName1, new string(xLongNameWithPad, i * 13, 5)); SetLongFilenameEntryMetadataValue(xEntry, FatDirectoryEntryMetadata.LongFilenameEntryMetadata.LongName2, new string(xLongNameWithPad, i * 13 + 5, 6)); SetLongFilenameEntryMetadataValue(xEntry, FatDirectoryEntryMetadata.LongFilenameEntryMetadata.LongName3, new string(xLongNameWithPad, i * 13 + 11, 2)); } } string xFullPath = Path.Combine(mFullPath, aName); uint xFirstCluster = ((FatFileSystem)mFileSystem).GetFat(0).GetNextUnallocatedFatEntry(); uint xEntryHeaderDataOffset = xDirectoryEntriesToAllocate == null ? GetNextUnallocatedDirectoryEntry() : xDirectoryEntriesToAllocate[xDirectoryEntriesToAllocate.Length - 1]; Global.mFileSystemDebugger.SendInternal("xFullPath ="); Global.mFileSystemDebugger.SendInternal(xFullPath); Global.mFileSystemDebugger.SendInternal("xFirstCluster ="); Global.mFileSystemDebugger.SendInternal(xFirstCluster); Global.mFileSystemDebugger.SendInternal("xEntryHeaderDataOffset ="); Global.mFileSystemDebugger.SendInternal(xEntryHeaderDataOffset); var xNewEntry = new FatDirectoryEntry((FatFileSystem)mFileSystem, this, xFullPath, aName, 0, xFirstCluster, xEntryHeaderDataOffset, aEntryType); xNewEntry.AllocateDirectoryEntry(xShortName); return xNewEntry; } throw new ArgumentOutOfRangeException(nameof(aEntryType), "Unknown directory entry type."); }
public FatDirectoryEntry AddDirectoryEntry(string aName, DirectoryEntryTypeEnum aType) { FileSystemHelpers.Debug("FatDirectoryEntry.AddDirectoryEntry", "aName =", aName, ", aType =", aType.ToString()); if (aType == DirectoryEntryTypeEnum.Directory) { uint xFirstCluster = mFileSystem.GetFat(0).GetNextUnallocatedFatEntry(); uint xEntryHeaderDataOffset = GetNextUnallocatedEntry(); var xNewEntry = new FatDirectoryEntry( mFileSystem, this, aName, 0, xFirstCluster, xEntryHeaderDataOffset, aType); xNewEntry.AllocateDirectoryEntry(); return xNewEntry; } if (aType == DirectoryEntryTypeEnum.File) { throw new NotImplementedException("Creating new files is currently not implemented."); } throw new ArgumentOutOfRangeException("aType", "Unknown directory entry type."); }
private void SetDirectoryEntryData(FatDirectoryEntry aDirectoryEntry, byte[] aData) { if (aDirectoryEntry == null) { throw new ArgumentNullException("aDirectoryEntry"); } if (aData == null) { throw new ArgumentNullException("aData"); } if (aData.Length == 0) { FatHelpers.Debug("SetDirectoryEntryData: No data to write."); return; } FatHelpers.Debug("SetDirectoryEntryData: Name = " + aDirectoryEntry.Name); FatHelpers.Debug("SetDirectoryEntryData: Size = " + aDirectoryEntry.Size); FatHelpers.Debug("SetDirectoryEntryData: FirstClusterNum = " + aDirectoryEntry.FirstClusterNum); FatHelpers.Debug("SetDirectoryEntryData: aData.Length = " + aData.Length); if (aDirectoryEntry.EntryType != DirectoryEntryTypeEnum.Unknown) { if (mFatType == FatTypeEnum.Fat32) { WriteCluster(aDirectoryEntry.FirstClusterNum, aData); } else { mDevice.WriteBlock(aDirectoryEntry.FirstClusterNum, RootSectorCount, aData); } } else { throw new Exception("Invalid directory entry type"); } }
public FatDirectoryEntry AddDirectoryEntry(string aName, DirectoryEntryTypeEnum aType) { FileSystemHelpers.Debug("FatDirectoryEntry.AddDirectoryEntry"); if ((aType == DirectoryEntryTypeEnum.Directory) || (aType == DirectoryEntryTypeEnum.File)) { uint xFirstCluster = mFileSystem.GetFat(0).GetNextUnallocatedFatEntry(); uint xEntryHeaderDataOffset = GetNextUnallocatedEntry(); var xNewEntry = new FatDirectoryEntry(mFileSystem, this, aName, 0, xFirstCluster, xEntryHeaderDataOffset, aType); xNewEntry.AllocateDirectoryEntry(); return xNewEntry; } throw new ArgumentOutOfRangeException("aType", "Unknown directory entry type."); }
public override DirectoryEntry GetRootDirectory() { FileSystemHelpers.Debug("FatFileSystem.GetRootDirectory", "RootCluster =" + RootCluster); var xRootEntry = new FatDirectoryEntry(this, null, mRootPath, RootCluster); return xRootEntry; }
private List<FatDirectoryEntry> ReadDirectoryContents(byte[] xData, FatDirectoryEntry aDirectory) { var xResult = new List<FatDirectoryEntry>(); //TODO: Change xLongName to StringBuilder string xLongName = ""; string xName = ""; for (uint i = 0; i < xData.Length; i = i + 32) { FatHelpers.Debug("-------------------------------------------------"); byte xAttrib = xData[i + 11]; byte xStatus = xData[i]; FatHelpers.Debug("Attrib = " + xAttrib + ", Status = " + xStatus); if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { byte xType = xData[i + 12]; byte xOrd = xData[i]; FatHelpers.Debug("Reading LFN with Seqnr " + xOrd + ", Type = " + xType); if (xOrd == 0xE5) { FatHelpers.Debug("Skipping deleted entry"); continue; } if (xType == 0) { if ((xOrd & 0x40) > 0) { xLongName = ""; } //TODO: Check LDIR_Ord for ordering and throw exception // if entries are found out of order. // Also save buffer and only copy name if a end Ord marker is found. string xLongPart = xData.GetUtf16String(i + 1, 5); // We have to check the length because 0xFFFF is a valid Unicode codepoint. // So we only want to stop if the 0xFFFF is AFTER a 0x0000. We can determin // this by also looking at the length. Since we short circuit the or, the length // is rarely evaluated. if (xData.ToUInt16(i + 14) != 0xFFFF || xLongPart.Length == 5) { xLongPart = xLongPart + xData.GetUtf16String(i + 14, 6); if (xData.ToUInt16(i + 28) != 0xFFFF || xLongPart.Length == 11) { xLongPart = xLongPart + xData.GetUtf16String(i + 28, 2); } } xLongName = xLongPart + xLongName; xLongPart = null; //TODO: LDIR_Chksum } } else { xName = xLongName; if (xStatus == 0x00) { FatHelpers.Debug("End of directory"); break; } switch (xStatus) { case 0x05: // Japanese characters - We dont handle these break; case 0xE5: // Empty slot, skip it break; default: if (xStatus >= 0x20) { if (xLongName.Length > 0) { // Leading and trailing spaces are to be ignored according to spec. // Many programs (including Windows) pad trailing spaces although it // it is not required for long names. // As per spec, ignore trailing periods xName = xLongName.Trim(); //If there are trailing periods int nameIndex = xName.Length - 1; if (xName[nameIndex] == '.') { //Search backwards till we find the first non-period character for (; nameIndex > 0; nameIndex--) { if (xName[nameIndex] != '.') { break; } } //Substring to remove the periods xName = xName.Substring(0, nameIndex + 1); } xLongName = ""; } else { string xEntry = xData.GetAsciiString(i, 11); xName = xEntry.Substring(0, 8).TrimEnd(); string xExt = xEntry.Substring(8, 3).TrimEnd(); if (xExt.Length > 0) { xName = xName + "." + xExt; } } } break; } } uint xFirstCluster = (uint)(xData.ToUInt16(i + 20) << 16 | xData.ToUInt16(i + 26)); var xTest = xAttrib & (FatDirectoryEntryAttributeConsts.Directory | FatDirectoryEntryAttributeConsts.VolumeID); if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { // skip adding, as it's a LongFileName entry, meaning the next normal entry is the item with the name. FatHelpers.Debug("Entry was a Long FileName entry. Current LongName = '" + xLongName + "'"); } else if (xTest == 0) { uint xSize = xData.ToUInt32(i + 28); if (xSize == 0 && xName.Length == 0) { continue; } var xEntry = new FatDirectoryEntry(this, aDirectory, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.File); xResult.Add(xEntry); FatHelpers.Debug("Returning file '" + xEntry.Name + "', FirstCluster = " + xEntry.FirstClusterNum + ", Size = " + xEntry.Size); } else if (xTest == FatDirectoryEntryAttributeConsts.Directory) { uint xSize = xData.ToUInt32(i + 28); var xEntry = new FatDirectoryEntry(this, aDirectory, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.Directory); FatHelpers.Debug("Returning directory '" + xEntry.Name + "', FirstCluster = " + xEntry.FirstClusterNum + ", Size = " + xEntry.Size); xResult.Add(xEntry); } else if (xTest == FatDirectoryEntryAttributeConsts.VolumeID) { FatHelpers.Debug("Directory entry is VolumeID"); } else { FatHelpers.Debug("Not sure what to do!"); } } return xResult; }
private List<FatDirectoryEntry> GetDirectoryContents(FatDirectoryEntry directory) { if (directory == null) { throw new ArgumentNullException("directory"); } byte[] xData = GetDirectoryEntryData(directory); // todo: what about larger directories? return ReadDirectoryContents(xData, directory); }
internal void SetDirectoryEntryMetadataValue(FatDirectoryEntry aDirectoryEntry, FatDirectoryEntryMetadata aEntryMetadata, string aValue) { var xData = GetDirectoryEntryData(aDirectoryEntry.Parent); if (xData.Length > 0) { byte[] xValue = new byte[aEntryMetadata.DataLength]; xValue = aValue.ToString().GetUtf8Bytes(0, aEntryMetadata.DataLength); uint offset = aDirectoryEntry.EntryHeaderDataOffset + aEntryMetadata.DataOffset; Array.Copy(xValue, 0, xData, offset, aEntryMetadata.DataLength); FatHelpers.Debug("SetDirectoryEntryMetadataValue: DataLength = " + aEntryMetadata.DataLength); FatHelpers.Debug("SetDirectoryEntryMetadataValue: DataOffset = " + aEntryMetadata.DataOffset); FatHelpers.Debug("SetDirectoryEntryMetadataValue: EntryHeaderDataOffset = " + aDirectoryEntry.EntryHeaderDataOffset); FatHelpers.Debug("SetDirectoryEntryMetadataValue: TotalOffset = " + offset); FatHelpers.Debug("SetDirectoryEntryMetadataValue: aValue = " + aValue); for (int i = 0; i < xValue.Length; i++) { FatHelpers.DebugNumber(xValue[i]); } SetDirectoryEntryData(aDirectoryEntry.Parent, xData); } }
public override DirectoryEntry GetRootDirectory() { Global.mFileSystemDebugger.SendInternal("-- FatFileSystem.GetRootDirectory --"); var xRootEntry = new FatDirectoryEntry(this, null, mRootPath, mRootPath, RootCluster); return xRootEntry; }
public List <FatDirectoryEntry> ReadDirectoryContents() { FileSystemHelpers.Debug("FatDirectoryEntry.ReadDirectoryContents"); var xData = GetDirectoryEntryData(); var xResult = new List <FatDirectoryEntry>(); FatDirectoryEntry xParent = (FatDirectoryEntry)(mParent ?? mFileSystem.GetRootDirectory()); //TODO: Change xLongName to StringBuilder string xLongName = ""; string xName = ""; for (uint i = 0; i < xData.Length; i = i + 32) { FileSystemHelpers.Debug("-------------------------------------------------"); byte xAttrib = xData[i + 11]; byte xStatus = xData[i]; FileSystemHelpers.Debug("Attrib =", xAttrib, ", Status =", xStatus); if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { byte xType = xData[i + 12]; byte xOrd = xData[i]; FileSystemHelpers.Debug("Reading LFN with Seqnr " + xOrd, ", Type =", xType); if (xOrd == 0xE5) { FileSystemHelpers.Debug("<DELETED>", "Attrib =", xAttrib, ", Status =", xStatus); continue; } if (xType == 0) { if ((xOrd & 0x40) > 0) { xLongName = ""; } //TODO: Check LDIR_Ord for ordering and throw exception // if entries are found out of order. // Also save buffer and only copy name if a end Ord marker is found. string xLongPart = xData.GetUtf16String(i + 1, 5); // We have to check the length because 0xFFFF is a valid Unicode codepoint. // So we only want to stop if the 0xFFFF is AFTER a 0x0000. We can determin // this by also looking at the length. Since we short circuit the or, the length // is rarely evaluated. if (xData.ToUInt16(i + 14) != 0xFFFF || xLongPart.Length == 5) { xLongPart = xLongPart + xData.GetUtf16String(i + 14, 6); if (xData.ToUInt16(i + 28) != 0xFFFF || xLongPart.Length == 11) { xLongPart = xLongPart + xData.GetUtf16String(i + 28, 2); } } xLongName = xLongPart + xLongName; xLongPart = null; //TODO: LDIR_Chksum } } else { xName = xLongName; if (xStatus == 0x00) { FileSystemHelpers.Debug("<EOF>", "Attrib =", xAttrib, ", Status =", xStatus); break; } switch (xStatus) { case 0x05: // Japanese characters - We dont handle these break; case 0xE5: // Empty slot, skip it break; default: if (xStatus >= 0x20) { if (xLongName.Length > 0) { // Leading and trailing spaces are to be ignored according to spec. // Many programs (including Windows) pad trailing spaces although it // it is not required for long names. // As per spec, ignore trailing periods xName = xLongName.Trim(); //If there are trailing periods int nameIndex = xName.Length - 1; if (xName[nameIndex] == '.') { //Search backwards till we find the first non-period character for (; nameIndex > 0; nameIndex--) { if (xName[nameIndex] != '.') { break; } } //Substring to remove the periods xName = xName.Substring(0, nameIndex + 1); } xLongName = ""; } else { string xEntry = xData.GetAsciiString(i, 11); xName = xEntry.Substring(0, 8).TrimEnd(); string xExt = xEntry.Substring(8, 3).TrimEnd(); if (xExt.Length > 0) { xName = xName + "." + xExt; } } } break; } } uint xFirstCluster = (uint)(xData.ToUInt16(i + 20) << 16 | xData.ToUInt16(i + 26)); int xTest = xAttrib & (FatDirectoryEntryAttributeConsts.Directory | FatDirectoryEntryAttributeConsts.VolumeID); if (xAttrib == FatDirectoryEntryAttributeConsts.LongName) { // skip adding, as it's a LongFileName entry, meaning the next normal entry is the item with the name. FileSystemHelpers.Debug("Entry was a Long FileName entry. Current LongName = '" + xLongName + "'"); } else if (xTest == 0) { uint xSize = xData.ToUInt32(i + 28); if (xSize == 0 && xName.Length == 0) { continue; } var xEntry = new FatDirectoryEntry(mFileSystem, xParent, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.File); xResult.Add(xEntry); FileSystemHelpers.Debug(xEntry.mName + " -" + xEntry.mSize + " bytes"); } else if (xTest == FatDirectoryEntryAttributeConsts.Directory) { uint xSize = xData.ToUInt32(i + 28); var xEntry = new FatDirectoryEntry(mFileSystem, xParent, xName, xSize, xFirstCluster, i, DirectoryEntryTypeEnum.Directory); FileSystemHelpers.Debug(xEntry.mName + " <DIR> " + xEntry.mSize + " bytes", "Attrib =", xAttrib, ", Status =", xStatus); xResult.Add(xEntry); } else if (xTest == FatDirectoryEntryAttributeConsts.VolumeID) { FileSystemHelpers.Debug("<VOLUME ID>", "Attrib =", xAttrib, ", Status =", xStatus); } else { FileSystemHelpers.Debug("<INVALID ENTRY>", "Attrib =", xAttrib, ", Status =", xStatus); } } return(xResult); }
private byte[] GetDirectoryEntryData(FatDirectoryEntry aDirectoryEntry) { byte[] xData; if (mFatType == FatTypeEnum.Fat32) { if (aDirectoryEntry.EntryType != DirectoryEntryTypeEnum.Unknown) { xData = NewClusterArray(); ReadCluster(aDirectoryEntry.FirstClusterNum, xData); } else { throw new Exception("Invalid directory entry type"); } } else { if (aDirectoryEntry.EntryType != DirectoryEntryTypeEnum.Unknown) { xData = mDevice.NewBlockArray(1); mDevice.ReadBlock(aDirectoryEntry.FirstClusterNum, RootSectorCount, xData); } else { throw new Exception("Invalid directory entry type"); } } return xData; }