]> Cypherpunks.ru repositories - gostls13.git/commitdiff
archive/tar: add FileInfoNames interface
authorqiulaidongfeng <2645477756@qq.com>
Fri, 4 Aug 2023 05:15:41 +0000 (05:15 +0000)
committerGopher Robot <gobot@golang.org>
Mon, 7 Aug 2023 00:25:25 +0000 (00:25 +0000)
An optional interface FileInfoNames has been added.

If the parameter fi of FileInfoHeader implements the interface
the Gname and Uname of the return value Header are
provided by the method of the interface.

Also added testing.

Fixes #50102

Change-Id: I6fd06c7c9aaf29b22b7384542fe57affed33009a

Change-Id: I6fd06c7c9aaf29b22b7384542fe57affed33009a
GitHub-Last-Rev: 5e82257948759e13880d8af12743b9524ae3df5a
GitHub-Pull-Request: golang/go#61662
Reviewed-on: https://go-review.googlesource.com/c/go/+/514235
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>

api/next/50102.txt [new file with mode: 0644]
src/archive/tar/common.go
src/archive/tar/stat_unix.go
src/archive/tar/tar_test.go

diff --git a/api/next/50102.txt b/api/next/50102.txt
new file mode 100644 (file)
index 0000000..dcb7977
--- /dev/null
@@ -0,0 +1,9 @@
+pkg archive/tar, type FileInfoNames interface { Gname, IsDir, ModTime, Mode, Name, Size, Sys, Uname } #50102
+pkg archive/tar, type FileInfoNames interface, Gname(int) (string, error) #50102
+pkg archive/tar, type FileInfoNames interface, IsDir() bool #50102
+pkg archive/tar, type FileInfoNames interface, ModTime() time.Time #50102
+pkg archive/tar, type FileInfoNames interface, Mode() fs.FileMode #50102
+pkg archive/tar, type FileInfoNames interface, Name() string #50102
+pkg archive/tar, type FileInfoNames interface, Size() int64 #50102
+pkg archive/tar, type FileInfoNames interface, Sys() interface{} #50102
+pkg archive/tar, type FileInfoNames interface, Uname(int) (string, error) #50102
index d26463501ba06513e3e31a48ae755ba90037a2a0..f141548db89cb0768647506979907b0941cecdc1 100644 (file)
@@ -614,6 +614,8 @@ func (fi headerFileInfo) String() string {
 // sysStat, if non-nil, populates h from system-dependent fields of fi.
 var sysStat func(fi fs.FileInfo, h *Header) error
 
+var loadUidAndGid func(fi fs.FileInfo, uid, gid *int)
+
 const (
        // Mode constants from the USTAR spec:
        // See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
@@ -639,6 +641,10 @@ const (
 // Since fs.FileInfo's Name method only returns the base name of
 // the file it describes, it may be necessary to modify Header.Name
 // to provide the full path name of the file.
+//
+// If fi implements [FileInfoNames]
+// the Gname and Uname of the header are
+// provided by the methods of the interface.
 func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
        if fi == nil {
                return nil, errors.New("archive/tar: FileInfo is nil")
@@ -711,12 +717,38 @@ func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
                        }
                }
        }
+       if iface, ok := fi.(FileInfoNames); ok {
+               var err error
+               if loadUidAndGid != nil {
+                       loadUidAndGid(fi, &h.Uid, &h.Gid)
+               }
+               h.Gname, err = iface.Gname(h.Gid)
+               if err != nil {
+                       return nil, err
+               }
+               h.Uname, err = iface.Uname(h.Gid)
+               if err != nil {
+                       return nil, err
+               }
+               return h, nil
+       }
        if sysStat != nil {
                return h, sysStat(fi, h)
        }
        return h, nil
 }
 
+// FileInfoNames extends [FileInfo] to translate UID/GID to names.
+// Passing an instance of this to [FileInfoHeader] permits the caller
+// to control UID/GID resolution.
+type FileInfoNames interface {
+       fs.FileInfo
+       // Uname should translate a UID into a user name.
+       Uname(uid int) (string, error)
+       // Gname should translate a GID into a group name.
+       Gname(gid int) (string, error)
+}
+
 // isHeaderOnlyType checks if the given type flag is of the type that has no
 // data section even if a size is specified.
 func isHeaderOnlyType(flag byte) bool {
index 0f3428bc24b47d3683ace47bd38bd0548f7d5dd7..5b23d3c8302f488cee4f504183fc20b32a1bc10a 100644 (file)
@@ -17,6 +17,7 @@ import (
 
 func init() {
        sysStat = statUnix
+       loadUidAndGid = loadUidAndGidFunc
 }
 
 // userMap and groupMap caches UID and GID lookups for performance reasons.
@@ -99,3 +100,12 @@ func statUnix(fi fs.FileInfo, h *Header) error {
        }
        return nil
 }
+
+func loadUidAndGidFunc(fi fs.FileInfo, uid, gid *int) {
+       sys, ok := fi.Sys().(*syscall.Stat_t)
+       if !ok {
+               return
+       }
+       *uid = int(sys.Uid)
+       *gid = int(sys.Gid)
+}
index a476f5eb010f21d7cc4559bf860a83aa516a0553..6bb27ec3e846d1b8771b9cf53c313ee73bf028db 100644 (file)
@@ -848,3 +848,51 @@ func Benchmark(b *testing.B) {
        })
 
 }
+
+type fileInfoNames struct{}
+
+func (f *fileInfoNames) Name() string {
+       return "tmp"
+}
+
+func (f *fileInfoNames) Size() int64 {
+       return 0
+}
+
+func (f *fileInfoNames) Mode() fs.FileMode {
+       return 0777
+}
+
+func (f *fileInfoNames) ModTime() time.Time {
+       return time.Time{}
+}
+
+func (f *fileInfoNames) IsDir() bool {
+       return false
+}
+
+func (f *fileInfoNames) Sys() any {
+       return nil
+}
+
+func (f *fileInfoNames) Uname(uid int) (string, error) {
+       return "Uname", nil
+}
+
+func (f *fileInfoNames) Gname(gid int) (string, error) {
+       return "Gname", nil
+}
+
+func TestFileInfoHeaderUseFileInfoNames(t *testing.T) {
+       info := &fileInfoNames{}
+       header, err := FileInfoHeader(info, "")
+       if err != nil {
+               t.Fatal(err)
+       }
+       if header.Uname != "Uname" {
+               t.Fatalf("header.Uname: got %v, want %v", header.Uname, "Uname")
+       }
+       if header.Gname != "Gname" {
+               t.Fatalf("header.Gname: got %v, want %v", header.Gname, "Gname")
+       }
+}