Go version
go version go1.26.2 linux/amd64
Output of go env in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1088487257=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/root/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.26.2'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
Create bad.zip with this code:
package main
import (
"archive/zip"
"os"
)
func main() {
f, err := os.Create("bad.zip")
if err != nil {
panic(err)
}
defer f.Close()
zw := zip.NewWriter(f)
defer zw.Close()
w, err := zw.Create("uploads/Это строка в UTF8.png")
if err != nil {
panic(err)
}
_, err = w.Write([]byte("test"))
if err != nil {
panic(err)
}
}
Then check output with:
go run main.go
unzip -Z -1 bad.zip
unzip -l bad.zip
It will be broken.
What did you see happen?
inside docker run --rm -ti golang:1.26:
root@3938f10f21ec:/tmp# go run main.go
root@3938f10f21ec:/tmp# unzip -Z -1 bad.zip
uploads/���� ��������� � UTF8.png
root@3938f10f21ec:/tmp# unzip -l bad.zip
Archive: bad.zip
Length Date Time Name
--------- ---------- ----- ----
4 1980-00-00 00:00 uploads/���� ��������� � UTF8.png
--------- -------
4 1 file
What did you expect to see?
If we change program to:
package main
import (
"archive/zip"
"encoding/binary"
"hash/crc32"
"os"
)
const infoZipUnicodePathExtraID = 0x7075
func main() {
f, err := os.Create("good.zip")
if err != nil {
panic(err)
}
defer f.Close()
zw := zip.NewWriter(f)
defer zw.Close()
name := "uploads/Это строка в UTF8.png"
w, err := zw.CreateHeader(&zip.FileHeader{
Name: name,
Method: zip.Deflate,
Extra: unicodePathExtraField(name),
})
if err != nil {
panic(err)
}
_, err = w.Write([]byte("test"))
if err != nil {
panic(err)
}
}
func unicodePathExtraField(name string) []byte {
nameBytes := []byte(name)
dataSize := uint16(1 + 4 + len(nameBytes))
extra := binary.LittleEndian.AppendUint16(nil, infoZipUnicodePathExtraID)
extra = binary.LittleEndian.AppendUint16(extra, dataSize)
extra = append(extra, 1) // Info-ZIP Unicode Path version.
extra = binary.LittleEndian.AppendUint32(extra, crc32.ChecksumIEEE(nameBytes))
extra = append(extra, nameBytes...)
return extra
}
Then:
root@3938f10f21ec:/tmp# go run main.go
root@3938f10f21ec:/tmp# unzip -Z -1 good.zip
uploads/Это строка в UTF8.png
root@3938f10f21ec:/tmp# unzip -l good.zip
Archive: good.zip
Length Date Time Name
--------- ---------- ----- ----
4 1980-00-00 00:00 uploads/Это строка в UTF8.png
--------- -------
4 1 file
And here is correct filename output into console.
So library archive/zip doesn't automatically handles unicode filenames as expected.
Go version
go version go1.26.2 linux/amd64
Output of
go envin your module/workspace:What did you do?
Create
bad.zipwith this code:Then check output with:
It will be broken.
What did you see happen?
inside
docker run --rm -ti golang:1.26:What did you expect to see?
If we change program to:
Then:
And here is correct filename output into console.
So library
archive/zipdoesn't automatically handles unicode filenames as expected.