Merge pull request #52884 from vvoland/containerfs-xplat

internal/containerfs: Make cross platform
This commit is contained in:
Paweł Gronowski
2026-06-15 21:04:05 +02:00
committed by GitHub
3 changed files with 55 additions and 18 deletions

View File

@@ -1,14 +1,8 @@
//go:build !darwin && !windows
package containerfs
import (
"os"
"syscall"
"time"
"github.com/moby/sys/mount"
"github.com/pkg/errors"
)
// EnsureRemoveAll wraps [os.RemoveAll] to check for specific errors that can
@@ -30,8 +24,8 @@ func EnsureRemoveAll(dir string) error {
exitOnErr := make(map[string]int)
maxRetry := 50
// Attempt to unmount anything beneath this dir first
mount.RecursiveUnmount(dir)
// Allow the platform to prepare for removal before os.RemoveAll.
prepareRemoveAll(dir)
for {
err := os.RemoveAll(dir)
@@ -61,17 +55,17 @@ func EnsureRemoveAll(dir string) error {
continue
}
if errors.Is(pe.Err, syscall.ENOTEMPTY) && !notEmptyDir[pe.Path] {
if isNotEmptyDirError(pe.Err) && !notEmptyDir[pe.Path] {
notEmptyDir[pe.Path] = true
continue
}
if !errors.Is(pe.Err, syscall.EBUSY) {
return err
retry, removeErr := retryRemoveAllError(dir, pe)
if removeErr != nil {
return removeErr
}
if e := mount.Unmount(pe.Path); e != nil {
return errors.Wrapf(e, "error while removing %s", dir)
if !retry {
return err
}
if exitOnErr[pe.Path] == maxRetry {

View File

@@ -0,0 +1,29 @@
//go:build !windows
package containerfs
import (
"os"
"syscall"
"github.com/moby/sys/mount"
"github.com/pkg/errors"
)
func prepareRemoveAll(dir string) {
mount.RecursiveUnmount(dir)
}
func isNotEmptyDirError(err error) bool {
return errors.Is(err, syscall.ENOTEMPTY)
}
func retryRemoveAllError(dir string, pe *os.PathError) (bool, error) {
if !errors.Is(pe.Err, syscall.EBUSY) {
return false, nil
}
if err := mount.Unmount(pe.Path); err != nil {
return false, errors.Wrapf(err, "error while removing %s", dir)
}
return true, nil
}

View File

@@ -1,8 +1,22 @@
package containerfs
import "os"
import (
"errors"
"os"
// EnsureRemoveAll is an alias to [os.RemoveAll] on Windows.
func EnsureRemoveAll(path string) error {
return os.RemoveAll(path)
"golang.org/x/sys/windows"
)
func prepareRemoveAll(string) {
}
func isNotEmptyDirError(err error) bool {
return false
}
func retryRemoveAllError(_ string, pe *os.PathError) (bool, error) {
return errors.Is(pe.Err, windows.ERROR_ACCESS_DENIED) ||
errors.Is(pe.Err, windows.ERROR_SHARING_VIOLATION) ||
errors.Is(pe.Err, windows.ERROR_LOCK_VIOLATION) ||
errors.Is(pe.Err, windows.ERROR_DIR_NOT_EMPTY), nil
}