| package compactscan |
|
|
| import ( |
| "errors" |
| "io/fs" |
| "os" |
| "path/filepath" |
| ) |
|
|
| |
| |
| |
| const preflightMaxFiles = 4096 |
|
|
| |
| |
| |
| |
| func preflightPackage(rootPath string) error { |
| rootInfo, err := os.Lstat(rootPath) |
| if err != nil { |
| return errors.New("inspect package root") |
| } |
| if rootInfo.Mode()&os.ModeSymlink != 0 || !rootInfo.IsDir() { |
| return errors.New("package root is not an unlinked directory") |
| } |
|
|
| root, err := os.OpenRoot(rootPath) |
| if err != nil { |
| return errors.New("open package root") |
| } |
| defer root.Close() |
|
|
| fileCount := 0 |
| err = filepath.WalkDir(rootPath, func(path string, entry fs.DirEntry, walkErr error) error { |
| if walkErr != nil { |
| return errors.New("walk package tree") |
| } |
| if path == rootPath { |
| return nil |
| } |
| rel, err := filepath.Rel(rootPath, path) |
| if err != nil || rel == "." || filepath.IsAbs(rel) || hasTraversal(rel) { |
| return errors.New("package tree contains a non-canonical member") |
| } |
| info, err := root.Lstat(rel) |
| if err != nil { |
| return errors.New("package member changed during preflight") |
| } |
| if info.Mode()&os.ModeSymlink != 0 { |
| return errors.New("package tree contains a symlink") |
| } |
| if info.IsDir() { |
| return nil |
| } |
| if !info.Mode().IsRegular() { |
| return errors.New("package tree contains a non-regular file") |
| } |
| fileCount++ |
| if fileCount > preflightMaxFiles { |
| return errors.New("package tree exceeds the file limit") |
| } |
|
|
| file, err := openPreflightFile(root, rel) |
| if err != nil { |
| return errors.New("open package member during preflight") |
| } |
| opened, statErr := file.Stat() |
| if statErr != nil { |
| _ = file.Close() |
| return errors.New("stat package member during preflight") |
| } |
| links, linkErr := openedHardLinkCount(file, opened) |
| closeErr := file.Close() |
| if linkErr != nil || closeErr != nil || !opened.Mode().IsRegular() || !os.SameFile(info, opened) { |
| return errors.New("package member changed during preflight") |
| } |
| if links != 1 { |
| return errors.New("package tree contains a hard-linked file") |
| } |
| return nil |
| }) |
| if err != nil { |
| return err |
| } |
| return nil |
| } |
|
|