Skip to content

Commit 38a851d

Browse files
authored
fix(deb): content file modes to support gdebi (#904)
* deb: Fix content file modes to support gdebi, etc. * deb: Better errors and fewer shadowing danger during data.tar creation
1 parent 0d40536 commit 38a851d

File tree

2 files changed

+94
-35
lines changed

2 files changed

+94
-35
lines changed

deb/deb.go

+93-34
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"errors"
1313
"fmt"
1414
"io"
15+
"io/fs"
1516
"os"
1617
"path/filepath"
1718
"strings"
@@ -386,40 +387,49 @@ func fillDataTar(info *nfpm.Info, w io.Writer) (md5sums []byte, instSize int64,
386387
}
387388

388389
func createFilesInsideDataTar(info *nfpm.Info, tw *tar.Writer) (md5buf bytes.Buffer, instSize int64, err error) {
389-
// create files and implicit directories
390390
for _, file := range info.Contents {
391-
var size int64 // declare early to avoid shadowing err
392391
switch file.Type {
393392
case files.TypeRPMGhost:
394-
// skip ghost files in deb
395-
continue
393+
continue // skip ghost files in deb
396394
case files.TypeDir, files.TypeImplicitDir:
397-
err = tw.WriteHeader(&tar.Header{
398-
Name: files.AsExplicitRelativePath(file.Destination),
399-
Mode: int64(file.FileInfo.Mode),
400-
Typeflag: tar.TypeDir,
401-
Format: tar.FormatGNU,
402-
Uname: file.FileInfo.Owner,
403-
Gname: file.FileInfo.Group,
404-
ModTime: modtime.Get(info.MTime),
405-
})
395+
header, err := tarHeader(file, info.MTime)
396+
if err != nil {
397+
return md5buf, 0, fmt.Errorf("build directory header for %q: %w",
398+
file.Destination, err)
399+
}
400+
401+
err = tw.WriteHeader(header)
402+
if err != nil {
403+
return md5buf, 0, fmt.Errorf("create directory %q in data tar: %w",
404+
header.Name, err)
405+
}
406406
case files.TypeSymlink:
407-
err = newItemInsideTar(tw, []byte{}, &tar.Header{
408-
Name: files.AsExplicitRelativePath(file.Destination),
409-
Linkname: file.Source,
410-
Typeflag: tar.TypeSymlink,
411-
ModTime: modtime.Get(info.MTime),
412-
Format: tar.FormatGNU,
413-
})
407+
header, err := tarHeader(file, info.MTime)
408+
if err != nil {
409+
return md5buf, 0, fmt.Errorf("build symlink header for %q: %w",
410+
file.Destination, err)
411+
}
412+
413+
err = newItemInsideTar(tw, []byte{}, header)
414+
if err != nil {
415+
return md5buf, 0, fmt.Errorf("create symlink %q in data tar: %w",
416+
header.Linkname, err)
417+
}
414418
case files.TypeDebChangelog:
415-
size, err = createChangelogInsideDataTar(tw, &md5buf, info, file.Destination)
419+
size, err := createChangelogInsideDataTar(tw, &md5buf, info, file.Destination)
420+
if err != nil {
421+
return md5buf, 0, fmt.Errorf("write changelog to data tar: %w", err)
422+
}
423+
424+
instSize += size
416425
default:
417-
size, err = copyToTarAndDigest(file, tw, &md5buf)
418-
}
419-
if err != nil {
420-
return md5buf, 0, err
426+
size, err := copyToTarAndDigest(file, tw, &md5buf)
427+
if err != nil {
428+
return md5buf, 0, fmt.Errorf("write %q to data tar: %w", file.Destination, err)
429+
}
430+
431+
instSize += size
421432
}
422-
instSize += size
423433
}
424434

425435
return md5buf, instSize, nil
@@ -433,18 +443,11 @@ func copyToTarAndDigest(file *files.Content, tw *tar.Writer, md5w io.Writer) (in
433443
// don't care if it errs while closing...
434444
defer tarFile.Close() // nolint: errcheck,gosec
435445

436-
header, err := tar.FileInfoHeader(file, file.Source)
446+
header, err := tarHeader(file)
437447
if err != nil {
438448
return 0, err
439449
}
440450

441-
// tar.FileInfoHeader only uses file.Mode().Perm() which masks the mode with
442-
// 0o777 which we don't want because we want to be able to set the suid bit.
443-
header.Mode = int64(file.Mode())
444-
header.Format = tar.FormatGNU
445-
header.Name = files.AsExplicitRelativePath(file.Destination)
446-
header.Uname = file.FileInfo.Owner
447-
header.Gname = file.FileInfo.Group
448451
if err := tw.WriteHeader(header); err != nil {
449452
return 0, fmt.Errorf("cannot write header of %s to data.tar.gz: %w", file.Source, err)
450453
}
@@ -804,3 +807,59 @@ func writeControl(w io.Writer, data controlData) error {
804807
})
805808
return template.Must(tmpl.Parse(controlTemplate)).Execute(w, data)
806809
}
810+
811+
func tarHeader(content *files.Content, preferredModTimes ...time.Time) (*tar.Header, error) {
812+
const (
813+
ISUID = 0o4000 // Set uid
814+
ISGID = 0o2000 // Set gid
815+
ISVTX = 0o1000 // Save text (sticky bit)
816+
)
817+
818+
fm := content.Mode()
819+
820+
h := &tar.Header{
821+
Name: content.Name(),
822+
ModTime: modtime.Get(
823+
append(preferredModTimes, content.ModTime())...),
824+
Mode: int64(fm & 0o7777),
825+
Uname: content.FileInfo.Owner,
826+
Gname: content.FileInfo.Group,
827+
Format: tar.FormatGNU,
828+
}
829+
830+
switch {
831+
case content.IsDir() || fm&fs.ModeDir != 0:
832+
h.Typeflag = tar.TypeDir
833+
h.Name = files.AsExplicitRelativePath(content.Destination)
834+
case content.Type == files.TypeSymlink || fm&fs.ModeSymlink != 0:
835+
h.Typeflag = tar.TypeSymlink
836+
h.Name = files.AsExplicitRelativePath(content.Destination)
837+
h.Linkname = content.Source
838+
case fm&fs.ModeDevice != 0:
839+
if fm&fs.ModeCharDevice != 0 {
840+
h.Typeflag = tar.TypeChar
841+
} else {
842+
h.Typeflag = tar.TypeBlock
843+
}
844+
case fm&fs.ModeNamedPipe != 0:
845+
h.Typeflag = tar.TypeFifo
846+
case fm&fs.ModeSocket != 0:
847+
return nil, fmt.Errorf("archive/tar: sockets not supported")
848+
default:
849+
h.Typeflag = tar.TypeReg
850+
h.Name = files.AsExplicitRelativePath(content.Destination)
851+
h.Size = content.Size()
852+
}
853+
854+
if fm&fs.ModeSetuid != 0 {
855+
h.Mode |= ISUID
856+
}
857+
if fm&fs.ModeSetgid != 0 {
858+
h.Mode |= ISGID
859+
}
860+
if fm&fs.ModeSticky != 0 {
861+
h.Mode |= ISVTX
862+
}
863+
864+
return h, nil
865+
}

files/files.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func (c *Content) ModTime() time.Time {
183183

184184
// IsDir to part of the os.FileInfo interface
185185
func (c *Content) IsDir() bool {
186-
return false
186+
return c.Type == TypeDir || c.Type == TypeImplicitDir
187187
}
188188

189189
// Sys to part of the os.FileInfo interface

0 commit comments

Comments
 (0)