]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[release-branch.go1.21] cmd/distpack: include directory entries in tar files
authorRuss Cox <rsc@golang.org>
Thu, 10 Aug 2023 03:47:27 +0000 (23:47 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 11 Aug 2023 17:56:21 +0000 (17:56 +0000)
Various tools expect tar files to contain entries for directories.
I dropped them when writing cmd/distpack because they're not
strictly necessary and omitting them saves space, but it also
turns out to break some things, so add them back.

We will backport this to release-branch.go1.21 so that Go 1.21.1
will include the directory entries. We can't do anything about
Go 1.21.0 retroactively.

% tar tzvf go1.22rsc1.src.tar.gz | sed 10q
drwxr-xr-x  0 0      0           0 Aug 10 10:07 go/
-rw-r--r--  0 0      0        1337 Aug 10 10:07 go/CONTRIBUTING.md
-rw-r--r--  0 0      0        1479 Aug 10 10:07 go/LICENSE
-rw-r--r--  0 0      0        1303 Aug 10 10:07 go/PATENTS
-rw-r--r--  0 0      0        1455 Aug 10 10:07 go/README.md
-rw-r--r--  0 0      0         419 Aug 10 10:07 go/SECURITY.md
-rw-r--r--  0 0      0          42 Aug 10 10:07 go/VERSION
drwxr-xr-x  0 0      0           0 Aug 10 10:07 go/api/
-rw-r--r--  0 0      0        1142 Aug 10 10:07 go/api/README
-rw-r--r--  0 0      0       35424 Aug 10 10:07 go/api/except.txt
% tar tzvf go1.22rsc1.darwin-amd64.tar.gz | sed 10q
drwxr-xr-x  0 0      0           0 Aug 10 10:07 go/
-rw-r--r--  0 0      0        1337 Aug 10 10:07 go/CONTRIBUTING.md
-rw-r--r--  0 0      0        1479 Aug 10 10:07 go/LICENSE
-rw-r--r--  0 0      0        1303 Aug 10 10:07 go/PATENTS
-rw-r--r--  0 0      0        1455 Aug 10 10:07 go/README.md
-rw-r--r--  0 0      0         419 Aug 10 10:07 go/SECURITY.md
-rw-r--r--  0 0      0          42 Aug 10 10:07 go/VERSION
drwxr-xr-x  0 0      0           0 Aug 10 10:07 go/api/
-rw-r--r--  0 0      0        1142 Aug 10 10:07 go/api/README
-rw-r--r--  0 0      0       35424 Aug 10 10:07 go/api/except.txt
%

Fixes #61862.
Fixes #61927.

Change-Id: Iecd9ba893015295e88715b031b79a104236b9ced
Reviewed-on: https://go-review.googlesource.com/c/go/+/518335
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-on: https://go-review.googlesource.com/c/go/+/518835
Auto-Submit: Russ Cox <rsc@golang.org>

src/cmd/distpack/archive.go
src/cmd/distpack/pack.go

index f731b3792f8c9fc2c6ee1c9ac73b1986f69f7484..24ed077610ffc6fbd2784ff7f626fa61cf7aaedf 100644 (file)
@@ -44,7 +44,7 @@ type fileInfo struct {
 func (i fileInfo) Name() string       { return path.Base(i.f.Name) }
 func (i fileInfo) ModTime() time.Time { return i.f.Time }
 func (i fileInfo) Mode() fs.FileMode  { return i.f.Mode }
-func (i fileInfo) IsDir() bool        { return false }
+func (i fileInfo) IsDir() bool        { return i.f.Mode&fs.ModeDir != 0 }
 func (i fileInfo) Size() int64        { return i.f.Size }
 func (i fileInfo) Sys() any           { return nil }
 
index e8b5255e63d88e32d117ad8812952f7e233099b4..cf507edb4de229335489002c72939d4f80dd8bbe 100644 (file)
@@ -329,8 +329,47 @@ func writeTgz(name string, a *Archive) {
 
        zw := check(gzip.NewWriterLevel(out, gzip.BestCompression))
        tw := tar.NewWriter(zw)
+
+       // Find the mode and mtime to use for directory entries,
+       // based on the mode and mtime of the first file we see.
+       // We know that modes and mtimes are uniform across the archive.
+       var dirMode fs.FileMode
+       var mtime time.Time
+       for _, f := range a.Files {
+               dirMode = fs.ModeDir | f.Mode | (f.Mode&0444)>>2 // copy r bits down to x bits
+               mtime = f.Time
+               break
+       }
+
+       // mkdirAll ensures that the tar file contains directory
+       // entries for dir and all its parents. Some programs reading
+       // these tar files expect that. See go.dev/issue/61862.
+       haveDir := map[string]bool{".": true}
+       var mkdirAll func(string)
+       mkdirAll = func(dir string) {
+               if dir == "/" {
+                       panic("mkdirAll /")
+               }
+               if haveDir[dir] {
+                       return
+               }
+               haveDir[dir] = true
+               mkdirAll(path.Dir(dir))
+               df := &File{
+                       Name: dir + "/",
+                       Time: mtime,
+                       Mode: dirMode,
+               }
+               h := check(tar.FileInfoHeader(df.Info(), ""))
+               h.Name = dir + "/"
+               if err := tw.WriteHeader(h); err != nil {
+                       panic(err)
+               }
+       }
+
        for _, f = range a.Files {
                h := check(tar.FileInfoHeader(f.Info(), ""))
+               mkdirAll(path.Dir(f.Name))
                h.Name = f.Name
                if err := tw.WriteHeader(h); err != nil {
                        panic(err)