@@ -401,6 +401,66 @@ func (fs *Filesystem) Delete(p string) error {
401401 return fs .unixFS .RemoveAll (p )
402402}
403403
404+ // SafeDeleteRecursively deletes a file or directory while respecting the denylist.
405+ // For files, deletion is skipped if the file matches the denylist. For directories,
406+ // it recursively deletes all non-denylisted files and subdirectories. Empty directories
407+ // are removed automatically, but directories containing denylisted files are preserved.
408+ func (fs * Filesystem ) SafeDeleteRecursively (p string ) error {
409+ info , err := fs .Stat (p )
410+ if err != nil {
411+ return err
412+ }
413+
414+ // Check if this path (file or directory) is denylisted
415+ if err := fs .IsIgnored (p ); err != nil {
416+ // Skip denylisted file or directory
417+ return nil
418+ }
419+
420+ if ! info .IsDir () {
421+ return fs .Delete (p )
422+ }
423+
424+ entries , err := fs .ReadDir (p )
425+ if err != nil {
426+ return err
427+ }
428+
429+ hasRemainingFiles := false
430+
431+ for _ , e := range entries {
432+ child := filepath .Join (p , e .Name ())
433+
434+ if e .IsDir () {
435+ if err := fs .SafeDeleteRecursively (child ); err != nil {
436+ return err
437+ }
438+ // Check if the directory still exists after recursive deletion
439+ if _ , statErr := fs .Stat (child ); statErr == nil {
440+ hasRemainingFiles = true
441+ }
442+ continue
443+ }
444+
445+ // File handling - check if ignored
446+ if err := fs .IsIgnored (child ); err != nil {
447+ hasRemainingFiles = true
448+ continue // skip denylisted
449+ }
450+
451+ if err := fs .Delete (child ); err != nil {
452+ return err
453+ }
454+ }
455+
456+ // Only remove directory if no files remain
457+ if ! hasRemainingFiles {
458+ return fs .unixFS .Remove (p )
459+ }
460+
461+ return nil
462+ }
463+
404464//type fileOpener struct {
405465// fs *Filesystem
406466// busy uint
0 commit comments