fix Task1 publication and secret preflight
This commit is contained in:
@@ -92,8 +92,6 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
if err != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
// Every superseded descriptor is closed in the traversal. Capture the
|
||||
// variable, rather than its initial value, so the final parent is closed too.
|
||||
defer func() { _ = unix.Close(dir) }()
|
||||
for _, component := range components[:len(components)-1] {
|
||||
next, openErr := unix.Openat(dir, component, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_CLOEXEC|unix.O_NOFOLLOW, 0)
|
||||
@@ -103,14 +101,12 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
_ = unix.Close(dir)
|
||||
dir = next
|
||||
}
|
||||
// This is a capability publication API: the retained parent is the namespace
|
||||
// anchor. The lexical check is only a pre-commit diagnostic and cannot close an
|
||||
// ancestor rename race atomically.
|
||||
if !recheckUnixParentPath(components[:len(components)-1], dir) {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
|
||||
// O_TMPFILE creates an inode with no directory entry. Consequently no
|
||||
// same-identity actor can discover or hard-link candidate bytes while they
|
||||
// are being written. AT_EMPTY_PATH then links that already-synced inode into
|
||||
// the destination in one no-replace operation.
|
||||
fd, err := unix.Openat(dir, ".", unix.O_RDWR|unix.O_CLOEXEC|unix.O_TMPFILE, uint32(mode.Perm()))
|
||||
if err != nil {
|
||||
return ErrUnsafeFile
|
||||
@@ -128,30 +124,18 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
closed = true
|
||||
return file.Close()
|
||||
}
|
||||
var expected unix.Stat_t
|
||||
if err := unix.Fstat(fd, &expected); err != nil || expected.Nlink != 0 || expected.Mode&unix.S_IFMT != unix.S_IFREG {
|
||||
_ = closeFile()
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
cleanup := func() {
|
||||
// expected is immutable. Never use a post-race stat as the identity to
|
||||
// remove: a replacement at the public name must survive our cleanup.
|
||||
var current unix.Stat_t
|
||||
leaf := components[len(components)-1]
|
||||
if unix.Fstatat(dir, leaf, ¤t, unix.AT_SYMLINK_NOFOLLOW) == nil && current.Ino == expected.Ino && current.Dev == expected.Dev {
|
||||
_ = unix.Unlinkat(dir, leaf, 0)
|
||||
}
|
||||
}
|
||||
fail := func() error {
|
||||
_ = closeFile()
|
||||
cleanup()
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
var expected unix.Stat_t
|
||||
if err := unix.Fstat(fd, &expected); err != nil || expected.Nlink != 0 || expected.Mode&unix.S_IFMT != unix.S_IFREG {
|
||||
return fail()
|
||||
}
|
||||
if err := file.Chmod(mode); err != nil {
|
||||
return fail()
|
||||
}
|
||||
n, err := file.Write(contents)
|
||||
if err != nil || n != len(contents) {
|
||||
if n, err := file.Write(contents); err != nil || n != len(contents) {
|
||||
return fail()
|
||||
}
|
||||
if err := file.Sync(); err != nil {
|
||||
@@ -164,24 +148,24 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
if !recheckUnixParentPath(components[:len(components)-1], dir) {
|
||||
return fail()
|
||||
}
|
||||
leaf := components[len(components)-1]
|
||||
if err := unix.Linkat(fd, "", dir, leaf, unix.AT_EMPTY_PATH); err != nil {
|
||||
// All fallible preparation, checks, and syncs happen before the linearization
|
||||
// point. A directory sync here is best effort durability for the retained
|
||||
// parent; it cannot be used to report failure after Linkat.
|
||||
if err := unix.Fsync(dir); err != nil {
|
||||
return fail()
|
||||
}
|
||||
var published unix.Stat_t
|
||||
if err := unix.Fstatat(dir, leaf, &published, unix.AT_SYMLINK_NOFOLLOW); err != nil || published.Ino != expected.Ino || published.Dev != expected.Dev || published.Nlink != 1 {
|
||||
if !recheckUnixParentPath(components[:len(components)-1], dir) {
|
||||
return fail()
|
||||
}
|
||||
if err := unix.Fsync(dir); err != nil || !recheckUnixParentPath(components[:len(components)-1], dir) {
|
||||
if err := unix.Linkat(fd, "", dir, components[len(components)-1], unix.AT_EMPTY_PATH); err != nil {
|
||||
return fail()
|
||||
}
|
||||
if err := closeFile(); err != nil {
|
||||
cleanup()
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
// Linkat is the final commit. Close errors and any post-commit observations
|
||||
// are deliberately ignored: returning ErrUnsafeFile here would lie about a
|
||||
// candidate that is already committed, and pathname cleanup would be racy.
|
||||
_ = closeFile()
|
||||
return nil
|
||||
}
|
||||
|
||||
func privateStageName() (string, error) {
|
||||
var random [16]byte
|
||||
if _, err := rand.Read(random[:]); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user