diff --git a/deb/deb.go b/deb/deb.go index a522a8d3..eda08431 100644 --- a/deb/deb.go +++ b/deb/deb.go @@ -394,15 +394,20 @@ func createFilesInsideDataTar(info *nfpm.Info, tw *tar.Writer) (md5buf bytes.Buf // skip ghost files in deb continue case files.TypeDir, files.TypeImplicitDir: - err = tw.WriteHeader(&tar.Header{ - Name: files.AsExplicitRelativePath(file.Destination), - Mode: int64(file.FileInfo.Mode), - Typeflag: tar.TypeDir, - Format: tar.FormatGNU, - Uname: file.FileInfo.Owner, - Gname: file.FileInfo.Group, - ModTime: modtime.Get(info.MTime), - }) + header, headerErr := tar.FileInfoHeader(file, "") // headerErr to avoid shadowing err + if err != nil { + return md5buf, 0, fmt.Errorf("build directory header: %w", headerErr) + } + + // we need to change the type from file to dir because + // tar.FileInfoHEader thinks it is a file because the file mode does + // not contain type flags and in this case, it ignores file.IsDir(). + header.Typeflag = tar.TypeDir + header.Name = files.AsExplicitRelativePath(file.Destination) + header.Format = tar.FormatGNU + header.ModTime = modtime.Get(info.MTime) + + err = tw.WriteHeader(header) case files.TypeSymlink: err = newItemInsideTar(tw, []byte{}, &tar.Header{ Name: files.AsExplicitRelativePath(file.Destination), @@ -438,13 +443,9 @@ func copyToTarAndDigest(file *files.Content, tw *tar.Writer, md5w io.Writer) (in return 0, err } - // tar.FileInfoHeader only uses file.Mode().Perm() which masks the mode with - // 0o777 which we don't want because we want to be able to set the suid bit. - header.Mode = int64(file.Mode()) header.Format = tar.FormatGNU header.Name = files.AsExplicitRelativePath(file.Destination) - header.Uname = file.FileInfo.Owner - header.Gname = file.FileInfo.Group + if err := tw.WriteHeader(header); err != nil { return 0, fmt.Errorf("cannot write header of %s to data.tar.gz: %w", file.Source, err) } diff --git a/files/files.go b/files/files.go index 17132d84..0e23ef84 100644 --- a/files/files.go +++ b/files/files.go @@ -66,6 +66,15 @@ type Content struct { Expand bool `yaml:"expand,omitempty" json:"expand,omitempty"` } +// FileInfoNames is used to make sure *Content satisfies tar.FileInfoNames. +type FileInfoNames interface { + fs.FileInfo + Uname() (string, error) + Gname() (string, error) +} + +var _ FileInfoNames = &Content{} + type ContentFileInfo struct { Owner string `yaml:"owner,omitempty" json:"owner,omitempty"` Group string `yaml:"group,omitempty" json:"group,omitempty"` @@ -183,7 +192,15 @@ func (c *Content) ModTime() time.Time { // IsDir to part of the os.FileInfo interface func (c *Content) IsDir() bool { - return false + return c.Type == TypeDir || c.Type == TypeImplicitDir +} + +func (c *Content) Uname() (string, error) { + return c.FileInfo.Owner, nil +} + +func (c *Content) Gname() (string, error) { + return c.FileInfo.Group, nil } // Sys to part of the os.FileInfo interface