internal DirectoryEntry(DirectoryEntry toCopy) { _options = toCopy._options; _name = toCopy._name; _attr = toCopy._attr; _creationTimeTenth = toCopy._creationTimeTenth; _creationTime = toCopy._creationTime; _creationDate = toCopy._creationDate; _lastAccessDate = toCopy._lastAccessDate; _firstClusterHi = toCopy._firstClusterHi; _lastWriteTime = toCopy._lastWriteTime; _firstClusterLo = toCopy._firstClusterLo; _fileSize = toCopy._fileSize; }
internal void ForgetDirectory(DirectoryEntry entry) { uint index = entry.FirstCluster; if (index != 0 && _dirCache.ContainsKey(index)) { Directory dir = _dirCache[index]; _dirCache.Remove(index); dir.Dispose(); } }
/// <summary> /// Moves a file, allowing an existing file to be overwritten. /// </summary> /// <param name="sourceName">The file to move.</param> /// <param name="destinationName">The target file name.</param> /// <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); if (sourceDir == null || sourceEntryId < 0) { throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "The source file '{0}' was not found", sourceName)); } DirectoryEntry sourceEntry = sourceDir.GetEntry(sourceEntryId); if ((sourceEntry.Attributes & FatAttributes.Directory) != 0) { throw new IOException("The source file is a directory"); } DirectoryEntry newEntry = new DirectoryEntry(sourceEntry); newEntry.Name = FileName.FromPath(destinationName, FatOptions.FileNameEncoding); Directory destDir; long destEntryId = GetDirectoryEntry(destinationName, out destDir); if (destDir == null) { throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The destination directory for '{0}' was not found", destinationName)); } // If the destination is a directory, use the old file name to construct a full path. if (destEntryId >= 0) { DirectoryEntry destEntry = destDir.GetEntry(destEntryId); if ((destEntry.Attributes & FatAttributes.Directory) != 0) { newEntry.Name = FileName.FromPath(sourceName, FatOptions.FileNameEncoding); destinationName = Utilities.CombinePaths(destinationName, Utilities.GetFileFromPath(sourceName)); destEntryId = GetDirectoryEntry(destinationName, out destDir); } } // If there's an existing entry... if (destEntryId >= 0) { DirectoryEntry destEntry = destDir.GetEntry(destEntryId); if ((destEntry.Attributes & FatAttributes.Directory) != 0) { throw new IOException("Destination file is an existing directory"); } if (!overwrite) { throw new IOException("Destination file already exists"); } // Remove the old file destDir.DeleteEntry(destEntryId, true); } // Add the new file's entry and remove the old link to the file's contents destDir.AddEntry(newEntry); sourceDir.DeleteEntry(sourceEntryId, false); }
/// <summary> /// Copies an existing file to a new file, allowing overwriting of an existing file. /// </summary> /// <param name="sourceFile">The source file</param> /// <param name="destinationFile">The destination file</param> /// <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); if (sourceDir == null || sourceEntryId < 0) { throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "The source file '{0}' was not found", sourceFile)); } DirectoryEntry sourceEntry = sourceDir.GetEntry(sourceEntryId); if ((sourceEntry.Attributes & FatAttributes.Directory) != 0) { throw new IOException("The source file is a directory"); } DirectoryEntry newEntry = new DirectoryEntry(sourceEntry); newEntry.Name = FileName.FromPath(destinationFile, FatOptions.FileNameEncoding); newEntry.FirstCluster = 0; Directory destDir; long destEntryId = GetDirectoryEntry(destinationFile, out destDir); if (destDir == null) { throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The destination directory for '{0}' was not found", destinationFile)); } // If the destination is a directory, use the old file name to construct a full path. if (destEntryId >= 0) { DirectoryEntry destEntry = destDir.GetEntry(destEntryId); if ((destEntry.Attributes & FatAttributes.Directory) != 0) { newEntry.Name = FileName.FromPath(sourceFile, FatOptions.FileNameEncoding); destinationFile = Utilities.CombinePaths(destinationFile, Utilities.GetFileFromPath(sourceFile)); destEntryId = GetDirectoryEntry(destinationFile, out destDir); } } // If there's an existing entry... if (destEntryId >= 0) { DirectoryEntry destEntry = destDir.GetEntry(destEntryId); if ((destEntry.Attributes & FatAttributes.Directory) != 0) { throw new IOException("Destination file is an existing directory"); } if (!overwrite) { throw new IOException("Destination file already exists"); } // Remove the old file destDir.DeleteEntry(destEntryId, true); } // Add the new file's entry 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)) { Utilities.PumpStreams(sourceStream, destStream); } }
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); // 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); } }
internal void UpdateEntry(long id, DirectoryEntry entry) { if (id < 0) { throw new IOException("Attempt to update unknown directory entry"); } _dirStream.Position = id; entry.WriteTo(_dirStream); _entries[id] = entry; }
private void LoadEntries() { _entries = new Dictionary<long, DirectoryEntry>(); _freeEntries = new List<long>(); _selfEntryLocation = -1; _parentEntryLocation = -1; while (_dirStream.Position < _dirStream.Length) { long streamPos = _dirStream.Position; DirectoryEntry entry = new DirectoryEntry(_fileSystem.FatOptions, _dirStream); if (entry.Attributes == (FatAttributes.ReadOnly | FatAttributes.Hidden | FatAttributes.System | FatAttributes.VolumeId)) { // Long File Name entry } else if (entry.Name.IsDeleted()) { // E5 = Free Entry _freeEntries.Add(streamPos); } else if (entry.Name == FileName.SelfEntryName) { _selfEntry = entry; _selfEntryLocation = streamPos; } else if (entry.Name == FileName.ParentEntryName) { _parentEntry = entry; _parentEntryLocation = streamPos; } else if (entry.Name == FileName.Null) { // Free Entry, no more entries available _endOfEntries = streamPos; break; } else { _entries.Add(streamPos, entry); } } }
internal void DeleteEntry(long id, bool releaseContents) { if (id < 0) { throw new IOException("Attempt to delete unknown directory entry"); } try { DirectoryEntry entry = _entries[id]; DirectoryEntry copy = new DirectoryEntry(entry); copy.Name = entry.Name.Deleted(); _dirStream.Position = id; copy.WriteTo(_dirStream); if (releaseContents) { _fileSystem.Fat.FreeChain(entry.FirstCluster); } _entries.Remove(id); _freeEntries.Add(id); HandleAccessed(true); } finally { _fileSystem.Fat.Flush(); } }
internal long AddEntry(DirectoryEntry newEntry) { // Unlink an entry from the free list (or add to the end of the existing directory) long pos; if (_freeEntries.Count > 0) { pos = _freeEntries[0]; _freeEntries.RemoveAt(0); } else { pos = _endOfEntries; _endOfEntries += 32; } // Put the new entry into it's slot _dirStream.Position = pos; newEntry.WriteTo(_dirStream); // Update internal structures to reflect new entry (as if read from disk) _entries.Add(pos, newEntry); HandleAccessed(true); return pos; }
internal SparseStream OpenFile(FileName name, FileMode mode, FileAccess fileAccess) { if (mode == FileMode.Append || mode == FileMode.Truncate) { throw new NotImplementedException(); } long fileId = FindEntry(name); bool exists = fileId != -1; if (mode == FileMode.CreateNew && exists) { throw new IOException("File already exists"); } else if (mode == FileMode.Open && !exists) { throw new FileNotFoundException("File not found", name.GetDisplayName(_fileSystem.FatOptions.FileNameEncoding)); } else if ((mode == FileMode.Open || mode == FileMode.OpenOrCreate || mode == FileMode.Create) && exists) { SparseStream stream = new FatFileStream(_fileSystem, this, fileId, fileAccess); if (mode == FileMode.Create) { stream.SetLength(0); } HandleAccessed(false); return stream; } else if ((mode == FileMode.OpenOrCreate || mode == FileMode.CreateNew || mode == FileMode.Create) && !exists) { // Create new file DirectoryEntry newEntry = new DirectoryEntry(_fileSystem.FatOptions, name, FatAttributes.Archive); newEntry.FirstCluster = 0; // i.e. Zero-length newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow); newEntry.LastWriteTime = newEntry.CreationTime; fileId = AddEntry(newEntry); return new FatFileStream(_fileSystem, this, fileId, fileAccess); } else { // Should never get here... throw new NotImplementedException(); } }
internal void AttachChildDirectory(FileName name, Directory newChild) { long id = FindEntry(name); if (id >= 0) { throw new IOException("Directory entry already exists"); } DirectoryEntry newEntry = new DirectoryEntry(newChild.ParentsChildEntry); newEntry.Name = name; AddEntry(newEntry); DirectoryEntry newParentEntry = new DirectoryEntry(SelfEntry); newParentEntry.Name = FileName.ParentEntryName; newChild.ParentEntry = newParentEntry; }
internal Directory CreateChildDirectory(FileName name) { long id = FindEntry(name); if (id >= 0) { if ((_entries[id].Attributes & FatAttributes.Directory) == 0) { throw new IOException("A file exists with the same name"); } else { return _fileSystem.GetDirectory(this, id); } } else { try { uint firstCluster; if (!_fileSystem.Fat.TryGetFreeCluster(out 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); newEntry.FirstCluster = firstCluster; newEntry.CreationTime = _fileSystem.ConvertFromUtc(DateTime.UtcNow); newEntry.LastWriteTime = newEntry.CreationTime; id = AddEntry(newEntry); PopulateNewChildDirectory(newEntry); // Rather than just creating a new instance, pull it through the fileSystem cache // to ensure the cache model is preserved. return _fileSystem.GetDirectory(this, id); } finally { _fileSystem.Fat.Flush(); } } }