// Spludlow Software
// Copyright © Samuel P. Ludlow 2020 All Rights Reserved
// Distributed under the terms of the GNU General Public License version 3
// Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
// https://www.spludlow.co.uk/LICENCE.TXT
// The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
// v1.14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;
namespace Spludlow.Io
{
///
/// Make random test binary files, entire contents is random (no headers or anything).
/// Note these files will not compress with any gain.
///
public class TestFiles
{
[ThreadStatic]
private static Random _Random = null;
private static object _RandomLock = new object();
private static int _RandomSeed = 0;
///
/// Must be called by each thread to use _Random
/// Ensures each thread's Random will have a unique seed
///
private static void RandomInitialize()
{
if (_Random != null)
return;
lock (_RandomLock)
{
_Random = new Random(_RandomSeed++);
}
}
///
/// Make random test data file
///
public static ulong Make(string filename, ulong bytes)
{
RandomInitialize();
int bufferSize = 128 * 1024 * 1024;
byte[] buffer = new byte[bufferSize];
ulong remaining = bytes;
using (FileStream stream = new FileStream(filename, FileMode.Create))
{
while (remaining > 0)
{
ulong todo = remaining;
if (todo > (ulong)buffer.Length)
todo = (ulong)buffer.Length;
_Random.NextBytes(buffer);
stream.Write(buffer, 0, (int)todo);
remaining -= todo;
}
}
return bytes;
}
public static ulong MakeGiga(string filename, decimal gigabytes)
{
return Make(filename, (ulong)(gigabytes * 1024 * 1024 * 1024));
}
public static ulong MakeMega(string filename, decimal megabytes)
{
return Make(filename, (ulong)(megabytes * 1024 * 1024));
}
public static ulong MakeKilo(string filename, decimal kilobytes)
{
return Make(filename, (ulong)(kilobytes * 1024));
}
///
/// Rain down random test files to a directory keeping them locked upto a specifed time
/// Files are named with the SHA1 in the name
///
public static void DirectoryWritesSHA1(string directory, int threads, int threadFileCount, int minMeg, int maxMeg, int maxSleepSeconds)
{
Task[] tasks = new Task[threads];
for (int index = 0; index < threads; ++index)
{
int threadId = index;
tasks[index] = new Task(() => DirectoryWritesSHA1Worker(directory, threadId, threadFileCount, minMeg, maxMeg, maxSleepSeconds));
}
foreach (Task task in tasks)
task.Start();
Task.WaitAll(tasks);
}
private static void DirectoryWritesSHA1Worker(string directory, int threadId, int threadFileCount, int minMeg, int maxMeg, int maxSleepSeconds)
{
RandomInitialize();
int diffMeg = maxMeg - minMeg;
using (Spludlow.TempDirectory tempDir = new Spludlow.TempDirectory())
{
string tempFilename = tempDir.Path + @"\file.dat";
for (int fileId = 0; fileId < threadFileCount; ++fileId)
{
int meg = minMeg + _Random.Next(diffMeg);
int sleepSeconds = _Random.Next(maxSleepSeconds);
string hash = MakeSHA1Mega(tempFilename, meg);
string targetFilename = directory + @"\" + threadId.ToString("0000") + "-" + fileId.ToString("0000") + "-" + meg.ToString("0000") + "mb-" + sleepSeconds.ToString("0000") + "s-" + hash + ".dat";
if (maxSleepSeconds == 0)
File.Copy(tempFilename, targetFilename);
else
CopySlow(tempFilename, targetFilename, sleepSeconds);
File.Delete(tempFilename);
}
}
}
///
/// Crate a random test data file and return the SHA1 hash while doing it
///
public static string MakeSHA1(string filename, ulong filesize)
{
RandomInitialize();
int bufferSize = 128 * 1024 * 1024;
byte[] buffer = new byte[bufferSize];
using (SHA1 hash = new SHA1Managed())
{
using (FileStream stream = new FileStream(filename, FileMode.CreateNew, FileAccess.Write))
{
using (CryptoStream cryStream = new CryptoStream(stream, hash, CryptoStreamMode.Write))
{
while (filesize > 0)
{
ulong writeSize = (filesize < (ulong)buffer.Length ? filesize : (ulong)buffer.Length);
_Random.NextBytes(buffer);
cryStream.Write(buffer, 0, (int)writeSize);
filesize -= writeSize;
}
cryStream.FlushFinalBlock();
return Spludlow.Hashing.Hex(hash.Hash);
}
}
}
}
public static string MakeSHA1Giga(string filename, decimal gigabytes)
{
return MakeSHA1(filename, (ulong)(gigabytes * 1024 * 1024 * 1024));
}
public static string MakeSHA1Mega(string filename, decimal megabytes)
{
return MakeSHA1(filename, (ulong)(megabytes * 1024 * 1024));
}
public static string MakeSHA1Kilo(string filename, decimal kilobytes)
{
return MakeSHA1(filename, (ulong)(kilobytes * 1024));
}
///
/// Copy file and keep exclusivly open for specified number of seconds
///
public static void CopySlow(string sourceFilename, string targetFilename, int seconds)
{
using (FileStream readStream = new FileStream(sourceFilename, FileMode.Open))
{
using (FileStream writeStream = new FileStream(targetFilename, FileMode.Create, FileAccess.Write, FileShare.None))
{
readStream.CopyTo(writeStream);
System.Threading.Thread.Sleep(seconds * 1000);
}
}
}
}
}