@@ -16,6 +16,7 @@ package gofer
16
16
17
17
import (
18
18
goContext "context"
19
+ "encoding/hex"
19
20
"fmt"
20
21
"io"
21
22
@@ -27,6 +28,7 @@ import (
27
28
"gvisor.dev/gvisor/pkg/fdnotifier"
28
29
"gvisor.dev/gvisor/pkg/hostarch"
29
30
"gvisor.dev/gvisor/pkg/log"
31
+ "gvisor.dev/gvisor/pkg/rand"
30
32
"gvisor.dev/gvisor/pkg/refs"
31
33
"gvisor.dev/gvisor/pkg/safemem"
32
34
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
@@ -327,7 +329,7 @@ func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRest
327
329
}
328
330
329
331
// Restore deleted files which are still accessible via open application FDs.
330
- dirsToDelete := make (map [* dentry ]struct {} )
332
+ dirsToDelete := make (map [* dentry ]string )
331
333
for d := range fs .savedDeletedOpenDentries {
332
334
if err := d .restoreDeleted (ctx , & opts , dirsToDelete ); err != nil {
333
335
return err
@@ -344,7 +346,10 @@ func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRest
344
346
delete (leafDirectories , d .parent .Load ())
345
347
}
346
348
for leafD := range leafDirectories {
347
- if err := leafD .parent .Load ().unlink (ctx , leafD .name , linux .AT_REMOVEDIR ); err != nil {
349
+ // Note that we use the name specified in dirsToDelete map, which is the
350
+ // name used to create the temporary directory. This name may differ from
351
+ // leafD.name if another non-deleted directory already exists there.
352
+ if err := leafD .parent .Load ().unlink (ctx , dirsToDelete [leafD ], linux .AT_REMOVEDIR ); err != nil {
348
353
return fmt .Errorf ("failed to clean up recreated deleted directory %q: %v" , genericDebugPathname (fs , leafD ), err )
349
354
}
350
355
delete (dirsToDelete , leafD )
@@ -384,7 +389,7 @@ func (d *dentry) restoreDescendantsRecursive(ctx context.Context, opts *vfs.Comp
384
389
// Preconditions:
385
390
// - d.isRegularFile() || d.isDir()
386
391
// - d.savedDeletedData != nil iff d.isRegularFile()
387
- func (d * dentry ) restoreDeleted (ctx context.Context , opts * vfs.CompleteRestoreOptions , dirsToDelete map [* dentry ]struct {} ) error {
392
+ func (d * dentry ) restoreDeleted (ctx context.Context , opts * vfs.CompleteRestoreOptions , dirsToDelete map [* dentry ]string ) error {
388
393
parent := d .parent .Load ()
389
394
if _ , ok := d .fs .savedDeletedOpenDentries [parent ]; ok {
390
395
// Recursively restore the parent first if the parent is also deleted.
@@ -402,10 +407,26 @@ func (d *dentry) restoreDeleted(ctx context.Context, opts *vfs.CompleteRestoreOp
402
407
}
403
408
}
404
409
405
- func (d * dentry ) restoreDeletedDirectory (ctx context.Context , opts * vfs.CompleteRestoreOptions , dirsToDelete map [* dentry ]struct {}) error {
410
+ func randomNameForDeleted (name string ) string {
411
+ var randBuf [8 ]byte
412
+ rand .Read (randBuf [:])
413
+ return fmt .Sprintf ("%s.tmp-gvisor-restore-%s" , name , hex .EncodeToString (randBuf [:]))
414
+ }
415
+
416
+ func (d * dentry ) restoreDeletedDirectory (ctx context.Context , opts * vfs.CompleteRestoreOptions , dirsToDelete map [* dentry ]string ) error {
406
417
// Recreate the directory on the host filesystem. This will be deleted later.
407
418
parent := d .parent .Load ()
408
419
_ , err := parent .mkdir (ctx , d .name , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
420
+ if linuxerr .Equals (linuxerr .EEXIST , err ) {
421
+ // Change d.name for the remainder of this function.
422
+ origName := d .name
423
+ d .name = randomNameForDeleted (d .name )
424
+ defer func () {
425
+ d .name = origName
426
+ }()
427
+ log .Warningf ("Deleted directory %q was replaced with a new directory at the same path, using new name %q" , genericDebugPathname (d .fs , d ), d .name )
428
+ _ , err = parent .mkdir (ctx , d .name , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
429
+ }
409
430
if err != nil {
410
431
return fmt .Errorf ("failed to re-create deleted directory %q: %w" , genericDebugPathname (d .fs , d ), err )
411
432
}
@@ -418,28 +439,32 @@ func (d *dentry) restoreDeletedDirectory(ctx context.Context, opts *vfs.Complete
418
439
}
419
440
// We will delete the directory later. We need to keep it around in case any
420
441
// of its children need to be restored after this.
421
- dirsToDelete [d ] = struct {}{}
442
+ dirsToDelete [d ] = d . name
422
443
delete (d .fs .savedDeletedOpenDentries , d )
423
444
return nil
424
445
}
425
446
426
447
func (d * dentry ) restoreDeletedRegularFile (ctx context.Context , opts * vfs.CompleteRestoreOptions ) error {
427
448
// Recreate the file on the host filesystem (this is temporary).
428
449
parent := d .parent .Load ()
429
- name := d .name
430
- _ , h , err := parent .openCreate (ctx , name , linux .O_WRONLY , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
450
+ _ , h , err := parent .openCreate (ctx , d .name , linux .O_WRONLY , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
431
451
if linuxerr .Equals (linuxerr .EEXIST , err ) {
432
- name = fmt .Sprintf ("%s.tmp-gvisor-restore" , name )
433
- log .Warningf ("Deleted file %q was replaced with a new file at the same path, using new name %q" , genericDebugPathname (d .fs , d ), name )
434
- _ , h , err = parent .openCreate (ctx , name , linux .O_WRONLY , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
452
+ // Change d.name for the remainder of this function.
453
+ origName := d .name
454
+ d .name = randomNameForDeleted (d .name )
455
+ defer func () {
456
+ d .name = origName
457
+ }()
458
+ log .Warningf ("Deleted file %q was replaced with a new file at the same path, using new name %q" , genericDebugPathname (d .fs , d ), d .name )
459
+ _ , h , err = parent .openCreate (ctx , d .name , linux .O_WRONLY , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
435
460
}
436
461
if err != nil {
437
462
return fmt .Errorf ("failed to re-create deleted file %q: %w" , genericDebugPathname (d .fs , d ), err )
438
463
}
439
464
defer h .close (ctx )
440
465
// In case of errors, clean up the recreated file.
441
466
unlinkCU := cleanup .Make (func () {
442
- if err := parent .unlink (ctx , name , 0 /* flags */ ); err != nil {
467
+ if err := parent .unlink (ctx , d . name , 0 /* flags */ ); err != nil {
443
468
log .Warningf ("failed to clean up recreated deleted file %q: %v" , genericDebugPathname (d .fs , d ), err )
444
469
}
445
470
})
@@ -462,7 +487,7 @@ func (d *dentry) restoreDeletedRegularFile(ctx context.Context, opts *vfs.Comple
462
487
}
463
488
// Finally, unlink the recreated file.
464
489
unlinkCU .Release ()
465
- if err := parent .unlink (ctx , name , 0 /* flags */ ); err != nil {
490
+ if err := parent .unlink (ctx , d . name , 0 /* flags */ ); err != nil {
466
491
return fmt .Errorf ("failed to clean up recreated deleted file %q: %v" , genericDebugPathname (d .fs , d ), err )
467
492
}
468
493
delete (d .fs .savedDeletedOpenDentries , d )
0 commit comments