From 8ac5891d46f00d10af7010c220402ced878f805f Mon Sep 17 00:00:00 2001
From: Flo <62435410+FRFlo@users.noreply.github.com>
Date: Mon, 11 Mar 2024 14:53:09 +0100
Subject: [PATCH 1/6] feat: Added CopyFilter
---
Copy/Types/CopyFilter.cs | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Copy/Types/CopyFilter.cs
diff --git a/Copy/Types/CopyFilter.cs b/Copy/Types/CopyFilter.cs
new file mode 100644
index 0000000..4dc25a1
--- /dev/null
+++ b/Copy/Types/CopyFilter.cs
@@ -0,0 +1,36 @@
+using Newtonsoft.Json;
+
+namespace Copy.Types
+{
+ ///
+ /// Filter for files to copy.
+ ///
+ public class CopyFilter
+ {
+ ///
+ /// Pattern the name of the files must match.
+ ///
+ [JsonProperty(PropertyName = "Name", Required = Required.DisallowNull)]
+ public string Name { get; set; } = ".*";
+ ///
+ /// Pattern the author of the files must match.
+ ///
+ [JsonProperty(PropertyName = "Author", Required = Required.DisallowNull)]
+ public string Author { get; set; } = ".*";
+ ///
+ /// Date the files must be created after.
+ ///
+ [JsonProperty(PropertyName = "CreatedAfter", Required = Required.DisallowNull)]
+ public DateTime CreatedAfter { get; set; } = DateTime.MinValue;
+ ///
+ /// Size the files must not exceed.
+ ///
+ [JsonProperty(PropertyName = "MaxSize", Required = Required.DisallowNull)]
+ public ulong MaxSize { get; set; } = ulong.MaxValue;
+ ///
+ /// Size the files must exceed.
+ ///
+ [JsonProperty(PropertyName = "MinSize", Required = Required.DisallowNull)]
+ public ulong MinSize { get; set; } = 0;
+ }
+}
From 3c433e44e8f4265cb23635d75be005125441fb64 Mon Sep 17 00:00:00 2001
From: Flo <62435410+FRFlo@users.noreply.github.com>
Date: Mon, 11 Mar 2024 14:59:33 +0100
Subject: [PATCH 2/6] feat(CopyTask.cs): Changed type of Filter property
---
Copy/Types/CopyTask.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Copy/Types/CopyTask.cs b/Copy/Types/CopyTask.cs
index 75cb2e9..b95ced9 100644
--- a/Copy/Types/CopyTask.cs
+++ b/Copy/Types/CopyTask.cs
@@ -31,6 +31,6 @@ public class CopyTask
/// Filter for files to copy.
///
[JsonProperty(PropertyName = "Filter", Required = Required.DisallowNull)]
- public string Filter { get; set; } = ".*";
+ public CopyFilter Filter { get; set; } = new();
}
}
\ No newline at end of file
From 07815414929d0db4c76253107302b0403a2a46a9 Mon Sep 17 00:00:00 2001
From: Flo <62435410+FRFlo@users.noreply.github.com>
Date: Mon, 11 Mar 2024 14:59:50 +0100
Subject: [PATCH 3/6] feat(IClient.cs): Added filter to the list files method
---
Copy/Types/IClient.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Copy/Types/IClient.cs b/Copy/Types/IClient.cs
index 8b5a3fd..bd0a0a7 100644
--- a/Copy/Types/IClient.cs
+++ b/Copy/Types/IClient.cs
@@ -13,8 +13,9 @@ internal interface IClient : IDisposable
/// List files in a directory.
///
/// Path to the directory.
+ /// Filter for files to list.
/// Array of file names.
- string[] ListFiles(string path);
+ string[] ListFiles(string path, CopyFilter filter);
///
/// Check if a file exists.
///
From 540e16178b7455694f0214fc526a0279932da754 Mon Sep 17 00:00:00 2001
From: Flo <62435410+FRFlo@users.noreply.github.com>
Date: Mon, 11 Mar 2024 15:02:52 +0100
Subject: [PATCH 4/6] feat(Config.cs): Conversion to new Filter
---
Copy/Config.cs | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/Copy/Config.cs b/Copy/Config.cs
index 42c07de..093f2ba 100644
--- a/Copy/Config.cs
+++ b/Copy/Config.cs
@@ -111,7 +111,10 @@ public static string GetDefault()
Source = "source",
Destination = "destination",
Client = "SFTP",
- Filter = "*.txt"
+ Filter = new CopyFilter()
+ {
+ Name = ".*\\.txt"
+ }
},
new CopyTask()
{
@@ -119,7 +122,10 @@ public static string GetDefault()
Destination = "destination",
Client = "Local",
Delete = true,
- Filter = "*.txt"
+ Filter = new CopyFilter()
+ {
+ Name = ".*\\.txt"
+ }
},
new CopyTask()
{
From 594c48ef8f53f719c3bccdd133a15eaebbbeaa57 Mon Sep 17 00:00:00 2001
From: Flo <62435410+FRFlo@users.noreply.github.com>
Date: Mon, 11 Mar 2024 16:38:59 +0100
Subject: [PATCH 5/6] feat(Clients): New implementation
---
Copy/Clients/Exchange.cs | 2 +-
Copy/Clients/FTP.cs | 10 ++++++++--
Copy/Clients/Local.cs | 18 ++++++++++++++++--
Copy/Clients/SFTP.cs | 11 +++++++++--
Copy/Types/Exceptions.cs | 8 ++++++++
5 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/Copy/Clients/Exchange.cs b/Copy/Clients/Exchange.cs
index f47cf44..e2847bd 100644
--- a/Copy/Clients/Exchange.cs
+++ b/Copy/Clients/Exchange.cs
@@ -35,7 +35,7 @@ public bool DoFileExist(string path)
throw new NotImplementedException();
}
- public string[] ListFiles(string path)
+ public string[] ListFiles(string path, CopyFilter filter)
{
throw new NotImplementedException();
}
diff --git a/Copy/Clients/FTP.cs b/Copy/Clients/FTP.cs
index d5c53f9..151500b 100644
--- a/Copy/Clients/FTP.cs
+++ b/Copy/Clients/FTP.cs
@@ -1,6 +1,7 @@
using Copy.Types;
using FluentFTP;
using System.Net;
+using System.Text.RegularExpressions;
namespace Copy.Clients
{
@@ -37,7 +38,7 @@ public bool DoFileExist(string path)
return FtpClient.FileExists(path);
}
- public string[] ListFiles(string path)
+ public string[] ListFiles(string path, CopyFilter filter)
{
if (!FtpClient.DirectoryExists(path))
{
@@ -45,7 +46,12 @@ public string[] ListFiles(string path)
throw new DirectoryNotFoundException($"Directory {path} does not exist");
}
- FtpListItem[] files = FtpClient.GetListing(path);
+ Regex nameRegex = new(filter.Name);
+ Regex authorRegex = new(filter.Author);
+
+ FtpListItem[] files = FtpClient.GetListing(path)
+ .Where(f => nameRegex.IsMatch(f.Name) && authorRegex.IsMatch(f.RawOwner) && f.Created >= filter.CreatedAfter && (ulong)f.Size <= filter.MaxSize && (ulong)f.Size >= filter.MinSize)
+ .ToArray();
return files.Select(f => Path.Combine(path, f.Name)).ToArray();
}
diff --git a/Copy/Clients/Local.cs b/Copy/Clients/Local.cs
index 1835dd6..64f6372 100644
--- a/Copy/Clients/Local.cs
+++ b/Copy/Clients/Local.cs
@@ -1,4 +1,7 @@
using Copy.Types;
+using System.Runtime.Versioning;
+using System.Security.Principal;
+using System.Text.RegularExpressions;
namespace Copy.Clients
{
@@ -28,7 +31,8 @@ public bool DoFileExist(string path)
return File.Exists(path);
}
- public string[] ListFiles(string path)
+ [SupportedOSPlatform("windows")]
+ public string[] ListFiles(string path, CopyFilter filter)
{
if (!Directory.Exists(path))
{
@@ -36,7 +40,17 @@ public string[] ListFiles(string path)
throw new DirectoryNotFoundException($"Directory {path} does not exist");
}
- return Directory.GetFiles(path);
+ Regex nameRegex = new(filter.Name);
+ Regex authorRegex = new(filter.Author);
+
+ return Directory.GetFiles(path)
+ .Where(f =>
+ {
+ FileInfo fileInfo = new(f);
+ bool authorMatch = authorRegex.IsMatch(fileInfo.GetAccessControl().GetOwner(typeof(NTAccount))?.Value ?? throw new FileOwnerNotFoundException($"Impossible to get owner of {f}"));
+ return nameRegex.IsMatch(Path.GetFileName(f)) && authorMatch && File.GetCreationTime(f) >= filter.CreatedAfter && (ulong)fileInfo.Length <= filter.MaxSize && (ulong)fileInfo.Length >= filter.MinSize;
+ })
+ .ToArray();
}
public Stream GetFile(string path)
diff --git a/Copy/Clients/SFTP.cs b/Copy/Clients/SFTP.cs
index 80c004e..d057a70 100644
--- a/Copy/Clients/SFTP.cs
+++ b/Copy/Clients/SFTP.cs
@@ -1,5 +1,6 @@
using Copy.Types;
using Renci.SshNet;
+using System.Text.RegularExpressions;
namespace Copy.Clients
{
@@ -23,7 +24,7 @@ public SFTP(Client credentials)
SftpClient.Connect();
}
- public string[] ListFiles(string path)
+ public string[] ListFiles(string path, CopyFilter filter)
{
if (!SftpClient.Exists(path))
{
@@ -31,7 +32,13 @@ public string[] ListFiles(string path)
throw new DirectoryNotFoundException($"Directory {path} does not exist");
}
- var files = SftpClient.ListDirectory(path);
+ if (filter.Author != ".*") Logger.Warn($"Filtering by author is not supported by SFTP");
+
+ Regex nameRegex = new(filter.Name);
+ Regex authorRegex = new(filter.Author);
+
+ var files = SftpClient.ListDirectory(path)
+ .Where(f => nameRegex.IsMatch(f.Name) && f.LastWriteTime >= filter.CreatedAfter && (ulong)f.Length <= filter.MaxSize && (ulong)f.Length >= filter.MinSize);
return files.Select(f => f.FullName.Remove(0, 1)).ToArray();
}
diff --git a/Copy/Types/Exceptions.cs b/Copy/Types/Exceptions.cs
index b40414f..fb70a2a 100644
--- a/Copy/Types/Exceptions.cs
+++ b/Copy/Types/Exceptions.cs
@@ -7,4 +7,12 @@
internal class ClientNotFoundException(string message) : Exception(message)
{
}
+
+ ///
+ /// Exception thrown when a file owner is not found.
+ ///
+ /// The message to display.
+ internal class FileOwnerNotFoundException(string message) : Exception(message)
+ {
+ }
}
From 557e8c89f917cca14c17074ce7648df9e5c2b1b0 Mon Sep 17 00:00:00 2001
From: Flo <62435410+FRFlo@users.noreply.github.com>
Date: Mon, 11 Mar 2024 16:39:16 +0100
Subject: [PATCH 6/6] feat(Program.cs): New filter system
---
Copy/Program.cs | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/Copy/Program.cs b/Copy/Program.cs
index 05eae99..9fcc73b 100644
--- a/Copy/Program.cs
+++ b/Copy/Program.cs
@@ -1,6 +1,5 @@
using Copy.Clients;
using Copy.Types;
-using System.Text.RegularExpressions;
namespace Copy
{
@@ -63,10 +62,9 @@ public static void Main(string[] args)
throw new ClientNotFoundException($"Client {task.Source} not found");
}
- Regex filter = new(task.Filter);
- IEnumerable files = client.ListFiles(task.Source).Where(f => filter.IsMatch(f));
+ string[] files = client.ListFiles(task.Source, task.Filter);
- Logger.Info($"Treating {files.Count()} files");
+ Logger.Info($"Treating {files.Length} files");
foreach (string file in files)
{
@@ -86,7 +84,7 @@ public static void Main(string[] args)
Logger.Debug($"Copied {file} to {task.Destination}");
}
- Logger.Info($"Copied {files.Count()} files from {task.Source} to {task.Destination} using {task.Client}");
+ Logger.Info($"Copied {files.Length} files from {task.Source} to {task.Destination} using {task.Client}");
}
Logger.Info("All tasks executed");