1- // Copyright (c) Microsoft Corporation. Licensed under the MIT License.
1+ // Copyright (c) Microsoft Corporation. Licensed under the MIT License.
22
33using Microsoft . CST . RecursiveExtractor ;
4+ using System . Collections . Generic ;
45using System . IO ;
56using System . Linq ;
7+ using System . Runtime . InteropServices ;
68using System . Threading . Tasks ;
79using Xunit ;
810
@@ -144,23 +146,28 @@ public void FileEntry_MetadataDefaultsToNull()
144146 }
145147
146148 [ Fact ]
147- public async Task IsoEntries_MetadataIsNullWithoutRockRidge ( )
149+ public async Task IsoEntries_HaveDosAttributesButNoUnixMetadataWithoutRockRidge ( )
148150 {
149- // TestData.iso does not have RockRidge extensions, so Unix metadata is not available
151+ // TestData.iso has no RockRidge extensions, so Unix metadata is unavailable.
152+ // CDReader still implements IDosFileSystem, so file attributes are reported.
150153 var extractor = new Extractor ( ) ;
151154 var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.iso" ) ;
152155 var results = await extractor . ExtractAsync ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToListAsync ( ) ;
153156
154157 Assert . NotEmpty ( results ) ;
155158 foreach ( var entry in results )
156159 {
157- // Without RockRidge extensions, metadata should be null
158- Assert . Null ( entry . Metadata ) ;
160+ Assert . NotNull ( entry . Metadata ) ;
161+ Assert . Equal ( FileAttributes . ReadOnly , entry . Metadata ! . FileAttributes ) ;
162+ Assert . Null ( entry . Metadata . Mode ) ;
163+ Assert . Null ( entry . Metadata . Uid ) ;
164+ Assert . Null ( entry . Metadata . Gid ) ;
165+ Assert . Null ( entry . Metadata . SecurityDescriptorSddl ) ;
159166 }
160167 }
161168
162169 [ Fact ]
163- public void IsoEntries_MetadataIsNullWithoutRockRidge_Sync ( )
170+ public void IsoEntries_HaveDosAttributesButNoUnixMetadataWithoutRockRidge_Sync ( )
164171 {
165172 var extractor = new Extractor ( ) ;
166173 var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.iso" ) ;
@@ -169,7 +176,12 @@ public void IsoEntries_MetadataIsNullWithoutRockRidge_Sync()
169176 Assert . NotEmpty ( results ) ;
170177 foreach ( var entry in results )
171178 {
172- Assert . Null ( entry . Metadata ) ;
179+ Assert . NotNull ( entry . Metadata ) ;
180+ Assert . Equal ( FileAttributes . ReadOnly , entry . Metadata ! . FileAttributes ) ;
181+ Assert . Null ( entry . Metadata . Mode ) ;
182+ Assert . Null ( entry . Metadata . Uid ) ;
183+ Assert . Null ( entry . Metadata . Gid ) ;
184+ Assert . Null ( entry . Metadata . SecurityDescriptorSddl ) ;
173185 }
174186 }
175187
@@ -181,30 +193,67 @@ public async Task IsoRockRidgeEntries_HaveMetadata()
181193 var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestDataRockRidge.iso" ) ;
182194 var results = await extractor . ExtractAsync ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToListAsync ( ) ;
183195
184- Assert . NotEmpty ( results ) ;
196+ AssertRockRidgeMetadata ( results ) ;
197+ }
198+
199+ [ Fact ]
200+ public void IsoRockRidgeEntries_HaveMetadata_Sync ( )
201+ {
202+ var extractor = new Extractor ( ) ;
203+ var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestDataRockRidge.iso" ) ;
204+ var results = extractor . Extract ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToList ( ) ;
205+
206+ AssertRockRidgeMetadata ( results ) ;
207+ }
208+
209+ private static void AssertRockRidgeMetadata ( IList < FileEntry > results )
210+ {
211+ Assert . Equal ( 2 , results . Count ) ;
185212 foreach ( var entry in results )
186213 {
187214 Assert . NotNull ( entry . Metadata ) ;
188- Assert . NotNull ( entry . Metadata ! . Mode ) ;
189- Assert . NotNull ( entry . Metadata . Uid ) ;
190- Assert . NotNull ( entry . Metadata . Gid ) ;
215+ Assert . Equal ( 1001 , entry . Metadata ! . Uid ) ;
216+ Assert . Equal ( 1001 , entry . Metadata . Gid ) ;
217+ Assert . NotNull ( entry . Metadata . FileAttributes ) ;
191218 }
219+
220+ // testfile.txt is 0755 (493 decimal), subdir/nested.txt is 0644 (420 decimal)
221+ var topLevel = results . Single ( x => x . Name == "testfile.txt" ) ;
222+ Assert . Equal ( 493 , topLevel . Metadata ! . Mode ) ;
223+ Assert . True ( topLevel . Metadata . IsExecutable ) ;
224+
225+ var nested = results . Single ( x => x . Name == "nested.txt" ) ;
226+ Assert . Equal ( 420 , nested . Metadata ! . Mode ) ;
227+ Assert . False ( nested . Metadata . IsExecutable ) ;
192228 }
193229
194230 [ Fact ]
195- public void IsoRockRidgeEntries_HaveMetadata_Sync ( )
231+ public async Task UdfEntries_HaveNoMetadata ( )
196232 {
233+ // UdfReader implements none of the Unix/DOS/Windows file system interfaces,
234+ // so no metadata is available for pure UDF images.
197235 var extractor = new Extractor ( ) ;
198- var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestDataRockRidge.iso" ) ;
236+ var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "UdfTest.iso" ) ;
237+ var results = await extractor . ExtractAsync ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToListAsync ( ) ;
238+
239+ Assert . NotEmpty ( results ) ;
240+ foreach ( var entry in results )
241+ {
242+ Assert . Null ( entry . Metadata ) ;
243+ }
244+ }
245+
246+ [ Fact ]
247+ public void UdfEntries_HaveNoMetadata_Sync ( )
248+ {
249+ var extractor = new Extractor ( ) ;
250+ var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "UdfTest.iso" ) ;
199251 var results = extractor . Extract ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToList ( ) ;
200252
201253 Assert . NotEmpty ( results ) ;
202254 foreach ( var entry in results )
203255 {
204- Assert . NotNull ( entry . Metadata ) ;
205- Assert . NotNull ( entry . Metadata ! . Mode ) ;
206- Assert . NotNull ( entry . Metadata . Uid ) ;
207- Assert . NotNull ( entry . Metadata . Gid ) ;
256+ Assert . Null ( entry . Metadata ) ;
208257 }
209258 }
210259
@@ -216,14 +265,30 @@ public async Task VhdxNtfsEntries_HaveWindowsMetadata()
216265 var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.vhdx" ) ;
217266 var results = await extractor . ExtractAsync ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToListAsync ( ) ;
218267
268+ AssertNtfsMetadata ( results ) ;
269+ }
270+
271+ [ Fact ]
272+ public void VhdxNtfsEntries_HaveWindowsMetadata_Sync ( )
273+ {
274+ var extractor = new Extractor ( ) ;
275+ var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.vhdx" ) ;
276+ var results = extractor . Extract ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToList ( ) ;
277+
278+ AssertNtfsMetadata ( results ) ;
279+ }
280+
281+ private static void AssertNtfsMetadata ( IList < FileEntry > results )
282+ {
219283 Assert . NotEmpty ( results ) ;
220284 foreach ( var entry in results )
221285 {
222286 Assert . NotNull ( entry . Metadata ) ;
223287 // NTFS provides Windows file attributes
224- Assert . NotNull ( entry . Metadata ! . FileAttributes ) ;
288+ Assert . Equal ( FileAttributes . Archive , entry . Metadata ! . FileAttributes ) ;
225289 // NTFS provides security descriptors
226290 Assert . NotNull ( entry . Metadata . SecurityDescriptorSddl ) ;
291+ Assert . Contains ( "O:" , entry . Metadata . SecurityDescriptorSddl ) ; // Owner present
227292 Assert . Contains ( "D:" , entry . Metadata . SecurityDescriptorSddl ) ; // DACL present
228293 // NTFS does not provide Unix metadata
229294 Assert . Null ( entry . Metadata . Mode ) ;
@@ -233,19 +298,48 @@ public async Task VhdxNtfsEntries_HaveWindowsMetadata()
233298 }
234299
235300 [ Fact ]
236- public void VhdxNtfsEntries_HaveWindowsMetadata_Sync ( )
301+ public async Task WimEntries_HaveWindowsFileAttributes ( )
237302 {
303+ // WIM extraction is only supported on Windows
304+ if ( ! RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
305+ {
306+ return ;
307+ }
308+
238309 var extractor = new Extractor ( ) ;
239- var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.vhdx" ) ;
310+ var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.wim" ) ;
311+ var results = await extractor . ExtractAsync ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToListAsync ( ) ;
312+
313+ AssertWimMetadata ( results ) ;
314+ }
315+
316+ [ Fact ]
317+ public void WimEntries_HaveWindowsFileAttributes_Sync ( )
318+ {
319+ if ( ! RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
320+ {
321+ return ;
322+ }
323+
324+ var extractor = new Extractor ( ) ;
325+ var path = Path . Combine ( Directory . GetCurrentDirectory ( ) , "TestData" , "TestDataArchives" , "TestData.wim" ) ;
240326 var results = extractor . Extract ( path , new ExtractorOptions ( ) { Recurse = false } ) . ToList ( ) ;
241327
328+ AssertWimMetadata ( results ) ;
329+ }
330+
331+ private static void AssertWimMetadata ( IList < FileEntry > results )
332+ {
242333 Assert . NotEmpty ( results ) ;
243334 foreach ( var entry in results )
244335 {
245336 Assert . NotNull ( entry . Metadata ) ;
246- Assert . NotNull ( entry . Metadata ! . FileAttributes ) ;
247- Assert . NotNull ( entry . Metadata . SecurityDescriptorSddl ) ;
337+ Assert . Equal ( FileAttributes . Archive , entry . Metadata ! . FileAttributes ) ;
248338 Assert . Null ( entry . Metadata . Mode ) ;
339+ Assert . Null ( entry . Metadata . Uid ) ;
340+ Assert . Null ( entry . Metadata . Gid ) ;
341+ // This WIM records no security descriptors, so an empty SDDL is normalized to null
342+ Assert . Null ( entry . Metadata . SecurityDescriptorSddl ) ;
249343 }
250344 }
251345}
0 commit comments