@@ -126,52 +126,48 @@ public void SetMode(FusionArchiveMode mode)
126126
127127 public async Task CommitAsync ( CancellationToken cancellationToken )
128128 {
129- foreach ( var file in _files . Values )
129+ foreach ( var file in _files . Values . OrderBy ( f => f . Path , StringComparer . Ordinal ) )
130130 {
131- #if NET10_0_OR_GREATER
132131 switch ( file . State )
133132 {
134133 case FileState . Created :
135- await _archive . CreateEntryFromFileAsync (
136- file . TempPath ,
137- file . Path ,
138- cancellationToken : cancellationToken ) ;
134+ await CreateEntryFromFileAsync ( file . TempPath , file . Path , cancellationToken ) ;
139135 break ;
140136
141137 case FileState . Replaced :
142138 _archive . GetEntry ( file . Path ) ? . Delete ( ) ;
143- await _archive . CreateEntryFromFileAsync (
144- file . TempPath ,
145- file . Path ,
146- cancellationToken ) ;
139+ await CreateEntryFromFileAsync ( file . TempPath , file . Path , cancellationToken ) ;
147140 break ;
148141
149142 case FileState . Deleted :
150143 _archive . GetEntry ( file . Path ) ? . Delete ( ) ;
151144 break ;
152145 }
153- #else
154- switch ( file . State )
155- {
156- case FileState . Created :
157- _archive . CreateEntryFromFile ( file . TempPath , file . Path ) ;
158- break ;
159146
160- case FileState . Replaced :
161- _archive . GetEntry ( file . Path ) ? . Delete ( ) ;
162- _archive . CreateEntryFromFile ( file . TempPath , file . Path ) ;
163- break ;
147+ file . MarkRead ( ) ;
148+ }
149+ }
164150
165- case FileState . Deleted :
166- _archive . GetEntry ( file . Path ) ? . Delete ( ) ;
167- break ;
168- }
151+ /// <summary>
152+ /// Creates a ZIP entry from a file with a deterministic timestamp.
153+ /// Using a fixed timestamp ensures binary reproducibility of the archive.
154+ /// </summary>
155+ private async Task CreateEntryFromFileAsync (
156+ string sourceFileName ,
157+ string entryName ,
158+ CancellationToken cancellationToken )
159+ {
160+ var entry = _archive . CreateEntry ( entryName ) ;
161+ // Use a fixed timestamp to ensure deterministic archive output
162+ entry . LastWriteTime = new DateTimeOffset ( 2000 , 1 , 1 , 0 , 0 , 0 , TimeSpan . Zero ) ;
169163
170- await Task . CompletedTask ;
164+ await using var source = File . OpenRead ( sourceFileName ) ;
165+ #if NET10_0_OR_GREATER
166+ await using var destination = await entry . OpenAsync ( cancellationToken ) ;
167+ #else
168+ await using var destination = entry . Open ( ) ;
171169#endif
172-
173- file . MarkRead ( ) ;
174- }
170+ await source . CopyToAsync ( destination , cancellationToken ) ;
175171 }
176172
177173 private static async Task ExtractFileAsync (
0 commit comments