77var daybreakExecutable = OperatingSystem . IsWindows ( ) ? "Daybreak.exe" : "Daybreak" ;
88var daybreakProcessName = "Daybreak" ;
99var releaseAssetSuffix = OperatingSystem . IsWindows ( ) ? "" : "-linux" ;
10+ var installerExtension = OperatingSystem . IsWindows ( ) ? ".exe" : "" ;
11+
12+ // Paths relative to the zip root that should be skipped during extraction
13+ // These are the installer executables that may be currently running
14+ var skipEntriesOnExtract = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
15+ {
16+ $ "Installer/Daybreak.Installer{ installerExtension } ",
17+ $ "Installer/Daybreak.Installer.Temp{ installerExtension } ",
18+ } ;
1019
1120static void RenderProgressBar ( int currentStep , int totalSteps , int barSize )
1221{
@@ -23,18 +32,64 @@ static void RenderProgressBar(int currentStep, int totalSteps, int barSize)
2332 Console . Write ( $ "{ pctComplete : P0} ") ; // Display the percentage completed
2433}
2534
26- static void CleanWorkingDirectory ( string workingDirectory )
35+ static void ExtractZipSkippingEntries ( string zipPath , string destinationDirectory , HashSet < string > skipEntries )
36+ {
37+ using var archive = ZipFile . OpenRead ( zipPath ) ;
38+ foreach ( var entry in archive . Entries )
39+ {
40+ // Normalize entry path separators
41+ var entryPath = entry . FullName . Replace ( '\\ ' , '/' ) ;
42+
43+ // Skip entries in the skip list
44+ if ( skipEntries . Any ( skip => entryPath . Equals ( skip , StringComparison . OrdinalIgnoreCase ) ) )
45+ {
46+ Console . WriteLine ( $ "Skipping: { entry . FullName } ") ;
47+ continue ;
48+ }
49+
50+ var destinationPath = Path . GetFullPath ( Path . Combine ( destinationDirectory , entry . FullName ) ) ;
51+
52+ // Ensure the destination is within the target directory (security check)
53+ if ( ! destinationPath . StartsWith ( Path . GetFullPath ( destinationDirectory ) , StringComparison . OrdinalIgnoreCase ) )
54+ {
55+ continue ;
56+ }
57+
58+ // If entry is a directory, create it
59+ if ( entry . FullName . EndsWith ( '/' ) || entry . FullName . EndsWith ( '\\ ' ) )
60+ {
61+ Directory . CreateDirectory ( destinationPath ) ;
62+ }
63+ else
64+ {
65+ // Ensure parent directory exists
66+ var parentDir = Path . GetDirectoryName ( destinationPath ) ;
67+ if ( ! string . IsNullOrEmpty ( parentDir ) )
68+ {
69+ Directory . CreateDirectory ( parentDir ) ;
70+ }
71+
72+ entry . ExtractToFile ( destinationPath , overwrite : true ) ;
73+ }
74+ }
75+ }
76+
77+ static void CleanWorkingDirectory ( string workingDirectory , string installerExtension )
2778{
2879 if ( ! Directory . Exists ( workingDirectory ) )
2980 {
3081 return ;
3182 }
3283
33- var installerPath = Path . GetFullPath ( Path . Combine ( workingDirectory , "Installer" ) ) ;
84+ var installerFolder = Path . GetFullPath ( Path . Combine ( workingDirectory , "Installer" ) ) ;
85+ var installerPath = Path . GetFullPath ( Path . Combine ( installerFolder , $ "Daybreak.Installer{ installerExtension } ") ) ;
86+ var installerTempPath = Path . GetFullPath ( Path . Combine ( installerFolder , $ "Daybreak.Installer.Temp{ installerExtension } ") ) ;
3487 var optionsPath = Path . GetFullPath ( Path . Combine ( workingDirectory , "Daybreak.options" ) ) ;
3588 var preserve = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
3689 {
90+ installerFolder ,
3791 installerPath ,
92+ installerTempPath ,
3893 optionsPath ,
3994 } ;
4095 var preserveExtensions = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) { ".tpf" } ;
@@ -149,7 +204,7 @@ async ValueTask PerformUpdate(string workingDirectory)
149204 Console . WriteLine ( "Unpacking files..." ) ;
150205 try
151206 {
152- ZipFile . ExtractToDirectory ( tempFile , Path . GetFullPath ( workingDirectory ) , true ) ;
207+ ExtractZipSkippingEntries ( tempFile , Path . GetFullPath ( workingDirectory ) , skipEntriesOnExtract ) ;
153208 }
154209 catch { }
155210
@@ -224,7 +279,7 @@ or HttpStatusCode.TemporaryRedirect
224279 var tempFile = Path . GetFullPath ( "tempfile.zip" , workingDirectory ) ;
225280
226281 Console . WriteLine ( $ "Cleaning installation directory { workingDirectory } ") ;
227- CleanWorkingDirectory ( workingDirectory ) ;
282+ CleanWorkingDirectory ( workingDirectory , installerExtension ) ;
228283
229284 Console . WriteLine ( $ "Downloading Daybreak { version } ...") ;
230285
@@ -272,7 +327,7 @@ or HttpStatusCode.TemporaryRedirect
272327 Console . WriteLine ( "\n Download complete. Extracting files..." ) ;
273328 try
274329 {
275- ZipFile . ExtractToDirectory ( tempFile , Path . GetFullPath ( workingDirectory ) , true ) ;
330+ ExtractZipSkippingEntries ( tempFile , Path . GetFullPath ( workingDirectory ) , skipEntriesOnExtract ) ;
276331 }
277332 catch ( Exception e )
278333 {
0 commit comments