Cosmetic changes to BITS code files

pull/303/head
dahall 2022-05-21 13:42:27 -06:00
parent ec712439e4
commit b2bb3ce4ea
2 changed files with 310 additions and 429 deletions

View File

@ -79,7 +79,7 @@ namespace Vanara.IO
/// BackgroundCopyManager.CopyAsync(src, dest, cts.Token, prog); /// BackgroundCopyManager.CopyAsync(src, dest, cts.Token, prog);
/// </code> /// </code>
/// </example> /// </example>
public static async Task CopyAsync(string sourceFileName, string destFileName, CancellationToken cancellationToken, IProgress<Tuple<BackgroundCopyJobState, byte>> progress) public static async Task CopyAsync(string sourceFileName, string destFileName, [Optional] CancellationToken cancellationToken, [Optional] IProgress<Tuple<BackgroundCopyJobState, byte>> progress)
{ {
#if NET40 #if NET40
await TaskEx.Run(() => CopyTemplate(destFileName, cancellationToken, (s, p) => progress?.Report(new Tuple<BackgroundCopyJobState, byte>(s,p)), f => f.Add(sourceFileName, destFileName)), cancellationToken); await TaskEx.Run(() => CopyTemplate(destFileName, cancellationToken, (s, p) => progress?.Report(new Tuple<BackgroundCopyJobState, byte>(s,p)), f => f.Add(sourceFileName, destFileName)), cancellationToken);
@ -93,7 +93,7 @@ namespace Vanara.IO
{ {
try try
{ {
IMgr.CreateJob(displayName, jobType, out var newJobID, out var newJob); IMgr.CreateJob(displayName, jobType, out Guid newJobID, out IBackgroundCopyJob newJob);
return newJob; return newJob;
} }
catch (COMException cex) catch (COMException cex)
@ -143,18 +143,16 @@ namespace Vanara.IO
return wp.IsInRole(WindowsBuiltInRole.Administrator); return wp.IsInRole(WindowsBuiltInRole.Administrator);
} }
private static void CopyTemplate(string destFileName, CancellationToken ct, Action<BackgroundCopyJobState, byte> report, Action<BackgroundCopyFileCollection> add) private static void CopyTemplate(string destFileName, CancellationToken ct, Action<BackgroundCopyJobState, byte> report, Action<BackgroundCopyFileCollection> add)
{ {
var type = (Uri.TryCreate(destFileName, UriKind.Absolute, out var uri) && !uri.IsFile) ? BackgroundCopyJobType.Upload : BackgroundCopyJobType.Download; BackgroundCopyJobType type = (Uri.TryCreate(destFileName, UriKind.Absolute, out Uri uri) && !uri.IsFile) ? BackgroundCopyJobType.Upload : BackgroundCopyJobType.Download;
using var mainJob = Jobs.Add("Temp" + Guid.NewGuid().ToString(), string.Empty, type); using BackgroundCopyJob mainJob = Jobs.Add("Temp" + Guid.NewGuid().ToString(), string.Empty, type);
using var manualReset = new ManualResetEventSlim(false); using var manualReset = new ManualResetEventSlim(false);
BackgroundCopyException err = null; BackgroundCopyException err = null;
// Set event handlers for job, these are weak references. // Set event handlers for job, these are weak references.
mainJob.Completed += OnCompleted; mainJob.Completed += OnCompleted;
mainJob.Error += OnError; mainJob.Error += OnError;
@ -167,7 +165,6 @@ namespace Vanara.IO
manualReset.Wait(ct); manualReset.Wait(ct);
var raiseException = false; var raiseException = false;
if (ct.IsCancellationRequested) if (ct.IsCancellationRequested)
@ -176,26 +173,20 @@ namespace Vanara.IO
raiseException = true; raiseException = true;
} }
// Remove weak references to prevent memory leak. // Remove weak references to prevent memory leak.
mainJob.FileRangesTransferred -= OnFileRangesTransferred; mainJob.FileRangesTransferred -= OnFileRangesTransferred;
mainJob.FileTransferred -= OnFileTransferred; mainJob.FileTransferred -= OnFileTransferred;
mainJob.Completed -= OnCompleted; mainJob.Completed -= OnCompleted;
mainJob.Error -= OnError; mainJob.Error -= OnError;
if (raiseException) if (raiseException)
throw new OperationCanceledException(); throw new OperationCanceledException();
if (null != err) if (null != err)
throw err; throw err;
// Better performance when event methods are defined seperately, preferably static. // Better performance when event methods are defined seperately, preferably static.
void OnCompleted(object s, BackgroundCopyJobEventArgs e) void OnCompleted(object s, BackgroundCopyJobEventArgs e)
{ {
if (s is BackgroundCopyJob job) if (s is BackgroundCopyJob job)
@ -208,7 +199,6 @@ namespace Vanara.IO
} }
} }
void OnError(object s, BackgroundCopyJobEventArgs e) void OnError(object s, BackgroundCopyJobEventArgs e)
{ {
if (s is BackgroundCopyJob job) if (s is BackgroundCopyJob job)
@ -221,25 +211,19 @@ namespace Vanara.IO
} }
} }
void OnFileTransferred(object s, BackgroundCopyFileTransferredEventArgs e) void OnFileTransferred(object s, BackgroundCopyFileTransferredEventArgs e)
{ {
if (s is BackgroundCopyJob job) if (s is BackgroundCopyJob job)
ReportProgress(job, job.State); ReportProgress(job, job.State);
} }
void OnFileRangesTransferred(object s, BackgroundCopyFileRangesTransferredEventArgs e) void OnFileRangesTransferred(object s, BackgroundCopyFileRangesTransferredEventArgs e)
{ {
if (s is BackgroundCopyJob job) if (s is BackgroundCopyJob job)
ReportProgress(job, job.State); ReportProgress(job, job.State);
} }
void ReportProgress(BackgroundCopyJob job, BackgroundCopyJobState state) => report?.Invoke(state, job.Progress.PercentComplete);
void ReportProgress(BackgroundCopyJob job, BackgroundCopyJobState state)
{
report?.Invoke(state, job.Progress.PercentComplete);
}
} }
} }
} }

