fix(backup): privately stage restore archive
This commit is contained in:
@@ -275,25 +275,24 @@ func WriteCanonicalNewPrivateFile(path string, contents []byte, mode os.FileMode
|
||||
return writeCanonicalNewFile(path, contents, mode, true)
|
||||
}
|
||||
|
||||
// CreateCanonicalNewPrivateFile exclusively creates an owner-private regular file under an
|
||||
// already private parent and returns a read/write handle for streamed contents. Callers must close
|
||||
// the returned handle and remove the file if their stream fails.
|
||||
func CreateCanonicalNewPrivateFile(path string) (*os.File, error) {
|
||||
if err := validateCanonicalNewFile(path, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
file, err := createCanonicalNewPrivateParentReadWriteFile(path, 0o600)
|
||||
if err != nil {
|
||||
return nil, ErrUnsafeFile
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func writeCanonicalNewFile(path string, contents []byte, mode os.FileMode, requirePrivateParent bool) error {
|
||||
if err := ValidateCanonicalPath(path); err != nil {
|
||||
if err := validateCanonicalNewFile(path, requirePrivateParent); err != nil {
|
||||
return err
|
||||
}
|
||||
parent := filepath.Dir(path)
|
||||
if err := requireCanonicalDirectory(parent); err != nil {
|
||||
return err
|
||||
}
|
||||
if requirePrivateParent && ValidatePrivateDirectory(parent) != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
if info, err := os.Lstat(path); err == nil {
|
||||
if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 || info.Mode()&os.ModeType != 0 {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return ErrUnsafeFile
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
var (
|
||||
file *os.File
|
||||
err error
|
||||
@@ -323,6 +322,28 @@ func writeCanonicalNewFile(path string, contents []byte, mode os.FileMode, requi
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateCanonicalNewFile(path string, requirePrivateParent bool) error {
|
||||
if err := ValidateCanonicalPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
parent := filepath.Dir(path)
|
||||
if err := requireCanonicalDirectory(parent); err != nil {
|
||||
return err
|
||||
}
|
||||
if requirePrivateParent && ValidatePrivateDirectory(parent) != nil {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
if info, err := os.Lstat(path); err == nil {
|
||||
if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 || info.Mode()&os.ModeType != 0 {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return ErrUnsafeFile
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReplaceCanonicalRegular durably replaces one existing private regular file without following
|
||||
// symlinked path components. Platform implementations keep the temporary file in the target
|
||||
// directory and use the platform's atomic replace primitive.
|
||||
|
||||
Reference in New Issue
Block a user