33using System . IO ;
44using System . Linq ;
55using An2WinFileTransfer . Enums ;
6+ using An2WinFileTransfer . Interfaces ;
67using An2WinFileTransfer . Models ;
78using MediaDevices ;
89using Newtonsoft . Json ;
@@ -11,29 +12,29 @@ namespace An2WinFileTransfer.Services
1112{
1213 public class BackupService
1314 {
14- private readonly Action < string > _logAction ;
15+ private readonly ILoggingService _logService ;
1516
16- public BackupService ( Action < string > logAction )
17+ public BackupService ( ILoggingService log )
1718 {
18- _logAction = logAction ?? ( _ => { } ) ;
19+ _logService = log ?? throw new ArgumentNullException ( nameof ( log ) ) ;
1920 }
2021
2122 public void BackupFromDevice ( MediaDevice device , string sourcePath , string targetRoot , IEnumerable < FileType > fileTypes , bool copyAllFiles )
2223 {
2324 if ( ! device . DirectoryExists ( sourcePath ) )
2425 {
25- _logAction ( $ "Source folder not found: { sourcePath } ") ;
26+ _logService . Warn ( $ "Source folder not found: { sourcePath } ") ;
2627 return ;
2728 }
2829
2930 var timestampedRootFolder = CreateNewTimeStampedFolder ( targetRoot ) ;
3031
31- _logAction ( "Scanning previous backups..." ) ;
32+ _logService . Info ( "Scanning previous backups..." ) ;
3233
3334 var previousManifests = LoadPreviousManifests ( targetRoot ) ;
3435 var existingFiles = BuildExistingFileMap ( previousManifests ) ;
3536
36- _logAction ( $ "Loaded { existingFiles . Count } entries from previous backups.") ;
37+ _logService . Info ( $ "Loaded { existingFiles . Count } entries from previous backups.") ;
3738
3839 var manifest = new BackupManifest
3940 {
@@ -42,7 +43,7 @@ public void BackupFromDevice(MediaDevice device, string sourcePath, string targe
4243 Files = new List < BackupFileEntry > ( )
4344 } ;
4445
45- _logAction ( "Evaluating files to backup..." ) ;
46+ _logService . Info ( "Evaluating files to backup..." ) ;
4647
4748 var enabledExtensions = new HashSet < string > (
4849 fileTypes . Where ( ft => ft . IsEnabled && ! string . IsNullOrWhiteSpace ( ft . Extension ) )
@@ -68,14 +69,16 @@ public void BackupFromDevice(MediaDevice device, string sourcePath, string targe
6869 processedFileCount ++ ;
6970 var fileInfo = device . GetFileInfo ( file ) ;
7071
71- _logAction ( $ "Processing file { processedFileCount } of { totalFileCount } . Copied: { copiedFileCount } | Skipped: { skippedFileCount } | Failed: { copyFailedFileCount } ") ;
72+ _logService . Info ( $ "Processing file { processedFileCount } of { totalFileCount } . Copied: { copiedFileCount } | Skipped: { skippedFileCount } | Failed: { copyFailedFileCount } ") ;
7273
7374 if ( fileInfo == null )
7475 {
7576 copyFailedFileCount ++ ;
7677 continue ;
7778 }
7879
80+ _logService . Info ( $ "Evaluating file: { file } ") ;
81+
7982 var relativePath = GetRelativePath ( sourcePath , file ) ;
8083
8184 var entry = new BackupFileEntry
@@ -95,7 +98,7 @@ public void BackupFromDevice(MediaDevice device, string sourcePath, string targe
9598 continue ;
9699 }
97100
98- var localPath = Path . Combine ( timestampedRootFolder , relativePath ) ;
101+ var localPath = Path . Combine ( timestampedRootFolder , SanitizePath ( relativePath ) ) ;
99102 Directory . CreateDirectory ( Path . GetDirectoryName ( localPath ) ) ;
100103
101104 // Skip if file already backed up in a previous manifest
@@ -133,7 +136,7 @@ public void BackupFromDevice(MediaDevice device, string sourcePath, string targe
133136 {
134137 entry . CopyStatus = ECopyStatus . Failed ;
135138 copyFailedFileCount ++ ;
136- _logAction ( $ "Error copying { file } : { ex . Message } ") ;
139+ _logService . Error ( $ "Error copying { file } : { ex . Message } ") ;
137140 }
138141 }
139142
@@ -145,14 +148,14 @@ public void BackupFromDevice(MediaDevice device, string sourcePath, string targe
145148 var json = JsonConvert . SerializeObject ( manifest , Formatting . Indented ) ;
146149 File . WriteAllText ( manifestPath , json ) ;
147150
148- _logAction ( $ "Backup manifest saved: { manifestPath } . Backup duration: { manifest . BackupDuration } .") ;
151+ _logService . Info ( $ "Backup manifest saved: { manifestPath } . Backup duration: { manifest . BackupDuration } .") ;
149152 }
150153 catch ( Exception ex )
151154 {
152- _logAction ( $ "Failed to save manifest: { ex . Message } ") ;
155+ _logService . Error ( $ "Failed to save manifest: { ex . Message } ") ;
153156 }
154157
155- _logAction ( $ "Backup completed: Copied={ copiedFileCount } , Skipped={ skippedFileCount } , Failed={ copyFailedFileCount } , Total={ processedFileCount } ") ;
158+ _logService . Info ( $ "Backup completed: Copied={ copiedFileCount } , Skipped={ skippedFileCount } , Failed={ copyFailedFileCount } , Total={ processedFileCount } ") ;
156159 }
157160
158161 private string GetRelativePath ( string basePath , string fullPath )
@@ -215,13 +218,13 @@ private List<BackupManifest> LoadPreviousManifests(string baseBackupPath)
215218 }
216219 catch ( Exception ex )
217220 {
218- _logAction ( $ "Failed to read manifest { file } : { ex . Message } ") ;
221+ _logService . Info ( $ "Failed to read manifest { file } : { ex . Message } ") ;
219222 }
220223 }
221224 }
222225 catch ( Exception ex )
223226 {
224- _logAction ( $ "Error while scanning for manifests: { ex . Message } ") ;
227+ _logService . Error ( $ "Error while scanning for manifests: { ex . Message } ") ;
225228 }
226229
227230 return manifests ;
@@ -244,5 +247,31 @@ private Dictionary<string, BackupFileEntry> BuildExistingFileMap(IEnumerable<Bac
244247
245248 return map ;
246249 }
250+
251+ private string SanitizePath ( string relativePath )
252+ {
253+ foreach ( var pathPart in relativePath . Split ( new [ ] { '\\ ' , '/' } , StringSplitOptions . RemoveEmptyEntries ) )
254+ {
255+ var safePart = SanitizeFileOrFolderName ( pathPart ) ;
256+ relativePath = relativePath . Replace ( pathPart , safePart ) ;
257+ }
258+
259+ return relativePath ;
260+ }
261+
262+ private string SanitizeFileOrFolderName ( string name )
263+ {
264+ var invalidChars = Path . GetInvalidFileNameChars ( )
265+ . Concat ( Path . GetInvalidPathChars ( ) )
266+ . Distinct ( )
267+ . ToArray ( ) ;
268+
269+ var safePath = string . Join ( "_" ,
270+ name . Split ( Path . DirectorySeparatorChar , Path . AltDirectorySeparatorChar )
271+ . Select ( part => string . Concat ( part . Select ( ch => invalidChars . Contains ( ch ) ? '_' : ch ) ) )
272+ ) ;
273+
274+ return safePath ;
275+ }
247276 }
248277}
0 commit comments