diff --git a/internal/deb/extract.go b/internal/deb/extract.go index a534c7aa..81a16062 100644 --- a/internal/deb/extract.go +++ b/internal/deb/extract.go @@ -312,7 +312,14 @@ func extractData(pkgReader io.ReadSeeker, options *ExtractOptions) error { return err } tarReader := tar.NewReader(dataReader) - err = handlePendingHardLinks(options, pendingHardLinks, tarReader, pendingPaths) + extractHardLinkOptions := &extractHardLinkOptions{ + extractOptions: options, + links: pendingHardLinks, + tarReader: tarReader, + pendingPaths: pendingPaths, + } + + err = handlePendingHardLinks(extractHardLinkOptions) if err != nil { return err } @@ -336,10 +343,16 @@ func extractData(pkgReader io.ReadSeeker, options *ExtractOptions) error { return nil } -func handlePendingHardLinks(options *ExtractOptions, pendingHardLinks map[string][]HardLinkInfo, - tarReader *tar.Reader, pendingPaths map[string]bool) error { +type extractHardLinkOptions struct { + extractOptions *ExtractOptions + links map[string][]HardLinkInfo + tarReader *tar.Reader + pendingPaths map[string]bool +} + +func handlePendingHardLinks(opts *extractHardLinkOptions) error { for { - tarHeader, err := tarReader.Next() + tarHeader, err := opts.tarReader.Next() if err == io.EOF { break } @@ -352,43 +365,43 @@ func handlePendingHardLinks(options *ExtractOptions, pendingHardLinks map[string continue } - hardLinks, ok := pendingHardLinks[sourcePath] - if !ok || len(hardLinks) == 0 { + links, ok := opts.links[sourcePath] + if !ok || len(links) == 0 { continue } // Since the hard link target file was not extracted in the first pass, // we extract the first hard link as a regular file. For the rest of // the hard link entries, we link those paths to first file extracted. - targetPath := hardLinks[0].TargetPath - extractPath := filepath.Join(options.TargetDir, targetPath) + targetPath := links[0].TargetPath + extractPath := filepath.Join(opts.extractOptions.TargetDir, targetPath) // Write the content for the first file in the hard link group createOptions := &fsutil.CreateOptions{ Path: extractPath, Mode: tarHeader.FileInfo().Mode(), - Data: tarReader, + Data: opts.tarReader, } - err = options.Create(hardLinks[0].ExtractInfos, createOptions) + err = opts.extractOptions.Create(links[0].ExtractInfos, createOptions) if err != nil { return err } - delete(pendingPaths, sourcePath) - delete(pendingPaths, targetPath) + delete(opts.pendingPaths, sourcePath) + delete(opts.pendingPaths, targetPath) // Create the remaining hard links. - for _, hardLink := range hardLinks[1:] { + for _, link := range links[1:] { createOptions := &fsutil.CreateOptions{ - Path: filepath.Join(options.TargetDir, hardLink.TargetPath), + Path: filepath.Join(opts.extractOptions.TargetDir, link.TargetPath), Mode: tarHeader.FileInfo().Mode(), // Link to the first file extracted for the hard links. Link: extractPath, } - err := options.Create(hardLink.ExtractInfos, createOptions) + err := opts.extractOptions.Create(link.ExtractInfos, createOptions) if err != nil { return err } - delete(pendingPaths, hardLink.TargetPath) + delete(opts.pendingPaths, link.TargetPath) } } return nil diff --git a/internal/fsutil/create_test.go b/internal/fsutil/create_test.go index 123514f7..6db27bd0 100644 --- a/internal/fsutil/create_test.go +++ b/internal/fsutil/create_test.go @@ -17,7 +17,7 @@ import ( type createTest struct { summary string options fsutil.CreateOptions - hackopt func(c *C, targetDir string, options *fsutil.CreateOptions) + hackopt func(c *C, dir string, opts *fsutil.CreateOptions) result map[string]string error string } @@ -79,8 +79,8 @@ var createTests = []createTest{{ Path: "foo", Mode: fs.ModeDir | 0775, }, - hackopt: func(c *C, targetDir string, options *fsutil.CreateOptions) { - c.Assert(os.Mkdir(filepath.Join(targetDir, "foo/"), fs.ModeDir|0765), IsNil) + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { + c.Assert(os.Mkdir(filepath.Join(dir, "foo/"), fs.ModeDir|0765), IsNil) }, result: map[string]string{ // mode is not updated. @@ -94,8 +94,8 @@ var createTests = []createTest{{ Mode: 0644, Data: bytes.NewBufferString("changed"), }, - hackopt: func(c *C, targetDir string, options *fsutil.CreateOptions) { - c.Assert(os.WriteFile(filepath.Join(targetDir, "foo"), []byte("data"), 0666), IsNil) + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { + c.Assert(os.WriteFile(filepath.Join(dir, "foo"), []byte("data"), 0666), IsNil) }, result: map[string]string{ // mode is not updated. @@ -109,10 +109,10 @@ var createTests = []createTest{{ Mode: 0644, MakeParents: true, }, - hackopt: func(c *C, targetDir string, options *fsutil.CreateOptions) { - c.Assert(os.WriteFile(filepath.Join(targetDir, "file"), []byte("data"), 0644), IsNil) + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { + c.Assert(os.WriteFile(filepath.Join(dir, "file"), []byte("data"), 0644), IsNil) // An absolute path is required to create a hard link. - options.Link = filepath.Join(targetDir, options.Link) + opts.Link = filepath.Join(dir, opts.Link) }, result: map[string]string{ "/file": "file 0644 3a6eb079", @@ -126,8 +126,8 @@ var createTests = []createTest{{ Mode: 0644, MakeParents: true, }, - hackopt: func(c *C, targetDir string, options *fsutil.CreateOptions) { - options.Link = filepath.Join(targetDir, options.Link) + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { + opts.Link = filepath.Join(dir, opts.Link) }, error: `link target does not exist`, }, { @@ -138,10 +138,10 @@ var createTests = []createTest{{ Mode: 0644, MakeParents: true, }, - hackopt: func(c *C, targetDir string, options *fsutil.CreateOptions) { - c.Assert(os.WriteFile(filepath.Join(targetDir, "file"), []byte("data"), 0644), IsNil) - c.Assert(os.Link(filepath.Join(targetDir, "file"), filepath.Join(targetDir, "hardlink")), IsNil) - options.Link = filepath.Join(targetDir, options.Link) + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { + c.Assert(os.WriteFile(filepath.Join(dir, "file"), []byte("data"), 0644), IsNil) + c.Assert(os.Link(filepath.Join(dir, "file"), filepath.Join(dir, "hardlink")), IsNil) + opts.Link = filepath.Join(dir, opts.Link) }, result: map[string]string{ "/file": "file 0644 3a6eb079", @@ -155,10 +155,10 @@ var createTests = []createTest{{ Mode: 0644, MakeParents: true, }, - hackopt: func(c *C, targetDir string, options *fsutil.CreateOptions) { - c.Assert(os.WriteFile(filepath.Join(targetDir, "file"), []byte("data"), 0644), IsNil) - c.Assert(os.WriteFile(filepath.Join(targetDir, "hardlink"), []byte("data"), 0644), IsNil) - options.Link = filepath.Join(targetDir, options.Link) + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { + c.Assert(os.WriteFile(filepath.Join(dir, "file"), []byte("data"), 0644), IsNil) + c.Assert(os.WriteFile(filepath.Join(dir, "hardlink"), []byte("data"), 0644), IsNil) + opts.Link = filepath.Join(dir, opts.Link) }, error: `path \/[^ ]*\/hardlink already exists`, }, { @@ -167,7 +167,7 @@ var createTests = []createTest{{ Mode: fs.ModeDir | 0775, OverrideMode: true, }, - hackopt: func(c *C, dir string, options *fsutil.CreateOptions) { + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { c.Assert(os.Mkdir(filepath.Join(dir, "foo/"), fs.ModeDir|0765), IsNil) }, result: map[string]string{ @@ -181,7 +181,7 @@ var createTests = []createTest{{ Data: bytes.NewBufferString("whatever"), OverrideMode: true, }, - hackopt: func(c *C, dir string, options *fsutil.CreateOptions) { + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { err := os.WriteFile(filepath.Join(dir, "foo"), []byte("data"), 0666) c.Assert(err, IsNil) }, @@ -195,7 +195,7 @@ var createTests = []createTest{{ Link: "./bar", Mode: 0666 | fs.ModeSymlink, }, - hackopt: func(c *C, dir string, options *fsutil.CreateOptions) { + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { err := os.WriteFile(filepath.Join(dir, "foo"), []byte("data"), 0666) c.Assert(err, IsNil) }, @@ -209,7 +209,7 @@ var createTests = []createTest{{ Mode: 0776 | fs.ModeSymlink, OverrideMode: true, }, - hackopt: func(c *C, dir string, options *fsutil.CreateOptions) { + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { err := os.WriteFile(filepath.Join(dir, "bar"), []byte("data"), 0666) c.Assert(err, IsNil) err = os.WriteFile(filepath.Join(dir, "foo"), []byte("data"), 0666) @@ -227,7 +227,7 @@ var createTests = []createTest{{ Link: "other", Mode: 0666 | fs.ModeSymlink, }, - hackopt: func(c *C, dir string, options *fsutil.CreateOptions) { + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { err := os.Symlink("foo", filepath.Join(dir, "bar")) c.Assert(err, IsNil) }, @@ -241,7 +241,7 @@ var createTests = []createTest{{ Link: "foo", Mode: 0666 | fs.ModeSymlink, }, - hackopt: func(c *C, dir string, options *fsutil.CreateOptions) { + hackopt: func(c *C, dir string, opts *fsutil.CreateOptions) { err := os.Symlink("foo", filepath.Join(dir, "bar")) c.Assert(err, IsNil) },