View File

@ -1,434 +1,331 @@
/* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov /* Copyright (C) 2008-2018 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
*/ */
using NUnit.Framework; using NUnit.Framework;
using System; using System;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Security.AccessControl; using System.Security.AccessControl;
using static System.IO.Path;
namespace Vanara.IO.Tests namespace Vanara.IO.Tests
{ {
/// <summary>Used to create a temporary directory that will be deleted once this instance is disposed.</summary> /// <summary>Used to create a temporary directory that will be deleted once this instance is disposed.</summary>
public sealed class TemporaryDirectory : IDisposable public sealed class TemporaryDirectory : IDisposable
{ {
#region Fields public const int OneMebibyte = 1 << 20;
public const int OneMebibyte = 1048576; /// <summary>The path to the temporary folder, ending with a backslash.</summary>
private static readonly string TempPath = GetTempPath();
#endregion //Fields public TemporaryDirectory() : this(false)
{
}
public TemporaryDirectory(bool isNetwork, string folderPrefix = null, string root = null)
{
if (string.IsNullOrWhiteSpace(folderPrefix))
folderPrefix = "Vanara.TempRoot";
#region Constructors if (string.IsNullOrWhiteSpace(root))
root = TempPath;
public TemporaryDirectory() : this(false) { } //if (isNetwork)
// root = Alphaleonis.Win32.Filesystem.Path.LocalToUnc(root);
public TemporaryDirectory(bool isNetwork, string folderPrefix = null, string root = null) //UnitTestConstants.PrintUnitTestHeader(isNetwork);
{
if (string.IsNullOrWhiteSpace(folderPrefix))
folderPrefix = "Vanara.TempRoot";
if (string.IsNullOrWhiteSpace(root)) do
root = TempPath; {
Directory = new DirectoryInfo(Combine(root, folderPrefix + "." + RandomString));
} while (Directory.Exists);
Directory.Create();
}
~TemporaryDirectory()
{
Dispose(false);
}
//if (isNetwork) public DirectoryInfo Directory { get; private set; }
// root = Alphaleonis.Win32.Filesystem.Path.LocalToUnc(root);
/// <summary>Returns the full path to a non-existing directory with a random name, such as: "C:\Users\UserName\AppData\Local\Temp\AlphaFS.TempRoot.lpqdzf\Directory_wqáánmvh.z03".</summary>
public string RandomDirectoryFullPath => Combine(Directory.FullName, RandomDirectoryName);
//UnitTestConstants.PrintUnitTestHeader(isNetwork); /// <summary>Returns a random directory name, such as: "Directory_wqáánmvh".</summary>
public string RandomDirectoryName => string.Format(CultureInfo.InvariantCulture, "Directory.{0}", RandomString);
/// <summary>Returns the full path to a non-existing file with a random name and without an extension, such as: "C:\Users\UserName\AppData\Local\Temp\AlphaFS.TempRoot.lpqdzf\File_wqáánmvh".</summary>
public string RandomFileNoExtensionFullPath => Combine(Directory.FullName, GetFileNameWithoutExtension(RandomTxtFileName));
do /// <summary>Returns a random string of 8 characters in length, possibly with diacritic characters.</summary>
{ public string RandomString
Directory = new System.IO.DirectoryInfo(System.IO.Path.Combine(root, folderPrefix + "." + RandomString)); {
get
{
var randomFileName = GetFileNameWithoutExtension(GetRandomFileName());
return randomFileName;
//switch (new Random(DateTime.UtcNow.Millisecond).Next(1, 3))
//{
// case 1:
// return randomFileName.Replace("a", "ä").Replace("e", "ë").Replace("i", "ï").Replace("o", "ö").Replace("u", "ü");
// case 2: return randomFileName.Replace("a", "á").Replace("e", "é").Replace("i", "í").Replace("o", "ó").Replace("u", "ú");
// case 3: return randomFileName.Replace("a", "â").Replace("e", "ê").Replace("i", "î").Replace("o", "ô").Replace("u", "û");
// default:
// return randomFileName;
//}
}
}
/// <summary>Returns the full path to a non-existing file with a random name, such as: "C:\Users\UserName\AppData\Local\Temp\AlphaFS.TempRoot.lpqdzf\File_wqáánmvh.txt".</summary>
public string RandomTxtFileFullPath => Combine(Directory.FullName, RandomTxtFileName);
} while (Directory.Exists); /// <summary>Returns the full path to a non-existing file with a random name, such as: "File_wqáánmvh.txt".</summary>
public string RandomTxtFileName => string.Format(CultureInfo.InvariantCulture, "File_{0}.txt", RandomString);
Directory.Create(); /// <summary>Returns a <see cref="DirectoryInfo"/> instance to an existing directory.</summary>
} public DirectoryInfo CreateDirectory() => CreateDirectoryCore(null);
#endregion // Constructors /// <summary>Returns a <see cref="DirectoryInfo"/> instance to an existing directory.</summary>
public DirectoryInfo CreateDirectory(string directoryNameSuffix) => CreateDirectoryCore(Directory.FullName + directoryNameSuffix);
#region Properties /// <summary>
/// Returns a <see cref="DirectoryInfo"/> instance to an existing directory, possibly with read-only and/or hidden
public System.IO.DirectoryInfo Directory { get; private set; } /// attributes set.
/// </summary>
public DirectoryInfo CreateDirectoryRandomizedAttributes() => CreateDirectoryCore(null, false, true, true);
/// <summary>Returns a random directory name, such as: "Directory_wqáánmvh".</summary>
public string RandomDirectoryName /// <summary>
{ /// Returns a <see cref="DirectoryInfo"/> instance to an existing directory, possibly with read-only and/or hidden
get { return string.Format(CultureInfo.InvariantCulture, "Directory.{0}", RandomString); } /// attributes set.
} /// </summary>
public DirectoryInfo CreateDirectoryRandomizedAttributes(string directoryNameSuffix) => CreateDirectoryCore(Directory.FullName + directoryNameSuffix, false, true, true);
/// <summary>Returns the full path to a non-existing file with a random name, such as: "File_wqáánmvh.txt".</summary> /// <summary>Returns a <see cref="FileInfo"/> instance to an existing file.</summary>
public string RandomTxtFileName public FileInfo CreateFile() => CreateFileCore(null);
{
get { return string.Format(CultureInfo.InvariantCulture, "File_{0}.txt", RandomString); } /// <summary>Returns a <see cref="FileInfo"/> instance to an existing file of <paramref name="fileSize"/> bytes.</summary>
} public FileInfo CreateFile(int fileSize) => CreateFileCore(null, fileSize: fileSize);
/// <summary>
/// <summary>Returns the full path to a non-existing directory with a random name, such as: "C:\Users\UserName\AppData\Local\Temp\AlphaFS.TempRoot.lpqdzf\Directory_wqáánmvh.z03".</summary> /// Returns a <see cref="FileInfo"/> instance to an existing file, possibly with read-only and/or hidden attributes set.
public string RandomDirectoryFullPath /// </summary>
{ public FileInfo CreateFileRandomizedAttributes() => CreateFileCore(null, false, true, true);
get { return System.IO.Path.Combine(Directory.FullName, RandomDirectoryName); }
} /// <summary>
/// Creates a directory structure populated with subdirectories and files of random size and possibly with read-only and/or hidden
/// attributes set.
/// <summary>Returns the full path to a non-existing file with a random name, such as: "C:\Users\UserName\AppData\Local\Temp\AlphaFS.TempRoot.lpqdzf\File_wqáánmvh.txt".</summary> /// </summary>
public string RandomTxtFileFullPath public DirectoryInfo CreateRandomizedAttributesTree(int level = 1) => CreateTreeCore(null, level, false, false, true, true);
{
get { return System.IO.Path.Combine(Directory.FullName, RandomTxtFileName); } /// <summary>
} /// Creates a recursive directory structure populated with subdirectories and files of random size and possibly with read-only and/or
/// hidden attributes set.
/// </summary>
/// <summary>Returns the full path to a non-existing file with a random name and without an extension, such as: "C:\Users\UserName\AppData\Local\Temp\AlphaFS.TempRoot.lpqdzf\File_wqáánmvh".</summary> public DirectoryInfo CreateRecursiveRandomizedAttributesTree(int level = 1) => CreateTreeCore(null, level, true, false, true, true);
public string RandomFileNoExtensionFullPath
{ /// <summary>
get { return System.IO.Path.Combine(Directory.FullName, System.IO.Path.GetFileNameWithoutExtension(RandomTxtFileName)); } /// Creates a recursive directory structure populated with subdirectories and files, possibly with randomized CreationTime,
} /// LastAccessTime and/or LastWriteTime. The file size, read-only and/or hidden attributes might also be randomized.
/// </summary>
public DirectoryInfo CreateRecursiveRandomizedDatesAndAttributesTree(int level = 1) => CreateTreeCore(null, level, true, true, true, true);
/// <summary>Returns a random string of 8 characters in length, possibly with diacritic characters.</summary>
public string RandomString /// <summary>
{ /// Creates a recursive directory structure populated with subdirectories and files, possibly with randomized CreationTime,
get /// LastAccessTime and/or LastWriteTime.
{ /// </summary>
var randomFileName = System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName()); public DirectoryInfo CreateRecursiveRandomizedDatesTree(int level = 1) => CreateTreeCore(null, level, true, true);
return randomFileName;
/// <summary>Creates a recursive directory structure populated with subdirectories and files of random size.</summary>
//switch (new Random(DateTime.UtcNow.Millisecond).Next(1, 3)) public DirectoryInfo CreateRecursiveTree(int level = 1) => CreateTreeCore(null, level, true);
//{
// case 1: /// <summary>Creates a recursive directory structure populated with subdirectories and files of random size.</summary>
// return randomFileName.Replace("a", "ä").Replace("e", "ë").Replace("i", "ï").Replace("o", "ö").Replace("u", "ü"); public DirectoryInfo CreateRecursiveTree(int level, string rootFullPath) => CreateTreeCore(rootFullPath, level, true);
// case 2: /// <summary>Returns a <see cref="DirectoryInfo"/> instance to an existing directory.</summary>
// return randomFileName.Replace("a", "á").Replace("e", "é").Replace("i", "í").Replace("o", "ó").Replace("u", "ú"); public DirectoryInfo CreateSubDirectory(string directoryName) => CreateDirectoryCore(Combine(Directory.FullName, directoryName));
// case 3: /// <summary>Returns a <see cref="FileInfo"/> instance to an existing file.</summary>
// return randomFileName.Replace("a", "â").Replace("e", "ê").Replace("i", "î").Replace("o", "ô").Replace("u", "û"); public FileInfo CreateSubDirectoryFile(DirectoryInfo directoryInfo, string fileName = null, int fileSize = OneMebibyte) => CreateFileCore(Combine(directoryInfo.FullName, fileName ?? RandomTxtFileName), fileSize: fileSize);
// default: /// <summary>Creates a directory structure populated with subdirectories and files of random size.</summary>
// return randomFileName; public DirectoryInfo CreateTree(int level = 1) => CreateTreeCore(null, level);
//}
} /// <inheritdoc/>
} public void Dispose()
{
#endregion // Properties Dispose(true);
GC.SuppressFinalize(this);
}
#region Methods
public DateTime GetRandomFileDate()
/// <summary>Returns a <see cref="System.IO.DirectoryInfo"/> instance to an existing directory.</summary> {
public System.IO.DirectoryInfo CreateDirectory() var rnd = new Random(DateTime.Now.Millisecond);
{ return new DateTime(rnd.Next(1971, DateTime.Now.Year), rnd.Next(1, 12), rnd.Next(1, 28), rnd.Next(0, 23), rnd.Next(0, 59), rnd.Next(0, 59));
return CreateDirectoryCore(null); }
}
/// <summary>Enables or disables deny access for the current User.</summary>
public void SetDirectoryDenyPermission(bool enable, string folderFullPath)
/// <summary>Returns a <see cref="System.IO.DirectoryInfo"/> instance to an existing directory.</summary> {
public System.IO.DirectoryInfo CreateDirectory(string directoryNameSuffix) // ╔═════════════╦═════════════╦═══════════════════════════════╦════════════════════════╦══════════════════╦═══════════════════════╦═════════════╦═════════════╗
{ // ║ ║ folder only ║ folder, sub-folders and files ║ folder and sub-folders ║ folder and files ║ sub-folders and files ║
return CreateDirectoryCore(Directory.FullName + directoryNameSuffix); // sub-folders ║ files ║
} // ╠═════════════╬═════════════╬═══════════════════════════════╬════════════════════════╬══════════════════╬═══════════════════════╬═════════════╬═════════════╣
// ║ Propagation ║ none ║ none ║ none ║ none ║ InheritOnly ║ InheritOnly ║ InheritOnly ║ ║ Inheritance ║ none ║ Container|Object
// ║ Container ║ Object ║ Container|Object ║ Container ║ Object ║ ╚═════════════╩═════════════╩═══════════════════════════════╩════════════════════════╩══════════════════╩═══════════════════════╩═════════════╩═════════════╝
/// <summary>Returns a <see cref="System.IO.DirectoryInfo"/> instance to an existing directory.</summary>
public System.IO.DirectoryInfo CreateSubDirectory(string directoryName) var user = (Environment.UserDomainName + @"\" + Environment.UserName).TrimStart('\\');
{
return CreateDirectoryCore(System.IO.Path.Combine(Directory.FullName, directoryName)); var rule = new FileSystemAccessRule(user, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Deny);
}
DirectorySecurity dirSecurity;
/// <summary>Returns a <see cref="System.IO.DirectoryInfo"/> instance to an existing directory, possibly with read-only and/or hidden attributes set.</summary> DirectoryInfo dirInfo = CreateDirectoryCore(folderFullPath);
public System.IO.DirectoryInfo CreateDirectoryRandomizedAttributes()
{ // Set DENY for current User.
return CreateDirectoryCore(null, false, true, true); if (enable)
} {
dirSecurity = dirInfo.GetAccessControl();
dirSecurity.AddAccessRule(rule);
/// <summary>Returns a <see cref="System.IO.DirectoryInfo"/> instance to an existing directory, possibly with read-only and/or hidden attributes set.</summary> dirInfo.SetAccessControl(dirSecurity);
public System.IO.DirectoryInfo CreateDirectoryRandomizedAttributes(string directoryNameSuffix) }
{
return CreateDirectoryCore(Directory.FullName + directoryNameSuffix, false, true, true); // Remove DENY for current User.
} else
{
dirSecurity = dirInfo.GetAccessControl();
/// <summary>Returns a <see cref="System.IO.FileInfo"/> instance to an existing file.</summary> dirSecurity.RemoveAccessRule(rule);
public System.IO.FileInfo CreateFile() dirInfo.SetAccessControl(dirSecurity);
{ }
return CreateFileCore(null); }
}
/// <inheritdoc/>
public override string ToString() => Directory.FullName;
/// <summary>Returns a <see cref="System.IO.FileInfo"/> instance to an existing file.</summary>
public System.IO.FileInfo CreateSubDirectoryFile(System.IO.DirectoryInfo directoryInfo, string fileName = null, int fileSize = OneMebibyte) private static void SetReadOnlyAndOrHiddenAttributes(FileSystemInfo fsi, bool readOnly = false, bool hidden = false)
{ {
return CreateFileCore(System.IO.Path.Combine(directoryInfo.FullName, fileName ?? RandomTxtFileName), fileSize: fileSize); if (readOnly && new Random(DateTime.UtcNow.Millisecond).Next(0, 1000) % 2 == 0)
} fsi.Attributes |= FileAttributes.ReadOnly;
if (hidden && new Random(DateTime.UtcNow.Millisecond).Next(0, 1000) % 2 == 0)
/// <summary>Returns a <see cref="System.IO.FileInfo"/> instance to an existing file of <paramref name="fileSize"/> bytes.</summary> fsi.Attributes |= FileAttributes.Hidden;
public System.IO.FileInfo CreateFile(int fileSize) }
{
return CreateFileCore(null, fileSize: fileSize); /// <summary>
} /// Returns a <see cref="DirectoryInfo"/> instance to an existing directory, possibly with read-only and/or hidden
/// attributes set.
/// </summary>
/// <summary>Returns a <see cref="System.IO.FileInfo"/> instance to an existing file, possibly with read-only and/or hidden attributes set.</summary> private DirectoryInfo CreateDirectoryCore(string folderFullPath, bool randomizedDates = false, bool readOnly = false, bool hidden = false)
public System.IO.FileInfo CreateFileRandomizedAttributes() {
{ DirectoryInfo dirInfo = System.IO.Directory.CreateDirectory(!string.IsNullOrWhiteSpace(folderFullPath) ? folderFullPath : RandomDirectoryFullPath);
return CreateFileCore(null, false, true, true);
} SetRandomizedDates(dirInfo, randomizedDates);
SetReadOnlyAndOrHiddenAttributes(dirInfo, readOnly, hidden);
/// <summary>Creates a directory structure populated with subdirectories and files of random size.</summary>
public System.IO.DirectoryInfo CreateTree(int level = 1) return dirInfo;
{ }
return CreateTreeCore(null, level);
} /// <summary>
/// Returns a <see cref="FileInfo"/> instance to an existing file, possibly with read-only and/or hidden attributes set.
/// </summary>
/// <summary>Creates a recursive directory structure populated with subdirectories and files of random size.</summary> private FileInfo CreateFileCore(string fileFullPath, bool randomizedDates = false, bool readOnly = false, bool hidden = false, int fileSize = 0)
public System.IO.DirectoryInfo CreateRecursiveTree(int level = 1) {
{ var fileInfo = new FileInfo(!string.IsNullOrWhiteSpace(fileFullPath) ? fileFullPath : RandomTxtFileFullPath);
return CreateTreeCore(null, level, true);
} using (FileStream fs = fileInfo.Create())
{
if (fileSize > OneMebibyte)
/// <summary>Creates a recursive directory structure populated with subdirectories and files of random size.</summary> fs.SetLength(fileSize);
public System.IO.DirectoryInfo CreateRecursiveTree(int level, string rootFullPath) else
{ fs.SetLength(new Random(DateTime.UtcNow.Millisecond).Next(0, OneMebibyte));
return CreateTreeCore(rootFullPath, level, true); }
}
SetRandomizedDates(fileInfo, randomizedDates);
/// <summary>Creates a directory structure populated with subdirectories and files of random size and possibly with read-only and/or hidden attributes set.</summary> SetReadOnlyAndOrHiddenAttributes(fileInfo, readOnly, hidden);
public System.IO.DirectoryInfo CreateRandomizedAttributesTree(int level = 1)
{ return fileInfo;
return CreateTreeCore(null, level, false, false, true, true); }
}
/// <summary>
/// Creates an, optional recursive, directory structure of <param name="level"/> levels deep, populated with subdirectories and files
/// <summary>Creates a recursive directory structure populated with subdirectories and files of random size and possibly with read-only and/or hidden attributes set.</summary> /// of random size and possibly with read-only and/or hidden attributes set.
public System.IO.DirectoryInfo CreateRecursiveRandomizedAttributesTree(int level = 1) /// </summary>
{ private DirectoryInfo CreateTreeCore(string rootFullPath, int level = 1, bool recurse = false, bool randomizedDates = false, bool readOnly = false, bool hidden = false)
return CreateTreeCore(null, level, true, false, true, true); {
} DirectoryInfo dirInfo = CreateDirectoryCore(rootFullPath, randomizedDates, readOnly, hidden);
var folderCount = 0;
/// <summary>Creates a recursive directory structure populated with subdirectories and files, possibly with randomized CreationTime, LastAccessTime and/or LastWriteTime.</summary>
public System.IO.DirectoryInfo CreateRecursiveRandomizedDatesTree(int level = 1) for (var fsoCount = 0; fsoCount < level; fsoCount++)
{ {
return CreateTreeCore(null, level, true, true); folderCount++;
}
var fsoName = RandomString + "-" + fsoCount;
/// <summary>Creates a recursive directory structure populated with subdirectories and files, possibly with randomized CreationTime, LastAccessTime and/or LastWriteTime.
/// The file size, read-only and/or hidden attributes might also be randomized. // Always create folder.
/// </summary> DirectoryInfo di = CreateDirectoryCore(Combine(dirInfo.FullName, $"Directory_{fsoName}_directory"), randomizedDates, readOnly, hidden);
public System.IO.DirectoryInfo CreateRecursiveRandomizedDatesAndAttributesTree(int level = 1)
{ // Create file, every other iteration.
return CreateTreeCore(null, level, true, true, true, true); CreateFileCore(Combine(fsoCount % 2 == 0 ? di.FullName : dirInfo.FullName, $"File_{fsoName}_file.txt"), randomizedDates, readOnly, hidden);
} }
if (recurse)
public DateTime GetRandomFileDate() {
{ foreach (var folder in System.IO.Directory.EnumerateDirectories(dirInfo.FullName))
var rnd = new Random(DateTime.Now.Millisecond); CreateTreeCore(folder, level, false, randomizedDates, readOnly, hidden);
return new DateTime(rnd.Next(1971, DateTime.Now.Year), rnd.Next(1, 12), rnd.Next(1, 28), rnd.Next(0, 23), rnd.Next(0, 59), rnd.Next(0, 59)); }
}
Assert.AreEqual(level, folderCount, "The number of folders does not equal level argument, but is expected to.");
/// <summary>Enables or disables deny access for the current User.</summary> return dirInfo;
public void SetDirectoryDenyPermission(bool enable, string folderFullPath) }
{
// ╔═════════════╦═════════════╦═══════════════════════════════╦════════════════════════╦══════════════════╦═══════════════════════╦═════════════╦═════════════╗ private void Dispose(bool isDisposing)
// ║ ║ folder only ║ folder, sub-folders and files ║ folder and sub-folders ║ folder and files ║ sub-folders and files ║ sub-folders ║ files ║ {
// ╠═════════════╬═════════════╬═══════════════════════════════╬════════════════════════╬══════════════════╬═══════════════════════╬═════════════╬═════════════╣ try
// ║ Propagation ║ none ║ none ║ none ║ none ║ InheritOnly ║ InheritOnly ║ InheritOnly ║ {
// ║ Inheritance ║ none ║ Container|Object ║ Container ║ Object ║ Container|Object ║ Container ║ Object ║ if (isDisposing)
// ╚═════════════╩═════════════╩═══════════════════════════════╩════════════════════════╩══════════════════╩═══════════════════════╩═════════════╩═════════════╝ System.IO.Directory.Delete(Directory.FullName, true);
}
var user = (Environment.UserDomainName + @"\" + Environment.UserName).TrimStart('\\'); catch (Exception ex)
{
var rule = new FileSystemAccessRule(user, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Deny); Console.WriteLine($"{nameof(TemporaryDirectory)} delete failure. Error: {ex.Message.Replace(Environment.NewLine, string.Empty)}");
}
DirectorySecurity dirSecurity; }
var dirInfo = CreateDirectoryCore(folderFullPath); private void SetRandomizedDates(FileSystemInfo fsi, bool randomizedDates = false)
{
if (randomizedDates && new Random(DateTime.UtcNow.Millisecond).Next(0, 1000) % 2 == 0)
// Set DENY for current User. {
if (enable) fsi.CreationTime = GetRandomFileDate();
{ fsi.LastAccessTime = GetRandomFileDate();
dirSecurity = dirInfo.GetAccessControl(); fsi.LastWriteTime = GetRandomFileDate();
dirSecurity.AddAccessRule(rule); }
dirInfo.SetAccessControl(dirSecurity); }
} }
}
// Remove DENY for current User.
else
{
dirSecurity = dirInfo.GetAccessControl();
dirSecurity.RemoveAccessRule(rule);
dirInfo.SetAccessControl(dirSecurity);
}
}
public override string ToString()
{
return Directory.FullName;
}
#endregion // Methods
#region Private Members
/// <summary>The path to the temporary folder, ending with a backslash.</summary>
private static readonly string TempPath = System.IO.Path.GetTempPath();
/// <summary>Returns a <see cref="System.IO.DirectoryInfo"/> instance to an existing directory, possibly with read-only and/or hidden attributes set.</summary>
private System.IO.DirectoryInfo CreateDirectoryCore(string folderFullPath, bool randomizedDates = false, bool readOnly = false, bool hidden = false)
{
var dirInfo = System.IO.Directory.CreateDirectory(!string.IsNullOrWhiteSpace(folderFullPath) ? folderFullPath : RandomDirectoryFullPath);
SetRandomizedDates(dirInfo, randomizedDates);
SetReadOnlyAndOrHiddenAttributes(dirInfo, readOnly, hidden);
return dirInfo;
}
/// <summary>Returns a <see cref="System.IO.FileInfo"/> instance to an existing file, possibly with read-only and/or hidden attributes set.</summary>
private System.IO.FileInfo CreateFileCore(string fileFullPath, bool randomizedDates = false, bool readOnly = false, bool hidden = false, int fileSize = 0)
{
var fileInfo = new System.IO.FileInfo(!string.IsNullOrWhiteSpace(fileFullPath) ? fileFullPath : RandomTxtFileFullPath);
using (var fs = fileInfo.Create())
{
if (fileSize > OneMebibyte)
fs.SetLength(fileSize);
else
fs.SetLength(new Random(DateTime.UtcNow.Millisecond).Next(0, OneMebibyte));
}
SetRandomizedDates(fileInfo, randomizedDates);
SetReadOnlyAndOrHiddenAttributes(fileInfo, readOnly, hidden);
return fileInfo;
}
/// <summary>Creates an, optional recursive, directory structure of <param name="level"/> levels deep, populated with subdirectories and files of random size and possibly with read-only and/or hidden attributes set.</summary>
private System.IO.DirectoryInfo CreateTreeCore(string rootFullPath, int level = 1, bool recurse = false, bool randomizedDates = false, bool readOnly = false, bool hidden = false)
{
var dirInfo = CreateDirectoryCore(rootFullPath, randomizedDates, readOnly, hidden);
var folderCount = 0;
for (var fsoCount = 0; fsoCount < level; fsoCount++)
{
folderCount++;
var fsoName = RandomString + "-" + fsoCount;
// Always create folder.
var di = CreateDirectoryCore(System.IO.Path.Combine(dirInfo.FullName, $"Directory_{fsoName}_directory"), randomizedDates, readOnly, hidden);
// Create file, every other iteration.
CreateFileCore(System.IO.Path.Combine(fsoCount % 2 == 0 ? di.FullName : dirInfo.FullName, $"File_{fsoName}_file.txt"), randomizedDates, readOnly, hidden);
}
if (recurse)
{
foreach (var folder in System.IO.Directory.EnumerateDirectories(dirInfo.FullName))
CreateTreeCore(folder, level, false, randomizedDates, readOnly, hidden);
}
Assert.AreEqual(level, folderCount, "The number of folders does not equal level argument, but is expected to.");
return dirInfo;
}
private void SetRandomizedDates(System.IO.FileSystemInfo fsi, bool randomizedDates = false)
{
if (randomizedDates && new Random(DateTime.UtcNow.Millisecond).Next(0, 1000) % 2 == 0)
{
fsi.CreationTime = GetRandomFileDate();
fsi.LastAccessTime = GetRandomFileDate();
fsi.LastWriteTime = GetRandomFileDate();
}
}
private static void SetReadOnlyAndOrHiddenAttributes(System.IO.FileSystemInfo fsi, bool readOnly = false, bool hidden = false)
{
if (readOnly && new Random(DateTime.UtcNow.Millisecond).Next(0, 1000) % 2 == 0)
fsi.Attributes |= System.IO.FileAttributes.ReadOnly;
if (hidden && new Random(DateTime.UtcNow.Millisecond).Next(0, 1000) % 2 == 0)
fsi.Attributes |= System.IO.FileAttributes.Hidden;
}
#endregion Private Members
#region Disposable Members
~TemporaryDirectory()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool isDisposing)
{
try
{
if (isDisposing)
System.IO.Directory.Delete(Directory.FullName, true);
}
catch (Exception ex)
{
Console.WriteLine($"{nameof(TemporaryDirectory)} delete failure. Error: {ex.Message.Replace(Environment.NewLine, string.Empty)}");
}
}
#endregion // Disposable Members
}
}