Skip to content

Commit

Permalink
Add more clipboard infrastructure tests
Browse files Browse the repository at this point in the history
Pull from a filesystem, from the volume dir and a subdir.
  • Loading branch information
fadden committed Nov 2, 2023
1 parent dd56a6d commit 690f5a7
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 61 deletions.
45 changes: 1 addition & 44 deletions AppCommon/AddFileWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ public void AddFilesToDisk(IFileSystem fileSystem, IFileEntry targetDir,
// directory if we remembered the path / entry from the previous iteration.
string storageDir = doStripPaths ? string.Empty : addEnt.StorageDir;
IFileEntry subDirEnt;
subDirEnt = CreateSubdirectories(fileSystem, targetDirEnt, storageDir,
subDirEnt = fileSystem.CreateSubdirectories(targetDirEnt, storageDir,
addEnt.StorageDirSep);

// Add the new file to subDirEnt. See if it already exists.
Expand Down Expand Up @@ -524,49 +524,6 @@ public void AddFilesToDisk(IFileSystem fileSystem, IFileEntry targetDir,
isCancelled = false;
}

/// <summary>
/// Ensures that all of the directories in the path exist. If they don't exist, they
/// will be created.
/// </summary>
/// <param name="fileSystem">Filesystem to modify.</param>
/// <param name="targetDirEnt">Base directory.</param>
/// <param name="storageDir">Partial pathname, directories only.</param>
/// <param name="storageDirSep">Directory separator character used in storage dir.</param>
/// <returns>File entry for destination directory.</returns>
/// <exception cref="IOException">Something failed.</exception>
internal static IFileEntry CreateSubdirectories(IFileSystem fileSystem,
IFileEntry targetDirEnt, string storageDir, char storageDirSep) {
if (string.IsNullOrEmpty(storageDir)) {
return targetDirEnt;
}
IFileEntry subDirEnt = targetDirEnt;
string[] dirStrings = storageDir.Split(storageDirSep);
foreach (string dirName in dirStrings) {
// Adjust this directory name to be compatible with the target filesystem.
string adjDirName = fileSystem.AdjustFileName(dirName);

// See if it exists. If it does, and it's not a directory, is very bad.
if (fileSystem.TryFindFileEntry(subDirEnt, adjDirName,
out IFileEntry nextDirEnt)) {
if (!nextDirEnt.IsDirectory) {
throw new IOException("Error: path component '" + adjDirName +
"' (" + dirName + ") is not a directory");
}
subDirEnt = nextDirEnt;
} else {
// Not found, create new.
try {
subDirEnt = fileSystem.CreateFile(subDirEnt, adjDirName,
CreateMode.Directory);
} catch (IOException ex) {
throw new IOException("Error: unable to create directory '" +
adjDirName + "': " + ex.Message);
}
}
}
return subDirEnt;
}

/// <summary>
/// Copies a part (i.e fork) of a file to a disk image file stream. The file source may
/// be a plain or structured file.
Expand Down
1 change: 1 addition & 0 deletions AppCommon/ClipFileEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ public ClipFileEntry(object archiveOrFileSystem, IFileEntry entry, IFileEntry ad
Type? expectedType, AppHook appHook) {
Debug.Assert(!string.IsNullOrEmpty(attribs.FileNameOnly));
Debug.Assert(!string.IsNullOrEmpty(attribs.FullPathName));

mStreamGen = new StreamGenerator(archiveOrFileSystem, entry, adfEntry, part, attribs,
preserveMode, exportSpec, defaultSpecs, expectedType, appHook);

Expand Down
41 changes: 35 additions & 6 deletions AppCommon/ClipFileSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public class ClipFileSet {
private bool mUseRawData;

// Keep track of directories we've already added to the output.
private Dictionary<IFileEntry, IFileEntry> mAddedDirs =
private Dictionary<IFileEntry, IFileEntry> mAddedFiles =
new Dictionary<IFileEntry, IFileEntry>();


Expand Down Expand Up @@ -316,8 +316,13 @@ private void GenerateFromDisk(IFileSystem fs, List<IFileEntry> entries) {
/// Generates an entry in the ClipFileEntry set for the specified entry. If the entry is
/// a directory, we recursively generate clip objects for the entry's children.
/// </summary>
/// <remarks>
/// <para>We need to avoid creating two entries for the same file. This can happen if
/// the entry list includes "dir1" and "dir1/foo.txt"; note either of these could
/// appear first.</para>
/// </remarks>
/// <param name="fs">Filesystem reference.</param>
/// <param name="entry">File entry to process.</param>
/// <param name="entry">File entry to process. May be a file or directory.</param>
/// <param name="aboveRootEntry">Entry above the root, used to limit the partial path
/// prefix.</param>
private void GenerateDiskEntries(IFileSystem fs, IFileEntry entry,
Expand All @@ -329,7 +334,9 @@ private void GenerateDiskEntries(IFileSystem fs, IFileEntry entry,
// create empty directories, and a way to pass the directory file dates along.
AddMissingDirectories(fs, entry, aboveRootEntry);
}
if (entry.IsDirectory) {
if (mAddedFiles.ContainsKey(entry)) {
// Already added.
} else if (entry.IsDirectory) {
// Current directory, if not stripped, was added above.
foreach (IFileEntry child in entry) {
GenerateDiskEntries(fs, child, aboveRootEntry);
Expand All @@ -350,6 +357,10 @@ private void GenerateDiskEntries(IFileSystem fs, IFileEntry entry,
// Generate file attributes. The same object will be used for both forks.
FileAttribs attrs = new FileAttribs(entry);
attrs.FullPathName = ReRootedPathName(entry, aboveRootEntry);
if (string.IsNullOrEmpty(attrs.FullPathName)) {
mAppHook.LogW("Not adding below-root entry: " + entry);
return;
}
if (mStripPaths) {
extractPath = Path.GetFileName(extractPath);
attrs.FullPathName =
Expand All @@ -361,10 +372,10 @@ private void GenerateDiskEntries(IFileSystem fs, IFileEntry entry,
} else {
CreateForExport(fs, entry, IFileEntry.NO_ENTRY, attrs, extractPath);
}
mAddedFiles.Add(entry, entry);
}
}


/// <summary>
/// Adds entries for the directory hierarchy that contains the specified entry, if
/// they haven't yet been added. If the entry is itself a directory, it will be added.
Expand All @@ -381,10 +392,12 @@ private void AddMissingDirectories(IFileSystem fs, IFileEntry entry,
}
// Recursively check parents.
AddMissingDirectories(fs, entry.ContainingDir, aboveRootEntry);
if (entry.IsDirectory && !mAddedDirs.ContainsKey(entry)) {
// Add this one if it's not already present.
if (entry.IsDirectory && !mAddedFiles.ContainsKey(entry)) {
// Add this directory to the output list.
FileAttribs attrs = new FileAttribs(entry);
attrs.FullPathName = ReRootedPathName(entry, aboveRootEntry);
Debug.Assert(!string.IsNullOrEmpty(attrs.FullPathName));
attrs.FullPathSep = entry.DirectorySeparatorChar;
attrs.FileNameOnly = PathName.GetFileName(attrs.FullPathName, attrs.FullPathSep);
Debug.Assert(attrs.IsDirectory);
Expand All @@ -395,7 +408,7 @@ private void AddMissingDirectories(IFileSystem fs, IFileEntry entry,
mAppHook));
XferEntries.Add(new ClipFileEntry(fs, entry, IFileEntry.NO_ENTRY,
FilePart.DataFork, attrs, mAppHook));
mAddedDirs.Add(entry, entry);
mAddedFiles.Add(entry, entry);
}
}

Expand All @@ -407,7 +420,23 @@ private void AddMissingDirectories(IFileSystem fs, IFileEntry entry,
/// <param name="entry">File entry.</param>
/// <param name="aboveRootEntry">Entry above the root directory. For the volume dir,
/// or non-hierarchical filesystems, this will be NO_ENTRY.</param>
/// <returns>Partial pathname, or the empty string if the above-root entry is not actually
/// above the entry.</returns>
private static string ReRootedPathName(IFileEntry entry, IFileEntry aboveRootEntry) {
// Test to see if entry is at or above the root. If it's at the same level as the
// root, or above it, it shouldn't be part of the set.
if (entry.ContainingDir == aboveRootEntry) {
return string.Empty;
}
IFileEntry scanEntry = entry;
while (scanEntry.ContainingDir != aboveRootEntry) {
scanEntry = scanEntry.ContainingDir;
if (scanEntry == IFileEntry.NO_ENTRY) {
// Walked to the top without finding it.
return string.Empty;
}
}

StringBuilder sb = new StringBuilder();
ReRootedPathName(entry, aboveRootEntry, sb);
return sb.ToString();
Expand Down
2 changes: 1 addition & 1 deletion AppCommon/ClipPasteWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ public void AddFilesToDisk(IFileSystem fileSystem, IFileEntry targetDir,
string storageName = PathName.GetFileName(clipEntry.Attribs.FullPathName,
clipEntry.Attribs.FullPathSep);
IFileEntry subDirEnt;
subDirEnt = AddFileWorker.CreateSubdirectories(fileSystem, targetDirEnt, storageDir,
subDirEnt = fileSystem.CreateSubdirectories(targetDirEnt, storageDir,
clipEntry.Attribs.FullPathSep);

// Add the new file to subDirEnt. See if it already exists.
Expand Down
47 changes: 46 additions & 1 deletion DiskArc/DAExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ public static bool CheckStorageName(this IArchive archive, string storageName) {
/// <summary>
/// Formats an IDiskImage. This should only be used on a newly-created IDiskImage,
/// when the ChunkAccess property is non-null and the FileSystem property is null.
/// Query the FileSystem out of the IDiskImage when this returns.
/// The disk will be analyzed, so the caller can access the filesystem object via
/// <see cref="IDiskImage.Contents"/>.
/// </summary>
/// <remarks>
/// <para>The chunks will be zeroed out before the new filesystem is written.</para>
Expand Down Expand Up @@ -570,6 +571,50 @@ public static IFileEntry CreateFile(this IFileSystem fs, IFileEntry dirEntry,
return entry;
}

/// <summary>
/// Ensures that all of the directories in the path exist. If they don't exist, they
/// will be created.
/// </summary>
/// <param name="baseDir">Base directory.</param>
/// <param name="partialPath">Partial pathname, with directories only.</param>
/// <param name="dirSep">Directory separator character used in storage dir.</param>
/// <returns>File entry for destination directory.</returns>
/// <exception cref="IOException">I/O failure, or part of the path existed but was not
/// a regular file.</exception>
public static IFileEntry CreateSubdirectories(this IFileSystem fs,
IFileEntry baseDir, string partialPath, char dirSep) {
if (string.IsNullOrEmpty(partialPath)) {
return baseDir;
}
Debug.Assert(fs.Characteristics.IsHierarchical);
IFileEntry subDirEnt = baseDir;
string[] dirStrings = partialPath.Split(dirSep);
foreach (string dirName in dirStrings) {
// Adjust this directory name to be compatible with the target filesystem.
string adjDirName = fs.AdjustFileName(dirName);

// See if it exists. If it does, and it's not a directory, is very bad.
if (fs.TryFindFileEntry(subDirEnt, adjDirName,
out IFileEntry nextDirEnt)) {
if (!nextDirEnt.IsDirectory) {
throw new IOException("Error: path component '" + adjDirName +
"' (" + dirName + ") is not a directory");
}
subDirEnt = nextDirEnt;
} else {
// Not found, create new.
try {
subDirEnt = fs.CreateFile(subDirEnt, adjDirName,
IFileSystem.CreateMode.Directory);
} catch (IOException ex) {
throw new IOException("Error: unable to create directory '" +
adjDirName + "': " + ex.Message);
}
}
}
return subDirEnt;
}

//public static DiskFileStream OpenDataForkRO(this IFileSystem fs, IFileEntry entry) {
// return fs.OpenFile(entry, IFileSystem.FileAccessMode.ReadOnly, Defs.FilePart.DataFork);
//}
Expand Down
4 changes: 4 additions & 0 deletions cp2/Tests/Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ public static bool HandleRunTests(string cmdName, string[] args, ParamsBag parms
ResetConsole();
}

// Give any finalizer-based checks a chance to run.
GC.Collect();
GC.WaitForPendingFinalizers();

Console.WriteLine("Success");
return true;
}
Expand Down
Loading

0 comments on commit 690f5a7

Please sign in to comment.