Skip to content

Commit

Permalink
Fix directory contents cache in imagefs
Browse files Browse the repository at this point in the history
  • Loading branch information
mafredri committed Aug 30, 2024
1 parent 8cd5f9f commit 2800ccc
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 20 deletions.
66 changes: 47 additions & 19 deletions pkg/imagefs/imagefs.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,16 @@ type imageFSFile interface {
}

func New(parent vfs.FS, root string, image v1.Image, filesToCache []string) (vfs.FS, error) {
var ifs *imageFS
if image == nil {
return nil, errors.New("imagefs: image cannot be nil")
}

layers, err := image.Layers()
if err != nil {
return nil, errors.Wrap(err, "imagefs: get layers failed")
}

var ifs *imageFS
// Multiple layers of imageFS might get confusing, enable delayering.
if pfs, ok := parent.(*imageFS); ok {
pfs.mu.Lock()
Expand All @@ -75,39 +83,59 @@ func New(parent vfs.FS, root string, image v1.Image, filesToCache []string) (vfs
}
}

logrus.Debugf("imagefs: Caching files for %s", root)

// Keep track of directories so we can cache all of their contents.
var dirsToCache []string
// Walk the image and cache file info and hash of the requested files.
_, err := util.GetFSFromImage(root, image, func(dest string, hdr *tar.Header, cleanedName string, tr io.Reader) error {
_, err = util.GetFSFromLayers(root, layers, util.ExtractFunc(func(dest string, hdr *tar.Header, cleanedName string, tr io.Reader) error {
// Trim prefix for consistent path.
cleanedName = strings.TrimPrefix(cleanedName, "/")
path := filepath.Join(dest, cleanedName)

cacheFile := func() error {
logrus.Debugf("imagefs: Found cacheable file /%s (path=%s) (%d:%d)", cleanedName, path, hdr.Uid, hdr.Gid)

cf := newCachedFileInfo(path, hdr)
if cf.IsDir() {
dirsToCache = append(dirsToCache, cleanedName)
}

sum, err := hashFile(hdr, tr)
if err != nil {
return errors.Wrap(err, "imagefs: hash file failed")
}
ifs.files[path] = newCachedFileInfoWithMD5Sum(cf, sum)

return nil
}

// All files inside a cached directory should be cached as well.
for _, dir := range dirsToCache {
if strings.HasPrefix(cleanedName, dir+"/") {
return cacheFile()
}
}

for _, f := range filesToCache {
dest := filepath.Join(root, cleanedName)
f = strings.TrimPrefix(f, "/")

// Check if the file matches the requested file.
if ok, err := filepath.Match(f, cleanedName); ok && err == nil {
logrus.Debugf("imagefs: Found cacheable file %q (%s) (%d:%d)", f, dest, hdr.Uid, hdr.Gid)

sum, err := hashFile(hdr, tr)
if err != nil {
return errors.Wrap(err, "imagefs: hash file failed")
}

f := newCachedFileInfo(dest, hdr)
ifs.files[dest] = newCachedFileInfoWithMD5Sum(f, sum)

return nil
return cacheFile()
}

// Parent directories are needed for lookup.
// Cache parent directories for directory lookups.
if cleanedName == "" || strings.HasPrefix(f, cleanedName+"/") {
logrus.Debugf("imagefs: Found cacheable file parent %q (%s)", f, dest)

ifs.files[dest] = newCachedFileInfo(dest, hdr)
if _, ok := ifs.files[path]; !ok {
logrus.Debugf("imagefs: Found cacheable file parent /%s (file=/%s)", cleanedName, f)
ifs.files[path] = newCachedFileInfo(dest, hdr)
}
}
}

return nil
})
}))
if err != nil {
return nil, errors.Wrap(err, "imagefs: walk image failed")
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/util/fs_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ func ExtractFile(dest string, hdr *tar.Header, cleanedName string, tr io.Reader)
}
}
link := filepath.Clean(filepath.Join(dest, hdr.Linkname))
if err := os.Link(link, path); err != nil {
if err := filesystem.FS.Link(link, path); err != nil {
return err
}

Expand Down

0 comments on commit 2800ccc

Please sign in to comment.