@@ -152,6 +152,24 @@ extension FileManager {
152
152
return delegateResponse ?? true
153
153
}
154
154
155
+ fileprivate func _delegateImplementsRemoveItemConfirmation( ) -> Bool {
156
+ guard let delegate = self . safeDelegate else { return false }
157
+ #if FOUNDATION_FRAMEWORK
158
+ return delegate. responds ( to: #selector( FileManagerDelegate . fileManager ( _: shouldRemoveItemAt: ) ) ) || delegate. responds ( to: #selector( FileManagerDelegate . fileManager ( _: shouldRemoveItemAtPath: ) ) )
159
+ #else
160
+ return true
161
+ #endif
162
+ }
163
+
164
+ fileprivate func _delegateImplementsRemoveItemError( ) -> Bool {
165
+ guard let delegate = self . safeDelegate else { return false }
166
+ #if FOUNDATION_FRAMEWORK
167
+ return delegate. responds ( to: #selector( FileManagerDelegate . fileManager ( _: shouldProceedAfterError: removingItemAt: ) ) ) || delegate. responds ( to: #selector( FileManagerDelegate . fileManager ( _: shouldProceedAfterError: removingItemAtPath: ) ) )
168
+ #else
169
+ return true
170
+ #endif
171
+ }
172
+
155
173
fileprivate func _shouldProceedAfter( error: Error , copyingItemAtPath path: String , to dst: String ) -> Bool {
156
174
var delegateResponse : Bool ?
157
175
@@ -292,11 +310,15 @@ extension removefile_state_t {
292
310
return num
293
311
}
294
312
295
- fileprivate func attachCallbacks( context: UnsafeRawPointer ? , confirm: RemoveFileCallback , error: RemoveFileCallback ) {
296
- removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_CONFIRM_CONTEXT) , context)
297
- removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_CONFIRM_CALLBACK) , unsafeBitCast ( confirm, to: UnsafeRawPointer . self) )
298
- removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_ERROR_CONTEXT) , context)
299
- removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_ERROR_CALLBACK) , unsafeBitCast ( error, to: UnsafeRawPointer . self) )
313
+ fileprivate func attachCallbacks( context: UnsafeRawPointer ? , confirm: RemoveFileCallback ? , error: RemoveFileCallback ? ) {
314
+ if let confirm {
315
+ removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_CONFIRM_CONTEXT) , context)
316
+ removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_CONFIRM_CALLBACK) , unsafeBitCast ( confirm, to: UnsafeRawPointer . self) )
317
+ }
318
+ if let error {
319
+ removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_ERROR_CONTEXT) , context)
320
+ removefile_state_set ( self , UInt32 ( REMOVEFILE_STATE_ERROR_CALLBACK) , unsafeBitCast ( error, to: UnsafeRawPointer . self) )
321
+ }
300
322
}
301
323
}
302
324
#endif
@@ -411,49 +433,67 @@ enum _FileOperations {
411
433
#if canImport(Darwin)
412
434
fileprivate class _FileRemoveContext {
413
435
var error : CocoaError ?
414
- var manager : FileManager ?
436
+ var manager : FileManager
415
437
416
- init ( _ manager: FileManager ? ) {
438
+ init ( _ manager: FileManager ) {
417
439
self . manager = manager
418
440
}
419
441
}
420
442
443
+ private static func _removeFile( _ pathPtr: UnsafePointer < CChar > , _ pathStr: String , state: removefile_state_t ) throws {
444
+ let err = removefile ( pathPtr, state, removefile_flags_t ( REMOVEFILE_RECURSIVE) )
445
+ if err < 0 {
446
+ if errno != 0 {
447
+ throw CocoaError . removeFileError ( Int32 ( errno) , pathStr)
448
+ }
449
+ throw CocoaError . removeFileError ( state. errnum, pathStr)
450
+ }
451
+ }
452
+
421
453
private static func _removeFile( _ pathPtr: UnsafePointer < CChar > , _ pathStr: String , with fileManager: FileManager ? ) throws {
422
454
let state = removefile_state_alloc ( ) !
423
455
defer { removefile_state_free ( state) }
424
456
457
+ guard let fileManager else {
458
+ // We have no file manager with a delegate, simply call removefile and return
459
+ try Self . _removeFile ( pathPtr, pathStr, state: state)
460
+ return
461
+ }
462
+
425
463
let ctx = _FileRemoveContext ( fileManager)
426
464
try withExtendedLifetime ( ctx) {
427
465
let ctxPtr = Unmanaged . passUnretained ( ctx) . toOpaque ( )
428
- state. attachCallbacks ( context: ctxPtr, confirm: { _, pathPtr, contextPtr in
429
- let context = Unmanaged < _FileOperations . _FileRemoveContext > . fromOpaque ( contextPtr) . takeUnretainedValue ( )
430
- let path = String ( cString: pathPtr)
431
-
432
- // Proceed unless the delegate says to skip
433
- return ( context. manager? . _shouldRemoveItemAtPath ( path) ?? true ) ? REMOVEFILE_PROCEED : REMOVEFILE_SKIP
434
- } , error: { state, pathPtr, contextPtr in
435
- let context = Unmanaged < _FileOperations . _FileRemoveContext > . fromOpaque ( contextPtr) . takeUnretainedValue ( )
436
- let path = String ( cString: pathPtr)
437
-
438
- let err = CocoaError . removeFileError ( state. errnum, path)
439
-
440
- // Proceed only if the delegate says so
441
- if context. manager? . _shouldProceedAfter ( error: err, removingItemAtPath: path) ?? false {
442
- return REMOVEFILE_PROCEED
443
- } else {
444
- context. error = err
445
- return REMOVEFILE_STOP
446
- }
447
- } )
466
+ var confirmCallback : RemoveFileCallback ?
467
+ var errorCallback : RemoveFileCallback ?
448
468
449
- let err = removefile ( pathPtr, state, removefile_flags_t ( REMOVEFILE_RECURSIVE) )
450
- if err < 0 {
451
- if errno != 0 {
452
- throw CocoaError . removeFileError ( Int32 ( errno) , pathStr)
469
+ if fileManager. _delegateImplementsRemoveItemConfirmation ( ) {
470
+ confirmCallback = { _, pathPtr, contextPtr in
471
+ let context = Unmanaged < _FileOperations . _FileRemoveContext > . fromOpaque ( contextPtr) . takeUnretainedValue ( )
472
+ let path = String ( cString: pathPtr)
473
+
474
+ // Proceed unless the delegate says to skip
475
+ return ( context. manager. _shouldRemoveItemAtPath ( path) ) ? REMOVEFILE_PROCEED : REMOVEFILE_SKIP
476
+ }
477
+ }
478
+ if fileManager. _delegateImplementsRemoveItemError ( ) {
479
+ errorCallback = { state, pathPtr, contextPtr in
480
+ let context = Unmanaged < _FileOperations . _FileRemoveContext > . fromOpaque ( contextPtr) . takeUnretainedValue ( )
481
+ let path = String ( cString: pathPtr)
482
+
483
+ let err = CocoaError . removeFileError ( state. errnum, path)
484
+
485
+ // Proceed only if the delegate says so
486
+ if context. manager. _shouldProceedAfter ( error: err, removingItemAtPath: path) {
487
+ return REMOVEFILE_PROCEED
488
+ } else {
489
+ context. error = err
490
+ return REMOVEFILE_STOP
491
+ }
453
492
}
454
- throw CocoaError . removeFileError ( state. errnum, pathStr)
455
493
}
456
494
495
+ state. attachCallbacks ( context: ctxPtr, confirm: confirmCallback, error: errorCallback)
496
+ try Self . _removeFile ( pathPtr, pathStr, state: state)
457
497
if let error = ctx. error {
458
498
throw error
459
499
}
0 commit comments