aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/pkg.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/pkg/pkg.go')
-rw-r--r--internal/pkg/pkg.go70
1 files changed, 64 insertions, 6 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index b880b496..5d5d768b 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -376,6 +376,63 @@ func removeAll(pathname *check.Absolute) (chmodErr, removeErr error) {
return
}
+// overrideFileInfo overrides the permission bits of [fs.FileInfo] to 0500 and
+// is the concrete type returned by overrideFile.Stat.
+type overrideFileInfo struct{ fs.FileInfo }
+
+// Mode returns [fs.FileMode] with its permission bits set to 0500.
+func (fi overrideFileInfo) Mode() fs.FileMode {
+ return fi.FileInfo.Mode()&(^fs.FileMode(0777)) | 0500
+}
+
+// Sys returns nil to avoid passing the original permission bits.
+func (fi overrideFileInfo) Sys() any { return nil }
+
+// overrideFile overrides the permission bits of [fs.File] to 0500 and is the
+// concrete type returned by dotOverrideFS for calls with "." passed as name.
+type overrideFile struct{ fs.File }
+
+func (f overrideFile) Stat() (fi fs.FileInfo, err error) {
+ fi, err = f.File.Stat()
+ if err != nil {
+ return
+ }
+ fi = overrideFileInfo{fi}
+ return
+}
+
+// dirFS is implemented by the concrete type of the return value of [os.DirFS].
+type dirFS interface {
+ fs.StatFS
+ fs.ReadFileFS
+ fs.ReadDirFS
+ fs.ReadLinkFS
+}
+
+// dotOverrideFS overrides the permission bits of "." to 0500 to avoid the extra
+// system calls to add and remove write bit from the target directory.
+type dotOverrideFS struct{ dirFS }
+
+// Open wraps the underlying [fs.FS] with "." special case.
+func (fsys dotOverrideFS) Open(name string) (f fs.File, err error) {
+ f, err = fsys.dirFS.Open(name)
+ if err != nil || name != "." {
+ return
+ }
+ f = overrideFile{f}
+ return
+}
+
+// Stat wraps the underlying [fs.FS] with "." special case.
+func (fsys dotOverrideFS) Stat(name string) (fi fs.FileInfo, err error) {
+ fi, err = fsys.dirFS.Stat(name)
+ if err != nil || name != "." {
+ return
+ }
+ fi = overrideFileInfo{fi}
+ return
+}
+
// Cure cures the [Artifact] and returns its pathname and [Checksum].
func (c *Cache) Cure(a Artifact) (
pathname *check.Absolute,
@@ -556,13 +613,11 @@ func (c *Cache) Cure(a Artifact) (
return
}
- // override this before hashing since it will be made read-only after
- // the rename anyway so do not let perm bits affect the checksum
- if err = os.Chmod(workPathname.String(), 0700); err != nil {
- return
- }
var gotChecksum Checksum
- if gotChecksum, err = HashDir(workPathname); err != nil {
+ if gotChecksum, err = HashFS(
+ dotOverrideFS{os.DirFS(workPathname.String()).(dirFS)},
+ ".",
+ ); err != nil {
return
}
@@ -583,6 +638,9 @@ func (c *Cache) Cure(a Artifact) (
}
}
+ if err = os.Chmod(workPathname.String(), 0700); err != nil {
+ return
+ }
c.checksumMu.Lock()
if err = os.Rename(
workPathname.String(),