From 336611b4d051e72a15995490d3f415145b81aeb1 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 15:15:23 +0200 Subject: [PATCH 01/13] fileutils: new functions to check for path existence On unix they use the access syscall which is faster than stat for simply checking the existence of a file. with a file in the cache I see on my machine: $ go test -bench=. goos: linux goarch: amd64 pkg: github.com/containers/storage/pkg/fileutils cpu: Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz BenchmarkExists-12 925832 1245 ns/op BenchmarkStat-12 745896 1602 ns/op PASS I'd expect even better results if the file is not already in the cache. Signed-off-by: Giuseppe Scrivano --- pkg/fileutils/exists_test.go | 80 +++++++++++++++++++++++++++++++++ pkg/fileutils/exists_unix.go | 24 ++++++++++ pkg/fileutils/exists_windows.go | 18 ++++++++ 3 files changed, 122 insertions(+) create mode 100644 pkg/fileutils/exists_test.go create mode 100644 pkg/fileutils/exists_unix.go create mode 100644 pkg/fileutils/exists_windows.go diff --git a/pkg/fileutils/exists_test.go b/pkg/fileutils/exists_test.go new file mode 100644 index 0000000000..6a28b29e17 --- /dev/null +++ b/pkg/fileutils/exists_test.go @@ -0,0 +1,80 @@ +package fileutils + +import ( + "os" + "path" + "runtime" + "syscall" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExist(t *testing.T) { + tempDir := t.TempDir() + + symlinkPath := path.Join(tempDir, "sl-working") + danglingSymlinkPath := path.Join(tempDir, "sl-broken") + + err := os.Symlink(tempDir, symlinkPath) + require.NoError(t, err) + + err = os.Symlink("fooobar123", danglingSymlinkPath) + require.NoError(t, err) + + assertSameError := func(err1, err2 error, description string) { + assert.Equal(t, err1 == nil, err2 == nil, "only one error is set") + if err1 == nil { + return + } + // on Linux validates that the syscall error is the same + if runtime.GOOS == "linux" { + var syscallErr1 syscall.Errno + var syscallErr2 syscall.Errno + assert.ErrorAs(t, err1, &syscallErr1, "wrong error type") + assert.ErrorAs(t, err2, &syscallErr2, "wrong error type") + assert.Equal(t, syscallErr1, syscallErr2, "same error for existing path (follow=false)") + } + } + + err = Lexists(tempDir) + _, err2 := os.Lstat(tempDir) + assertSameError(err, err2, "same error for existing path (follow=false)") + + err = Lexists("foo123shouldnotexist") + _, err2 = os.Lstat("foo123shouldnotexist") + assertSameError(err, err2, "same error for not existing path (follow=false)") + + err = Lexists(symlinkPath) + _, err2 = os.Lstat(symlinkPath) + assertSameError(err, err2, "same error for existing symlink (follow=false)") + + err = Exists(symlinkPath) + _, err2 = os.Stat(symlinkPath) + assertSameError(err, err2, "same error for existing symlink (follow=true)") + + err = Lexists(danglingSymlinkPath) + _, err2 = os.Lstat(danglingSymlinkPath) + assertSameError(err, err2, "same error for not existing symlink (follow=false)") + + err = Exists(danglingSymlinkPath) + _, err2 = os.Stat(danglingSymlinkPath) + assertSameError(err, err2, "same error for not existing symlink (follow=true)") +} + +func BenchmarkExists(b *testing.B) { + tempDir := b.TempDir() + for i := 0; i < b.N; i++ { + Exists(tempDir) + Lexists(tempDir) + } +} + +func BenchmarkStat(b *testing.B) { + tempDir := b.TempDir() + for i := 0; i < b.N; i++ { + os.Stat(tempDir) + os.Lstat(tempDir) + } +} diff --git a/pkg/fileutils/exists_unix.go b/pkg/fileutils/exists_unix.go new file mode 100644 index 0000000000..6573e4890e --- /dev/null +++ b/pkg/fileutils/exists_unix.go @@ -0,0 +1,24 @@ +//go:build !windows +// +build !windows + +package fileutils + +import ( + "golang.org/x/sys/unix" +) + +// Exists checks whether a file or directory exists at the given path. +// If the path is a symlink, the symlink is followed. +func Exists(path string) error { + // It uses unix.Faccessat which is a faster operation compared to os.Stat for + // simply checking the existence of a file. + return unix.Faccessat(unix.AT_FDCWD, path, unix.F_OK, 0) +} + +// Lexists checks whether a file or directory exists at the given path. +// If the path is a symlink, the symlink itself is checked. +func Lexists(path string) error { + // It uses unix.Faccessat which is a faster operation compared to os.Stat for + // simply checking the existence of a file. + return unix.Faccessat(unix.AT_FDCWD, path, unix.F_OK, unix.AT_SYMLINK_NOFOLLOW) +} diff --git a/pkg/fileutils/exists_windows.go b/pkg/fileutils/exists_windows.go new file mode 100644 index 0000000000..355cf04647 --- /dev/null +++ b/pkg/fileutils/exists_windows.go @@ -0,0 +1,18 @@ +package fileutils + +import ( + "os" +) + +// Exists checks whether a file or directory exists at the given path. +func Exists(path string) error { + _, err := os.Stat(path) + return err +} + +// Lexists checks whether a file or directory exists at the given path, without +// resolving symlinks +func Lexists(path string) error { + _, err := os.Lstat(path) + return err +} From 81c2f5f2d04f92fc9f4b711039ce4130a95d778c Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 16:03:46 +0200 Subject: [PATCH 02/13] fileutils: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- pkg/fileutils/fileutils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/fileutils/fileutils.go b/pkg/fileutils/fileutils.go index 9d0714b1b9..85ce2d5260 100644 --- a/pkg/fileutils/fileutils.go +++ b/pkg/fileutils/fileutils.go @@ -344,7 +344,7 @@ func ReadSymlinkedPath(path string) (realPath string, err error) { if realPath, err = filepath.EvalSymlinks(realPath); err != nil { return "", fmt.Errorf("failed to canonicalise path for %q: %w", path, err) } - if _, err := os.Stat(realPath); err != nil { + if err := Exists(realPath); err != nil { return "", fmt.Errorf("failed to stat target %q of %q: %w", realPath, path, err) } return realPath, nil @@ -352,7 +352,7 @@ func ReadSymlinkedPath(path string) (realPath string, err error) { // CreateIfNotExists creates a file or a directory only if it does not already exist. func CreateIfNotExists(path string, isDir bool) error { - if _, err := os.Stat(path); err != nil { + if err := Exists(path); err != nil { if os.IsNotExist(err) { if isDir { return os.MkdirAll(path, 0o755) From a6b7d66e58addd6f55b806f661db8f0645eed4dc Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 15:40:19 +0200 Subject: [PATCH 03/13] overlay: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/overlay/overlay.go | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index b2f0e7a946..f26cf695bd 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -24,6 +24,7 @@ import ( "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chrootarchive" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/fsutils" "github.com/containers/storage/pkg/idmap" "github.com/containers/storage/pkg/idtools" @@ -574,7 +575,7 @@ func parseOptions(options []string) (*overlayOptions, error) { case "mount_program": logrus.Debugf("overlay: mount_program=%s", val) if val != "" { - _, err := os.Stat(val) + err := fileutils.Exists(val) if err != nil { return nil, fmt.Errorf("overlay: can't stat program %q: %w", val, err) } @@ -676,7 +677,7 @@ func SupportsNativeOverlay(home, runhome string) (bool, error) { } for _, dir := range []string{home, runhome} { - if _, err := os.Stat(dir); err != nil { + if err := fileutils.Exists(dir); err != nil { _ = idtools.MkdirAllAs(dir, 0o700, 0, 0) } } @@ -854,7 +855,7 @@ func (d *Driver) Status() [][2]string { // LowerDir, UpperDir, WorkDir and MergeDir used to store data. func (d *Driver) Metadata(id string) (map[string]string, error) { dir := d.dir(id) - if _, err := os.Stat(dir); err != nil { + if err := fileutils.Exists(dir); err != nil { return nil, err } @@ -1016,7 +1017,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl rootGID = int(st.GID()) } - if _, err := system.Lstat(dir); err == nil { + if err := fileutils.Lexists(dir); err == nil { logrus.Warnf("Trying to create a layer %#v while directory %q already exists; removing it first", id, dir) // Don’t just os.RemoveAll(dir) here; d.Remove also removes the link in linkDir, // so that we can’t end up with two symlinks in linkDir pointing to the same layer. @@ -1144,7 +1145,7 @@ func (d *Driver) getLower(parent string) (string, error) { parentDir := d.dir(parent) // Ensure parent exists - if _, err := os.Lstat(parentDir); err != nil { + if err := fileutils.Lexists(parentDir); err != nil { return "", err } @@ -1197,10 +1198,10 @@ func (d *Driver) dir2(id string, useImageStore bool) (string, string, bool) { newpath := path.Join(homedir, id) - if _, err := os.Stat(newpath); err != nil { + if err := fileutils.Exists(newpath); err != nil { for _, p := range d.getAllImageStores() { l := path.Join(p, d.name, id) - _, err = os.Stat(l) + err = fileutils.Exists(l) if err == nil { return l, homedir, true } @@ -1340,7 +1341,7 @@ func (d *Driver) recreateSymlinks() error { linkPath := path.Join(d.home, linkDir, strings.Trim(string(data), "\n")) // Check if the symlink exists, and if it doesn't, create it again with the // name we got from the "link" file - _, err = os.Lstat(linkPath) + err = fileutils.Lexists(linkPath) if err != nil && os.IsNotExist(err) { if err := os.Symlink(path.Join("..", dir.Name(), "diff"), linkPath); err != nil { errs = multierror.Append(errs, err) @@ -1417,7 +1418,7 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountOpts) (_ string, retErr error) { dir, _, inAdditionalStore := d.dir2(id, false) - if _, err := os.Stat(dir); err != nil { + if err := fileutils.Exists(dir); err != nil { return "", err } @@ -1528,8 +1529,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO composeFsLayersDir := filepath.Join(dir, "composefs-layers") maybeAddComposefsMount := func(lowerID string, i int, readWrite bool) (string, error) { composefsBlob := d.getComposefsData(lowerID) - _, err = os.Stat(composefsBlob) - if err != nil { + if err := fileutils.Exists(composefsBlob); err != nil { if os.IsNotExist(err) { return "", nil } @@ -1633,11 +1633,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO absLowers = append(absLowers, lower) diffN = 1 - _, err = os.Stat(dumbJoin(lower, "..", nameWithSuffix("diff", diffN))) + err = fileutils.Exists(dumbJoin(lower, "..", nameWithSuffix("diff", diffN))) for err == nil { absLowers = append(absLowers, dumbJoin(lower, "..", nameWithSuffix("diff", diffN))) diffN++ - _, err = os.Stat(dumbJoin(lower, "..", nameWithSuffix("diff", diffN))) + err = fileutils.Exists(dumbJoin(lower, "..", nameWithSuffix("diff", diffN))) } } @@ -1660,14 +1660,14 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO return "", err } // if it is in an additional store, do not fail if the directory already exists - if _, err2 := os.Stat(diffDir); err2 != nil { + if err2 := fileutils.Exists(diffDir); err2 != nil { return "", err } } mergedDir := path.Join(dir, "merged") // Attempt to create the merged dir only if it doesn't exist. - if _, err := os.Stat(mergedDir); err != nil && os.IsNotExist(err) { + if err := fileutils.Exists(mergedDir); err != nil && os.IsNotExist(err) { if err := idtools.MkdirAs(mergedDir, 0o700, rootUID, rootGID); err != nil && !os.IsExist(err) { return "", err } @@ -1836,14 +1836,14 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO // Put unmounts the mount path created for the give id. func (d *Driver) Put(id string) error { dir, _, inAdditionalStore := d.dir2(id, false) - if _, err := os.Stat(dir); err != nil { + if err := fileutils.Exists(dir); err != nil { return err } mountpoint := path.Join(dir, "merged") if count := d.ctr.Decrement(mountpoint); count > 0 { return nil } - if _, err := os.ReadFile(path.Join(dir, lowerFile)); err != nil && !os.IsNotExist(err) { + if err := fileutils.Exists(path.Join(dir, lowerFile)); err != nil && !os.IsNotExist(err) { return err } @@ -1851,7 +1851,7 @@ func (d *Driver) Put(id string) error { mappedRoot := filepath.Join(d.home, id, "mapped") // It should not happen, but cleanup any mapped mount if it was leaked. - if _, err := os.Stat(mappedRoot); err == nil { + if err := fileutils.Exists(mappedRoot); err == nil { mounts, err := os.ReadDir(mappedRoot) if err == nil { // Go through all of the mapped mounts. @@ -1922,7 +1922,7 @@ func (d *Driver) Put(id string) error { // Exists checks to see if the id is already mounted. func (d *Driver) Exists(id string) bool { - _, err := os.Stat(d.dir(id)) + err := fileutils.Exists(d.dir(id)) return err == nil } @@ -2334,7 +2334,7 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp } for err == nil { i++ - _, err = os.Stat(nameWithSuffix(diffDir, i)) + err = fileutils.Exists(nameWithSuffix(diffDir, i)) } for i > 0 { @@ -2419,7 +2419,7 @@ func (d *Driver) getAdditionalLayerPath(dgst digest.Digest, ref string) (string, filepath.Join(target, "info"), filepath.Join(target, "blob"), } { - if _, err := os.Stat(p); err != nil { + if err := fileutils.Exists(p); err != nil { wrapped := fmt.Errorf("failed to stat additional layer %q: %w", p, err) return "", fmt.Errorf("%v: %w", wrapped, graphdriver.ErrLayerUnknown) } From 171191ec54f0f11bb84d3085f9ac2733b3679b5c Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 15:53:08 +0200 Subject: [PATCH 04/13] idtools: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- pkg/idtools/idtools_unix.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/idtools/idtools_unix.go b/pkg/idtools/idtools_unix.go index d7cb4ac2fd..7900af38a9 100644 --- a/pkg/idtools/idtools_unix.go +++ b/pkg/idtools/idtools_unix.go @@ -13,6 +13,7 @@ import ( "sync" "syscall" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/system" "github.com/moby/sys/user" ) @@ -55,7 +56,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown if dirPath == "/" { break } - if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { + if err := fileutils.Exists(dirPath); err != nil && os.IsNotExist(err) { paths = append(paths, dirPath) } } From 9992cd2938baf028e3bfae0268cb83c521902873 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 15:54:13 +0200 Subject: [PATCH 05/13] chrootarchive: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- pkg/chrootarchive/archive.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/chrootarchive/archive.go b/pkg/chrootarchive/archive.go index f221a22835..5ff9f6b511 100644 --- a/pkg/chrootarchive/archive.go +++ b/pkg/chrootarchive/archive.go @@ -9,6 +9,7 @@ import ( "sync" "github.com/containers/storage/pkg/archive" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/unshare" ) @@ -76,7 +77,7 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions rootIDs := idMappings.RootPair() dest = filepath.Clean(dest) - if _, err := os.Stat(dest); os.IsNotExist(err) { + if err := fileutils.Exists(dest); os.IsNotExist(err) { if err := idtools.MkdirAllAndChownNew(dest, 0o755, rootIDs); err != nil { return err } From de0900aab7743455e6afa581a7f983ae564a9735 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 15:56:25 +0200 Subject: [PATCH 06/13] types: use fileutils.{Le,E}xist() Signed-off-by: Giuseppe Scrivano --- types/options.go | 7 ++++--- types/utils.go | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/types/options.go b/types/options.go index ad0bfa43a6..03e5f7ab64 100644 --- a/types/options.go +++ b/types/options.go @@ -11,6 +11,7 @@ import ( "github.com/BurntSushi/toml" cfg "github.com/containers/storage/pkg/config" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/homedir" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/unshare" @@ -76,7 +77,7 @@ func loadDefaultStoreOptions() { if path, ok := os.LookupEnv("XDG_CONFIG_HOME"); ok { homeConfigFile := filepath.Join(path, "containers", "storage.conf") - if _, err := os.Stat(homeConfigFile); err == nil { + if err := fileutils.Exists(homeConfigFile); err == nil { // user storage.conf in XDG_CONFIG_HOME if it exists defaultOverrideConfigFile = homeConfigFile } else { @@ -87,7 +88,7 @@ func loadDefaultStoreOptions() { } } - _, err := os.Stat(defaultOverrideConfigFile) + err := fileutils.Exists(defaultOverrideConfigFile) if err == nil { // The DefaultConfigFile() function returns the path // of the used storage.conf file, by returning defaultConfigFile @@ -150,7 +151,7 @@ func loadStoreOptionsFromConfFile(storageConf string) (StoreOptions, error) { return storageOpts, err } } - _, err = os.Stat(storageConf) + err = fileutils.Exists(storageConf) if err != nil && !os.IsNotExist(err) { return storageOpts, err } diff --git a/types/utils.go b/types/utils.go index 5b4b31b80a..b313a47288 100644 --- a/types/utils.go +++ b/types/utils.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/homedir" "github.com/sirupsen/logrus" ) @@ -31,7 +32,7 @@ func DefaultConfigFile() (string, error) { return path, nil } if !usePerUserStorage() { - if _, err := os.Stat(defaultOverrideConfigFile); err == nil { + if err := fileutils.Exists(defaultOverrideConfigFile); err == nil { return defaultOverrideConfigFile, nil } return defaultConfigFile, nil From 383e8e39c7563a0da8739b7ed86f57cfbca42937 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 15:59:59 +0200 Subject: [PATCH 07/13] drivers: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/driver.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/driver.go b/drivers/driver.go index aa99fdead2..049e295a79 100644 --- a/drivers/driver.go +++ b/drivers/driver.go @@ -10,6 +10,7 @@ import ( "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" digest "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" @@ -471,7 +472,7 @@ func ScanPriorDrivers(root string) map[string]bool { for driver := range drivers { p := filepath.Join(root, driver) - if _, err := os.Stat(p); err == nil { + if err := fileutils.Exists(p); err == nil { driversMap[driver] = true } } From 2b26cbfd37ff423bffbd634c625a88efa16fc4a5 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 16:01:08 +0200 Subject: [PATCH 08/13] archive: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- pkg/archive/archive.go | 2 +- pkg/archive/changes.go | 3 ++- pkg/archive/copy.go | 3 ++- pkg/archive/diff.go | 5 +++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/archive/archive.go b/pkg/archive/archive.go index 70f76d66d4..77c9c818c9 100644 --- a/pkg/archive/archive.go +++ b/pkg/archive/archive.go @@ -1023,7 +1023,7 @@ loop: // Not the root directory, ensure that the parent directory exists parent := filepath.Dir(hdr.Name) parentPath := filepath.Join(dest, parent) - if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) { + if err := fileutils.Lexists(parentPath); err != nil && os.IsNotExist(err) { err = idtools.MkdirAllAndChownNew(parentPath, 0o777, rootIDs) if err != nil { return err diff --git a/pkg/archive/changes.go b/pkg/archive/changes.go index 01c6f30c2d..4487845497 100644 --- a/pkg/archive/changes.go +++ b/pkg/archive/changes.go @@ -13,6 +13,7 @@ import ( "syscall" "time" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/pools" "github.com/containers/storage/pkg/system" @@ -106,7 +107,7 @@ func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) { func aufsWhiteoutPresent(root, path string) (bool, error) { f := filepath.Join(filepath.Dir(path), WhiteoutPrefix+filepath.Base(path)) - _, err := os.Stat(filepath.Join(root, f)) + err := fileutils.Exists(filepath.Join(root, f)) if err == nil { return true, nil } diff --git a/pkg/archive/copy.go b/pkg/archive/copy.go index 55f753bf41..4d46167d70 100644 --- a/pkg/archive/copy.go +++ b/pkg/archive/copy.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" + "github.com/containers/storage/pkg/fileutils" "github.com/sirupsen/logrus" ) @@ -94,7 +95,7 @@ func TarResource(sourceInfo CopyInfo) (content io.ReadCloser, err error) { // items in the resulting tar archive to match the given rebaseName if not "". func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, err error) { sourcePath = normalizePath(sourcePath) - if _, err = os.Lstat(sourcePath); err != nil { + if err = fileutils.Lexists(sourcePath); err != nil { // Catches the case where the source does not exist or is not a // directory if asserted to be a directory, as this also causes an // error. diff --git a/pkg/archive/diff.go b/pkg/archive/diff.go index 7135518598..ceaa8b0b79 100644 --- a/pkg/archive/diff.go +++ b/pkg/archive/diff.go @@ -10,6 +10,7 @@ import ( "runtime" "strings" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/pools" "github.com/containers/storage/pkg/system" @@ -84,7 +85,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, parent := filepath.Dir(hdr.Name) parentPath := filepath.Join(dest, parent) - if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) { + if err := fileutils.Lexists(parentPath); err != nil && os.IsNotExist(err) { err = os.MkdirAll(parentPath, 0o755) if err != nil { return 0, err @@ -130,7 +131,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, if strings.HasPrefix(base, WhiteoutPrefix) { dir := filepath.Dir(path) if base == WhiteoutOpaqueDir { - _, err := os.Lstat(dir) + err := fileutils.Lexists(dir) if err != nil { return 0, err } From 1f09fadeb6ddc400c18b447de835918103ac8d60 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 16:02:02 +0200 Subject: [PATCH 09/13] vfs: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/vfs/driver.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/vfs/driver.go b/drivers/vfs/driver.go index 9b552254b9..db9032117d 100644 --- a/drivers/vfs/driver.go +++ b/drivers/vfs/driver.go @@ -12,6 +12,7 @@ import ( graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/parsers" "github.com/containers/storage/pkg/system" @@ -210,7 +211,7 @@ func (d *Driver) dir2(id string, useImageStore bool) string { } else { homedir = filepath.Join(d.home, "dir", filepath.Base(id)) } - if _, err := os.Stat(homedir); err != nil { + if err := fileutils.Exists(homedir); err != nil { additionalHomes := d.additionalHomes[:] if d.imageStore != "" { additionalHomes = append(additionalHomes, d.imageStore) @@ -269,7 +270,7 @@ func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) { // Exists checks to see if the directory exists for the given id. func (d *Driver) Exists(id string) bool { - _, err := os.Stat(d.dir(id)) + err := fileutils.Exists(d.dir(id)) return err == nil } From 7bed6ea5efa0d8b94d1243019c02a5f9262badf1 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 16:06:15 +0200 Subject: [PATCH 10/13] devmapper: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/devmapper/deviceset.go | 5 +++-- drivers/devmapper/driver.go | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/devmapper/deviceset.go b/drivers/devmapper/deviceset.go index 5d8df8a78e..6ded90f7f7 100644 --- a/drivers/devmapper/deviceset.go +++ b/drivers/devmapper/deviceset.go @@ -22,6 +22,7 @@ import ( graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/devicemapper" "github.com/containers/storage/pkg/dmesg" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/loopback" "github.com/containers/storage/pkg/mount" @@ -257,7 +258,7 @@ func (devices *DeviceSet) hasImage(name string) bool { dirname := devices.loopbackDir() filename := path.Join(dirname, name) - _, err := os.Stat(filename) + err := fileutils.Exists(filename) return err == nil } @@ -1192,7 +1193,7 @@ func (devices *DeviceSet) growFS(info *devInfo) error { defer devices.deactivateDevice(info) fsMountPoint := "/run/containers/storage/mnt" - if _, err := os.Stat(fsMountPoint); os.IsNotExist(err) { + if err := fileutils.Exists(fsMountPoint); os.IsNotExist(err) { if err := os.MkdirAll(fsMountPoint, 0o700); err != nil { return err } diff --git a/drivers/devmapper/driver.go b/drivers/devmapper/driver.go index 8b8a1d1778..b188530318 100644 --- a/drivers/devmapper/driver.go +++ b/drivers/devmapper/driver.go @@ -12,6 +12,7 @@ import ( graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/devicemapper" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/locker" "github.com/containers/storage/pkg/mount" @@ -222,7 +223,7 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { } idFile := path.Join(mp, "id") - if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { + if err := fileutils.Exists(idFile); err != nil && os.IsNotExist(err) { // Create an "id" file with the container/image id in it to help reconstruct this in case // of later problems if err := os.WriteFile(idFile, []byte(id), 0o600); err != nil { From 55c15505008ed46357fa8db64b61f52a46275d00 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Thu, 4 Apr 2024 16:07:51 +0200 Subject: [PATCH 11/13] btrfs: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/btrfs/btrfs.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/btrfs/btrfs.go b/drivers/btrfs/btrfs.go index fd93d4e84d..11ae563647 100644 --- a/drivers/btrfs/btrfs.go +++ b/drivers/btrfs/btrfs.go @@ -32,6 +32,7 @@ import ( graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/mount" "github.com/containers/storage/pkg/parsers" @@ -589,11 +590,11 @@ func (d *Driver) setStorageSize(dir string, driver *Driver) error { // Remove the filesystem with given id. func (d *Driver) Remove(id string) error { dir := d.subvolumesDirID(id) - if _, err := os.Stat(dir); err != nil { + if err := fileutils.Exists(dir); err != nil { return err } quotasDir := d.quotasDirID(id) - if _, err := os.Stat(quotasDir); err == nil { + if err := fileutils.Exists(quotasDir); err == nil { if err := os.Remove(quotasDir); err != nil { return err } @@ -669,7 +670,7 @@ func (d *Driver) ReadWriteDiskUsage(id string) (*directory.DiskUsage, error) { // Exists checks if the id exists in the filesystem. func (d *Driver) Exists(id string) bool { dir := d.subvolumesDirID(id) - _, err := os.Stat(dir) + err := fileutils.Exists(dir) return err == nil } From 74f17e7f82a7bad060ecc57c24bf6a89751db8d1 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Mon, 8 Apr 2024 11:07:01 +0200 Subject: [PATCH 12/13] aufs: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/aufs/aufs.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/aufs/aufs.go b/drivers/aufs/aufs.go index 0b17662109..e00314d3fd 100644 --- a/drivers/aufs/aufs.go +++ b/drivers/aufs/aufs.go @@ -41,6 +41,7 @@ import ( "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chrootarchive" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/locker" mountpk "github.com/containers/storage/pkg/mount" @@ -243,7 +244,7 @@ func (a *Driver) Metadata(id string) (map[string]string, error) { // Exists returns true if the given id is registered with // this driver func (a *Driver) Exists(id string) bool { - if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil { + if err := fileutils.Lexists(path.Join(a.rootPath(), "layers", id)); err != nil { return false } return true @@ -431,7 +432,7 @@ func atomicRemove(source string) error { case err == nil, os.IsNotExist(err): case os.IsExist(err): // Got error saying the target dir already exists, maybe the source doesn't exist due to a previous (failed) remove - if _, e := os.Stat(source); !os.IsNotExist(e) { + if e := fileutils.Exists(source); !os.IsNotExist(e) { return fmt.Errorf("target rename dir '%s' exists but should not, this needs to be manually cleaned up: %w", target, err) } default: From cbec591bd61ad935a59d92b6c319f1bbda232249 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Mon, 8 Apr 2024 11:11:01 +0200 Subject: [PATCH 13/13] windows: use fileutils.{Le,E}xists() Signed-off-by: Giuseppe Scrivano --- drivers/windows/windows.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 8c2dc18aec..18f90fdc53 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -26,6 +26,7 @@ import ( graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/directory" + "github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/longpath" @@ -231,7 +232,7 @@ func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt if err != nil { return err } - if _, err := os.Stat(filepath.Join(parentPath, "Files")); err == nil { + if err := fileutils.Exists(filepath.Join(parentPath, "Files")); err == nil { // This is a legitimate parent layer (not the empty "-init" layer), // so include it in the layer chain. layerChain = []string{parentPath} @@ -266,7 +267,7 @@ func (d *Driver) create(id, parent, mountLabel string, readOnly bool, storageOpt } } - if _, err := os.Lstat(d.dir(parent)); err != nil { + if err := fileutils.Lexists(d.dir(parent)); err != nil { if err2 := hcsshim.DestroyLayer(d.info, id); err2 != nil { logrus.Warnf("Failed to DestroyLayer %s: %s", id, err2) }