| 1 | //go:build linux |
| 2 | |
| 3 | package host |
| 4 | |
| 5 | import ( |
| 6 | "errors" |
| 7 | "path/filepath" |
| 8 | |
| 9 | "github.com/carlosframework/platform/internal/hostbox" |
| 10 | "github.com/carlosframework/platform/internal/instancefs" |
| 11 | "golang.org/x/sys/unix" |
| 12 | ) |
| 13 | |
| 14 | // checkServingArtifactAbsence checks the root-recorded source directory and |
| 15 | // all four source names through one descriptor. Missing parents, links and |
| 16 | // replacement directories are errors, never evidence of absent artifacts. |
| 17 | func checkServingArtifactAbsence(db string, expected servingArtifactDirectory) error { |
| 18 | dir, err := instancefs.OpenDirBeneath(filepath.Dir(db), ".") |
| 19 | if err != nil { |
| 20 | return err |
| 21 | } |
| 22 | defer dir.Close() |
| 23 | var stat unix.Statx_t |
| 24 | if err = unix.Statx(int(dir.Fd()), "", unix.AT_EMPTY_PATH|unix.AT_SYMLINK_NOFOLLOW, unix.STATX_BASIC_STATS|unix.STATX_MNT_ID, &stat); err != nil { |
| 25 | return err |
| 26 | } |
| 27 | if stat.Mask&unix.STATX_MNT_ID == 0 || unix.Mkdev(stat.Dev_major, stat.Dev_minor) != expected.Device || stat.Ino != expected.Inode || stat.Mnt_id != expected.Mount { |
| 28 | return hostbox.ErrChanged |
| 29 | } |
| 30 | for _, suffix := range []string{"", ".gen", "-wal", "-shm"} { |
| 31 | var item unix.Stat_t |
| 32 | err = unix.Fstatat(int(dir.Fd()), filepath.Base(db)+suffix, &item, unix.AT_SYMLINK_NOFOLLOW) |
| 33 | if err == nil { |
| 34 | return hostbox.ErrChanged |
| 35 | } |
| 36 | if !errors.Is(err, unix.ENOENT) { |
| 37 | return err |
| 38 | } |
| 39 | } |
| 40 | return nil |
| 41 | } |
| 42 | |
| 43 | func servingAgentDirectory(db string) (servingArtifactDirectory, error) { |
| 44 | dir, err := instancefs.OpenDirBeneath(filepath.Dir(db), ".") |
| 45 | if err != nil { |
| 46 | return servingArtifactDirectory{}, err |
| 47 | } |
| 48 | defer dir.Close() |
| 49 | return servingParkDirID(dir) |
| 50 | } |
| 51 | |