Source File
zip.go
Belonging Package
golang.org/x/mod/zip
package zip
import (
)
MaxZipFile = 500 << 20
MaxGoMod = 16 << 20
MaxLICENSE = 16 << 20
)
Path() string
Open() (io.ReadCloser, error)
}
func ( CheckedFiles) () error {
if .SizeError != nil {
return .SizeError
}
if len(.Invalid) > 0 {
return FileErrorList(.Invalid)
}
return nil
}
type FileErrorList []FileError
func ( FileErrorList) () string {
:= &strings.Builder{}
:= ""
for , := range {
.WriteString()
.WriteString(.Error())
= "\n"
}
return .String()
}
type FileError struct {
Path string
Err error
}
func ( FileError) () string {
return fmt.Sprintf("%s: %s", .Path, .Err)
}
func ( FileError) () error {
return .Err
}
errPathNotClean = errors.New("file path is not clean")
errPathNotRelative = errors.New("file path is not relative")
errGoModCase = errors.New("go.mod files must have lowercase names")
errGoModSize = fmt.Errorf("go.mod file too large (max size is %d bytes)", MaxGoMod)
errLICENSESize = fmt.Errorf("LICENSE file too large (max size is %d bytes)", MaxLICENSE)
errVCS = errors.New("directory is a version control repository")
errVendored = errors.New("file is in vendor directory")
errSubmoduleFile = errors.New("file is in another module")
errSubmoduleDir = errors.New("directory is in another module")
errHgArchivalTxt = errors.New("file is inserted by 'hg archive' and is always omitted")
errSymlink = errors.New("file is a symbolic link")
errNotRegular = errors.New("not a regular file")
)
func ( []File) (CheckedFiles, error) {
, , := checkFiles()
return , .Err()
}
:= make(map[string]bool)
for , := range {
:= .Path()
, := path.Split()
if strings.EqualFold(, "go.mod") {
, := .Lstat()
if != nil {
(, false, )
continue
}
if .Mode().IsRegular() {
[] = true
}
}
}
:= func( string) bool {
for {
, := path.Split()
if == "" {
return false
}
if [] {
return true
}
= [:len()-1]
}
}
:= make(collisionChecker)
:= int64(MaxZipFile)
for , := range {
:= .Path()
if != path.Clean() {
(, false, errPathNotClean)
continue
}
if path.IsAbs() {
(, false, errPathNotRelative)
continue
}
if isVendoredPackage() {
(, true, errVendored)
continue
}
if () {
(, true, errSubmoduleFile)
continue
}
(, true, errSymlink)
continue
}
if !.Mode().IsRegular() {
(, true, errNotRegular)
continue
}
:= .Size()
if >= 0 && <= {
-=
} else if .SizeError == nil {
.SizeError = fmt.Errorf("module source tree too large (max size is %d bytes)", MaxZipFile)
}
if == "go.mod" && > MaxGoMod {
(, false, errGoModSize)
continue
}
if == "LICENSE" && > MaxLICENSE {
(, false, errLICENSESize)
continue
}
.Valid = append(.Valid, )
= append(, )
= append(, .Size())
}
return , ,
}
, , := listFilesInDir()
if != nil {
return CheckedFiles{},
}
, := CheckFiles()
_ = // ignore this error; we'll generate our own after rewriting paths.
, := .Stat()
if != nil {
return nil, CheckedFiles{},
}
:= .Size()
if > MaxZipFile {
:= CheckedFiles{SizeError: fmt.Errorf("module zip file is too large (%d bytes; limit is %d bytes)", , MaxZipFile)}
return nil, , .Err()
}
var CheckedFiles
:= func( *zip.File, error) {
.Invalid = append(.Invalid, FileError{Path: .Name, Err: })
}
, := zip.NewReader(, )
if != nil {
return nil, CheckedFiles{},
}
:= fmt.Sprintf("%s@%s/", .Path, .Version)
:= make(collisionChecker)
var int64
for , := range .File {
if !strings.HasPrefix(.Name, ) {
(, fmt.Errorf("path does not have prefix %q", ))
continue
}
:= .Name[len():]
if == "" {
continue
}
:= strings.HasSuffix(, "/")
if {
= [:len()-1]
}
if path.Clean() != {
(, errPathNotClean)
continue
}
if := module.CheckFilePath(); != nil {
(, )
continue
}
if := .check(, ); != nil {
(, )
continue
}
if {
continue
}
if := path.Base(); strings.EqualFold(, "go.mod") {
if != {
(, fmt.Errorf("go.mod file not in module root directory"))
continue
}
if != "go.mod" {
(, errGoModCase)
continue
}
}
:= int64(.UncompressedSize64)
if >= 0 && MaxZipFile- >= {
+=
} else if .SizeError == nil {
.SizeError = fmt.Errorf("total uncompressed size of module contents too large (max size is %d bytes)", MaxZipFile)
}
if == "go.mod" && > MaxGoMod {
(, fmt.Errorf("go.mod file too large (max size is %d bytes)", MaxGoMod))
continue
}
if == "LICENSE" && > MaxLICENSE {
(, fmt.Errorf("LICENSE file too large (max size is %d bytes)", MaxLICENSE))
continue
}
.Valid = append(.Valid, .Name)
}
return , , .Err()
}
, , := checkFiles()
if := .Err(); != nil {
return
}
:= zip.NewWriter()
:= fmt.Sprintf("%s@%s/", .Path, .Version)
:= func( File, string, int64) error {
, := .Open()
if != nil {
return
}
defer .Close()
, := .Create( + )
if != nil {
return
}
:= &io.LimitedReader{R: , N: + 1}
if , := io.Copy(, ); != nil {
return
}
if .N <= 0 {
return fmt.Errorf("file %q is larger than declared size", )
}
return nil
}
for , := range {
:= .Path()
:= []
if := (, , ); != nil {
return
}
}
return .Close()
}
func ( io.Writer, module.Version, string) ( error) {
defer func() {
if , := .(*zipError); {
.path =
} else if != nil {
= &zipError{verb: "create zip", path: , err: }
}
}()
, , := listFilesInDir()
if != nil {
return
}
return Create(, , )
}
type dirFile struct {
filePath, slashPath string
info os.FileInfo
}
func ( dirFile) () string { return .slashPath }
func ( dirFile) () (os.FileInfo, error) { return .info, nil }
func ( dirFile) () (io.ReadCloser, error) { return os.Open(.filePath) }
:= fmt.Sprintf("%s@%s/", .Path, .Version)
if := os.MkdirAll(, 0777); != nil {
return
}
for , := range .File {
:= .Name[len():]
if == "" || strings.HasSuffix(, "/") {
continue
}
:= filepath.Join(, )
if := os.MkdirAll(filepath.Dir(), 0777); != nil {
return
}
, := os.OpenFile(, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0444)
if != nil {
return
}
, := .Open()
if != nil {
.Close()
return
}
:= &io.LimitedReader{R: , N: int64(.UncompressedSize64) + 1}
_, = io.Copy(, )
.Close()
if != nil {
.Close()
return
}
if := .Close(); != nil {
return
}
if .N <= 0 {
return fmt.Errorf("uncompressed size of file %s is larger than declared size (%d bytes)", .Name, .UncompressedSize64)
}
}
return nil
}
type collisionChecker map[string]pathInfo
type pathInfo struct {
path string
isDir bool
}
func ( collisionChecker) ( string, bool) error {
:= strToFold()
if , := []; {
if != .path {
return fmt.Errorf("case-insensitive file name collision: %q and %q", .path, )
}
if != .isDir {
return fmt.Errorf("entry %q is both a file and a directory", )
}
if ! {
return fmt.Errorf("multiple entries for file %q", )
if isVendoredPackage() {
= append(, FileError{Path: , Err: errVendored})
return nil
}
if .IsDir() {
return nil
}
if !.Mode().IsRegular() {
= append(, FileError{Path: , Err: errNotRegular})
return nil
}
= append(, dirFile{
filePath: ,
slashPath: ,
info: ,
})
return nil
})
if != nil {
return nil, nil,
}
return , , nil
}
type zipError struct {
verb, path string
err error
}
func ( *zipError) () string {
if .path == "" {
return fmt.Sprintf("%s: %v", .verb, .err)
} else {
return fmt.Sprintf("%s %s: %v", .verb, .path, .err)
}
}
func ( *zipError) () error {
return .err
}
for {
:=
= unicode.SimpleFold()
if <= {
break
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |