@@ -48,6 +48,8 @@ protected override async ValueTask DeleteCoreAsync(CancellationToken cancellatio
4848 BucketName = _fs . BucketName
4949 } ;
5050
51+ dr . Objects ??= [ ] ;
52+
5153 do
5254 {
5355 // The maximum number of objects returned is MaxKeys, which is 1000,
@@ -59,8 +61,9 @@ protected override async ValueTask DeleteCoreAsync(CancellationToken cancellatio
5961 . ListObjectsV2Async ( lr , cancellationToken )
6062 . ConfigureAwait ( false ) ;
6163
62- foreach ( var obj in response . S3Objects )
63- dr . Objects . Add ( new KeyVersion { Key = obj . Key } ) ;
64+ if ( response . S3Objects is not null )
65+ foreach ( var obj in response . S3Objects )
66+ dr . Objects . Add ( new KeyVersion { Key = obj . Key } ) ;
6467
6568 if ( dr . Objects . Count != 0 )
6669 await _fs . AmazonClient
@@ -89,11 +92,13 @@ protected override async IAsyncEnumerable<VirtualNode> GetFileNodesCoreAsync([En
8992 . ListObjectsV2Async ( request , cancellationToken )
9093 . ConfigureAwait ( false ) ;
9194
92- foreach ( var prefix in response . CommonPrefixes )
93- yield return new S3Directory ( _fs , VirtualPath . Normalize ( prefix ) ) ;
95+ if ( response . CommonPrefixes is not null )
96+ foreach ( var prefix in response . CommonPrefixes )
97+ yield return new S3Directory ( _fs , VirtualPath . Normalize ( prefix ) ) ;
9498
95- foreach ( var obj in response . S3Objects )
96- yield return CreateVirtualFile ( obj ) ;
99+ if ( response . S3Objects is not null )
100+ foreach ( var obj in response . S3Objects )
101+ yield return CreateVirtualFile ( obj ) ;
97102
98103 request . ContinuationToken = response . NextContinuationToken ;
99104 }
@@ -116,8 +121,9 @@ protected override async IAsyncEnumerable<VirtualFile> GetFilesCoreAsync([Enumer
116121 . ListObjectsV2Async ( request , cancellationToken )
117122 . ConfigureAwait ( false ) ;
118123
119- foreach ( var obj in response . S3Objects )
120- yield return CreateVirtualFile ( obj ) ;
124+ if ( response . S3Objects is not null )
125+ foreach ( var obj in response . S3Objects )
126+ yield return CreateVirtualFile ( obj ) ;
121127
122128 request . ContinuationToken = response . NextContinuationToken ;
123129 }
@@ -140,8 +146,9 @@ protected override async IAsyncEnumerable<VirtualDirectory> GetDirectoriesCoreAs
140146 . ListObjectsV2Async ( request , cancellationToken )
141147 . ConfigureAwait ( false ) ;
142148
143- foreach ( var prefix in response . CommonPrefixes )
144- yield return new S3Directory ( _fs , VirtualPath . Normalize ( prefix ) ) ;
149+ if ( response . CommonPrefixes is not null )
150+ foreach ( var prefix in response . CommonPrefixes )
151+ yield return new S3Directory ( _fs , VirtualPath . Normalize ( prefix ) ) ;
145152
146153 request . ContinuationToken = response . NextContinuationToken ;
147154 }
@@ -179,28 +186,31 @@ protected override async IAsyncEnumerable<VirtualNode> GetFileNodesCoreAsync(str
179186 . ListObjectsV2Async ( request , cancellationToken )
180187 . ConfigureAwait ( false ) ;
181188
182- foreach ( var obj in response . S3Objects )
189+ if ( response . S3Objects is not null )
183190 {
184- var path = VirtualPath . Normalize ( obj . Key ) ;
185- var directoryPath = VirtualPath . GetDirectoryName ( path ) ;
186-
187- while ( directoryPath . Length != 0 && directories . Add ( directoryPath ) )
191+ foreach ( var obj in response . S3Objects )
188192 {
189- //
190- // Directories are yielded in reverse order (deepest first).
191- //
192- // Note: We could use a Stack<string> to control the order,
193- // but since order isn't guaranteed anyway and to avoid
194- // unnecessary memory allocation, we process them directly.
195- //
196- if ( IsMatched ( directoryPath . AsSpan ( FullName . Length ) , patterns , excludes ) )
197- yield return new S3Directory ( _fs , directoryPath ) ;
198-
199- directoryPath = VirtualPath . GetDirectoryName ( directoryPath ) ;
193+ var path = VirtualPath . Normalize ( obj . Key ) ;
194+ var directoryPath = VirtualPath . GetDirectoryName ( path ) ;
195+
196+ while ( directoryPath . Length != 0 && directories . Add ( directoryPath ) )
197+ {
198+ //
199+ // Directories are yielded in reverse order (deepest first).
200+ //
201+ // Note: We could use a Stack<string> to control the order,
202+ // but since order isn't guaranteed anyway and to avoid
203+ // unnecessary memory allocation, we process them directly.
204+ //
205+ if ( IsMatched ( directoryPath . AsSpan ( FullName . Length ) , patterns , excludes ) )
206+ yield return new S3Directory ( _fs , directoryPath ) ;
207+
208+ directoryPath = VirtualPath . GetDirectoryName ( directoryPath ) ;
209+ }
210+
211+ if ( IsMatched ( obj . Key . AsSpan ( request . Prefix . Length ) , patterns , excludes ) )
212+ yield return CreateVirtualFile ( obj , path ) ;
200213 }
201-
202- if ( IsMatched ( obj . Key . AsSpan ( request . Prefix . Length ) , patterns , excludes ) )
203- yield return CreateVirtualFile ( obj , path ) ;
204214 }
205215
206216 request . ContinuationToken = response . NextContinuationToken ;
@@ -234,9 +244,10 @@ protected override async IAsyncEnumerable<VirtualFile> GetFilesCoreAsync(string[
234244 . ListObjectsV2Async ( request , cancellationToken )
235245 . ConfigureAwait ( false ) ;
236246
237- foreach ( var obj in response . S3Objects )
238- if ( IsMatched ( obj . Key . AsSpan ( request . Prefix . Length ) , patterns , excludes ) )
239- yield return CreateVirtualFile ( obj ) ;
247+ if ( response . S3Objects is not null )
248+ foreach ( var obj in response . S3Objects )
249+ if ( IsMatched ( obj . Key . AsSpan ( request . Prefix . Length ) , patterns , excludes ) )
250+ yield return CreateVirtualFile ( obj ) ;
240251
241252 request . ContinuationToken = response . NextContinuationToken ;
242253 }
@@ -274,24 +285,27 @@ protected override async IAsyncEnumerable<VirtualDirectory> GetDirectoriesCoreAs
274285 . ListObjectsV2Async ( request , cancellationToken )
275286 . ConfigureAwait ( false ) ;
276287
277- foreach ( var obj in response . S3Objects )
288+ if ( response . S3Objects is not null )
278289 {
279- var directoryPath = VirtualPath . GetDirectoryName (
280- VirtualPath . Normalize ( obj . Key ) ) ;
281-
282- while ( directoryPath . Length != 0 && directories . Add ( directoryPath ) )
290+ foreach ( var obj in response . S3Objects )
283291 {
284- //
285- // Directories are yielded in reverse order (deepest first).
286- //
287- // Note: We could use a Stack<string> to control the order,
288- // but since order isn't guaranteed anyway and to avoid
289- // unnecessary memory allocation, we process them directly.
290- //
291- if ( IsMatched ( directoryPath . AsSpan ( FullName . Length ) , patterns , excludes ) )
292- yield return new S3Directory ( _fs , directoryPath ) ;
293-
294- directoryPath = VirtualPath . GetDirectoryName ( directoryPath ) ;
292+ var directoryPath = VirtualPath . GetDirectoryName (
293+ VirtualPath . Normalize ( obj . Key ) ) ;
294+
295+ while ( directoryPath . Length != 0 && directories . Add ( directoryPath ) )
296+ {
297+ //
298+ // Directories are yielded in reverse order (deepest first).
299+ //
300+ // Note: We could use a Stack<string> to control the order,
301+ // but since order isn't guaranteed anyway and to avoid
302+ // unnecessary memory allocation, we process them directly.
303+ //
304+ if ( IsMatched ( directoryPath . AsSpan ( FullName . Length ) , patterns , excludes ) )
305+ yield return new S3Directory ( _fs , directoryPath ) ;
306+
307+ directoryPath = VirtualPath . GetDirectoryName ( directoryPath ) ;
308+ }
295309 }
296310 }
297311
@@ -314,8 +328,8 @@ private S3File CreateVirtualFile(S3Object obj, string? normalizedName = null)
314328 . CreateFileProperties (
315329 creationTime : default ,
316330 lastAccessTime : default ,
317- lastWriteTime : obj . LastModified ,
318- length : obj . Size ) ;
331+ lastWriteTime : obj . LastModified . GetValueOrDefault ( ) ,
332+ length : obj . Size ?? 0 ) ;
319333
320334 var path = normalizedName ?? VirtualPath . Normalize ( obj . Key ) ;
321335 return new S3File ( _fs , path , properties ) ;
0 commit comments