From bdddc24a55e56e64cbc135ec8f4c27c8b1a15708 Mon Sep 17 00:00:00 2001 From: Amit Barve Date: Tue, 16 Mar 2021 13:38:42 -0700 Subject: [PATCH] Fix tar extraction issue where parent directories don't exist. Extracting LCOW layers to vhd fails when a file shows up in the tar list before the parent directory of that file shows up. This change fixes that by always creating any non existing parent directories and then updating their permissions later when actual directory entry shows up. Signed-off-by: Amit Barve --- ext4/internal/compactext4/compact.go | 39 ++++++++++++++++++++++++++++ ext4/tar2ext4/tar2ext4.go | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ext4/internal/compactext4/compact.go b/ext4/internal/compactext4/compact.go index aa0b8efad4..823a5c5d97 100644 --- a/ext4/internal/compactext4/compact.go +++ b/ext4/internal/compactext4/compact.go @@ -514,6 +514,45 @@ func (w *Writer) lookup(name string, mustExist bool) (*inode, *inode, string, er return dir, child, childname, nil } +// CreateWithParents adds a file to the file system creating the parent directories in the path if +// they don't exist (like `mkdir -p`). These non existing parent directories are created +// with the same permissions as that of it's parent directory. It is expected that the a +// call to make these parent directories will be made at a later point with the correct +// permissions, at that time the permissions of these directories will be updated. +func (w *Writer) CreateWithParents(name string, f *File) error { + // go through the directories in the path one by one and create the + // parent directories if they don't exist. + cleanname := path.Clean("/" + name)[1:] + parentDirs, _ := path.Split(cleanname) + currentPath := "" + root := w.root() + dirname := "" + for parentDirs != "" { + dirname, parentDirs = splitFirst(parentDirs) + currentPath += "/" + dirname + if _, ok := root.Children[dirname]; !ok { + f := &File{ + Mode: root.Mode, + Atime: time.Now(), + Mtime: time.Now(), + Ctime: time.Now(), + Crtime: time.Now(), + Size: 0, + Uid: root.Uid, + Gid: root.Gid, + Devmajor: root.Devmajor, + Devminor: root.Devminor, + Xattrs: make(map[string][]byte), + } + if err := w.Create(currentPath, f); err != nil { + return fmt.Errorf("failed while creating parent directories: %w", err) + } + } + root = root.Children[dirname] + } + return w.Create(name, f) +} + // Create adds a file to the file system. func (w *Writer) Create(name string, f *File) error { if err := w.finishInode(); err != nil { diff --git a/ext4/tar2ext4/tar2ext4.go b/ext4/tar2ext4/tar2ext4.go index 874855bca8..1aeae290b8 100644 --- a/ext4/tar2ext4/tar2ext4.go +++ b/ext4/tar2ext4/tar2ext4.go @@ -148,7 +148,7 @@ func Convert(r io.Reader, w io.ReadWriteSeeker, options ...Option) error { } f.Mode &= ^compactext4.TypeMask f.Mode |= typ - err = fs.Create(hdr.Name, f) + err = fs.CreateWithParents(hdr.Name, f) if err != nil { return err }