private void UpdateLocalDirectoryOrFile(List <LocalDirectoryContentInfo> localDirectoryContentInfos, byte[] directoryData, int directoryClusterIndex, int directoryEntryIndex, int entryStartClusterIndex, string newContentName) { string newContentPath = null; if (directoryClusterIndex != _rootDirectoryClusterIndex) { string newPathDirectory = _clusterInfos[directoryClusterIndex].LocalDirectoryContent.LocalPath; newContentPath = Path.Combine(newPathDirectory, newContentName); } else { newContentPath = newContentName; } try { if (directoryData[directoryEntryIndex + 11] == FAT16Helper.DirectoryIdentifier) { // Is it a directory with a valid start cluster? if (entryStartClusterIndex != 0) { _logger.Log("Creating local directory \"" + newContentPath + "\"", Constants.LoggingLevel.Info); var CreatedLocalDirectory = Directory.CreateDirectory(GetAbsolutePath(newContentPath)); var newLocalDirectoryContent = new LocalDirectoryContentInfo { ParentDirectory = _clusterInfos[directoryClusterIndex]?.LocalDirectoryContent, LocalFileName = newContentName, TOSFileName = newContentName, EntryIndex = directoryEntryIndex, DirectoryCluster = directoryClusterIndex, StartCluster = entryStartClusterIndex, FinalCluster = entryStartClusterIndex, WriteInProgress = false }; localDirectoryContentInfos.Add(newLocalDirectoryContent); _clusterInfos[entryStartClusterIndex].LocalDirectoryContent = newLocalDirectoryContent; _clusterInfos[entryStartClusterIndex].FileOffset = FAT16Helper.DirectoryFileOffset; } } // it's a file else { _logger.Log($"Checking if local file {newContentPath} should be updated", Constants.LoggingLevel.Debug); int fileSize = directoryData[directoryEntryIndex + 28] | (directoryData[directoryEntryIndex + 29] << 8) | (directoryData[directoryEntryIndex + 30] << 16) | (directoryData[directoryEntryIndex + 31] << 24); _logger.Log("File size to write:" + fileSize, Constants.LoggingLevel.All); int fileClusterIndex = entryStartClusterIndex; _logger.Log("Finding existing content info for local file \"" + newContentPath + "\".", Constants.LoggingLevel.All); var localDirectoryContent = localDirectoryContentInfos.Where(ldci => ldci.LocalPath == newContentPath).SingleOrDefault(); if (localDirectoryContent == null) { _logger.Log($"Creating local file: {newContentPath}", Constants.LoggingLevel.Info); File.Create(GetAbsolutePath(newContentPath)).Dispose(); var newLocalDirectoryContent = new LocalDirectoryContentInfo { ParentDirectory = _clusterInfos[directoryClusterIndex]?.LocalDirectoryContent, LocalFileName = newContentName, TOSFileName = newContentName, EntryIndex = directoryEntryIndex, DirectoryCluster = directoryClusterIndex, StartCluster = entryStartClusterIndex, FinalCluster = -1 }; localDirectoryContentInfos.Add(newLocalDirectoryContent); localDirectoryContent = newLocalDirectoryContent; } localDirectoryContent.StartCluster = entryStartClusterIndex; _logger.Log("File start cluster: " + localDirectoryContent.StartCluster + " (" + FatGetClusterValue(localDirectoryContent.StartCluster) + ")", Constants.LoggingLevel.All); // Entry cluster will be assigned if this is a non-empty file if (entryStartClusterIndex != 0) { localDirectoryContent.WriteInProgress = true; _logger.Log("Content marked for write: " + localDirectoryContent.WriteInProgress, Constants.LoggingLevel.All); int remainingBytes = fileSize; // Check if the file has been completely written. // Number of bytes in the cluster chain must be checked in case this file is being written // in multiple passes due to lack of available RAM on the Atari while (!FAT16Helper.IsEndOfClusterChain(fileClusterIndex)) { // Keep final cluster updated in case this file is being written in multiple passes localDirectoryContent.FinalCluster = fileClusterIndex; remainingBytes -= Parameters.BytesPerCluster; fileClusterIndex = FatGetClusterValue(fileClusterIndex); } bool allBytesAvailable = remainingBytes <= 0 && FAT16Helper.IsEndOfFile(fileClusterIndex); _logger.Log("All bytes available?: " + allBytesAvailable, Constants.LoggingLevel.All); // Final FAT cluster value in chain matches a fully written file if (allBytesAvailable) { localDirectoryContent.WriteInProgress = false; try { _logger.Log("Finding existing content info for local file \"" + newContentPath + "\".", Constants.LoggingLevel.All); localDirectoryContent = localDirectoryContentInfos.Where(ldci => ldci.LocalPath == newContentPath).Single(); localDirectoryContent.StartCluster = entryStartClusterIndex; _logger.Log("Writing to local file \"" + newContentPath + "\".", Constants.LoggingLevel.Info); using (BinaryWriter FileBinaryWriter = new BinaryWriter(File.OpenWrite(GetAbsolutePath(newContentPath)))) { fileClusterIndex = entryStartClusterIndex; remainingBytes = fileSize; int fileOffset = 0; while (!FAT16Helper.IsEndOfFile(fileClusterIndex)) { _clusterInfos[fileClusterIndex].LocalDirectoryContent = localDirectoryContent; _clusterInfos[fileClusterIndex].FileOffset = fileOffset; FileBinaryWriter.Write(_clusterInfos[fileClusterIndex].DataBuffer, 0, Math.Min(_clusterInfos[fileClusterIndex].DataBuffer.Length, remainingBytes)); remainingBytes -= _clusterInfos[fileClusterIndex].DataBuffer.Length; fileOffset += _clusterInfos[fileClusterIndex].DataBuffer.Length; // Buffer has been written to disk; free up RAM _clusterInfos[fileClusterIndex].DataBuffer = null; localDirectoryContent.FinalCluster = fileClusterIndex; fileClusterIndex = FatGetClusterValue(fileClusterIndex); } _logger.Log("Bytes remaining after write:" + remainingBytes, Constants.LoggingLevel.All); } } catch (Exception ex) { _logger.LogException(ex); } } } } } catch (Exception ex) { _logger.LogException(ex); } }
private void SyncDirectoryClusterToLocalDisk(List <LocalDirectoryContentInfo> localDirectoryContentInfos, int clusterIndex) { byte[] directoryData; directoryData = GetDirectoryClusterData(clusterIndex); // Only check for changes if this cluster contains directory entry information if (clusterIndex == _rootDirectoryClusterIndex || _clusterInfos[clusterIndex].FileOffset == -1) { bool continueCheckingEntries = true; do { _logger.Log($"Updating directory cluster {clusterIndex}", Constants.LoggingLevel.All); int directoryEntryIndex = 0; while (directoryEntryIndex < directoryData.Length && directoryData[directoryEntryIndex] != 0) { // The entry is not "." or "..". if (directoryData[directoryEntryIndex] != 0x2e) { string fileName = ASCIIEncoding.ASCII.GetString(directoryData, directoryEntryIndex, 8).Trim(); string fileExtension = ASCIIEncoding.ASCII.GetString(directoryData, directoryEntryIndex + 8, 3).Trim(); if (fileExtension != "") { fileName += "." + fileExtension; } int entryStartClusterIndex = directoryData[directoryEntryIndex + 26] | (directoryData[directoryEntryIndex + 27] << 8); // Find the matching local content and check what happened to it. var localContent = FindLocalDirectoryContentInfo(localDirectoryContentInfos, clusterIndex, directoryEntryIndex, entryStartClusterIndex); if (localContent != null) { if (localContent.TOSFileName != fileName) { if (directoryData[directoryEntryIndex] == FAT16Helper.DeletedEntryIdentifier) { DeleteLocalDirectoryOrFile(localDirectoryContentInfos, directoryData, directoryEntryIndex, localContent); } else { RenameLocalDirectoryOrFile(directoryData, directoryEntryIndex, localContent, fileName); } } } // Entry is new else if (directoryData[directoryEntryIndex] != FAT16Helper.DeletedEntryIdentifier) { UpdateLocalDirectoryOrFile(localDirectoryContentInfos, directoryData, clusterIndex, directoryEntryIndex, entryStartClusterIndex, fileName); } } directoryEntryIndex += 32; } if (directoryEntryIndex < directoryData.Length || FAT16Helper.IsEndOfClusterChain(FatGetClusterValue(clusterIndex))) { continueCheckingEntries = false; } else { var nextClusterIndex = FatGetClusterValue(clusterIndex); _logger.Log($"Directory cluster {clusterIndex} continues in cluster {nextClusterIndex}", Constants.LoggingLevel.All); // If the next directory cluster is new, ensure it has a LocalDirectoryContentInfo assigned if (_clusterInfos[nextClusterIndex].LocalDirectoryContent == null) { _clusterInfos[nextClusterIndex].LocalDirectoryContent = _clusterInfos[clusterIndex].LocalDirectoryContent; _clusterInfos[nextClusterIndex].FileOffset = FAT16Helper.DirectoryFileOffset; _logger.Log($"Directory cluster {clusterIndex} extended to cluster {nextClusterIndex}", Constants.LoggingLevel.All); } clusterIndex = nextClusterIndex; directoryData = GetDirectoryClusterData(clusterIndex); } } while (continueCheckingEntries); } }