-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request moby#48611 from stevvooe/sjd/stable-save-timestamps
image/save: set a stable timestamp for assets
- Loading branch information
Showing
2 changed files
with
110 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright 2009 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// Code in this file is a modified version of go stdlib; | ||
// https://cs.opensource.google/go/go/+/refs/tags/go1.23.4:src/os/path.go;l=19-66 | ||
|
||
package tarexport | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/docker/docker/pkg/system" | ||
) | ||
|
||
// mkdirAllWithChtimes is nearly an identical copy to the [os.MkdirAll] but | ||
// tracks created directories and applies the provided mtime and atime using | ||
// [system.Chtimes]. | ||
func mkdirAllWithChtimes(path string, perm os.FileMode, atime, mtime time.Time) error { | ||
// Fast path: if we can tell whether path is a directory or file, stop with success or error. | ||
dir, err := os.Stat(path) | ||
if err == nil { | ||
if dir.IsDir() { | ||
return nil | ||
} | ||
return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} | ||
} | ||
|
||
// Slow path: make sure parent exists and then call Mkdir for path. | ||
|
||
// Extract the parent folder from path by first removing any trailing | ||
// path separator and then scanning backward until finding a path | ||
// separator or reaching the beginning of the string. | ||
i := len(path) - 1 | ||
for i >= 0 && os.IsPathSeparator(path[i]) { | ||
i-- | ||
} | ||
for i >= 0 && !os.IsPathSeparator(path[i]) { | ||
i-- | ||
} | ||
if i < 0 { | ||
i = 0 | ||
} | ||
|
||
// If there is a parent directory, and it is not the volume name, | ||
// recurse to ensure parent directory exists. | ||
if parent := path[:i]; len(parent) > len(filepath.VolumeName(path)) { | ||
err = mkdirAllWithChtimes(parent, perm, atime, mtime) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Parent now exists; invoke Mkdir and use its result. | ||
err = os.Mkdir(path, perm) | ||
if err != nil { | ||
// Handle arguments like "foo/." by | ||
// double-checking that directory doesn't exist. | ||
dir, err1 := os.Lstat(path) | ||
if err1 == nil && dir.IsDir() { | ||
return nil | ||
} | ||
return err | ||
} | ||
|
||
if err := system.Chtimes(path, atime, mtime); err != nil { | ||
return fmt.Errorf("applying atime=%v and mtime=%v: %w", atime, mtime, err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters