// 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.Data; using System.Security.AccessControl; namespace Spludlow.Io { public class Dirs { public static string UniqueExistingName(string directoryName) { if (Directory.Exists(directoryName) == false) return directoryName; int existingCount = 2; string originalDirectoryName = directoryName; while (Directory.Exists(directoryName) == true) { directoryName = originalDirectoryName + " (" + existingCount + ")"; ++existingCount; } return directoryName; } public static void DeletePersistently(string directoryName) { int attempts = 6; int wait = 1000; for (int attempt = 0; attempt < attempts; ++attempt) { if (attempt > 0) System.Threading.Thread.Sleep(attempt * wait); try { if (Directory.Exists(directoryName) == false) break; Directory.Delete(directoryName, true); } catch (IOException ee) { Spludlow.Log.Warning("Delete Directory Persistently IOException\t" + directoryName, ee); } catch (System.UnauthorizedAccessException ee) { Spludlow.Log.Warning("Delete Directory Persistently UnauthorizedAccessException\t" + directoryName, ee); } } } public static void Copy(string sourceDirectoryName, string targetDirectoryName) { Directory.CreateDirectory(targetDirectoryName); DirectoryInfo source = new DirectoryInfo(sourceDirectoryName); DirectoryInfo target = new DirectoryInfo(targetDirectoryName); CopyWork(source, target); } private static void CopyWork(DirectoryInfo source, DirectoryInfo target) { foreach (DirectoryInfo dir in source.GetDirectories()) CopyWork(dir, target.CreateSubdirectory(dir.Name)); foreach (FileInfo file in source.GetFiles()) file.CopyTo(Path.Combine(target.FullName, file.Name)); } public static string[] GetDirectories(string directoryName) { return GetDirectories(directoryName, false); } public static string[] GetDirectories(string directoryName, bool excludeSelf) { string[] subDirs = Directory.GetDirectories(directoryName, "*", SearchOption.AllDirectories); if (excludeSelf == true) return subDirs; List result = new List(); result.Add(directoryName); foreach (string subDir in subDirs) result.Add(subDir); return result.ToArray(); } public static string[] GetFiles(string directoryName) { return GetContents(directoryName)[1]; } public static string[][] GetContents(string directoryName) // Don;t like !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! { List dirs = new List(); List files = new List(); foreach (FileSystemInfo info in GetInfos(directoryName)) { if (info is DirectoryInfo) dirs.Add(info.FullName); else if (info is FileInfo) files.Add(info.FullName); else throw new ApplicationException("Unexpected direectory info type:\t" + info.FullName + ",\t" + info.GetType().Name); } return new string[][] { dirs.ToArray(), files.ToArray() }; } public static FileSystemInfo[] GetInfos(string directoryName) { List list = new List(); DirectoryInfo directoryInfo = new DirectoryInfo(directoryName); GetInfosWork(directoryInfo, list); return list.ToArray(); } private static void GetInfosWork(DirectoryInfo directoryInfo, List list) { list.Add(directoryInfo); foreach (FileSystemInfo fsInfo in directoryInfo.GetFileSystemInfos()) { if (fsInfo is DirectoryInfo) GetInfosWork((DirectoryInfo)fsInfo, list); else list.Add(fsInfo); } } private static string TargetDirectory(string sourceDirectory, string targetDirectory) { if (targetDirectory == null) targetDirectory = sourceDirectory + "." + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"); if (Directory.Exists(targetDirectory) == true) Directory.Delete(targetDirectory, true); Directory.CreateDirectory(targetDirectory); return targetDirectory; } public static void CollectSeries(string sourceDirectory, string targetDirectory) { targetDirectory = TargetDirectory(sourceDirectory, targetDirectory); Dictionary> series = new Dictionary>(); foreach (string sourceFilename in Directory.GetFiles(sourceDirectory)) { string filename = Path.GetFileNameWithoutExtension(sourceFilename).ToLower(); for (int index = 0; index < filename.Length; ++index) { char ch = filename[index]; if (Char.IsDigit(ch) == true) { if (index == 0) throw new ApplicationException("First Char is digit:\t" + sourceFilename); string seriesName = filename.Substring(0, index); if (series.ContainsKey(seriesName) == false) series.Add(seriesName, new List()); series[seriesName].Add(sourceFilename); break; } } } foreach (string seriesKey in series.Keys) { string subDirectory = targetDirectory + @"\" + seriesKey; Directory.CreateDirectory(subDirectory); foreach (string sourceFilename in series[seriesKey]) { string targetFilename = subDirectory + @"\" + Path.GetFileName(sourceFilename); System.IO.File.Copy(sourceFilename, targetFilename); } } } public static void ExtractSeries(string sourceDirectory, string targetDirectory) { targetDirectory = TargetDirectory(sourceDirectory, targetDirectory); string[][] contents = GetContents(sourceDirectory); string[] sourceFilenames = contents[1]; foreach (string sourceFilename in sourceFilenames) { string ext = Path.GetExtension(sourceFilename).ToLower(); if (ext != ".7z" && ext != ".zip" && ext != ".rar") continue; string zipDir = sourceFilename.Substring(sourceDirectory.Length); zipDir = zipDir.Substring(0, zipDir.LastIndexOf(".")); string subDirectory = targetDirectory + zipDir; Directory.CreateDirectory(subDirectory); using (Spludlow.TempDirectory tempDir = new TempDirectory()) { try { Archive.Extract(sourceFilename, tempDir.Path); } catch // (Exception ee) { // Log continue; } string[][] zipContents = GetContents(tempDir.Path); string[] zipFilenames = zipContents[1]; foreach (string zipFilename in zipFilenames) { string targetFilename = subDirectory + @"\" + Path.GetFileName(zipFilename); if (File.Exists(targetFilename) == true) throw new ApplicationException("Dulplicate filenames in archive:\t" + targetFilename); File.Copy(zipFilename, targetFilename); } } } } public static DataTable IndexDirectory(string directoryName, string indexFilename) { DataTable table = IndexDirectory(directoryName); Spludlow.Data.TextTable.Write(indexFilename, table); return table; } public static DataTable IndexDirectory(string directoryName) { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "FullName Size LastWriteTime FsType Checksum", "String* Int64 DateTime String String", }); DirectoryInfo directoryInfo = new DirectoryInfo(directoryName); GetIndexTableWork(table, directoryInfo); return table; } private static void GetIndexTableWork( DataTable table, DirectoryInfo directoryInfo) { AddIndexRow(table, directoryInfo); foreach (FileSystemInfo fsInfo in directoryInfo.GetFileSystemInfos()) { if (fsInfo is DirectoryInfo) GetIndexTableWork(table, (DirectoryInfo)fsInfo); else AddIndexRow(table, fsInfo); } } private static void AddIndexRow(DataTable table, FileSystemInfo fsInfo) { char fsType = fsInfo.GetType().Name[0]; switch (fsType) { case 'F': FileInfo fileInfo = (FileInfo)fsInfo; string checksum = Spludlow.Io.Files.HashMD5(fileInfo.FullName); table.Rows.Add(new object[] { fileInfo.FullName, fileInfo.Length, fileInfo.LastWriteTime, "F", checksum }); break; case 'D': DirectoryInfo dirInfo = (DirectoryInfo)fsInfo; table.Rows.Add(new object[] { dirInfo.FullName, 0, dirInfo.LastWriteTime, "D", "" }); break; default: throw new ApplicationException("Unsupported FS type:\t" + fsInfo.GetType().Name); } } public static void CopyUniqueFiles(string indexFilename, string targetDirectory) { DataTable table = Spludlow.Data.TextTable.ReadFile(indexFilename); DataView view = new DataView(table); view.RowFilter = "Size > 0 AND FsType = 'F'"; view.Sort = "LastWriteTime, FullName"; List sums = new List(); foreach (DataRowView rowView in view) { DataRow row = rowView.Row; string checksum = (string)row["Checksum"]; if (sums.Contains(checksum) == true) continue; sums.Add(checksum); string sourceFilename = (string)row["FullName"]; string name; try { name = Path.GetFileName(sourceFilename); } catch (Exception ee) { Console.WriteLine(ee.Message + "\t" + sourceFilename); continue; } string targetName = targetDirectory + @"\" + name; targetName = Spludlow.Io.Files.UniqueExistingName(targetName); File.Copy(sourceFilename, targetName); } } public static void CopyAndDateFiles(string indexFilename, string targetDirectory) { DataTable table = Spludlow.Data.TextTable.ReadFile(indexFilename); if (table.Rows.Count == 0) return; string sourceDirectory = (string)table.Rows[0]["FullName"]; targetDirectory = TargetDirectory(sourceDirectory, targetDirectory); DataView view = new DataView(table); view.RowFilter = "Size > 0 AND FsType = 'F'"; view.Sort = "LastWriteTime, FullName"; List sums = new List(); //List dates = new List(); foreach (DataRowView rowView in view) { DataRow row = rowView.Row; string checksum = (string)row["Checksum"]; if (sums.Contains(checksum) == true) continue; //string dateDirectory = targetDirectory + @"\" + ((DateTime)row["LastWriteTime"]).ToString("yyyy-MM"); //-dd"); //if (dates.Contains(dateDirectory) == false) //{ // Directory.CreateDirectory(dateDirectory); // dates.Add(dateDirectory); //} string fullname = (string)row["FullName"]; //string ext = Path.GetExtension(fullname).ToLower(); sums.Add(checksum); int index = fullname.LastIndexOf('\\'); if (index == -1) throw new ApplicationException("Bad pathname:\t" + fullname); string filename = fullname.Substring(index + 1); try { //string targetFilename = Spludlow.Io.Files.UniqueExistingFilename(dateDirectory + @"\" + filename); string targetFilename = Spludlow.Io.Files.UniqueExistingName(targetDirectory + @"\" + filename); File.Copy(fullname, targetFilename); } catch (Exception ee) { Console.WriteLine(ee.Message + "\t" + fullname); } } } public static void AddSecurityFullControl(string directoryName, string identity) { AddSecurity(directoryName, identity, FileSystemRights.FullControl, AccessControlType.Allow); } public static void AddSecurity(string directoryName, string identity, FileSystemRights rights, AccessControlType controlType) { InheritanceFlags inheritanceFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit; DirectoryInfo dirInfo = new DirectoryInfo(directoryName); DirectorySecurity security = dirInfo.GetAccessControl(); FileSystemAccessRule rule = new FileSystemAccessRule(identity, rights, inheritanceFlags, PropagationFlags.None, controlType); security.AddAccessRule(rule); dirInfo.SetAccessControl(security); } } }