Documentation ¶
Overview ¶
message from the author:
+--------------------------------------------------------------+ | * * * ░░░░░░░░░░░░░░░░░░░░ Hello ░░░░░░░░░░░░░░░░░░░░░░░░░░| +--------------------------------------------------------------+ | | | ++ ______________________________________ | | ++++ / \ | | ++++ | | | | ++++++++++ | Feel free to contribute to this | | | +++ | | project or contact me on | | | ++ | | manfred.life if you like this | | | + -== ==| | project! | | | ( <*> <*> | | | | | | /| :) | | | | _) / | | | | | +++ / \______________________________________/ | | \ =+ / | | \ + | | |\++++++ | | | ++++ ||// | | ___| |___ _||/__ __| | / --- \ \| ||| __ _ ___ __ __/ /| |/ | | \ \ / / ' \/ _ \/ // / / | || | | | | | /_/_/_/\___/\_,_/_/ | +--------------------------------------------------------------+
Index ¶
- func B64Decode(input string) ([]byte, error)
- func B64Encode(input []byte) string
- func BoolPtr(val bool) *bool
- func CaptureStderr() (func() string, error)
- func CaptureStdout() (func() string, error)
- func CaptureStdoutAndStderr() (func() string, error)
- func CheckErr(err error)
- func CombineFuncs(left func(), right ...func()) func()
- func CommandExists(command string) bool
- func CreateEmptyFileWithSize(path string, size uint) error
- func CurrentUsername(fallback string) string
- func DirExists(path string) bool
- func ExecStandaloneOutputs(cmd *exec.Cmd) ([]byte, []byte, error)
- func ExpandPath(path string) (string, error)
- func FanIn(chans ...<-chan interface{}) <-chan interface{}
- func FileExists(path string) bool
- func Future(fn func() (interface{}, error)) <-chan FutureRet
- func IsASCII(buf []byte) bool
- func IsBinary(buf []byte) bool
- func JSON(input interface{}) string
- func MustCaptureStderr() func() string
- func MustCaptureStdout() func() string
- func MustCaptureStdoutAndStderr() func() string
- func MustExpandPath(path string) string
- func MustTempFileName(dir, pattern string) string
- func MustTempfileWithContent(content []byte) (*os.File, func())
- func PathExists(path string) bool
- func PrettyJSON(input interface{}) string
- func RandomLetters(n int) string
- func SafeExec(cmd *exec.Cmd) string
- func Sha1(data []byte) []byte
- func Sha1Hex(data []byte) string
- func ShortDuration(d time.Duration) string
- func SilentClose(closer io.Closer)
- func TempFileName(dir, pattern string) (string, error)
- func TempfileWithContent(content []byte) (*os.File, func(), error)
- func UniqueInterfaces(input []interface{}) []interface{}
- func UniqueInts(input []int) []int
- func UniqueStrings(input []string) []string
- func Unzip(src string, dest string) ([]string, error)
- func UnzipBytes(src []byte, dest string) ([]string, error)
- func WaitForCtrlC()
- type FutureRet
- type MutexMap
- type UniqueChild
Examples ¶
- B64Decode
- B64Encode
- BoolPtr
- CaptureStderr
- CaptureStdout
- CaptureStdoutAndStderr
- CheckErr
- CombineFuncs
- CommandExists
- CreateEmptyFileWithSize
- CurrentUsername
- DirExists
- ExecStandaloneOutputs
- ExpandPath
- FanIn
- FileExists
- Future
- IsASCII
- IsBinary
- JSON
- MustCaptureStderr
- MustCaptureStdout
- MustCaptureStdoutAndStderr
- MustExpandPath
- MustTempFileName
- MustTempfileWithContent
- MutexMap
- PathExists
- PrettyJSON
- RandomLetters
- SafeExec
- Sha1
- Sha1Hex
- ShortDuration
- SilentClose
- TempFileName
- TempfileWithContent
- UniqueChild
- UniqueInterfaces
- UniqueInts
- UniqueStrings
- Unzip
- Unzip (Zipslip)
- UnzipBytes
- UnzipBytes (CreateAndUnzip)
- UnzipBytes (CreateAndUnzipZipSlip)
- WaitForCtrlC
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func B64Decode ¶ added in v1.6.0
B64Decode try to decode an input string and returns bytes if success.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { ret, _ := u.B64Decode("aGVsbG8gd29ybGQh") fmt.Println(string(ret)) }
Output: hello world!
func B64Encode ¶ added in v1.6.0
B64Encode returns a base64 encoded string of input bytes.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.B64Encode([]byte("hello world!"))) }
Output: aGVsbG8gd29ybGQh
func BoolPtr ¶ added in v1.24.0
BoolPtr returns a pointer to a bool of value 'val'.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { truePtr := u.BoolPtr(true) falsePtr := u.BoolPtr(false) fmt.Println("true ptr: ", *truePtr) fmt.Println("false ptr: ", *falsePtr) }
Output: true ptr: true false ptr: false
func CaptureStderr ¶ added in v1.9.0
CaptureStderr temporarily pipes os.Stderr into a buffer.
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { os.Stderr = os.Stdout // hack to run this test as an example test fmt.Fprintln(os.Stderr, "AAA") closer, err := u.CaptureStderr() if err != nil { panic(err) } fmt.Fprintln(os.Stderr, "BBB") ret := closer() fmt.Fprintln(os.Stderr, "CCC") fmt.Fprintln(os.Stderr, ret) }
Output: AAA CCC BBB
func CaptureStdout ¶ added in v1.9.0
CaptureStdout temporarily pipes os.Stdout into a buffer.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println("AAA") closer, err := u.CaptureStdout() if err != nil { panic(err) } fmt.Println("BBB") ret := closer() fmt.Println("CCC") fmt.Println(ret) }
Output: AAA CCC BBB
func CaptureStdoutAndStderr ¶ added in v1.9.0
CaptureStdoutAndStderr temporarily pipes os.Stdout and os.Stderr into a buffer.
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { os.Stderr = os.Stdout // hack to run this test as an example test fmt.Fprintln(os.Stderr, "AAA") fmt.Println("BBB") closer, err := u.CaptureStdoutAndStderr() if err != nil { panic(err) } fmt.Fprintln(os.Stderr, "CCC") fmt.Println("DDD") ret := closer() fmt.Fprintln(os.Stderr, "EEE") fmt.Println("FFF") fmt.Println(ret) }
Output: AAA BBB EEE FFF CCC DDD
func CheckErr ¶ added in v1.19.0
func CheckErr(err error)
CheckErr panics if the passed error is not nil.
Example ¶
package main import ( "net/http" "moul.io/u" ) func main() { _, err := http.Get("http://foo.bar") u.CheckErr(err) // panic }
Output:
func CombineFuncs ¶ added in v1.6.0
func CombineFuncs(left func(), right ...func()) func()
CombineFuncs create a chain of functions. This can be particularly useful for creating cleanup function progressively. It solves the infinite loop you can have when trying to do it manually: https://play.golang.org/p/NQem8UJ500t.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { cleanup := func() { fmt.Print("A") } cleanup = u.CombineFuncs(cleanup, func() { fmt.Print("B") }) cleanup = u.CombineFuncs(func() { fmt.Print("C") }, cleanup) cleanup() }
Output: CAB
func CommandExists ¶ added in v1.18.0
CommandExists checks whether a command is available in the $PATH.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.CommandExists("go")) fmt.Println(u.CommandExists("asldkglsakdjaslkdg")) }
Output: true false
func CreateEmptyFileWithSize ¶ added in v1.18.0
CreateEmptyFileWithSize creates a new file of the desired size, filled with zeros.
Example ¶
package main import ( "fmt" "io/ioutil" "os" "moul.io/u" ) func main() { tempname := u.MustTempFileName("", "u") err := u.CreateEmptyFileWithSize(tempname, 42) if err != nil { panic(err) } defer os.Remove(tempname) fi, err := os.Stat(tempname) if err != nil { panic(err) } fmt.Println(fi.Size()) b, err := ioutil.ReadFile(tempname) if err != nil { panic(err) } fmt.Println(b) }
Output: 42 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
func CurrentUsername ¶ added in v1.18.0
CurrentUsename returns the current user's username. If username cannot be retrieved, it returns the passed fallback.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.CurrentUsername("fallback")) }
Output:
func DirExists ¶ added in v1.18.0
DirExists checks whether a path exists and is a directory.
Example ¶
package main import ( "fmt" "io/ioutil" "os" "path/filepath" "moul.io/u" ) func main() { file, err := ioutil.TempFile("", "bar") if err != nil { panic(err) } defer os.RemoveAll(file.Name()) fmt.Println(u.DirExists("/laksjdflkasdjflaksdjfalskdfjasdlfkj")) // should not exist fmt.Println(u.DirExists(file.Name())) fmt.Println(u.DirExists(filepath.Dir(file.Name()))) }
Output: false false true
func ExecStandaloneOutputs ¶ added in v1.18.0
ExecStandaloneOutputs runs the command and returns its standard output and standard error.
Example ¶
package main import ( "fmt" "os/exec" "moul.io/u" ) func main() { stdout, stderr, err := u.ExecStandaloneOutputs(exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")) fmt.Print("stdout: ", string(stdout)) fmt.Print("stderr: ", string(stderr)) fmt.Println("err: ", err) }
Output: stdout: stdout stderr: stderr err: <nil>
func ExpandPath ¶ added in v1.25.0
ExpandPath performs various expansions on a given path.
- Replaces ~/ with $HOME/. - Returns absolute path. - Expands env vars. TODO: - Follow symlinks.
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { os.Setenv("HOME", "/home/foo") // just for example ret, err := u.ExpandPath("~/hello-world.txt") if err != nil { panic(err) } fmt.Println(ret) }
Output: /home/foo/hello-world.txt
func FanIn ¶ added in v1.20.0
func FanIn(chans ...<-chan interface{}) <-chan interface{}
FanIn merges multiple input chans events into one.
Example ¶
package main import ( "fmt" "sort" "strings" "moul.io/u" ) func main() { ch1 := make(chan interface{}) ch2 := make(chan interface{}) ch3 := make(chan interface{}) merged := u.FanIn(ch1, ch2, ch3) done := make(chan bool) received := []string{} go func() { for item := range merged { fmt.Println("tick") received = append(received, fmt.Sprintf("%v", item)) } done <- true }() ch1 <- 1 ch2 <- 2 ch3 <- 3 close(ch1) ch2 <- 4 ch2 <- 5 ch3 <- 6 close(ch2) ch3 <- 7 close(ch3) <-done sort.Strings(received) fmt.Println(strings.Join(received, ", ")) }
Output: tick tick tick tick tick tick tick 1, 2, 3, 4, 5, 6, 7
func FileExists ¶ added in v1.18.0
FileExists checks whether a path exists and is a regular file.
Example ¶
package main import ( "fmt" "io/ioutil" "os" "path/filepath" "moul.io/u" ) func main() { file, err := ioutil.TempFile("", "bar") if err != nil { panic(err) } defer os.RemoveAll(file.Name()) fmt.Println(u.FileExists("/laksjdflkasdjflaksdjfalskdfjasdlfkj")) // should not exist fmt.Println(u.FileExists(file.Name())) fmt.Println(u.FileExists(filepath.Dir(file.Name()))) }
Output: false true false
func Future ¶ added in v1.20.0
Future starts running the given function in background and return a chan that will return the result of the execution.
Example ¶
package main import ( "fmt" "time" "moul.io/u" ) func main() { future := u.Future(func() (interface{}, error) { time.Sleep(100 * time.Millisecond) return "foobar", nil }) // here, we can do some stuff ret := <-future fmt.Println("Ret:", ret.Ret) fmt.Println("Err:", ret.Err) }
Output: Ret: foobar Err: <nil>
func IsASCII ¶ added in v1.26.0
IsASCII checks whether a buffer only contains ASCII characters.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.IsASCII([]byte("hello"))) }
Output: true
func IsBinary ¶ added in v1.23.0
IsBinary returns whether the provided buffer looks like binary or human-readable.
It is inspired by the implementation made in the Git project. https://github.com/git/git/blob/49f38e2de47a401fc2b0f4cce38e9f07fb63df48/xdiff-interface.c#L188.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.IsBinary([]byte{'c', 'h', 'i', 'c', 'k', 'e', 'n'})) fmt.Println(u.IsBinary([]byte{'c', 'h', 'i', 0, 'k', 'e', 'n'})) }
Output: false true
func JSON ¶ added in v1.6.0
func JSON(input interface{}) string
JSON returns a JSON representation of the passed input.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.JSON([]string{"hello", "world"})) fmt.Println(u.JSON(42)) fmt.Println(u.JSON(nil)) }
Output: ["hello","world"] 42 null
func MustCaptureStderr ¶ added in v1.9.0
func MustCaptureStderr() func() string
MustCaptureStderr wraps CaptureStderr and panics if initialization fails.
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { os.Stderr = os.Stdout // hack to run this test as an example test fmt.Fprintln(os.Stderr, "AAA") closer := u.MustCaptureStderr() fmt.Fprintln(os.Stderr, "BBB") ret := closer() fmt.Fprintln(os.Stderr, "CCC") fmt.Fprintln(os.Stderr, ret) }
Output: AAA CCC BBB
func MustCaptureStdout ¶ added in v1.9.0
func MustCaptureStdout() func() string
MustCaptureStdout wraps CaptureStdout and panics if initialization fails.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println("AAA") closer := u.MustCaptureStdout() fmt.Println("BBB") ret := closer() fmt.Println("CCC") fmt.Println(ret) }
Output: AAA CCC BBB
func MustCaptureStdoutAndStderr ¶ added in v1.9.0
func MustCaptureStdoutAndStderr() func() string
MustCaptureStdoutAndStderr wraps CaptureStdoutAndStderr and panics if initialization fails.
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { os.Stderr = os.Stdout // hack to run this test as an example test fmt.Fprintln(os.Stderr, "AAA") fmt.Println("BBB") closer := u.MustCaptureStdoutAndStderr() fmt.Fprintln(os.Stderr, "CCC") fmt.Println("DDD") ret := closer() fmt.Fprintln(os.Stderr, "EEE") fmt.Println("FFF") fmt.Println(ret) }
Output: AAA BBB EEE FFF CCC DDD
func MustExpandPath ¶ added in v1.25.0
MustExpandPath wraps ExpandPath and panics if initialization fails.
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { os.Setenv("HOME", "/home/foo") // just for example ret := u.MustExpandPath("~/hello-world.txt") fmt.Println(ret) }
Output: /home/foo/hello-world.txt
func MustTempFileName ¶ added in v1.18.0
MustTempFileName wraps TempFileName and panics if initialization fails.
Example ¶
package main import ( "os" "moul.io/u" ) func main() { tempname := u.MustTempFileName("", "u") f, _ := os.Create(tempname) f.Close() os.Remove(tempname) }
Output:
func MustTempfileWithContent ¶ added in v1.9.0
MustTempfileWithContent wraps TempfileWithContent and panics if initialization fails.
Example ¶
package main import ( "fmt" "io/ioutil" "moul.io/u" ) func main() { f, cleanup := u.MustTempfileWithContent([]byte("AAA\nBBB\nCCC")) defer cleanup() out, err := ioutil.ReadAll(f) if err != nil { panic(err) } fmt.Println(string(out)) }
Output: AAA BBB CCC
func PathExists ¶ added in v1.18.0
PathExists checks whether a path exists or not.
Example ¶
package main import ( "fmt" "io/ioutil" "os" "path/filepath" "moul.io/u" ) func main() { file, err := ioutil.TempFile("", "bar") if err != nil { panic(err) } defer os.RemoveAll(file.Name()) fmt.Println(u.PathExists("/laksjdflkasdjflaksdjfalskdfjasdlfkj")) // should not exist fmt.Println(u.PathExists(file.Name())) fmt.Println(u.PathExists(filepath.Dir(file.Name()))) }
Output: false true true
func PrettyJSON ¶ added in v1.6.0
func PrettyJSON(input interface{}) string
PrettyJSON returns an indented JSON representation of the passed input.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.PrettyJSON([]string{"hello", "world"})) fmt.Println(u.PrettyJSON(42)) fmt.Println(u.PrettyJSON(nil)) }
Output: [ "hello", "world" ] 42 null
func RandomLetters ¶ added in v1.22.0
RandomLetters returns a string containing 'n' random letters.
Example ¶
package main import ( "fmt" "math/rand" "moul.io/u" ) func main() { rand.Seed(42) fmt.Println(u.RandomLetters(8)) fmt.Println(u.RandomLetters(8)) fmt.Println(u.RandomLetters(8)) fmt.Println(u.RandomLetters(42)) }
Output: HRukpTTu eZPtNeuv unhuksqV GzAdxlgghEjkMVeZJpmKqakmTRgKfBSWYjUNGkdmdt
func SafeExec ¶ added in v1.18.0
SafeExec runs a command and return a string containing the combined standard output and standard error. If the program fails, the result of `err` is appended to the output.
Example ¶
package main import ( "fmt" "os/exec" "moul.io/u" ) func main() { out := u.SafeExec(exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr; exit 1")) fmt.Println(out) }
Output: stdout stderr error: exit status 1
func Sha1 ¶
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.Sha1([]byte("hello world!"))) }
Output: [67 12 227 77 2 7 36 237 117 161 150 223 194 173 103 199 119 114 209 105]
func Sha1Hex ¶
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.Sha1Hex([]byte("hello world!"))) }
Output: 430ce34d020724ed75a196dfc2ad67c77772d169
func ShortDuration ¶ added in v1.9.0
ShortDuration returns a short human-friendly representation of a duration. For duration < 100 days, the output length will be <= 7.
Example ¶
package main import ( "fmt" "time" "moul.io/u" ) func main() { fmt.Println(u.ShortDuration(time.Nanosecond * 0)) fmt.Println(u.ShortDuration(time.Nanosecond)) fmt.Println(u.ShortDuration(time.Nanosecond * 12)) fmt.Println(u.ShortDuration(time.Nanosecond * 123)) fmt.Println(u.ShortDuration(time.Nanosecond * 1234)) fmt.Println(u.ShortDuration(time.Nanosecond * 12345)) fmt.Println(u.ShortDuration(time.Nanosecond * 123456)) fmt.Println(u.ShortDuration(time.Nanosecond * 1234567)) fmt.Println(u.ShortDuration(time.Nanosecond * 12345678)) fmt.Println(u.ShortDuration(time.Nanosecond * 123456789)) fmt.Println(u.ShortDuration(time.Nanosecond * 1234567891)) fmt.Println(u.ShortDuration(time.Nanosecond * 12345678912)) fmt.Println(u.ShortDuration(time.Nanosecond * 123456789123)) fmt.Println(u.ShortDuration(time.Nanosecond * 1234567891234)) fmt.Println(u.ShortDuration(time.Nanosecond * 12345678912345)) fmt.Println(u.ShortDuration(time.Nanosecond * 123456789123456)) fmt.Println(u.ShortDuration(time.Nanosecond * 1234567891234567)) fmt.Println(u.ShortDuration(time.Nanosecond * 12345678912345678)) fmt.Println(u.ShortDuration(time.Nanosecond * 123456789123456789)) fmt.Println(u.ShortDuration(time.Nanosecond * 1234567891234567891)) fmt.Println("-------") fmt.Println(u.ShortDuration(time.Nanosecond)) fmt.Println(u.ShortDuration(time.Microsecond)) fmt.Println(u.ShortDuration(time.Millisecond)) fmt.Println(u.ShortDuration(time.Second)) fmt.Println(u.ShortDuration(time.Minute)) fmt.Println(u.ShortDuration(time.Hour)) fmt.Println(u.ShortDuration(time.Hour * 24)) fmt.Println(u.ShortDuration(time.Hour + time.Second)) }
Output: 0s 1ns 12ns 123ns 1.2µs 12.3µs 123.5µs 1.2ms 12.3ms 123.5ms 1.2s 12.3s 2m3s 20m35s 3h25m46s 1d10h18m 14d6h56m 142d21h21m 1428d21h33m 14288d23h32m ------- 1ns 1µs 1ms 1s 1m 1h 1d 1h0m1s
func SilentClose ¶ added in v1.6.0
SilentClose calls an io.Closer.Close() function and ignore potential errors.
You can use it as `defer SilenceClose(f)`
Example ¶
package main import ( "os" "moul.io/u" ) func main() { f, _ := os.Open("file.txt") defer u.SilentClose(f) }
Output:
func TempFileName ¶ added in v1.18.0
TempFileName returns a valid temporary file name (the file is not created).
Example ¶
package main import ( "fmt" "os" "moul.io/u" ) func main() { tempname, err := u.TempFileName("", "u") if err != nil { panic(err) } if u.FileExists(tempname) { panic("there is already one file with tempname") } f, err := os.Create(tempname) if err != nil { panic(err) } defer os.Remove(tempname) f.Close() fmt.Println("Everything is OK!") }
Output: Everything is OK!
func TempfileWithContent ¶ added in v1.9.0
TempfileWithContent creates a tempfile with specified content written in it, it also seeks the file pointer so you can read it directly. The second returned parameter is a cleanup function that closes and removes the temp file.
Example ¶
package main import ( "fmt" "io/ioutil" "moul.io/u" ) func main() { f, cleanup, err := u.TempfileWithContent([]byte("AAA\nBBB\nCCC")) if err != nil { panic(err) } defer cleanup() out, err := ioutil.ReadAll(f) if err != nil { panic(err) } fmt.Println(string(out)) }
Output: AAA BBB CCC
func UniqueInterfaces ¶ added in v1.21.0
func UniqueInterfaces(input []interface{}) []interface{}
UniqueInterfaces removes duplicate values from an interface slice.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.UniqueInterfaces([]interface{}{13, "foo", "bar", 42, 13, 43, "baz"})) }
Output: [13 foo bar 42 43 baz]
func UniqueInts ¶ added in v1.21.0
UniqueInts removes duplicate values from an int slice.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.UniqueInts([]int{13, 51, 36, 69, 92, 92, 42, 21, 36, 13, 51})) }
Output: [13 51 36 69 92 42 21]
func UniqueStrings ¶ added in v1.21.0
UniqueStrings removes duplicate values from a string slice.
Example ¶
package main import ( "fmt" "moul.io/u" ) func main() { fmt.Println(u.UniqueStrings([]string{"foo", "bar", "foo", "baz", "foo", "bar", "foobar", "baz", "foobaz"})) }
Output: [foo bar baz foobar foobaz]
func Unzip ¶ added in v1.18.0
Unzip decompresses a zip archive, moving all files and folders within the zip file to an output directory. Based on https://golangcode.com/unzip-files-in-go/ (MIT).
Example ¶
package main import ( "fmt" "io/ioutil" "os" "strings" "moul.io/u" ) func main() { // create zipfile on fs f, cleanup, err := u.TempfileWithContent(zipdata_simple) if err != nil { panic(err) } defer cleanup() // create tempdir for dest tempdir, err := ioutil.TempDir("", "u") if err != nil { panic(err) } defer os.RemoveAll(tempdir) // unzip to dest files, err := u.Unzip(f.Name(), tempdir) if err != nil { panic(err) } for _, file := range files { relPath := "." + strings.TrimPrefix(file, tempdir) fmt.Println(relPath) } } var zipdata_simple = []byte{ 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x81, 0x61, 0x25, 0x3d, 0xc0, 0xd7, 0xed, 0xc3, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x09, 0x00, 0x03, 0x71, 0xfc, 0x82, 0x4c, 0x76, 0xfc, 0x82, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x0b, 0xc9, 0xc8, 0x2c, 0x56, 0x00, 0xa2, 0x44, 0x85, 0x92, 0xd4, 0xe2, 0x12, 0x20, 0x51, 0x51, 0xa2, 0x90, 0x96, 0x99, 0x93, 0xaa, 0xc7, 0x05, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x7e, 0x25, 0x3d, 0xfe, 0x31, 0xd5, 0x54, 0x11, 0x03, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x36, 0x78, 0x31, 0x36, 0x2e, 0x70, 0x6e, 0x67, 0x55, 0x54, 0x09, 0x00, 0x03, 0x3a, 0x30, 0x83, 0x4c, 0x3b, 0x30, 0x83, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x06, 0x00, 0x00, 0x00, 0xed, 0x73, 0x4f, 0x2f, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xd6, 0xd8, 0xd4, 0x4f, 0x58, 0x32, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xc9, 0x65, 0x3c, 0x00, 0x00, 0x02, 0xa3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x74, 0x93, 0x5f, 0x48, 0x53, 0x51, 0x18, 0xc0, 0xbf, 0x7b, 0xcf, 0xee, 0xc6, 0x75, 0x5b, 0x56, 0xda, 0x2a, 0x25, 0x6d, 0x6c, 0x06, 0x51, 0x56, 0xf4, 0x5f, 0x23, 0xb7, 0x22, 0x22, 0xb0, 0x7a, 0x88, 0x41, 0x0f, 0x4b, 0x0c, 0x0a, 0xa3, 0x82, 0x02, 0x1f, 0x62, 0x1a, 0x45, 0x2f, 0xa1, 0x83, 0x7a, 0x49, 0x2a, 0x86, 0x15, 0x35, 0xff, 0x64, 0x98, 0x90, 0xa2, 0x91, 0x2e, 0x10, 0x9c, 0x2f, 0x53, 0x92, 0xc2, 0x07, 0xe9, 0xb6, 0x86, 0x28, 0xda, 0x5d, 0xb6, 0xed, 0x5e, 0x75, 0x0e, 0xd9, 0x9f, 0xd3, 0x39, 0x9b, 0x8d, 0xad, 0xf2, 0x83, 0xef, 0x9e, 0x7b, 0xbf, 0x3f, 0xbf, 0xf3, 0x7d, 0xdf, 0x39, 0x97, 0xc1, 0x18, 0x43, 0xa6, 0xd8, 0xed, 0x76, 0xb0, 0xd9, 0x6c, 0x97, 0xcf, 0x9d, 0x3a, 0x7a, 0x23, 0xaf, 0xd0, 0x58, 0x14, 0x94, 0xe4, 0x65, 0xdf, 0xc4, 0x97, 0x65, 0x25, 0x87, 0x14, 0x9c, 0x56, 0x57, 0xe1, 0x76, 0xbb, 0xbd, 0x99, 0xf1, 0x8a, 0xcc, 0x8f, 0x96, 0x96, 0x56, 0xf4, 0xba, 0xbd, 0xcd, 0xe1, 0x68, 0xa8, 0xbd, 0x64, 0x34, 0x1a, 0xe0, 0xb8, 0xe5, 0x1a, 0xdc, 0x6f, 0xb0, 0x43, 0x69, 0x91, 0x16, 0xa4, 0x90, 0x04, 0xf3, 0x6c, 0xfe, 0x26, 0x12, 0x96, 0x05, 0x60, 0x68, 0x05, 0x35, 0x35, 0x35, 0x10, 0x5e, 0x8a, 0xc0, 0xf0, 0xe0, 0x40, 0x67, 0xf3, 0x0b, 0xa7, 0xc5, 0xeb, 0x15, 0x40, 0xfc, 0x3a, 0x02, 0xe6, 0xb3, 0x55, 0xa0, 0xe2, 0x10, 0xc4, 0x7f, 0x8e, 0x83, 0x82, 0xc1, 0x70, 0xfb, 0x51, 0x57, 0xdd, 0x56, 0xc3, 0xb6, 0xc6, 0x58, 0x2c, 0x4a, 0x36, 0x6b, 0x49, 0x11, 0x28, 0x80, 0x65, 0x99, 0x63, 0x05, 0xba, 0x75, 0x1d, 0x77, 0x6f, 0x56, 0x61, 0x59, 0x0a, 0x61, 0xcf, 0xe8, 0x27, 0x7c, 0xe4, 0xd0, 0x5e, 0x7c, 0xa2, 0x6c, 0x27, 0x7e, 0xd3, 0x54, 0x8f, 0x27, 0x5c, 0xcf, 0xb0, 0x6f, 0xc8, 0x89, 0x2f, 0x5a, 0x4e, 0x0a, 0xeb, 0xf3, 0x36, 0xb0, 0x66, 0xb3, 0x39, 0x99, 0x47, 0x35, 0xd9, 0x82, 0x26, 0x87, 0x2f, 0x2b, 0xd1, 0x6f, 0x31, 0xed, 0x30, 0x16, 0xc1, 0xc8, 0x87, 0x56, 0x00, 0xa4, 0x84, 0xca, 0x8a, 0xdd, 0x10, 0x8c, 0xaa, 0x41, 0xa3, 0xd5, 0x42, 0x3c, 0x91, 0x80, 0x70, 0x64, 0x19, 0xce, 0x57, 0x56, 0x94, 0x08, 0x33, 0xf3, 0xd7, 0x37, 0x17, 0x14, 0x34, 0x65, 0xb5, 0xc0, 0x30, 0x0c, 0x47, 0xde, 0x4b, 0xaf, 0x5e, 0x38, 0xd3, 0x7f, 0xeb, 0x8a, 0x25, 0x7f, 0x61, 0x71, 0x09, 0x18, 0x16, 0xc1, 0xb4, 0x5f, 0x06, 0xdd, 0xda, 0x1c, 0x50, 0xa9, 0x38, 0x60, 0x48, 0x80, 0x4a, 0xc9, 0x81, 0xa3, 0x73, 0x10, 0x1c, 0x6d, 0x3d, 0x8d, 0xf3, 0x52, 0xa8, 0x8e, 0x02, 0xd8, 0x15, 0x50, 0x94, 0xe8, 0xd8, 0xdb, 0xf7, 0x43, 0x1d, 0x41, 0x39, 0x4c, 0xb0, 0xa4, 0xef, 0x78, 0x02, 0x8a, 0x37, 0xe6, 0x26, 0x93, 0x02, 0x52, 0x38, 0x09, 0xa3, 0x92, 0xa7, 0x51, 0xc2, 0x82, 0x2c, 0xf5, 0xfd, 0xa9, 0x80, 0xcd, 0x9c, 0xe8, 0x5c, 0x50, 0xbe, 0xf3, 0xc4, 0xd9, 0x33, 0xc9, 0xab, 0x94, 0x29, 0x2a, 0x81, 0x90, 0xf9, 0x80, 0x77, 0x4a, 0x04, 0x61, 0x46, 0x82, 0x68, 0x2c, 0x06, 0xba, 0xfc, 0x5c, 0xea, 0x0a, 0xfc, 0x17, 0x40, 0x44, 0x7a, 0xd5, 0xe5, 0xb2, 0xf9, 0xa6, 0x45, 0x40, 0x28, 0xe5, 0x8a, 0xc6, 0xe2, 0xb0, 0x6f, 0x7b, 0x31, 0x98, 0x76, 0x15, 0x26, 0xc3, 0x57, 0xe0, 0xea, 0xd5, 0x00, 0x10, 0x8b, 0xc7, 0x5d, 0xee, 0xd1, 0xf1, 0x25, 0x5a, 0x7a, 0x7a, 0x50, 0x2c, 0x4b, 0x1f, 0x69, 0x20, 0x0d, 0x5b, 0x15, 0x40, 0x44, 0x16, 0xe7, 0x82, 0x0b, 0x2c, 0xfb, 0xaf, 0x4b, 0xa1, 0x40, 0xf0, 0xc3, 0x1f, 0xa0, 0x04, 0x7f, 0xd6, 0x4d, 0x34, 0x18, 0x0c, 0x29, 0x1a, 0x49, 0xfa, 0xee, 0x9b, 0x04, 0x44, 0x56, 0xe6, 0xaf, 0x64, 0x6a, 0x63, 0x01, 0x43, 0x30, 0x82, 0x91, 0x5a, 0xb3, 0xe6, 0x34, 0x31, 0x35, 0xa7, 0x01, 0x1e, 0x8f, 0x27, 0x19, 0xa4, 0x25, 0x67, 0x6e, 0xab, 0xab, 0x57, 0x7b, 0x06, 0x7b, 0x79, 0xba, 0x1b, 0x47, 0x14, 0x21, 0xb2, 0x72, 0x0a, 0xa0, 0x47, 0xfb, 0xb8, 0xb5, 0xef, 0xd7, 0xc7, 0x51, 0xe1, 0xe5, 0xc1, 0x03, 0xfb, 0x67, 0xb3, 0x2a, 0x28, 0x2f, 0x2f, 0x4f, 0x57, 0x20, 0x8a, 0x62, 0x42, 0x92, 0xa4, 0xda, 0xa7, 0xed, 0xfd, 0x0f, 0x4d, 0x87, 0xf7, 0xe4, 0xce, 0xce, 0x4c, 0xc3, 0xb8, 0x30, 0x15, 0x78, 0x37, 0x30, 0xdc, 0x8b, 0x11, 0x7f, 0xaf, 0xba, 0xba, 0x7a, 0xd2, 0x6a, 0xb5, 0x66, 0xff, 0x4c, 0x82, 0x20, 0x64, 0x56, 0xbb, 0x48, 0xf4, 0xb9, 0xcb, 0x33, 0x61, 0x1d, 0xfb, 0xe6, 0x8f, 0xf0, 0x3c, 0xff, 0xa0, 0xbb, 0xbb, 0xfb, 0x33, 0xb1, 0x85, 0xf4, 0x7a, 0x3d, 0xbd, 0x74, 0x59, 0xad, 0xfd, 0x16, 0x60, 0x00, 0xa8, 0x08, 0x0d, 0x8b, 0x03, 0xe7, 0x62, 0xea, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x81, 0x61, 0x25, 0x3d, 0xc0, 0xd7, 0xed, 0xc3, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x05, 0x00, 0x03, 0x71, 0xfc, 0x82, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x7e, 0x25, 0x3d, 0xfe, 0x31, 0xd5, 0x54, 0x11, 0x03, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x5b, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x36, 0x78, 0x31, 0x36, 0x2e, 0x70, 0x6e, 0x67, 0x55, 0x54, 0x05, 0x00, 0x03, 0x3a, 0x30, 0x83, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xba, 0x03, 0x00, 0x00, 0x1a, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x7a, 0x69, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, }
Output: ./test.txt ./gophercolor16x16.png
Example (Zipslip) ¶
package main import ( "fmt" "io/ioutil" "os" "moul.io/u" ) func main() { // create zipfile on fs f, cleanup, err := u.TempfileWithContent(zipdata_zipline) if err != nil { panic(err) } defer cleanup() // create tempdir for dest tempdir, err := ioutil.TempDir("", "u") if err != nil { panic(err) } defer os.RemoveAll(tempdir) // unzip to dest _, err = u.Unzip(f.Name(), tempdir) fmt.Println(err) } var zipdata_zipline = []byte{ 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xb0, 0x8f, 0x4c, 0x0f, 0x6f, 0x4f, 0xf3, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x67, 0x6f, 0x6f, 0x64, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x09, 0x00, 0x03, 0x3d, 0xa2, 0xd3, 0x5a, 0x3e, 0xa2, 0xd3, 0x5a, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf6, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x67, 0x6f, 0x6f, 0x64, 0x20, 0x6f, 0x6e, 0x65, 0x0a, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xb0, 0x8f, 0x4c, 0x60, 0x41, 0x7b, 0x39, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x65, 0x76, 0x69, 0x6c, 0x2e, 0x74, 0x78, 0x74, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x76, 0x69, 0x6c, 0x20, 0x6f, 0x6e, 0x65, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xb0, 0x8f, 0x4c, 0x0f, 0x6f, 0x4f, 0xf3, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x6f, 0x64, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x05, 0x00, 0x03, 0x3d, 0xa2, 0xd3, 0x5a, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf6, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x03, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xb0, 0x8f, 0x4c, 0x60, 0x41, 0x7b, 0x39, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x55, 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x74, 0x6d, 0x70, 0x2f, 0x65, 0x76, 0x69, 0x6c, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, }
Output: /tmp/evil.txt: illegal file path
func UnzipBytes ¶ added in v1.18.0
UnzipBytes is similar to Unzip but takes a zip archive as bytes instead of looking for a real file.
Example ¶
package main import ( "fmt" "io/ioutil" "os" "strings" "moul.io/u" ) func main() { // create tempdir for dest tempdir, err := ioutil.TempDir("", "u") if err != nil { panic(err) } defer os.RemoveAll(tempdir) // unzip to dest files, err := u.UnzipBytes(zipdata_simple, tempdir) if err != nil { panic(err) } for _, file := range files { relPath := "." + strings.TrimPrefix(file, tempdir) fmt.Println(relPath) } } var zipdata_simple = []byte{ 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x81, 0x61, 0x25, 0x3d, 0xc0, 0xd7, 0xed, 0xc3, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1c, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x09, 0x00, 0x03, 0x71, 0xfc, 0x82, 0x4c, 0x76, 0xfc, 0x82, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x0b, 0xc9, 0xc8, 0x2c, 0x56, 0x00, 0xa2, 0x44, 0x85, 0x92, 0xd4, 0xe2, 0x12, 0x20, 0x51, 0x51, 0xa2, 0x90, 0x96, 0x99, 0x93, 0xaa, 0xc7, 0x05, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x7e, 0x25, 0x3d, 0xfe, 0x31, 0xd5, 0x54, 0x11, 0x03, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x36, 0x78, 0x31, 0x36, 0x2e, 0x70, 0x6e, 0x67, 0x55, 0x54, 0x09, 0x00, 0x03, 0x3a, 0x30, 0x83, 0x4c, 0x3b, 0x30, 0x83, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x06, 0x00, 0x00, 0x00, 0xed, 0x73, 0x4f, 0x2f, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xd6, 0xd8, 0xd4, 0x4f, 0x58, 0x32, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xc9, 0x65, 0x3c, 0x00, 0x00, 0x02, 0xa3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x74, 0x93, 0x5f, 0x48, 0x53, 0x51, 0x18, 0xc0, 0xbf, 0x7b, 0xcf, 0xee, 0xc6, 0x75, 0x5b, 0x56, 0xda, 0x2a, 0x25, 0x6d, 0x6c, 0x06, 0x51, 0x56, 0xf4, 0x5f, 0x23, 0xb7, 0x22, 0x22, 0xb0, 0x7a, 0x88, 0x41, 0x0f, 0x4b, 0x0c, 0x0a, 0xa3, 0x82, 0x02, 0x1f, 0x62, 0x1a, 0x45, 0x2f, 0xa1, 0x83, 0x7a, 0x49, 0x2a, 0x86, 0x15, 0x35, 0xff, 0x64, 0x98, 0x90, 0xa2, 0x91, 0x2e, 0x10, 0x9c, 0x2f, 0x53, 0x92, 0xc2, 0x07, 0xe9, 0xb6, 0x86, 0x28, 0xda, 0x5d, 0xb6, 0xed, 0x5e, 0x75, 0x0e, 0xd9, 0x9f, 0xd3, 0x39, 0x9b, 0x8d, 0xad, 0xf2, 0x83, 0xef, 0x9e, 0x7b, 0xbf, 0x3f, 0xbf, 0xf3, 0x7d, 0xdf, 0x39, 0x97, 0xc1, 0x18, 0x43, 0xa6, 0xd8, 0xed, 0x76, 0xb0, 0xd9, 0x6c, 0x97, 0xcf, 0x9d, 0x3a, 0x7a, 0x23, 0xaf, 0xd0, 0x58, 0x14, 0x94, 0xe4, 0x65, 0xdf, 0xc4, 0x97, 0x65, 0x25, 0x87, 0x14, 0x9c, 0x56, 0x57, 0xe1, 0x76, 0xbb, 0xbd, 0x99, 0xf1, 0x8a, 0xcc, 0x8f, 0x96, 0x96, 0x56, 0xf4, 0xba, 0xbd, 0xcd, 0xe1, 0x68, 0xa8, 0xbd, 0x64, 0x34, 0x1a, 0xe0, 0xb8, 0xe5, 0x1a, 0xdc, 0x6f, 0xb0, 0x43, 0x69, 0x91, 0x16, 0xa4, 0x90, 0x04, 0xf3, 0x6c, 0xfe, 0x26, 0x12, 0x96, 0x05, 0x60, 0x68, 0x05, 0x35, 0x35, 0x35, 0x10, 0x5e, 0x8a, 0xc0, 0xf0, 0xe0, 0x40, 0x67, 0xf3, 0x0b, 0xa7, 0xc5, 0xeb, 0x15, 0x40, 0xfc, 0x3a, 0x02, 0xe6, 0xb3, 0x55, 0xa0, 0xe2, 0x10, 0xc4, 0x7f, 0x8e, 0x83, 0x82, 0xc1, 0x70, 0xfb, 0x51, 0x57, 0xdd, 0x56, 0xc3, 0xb6, 0xc6, 0x58, 0x2c, 0x4a, 0x36, 0x6b, 0x49, 0x11, 0x28, 0x80, 0x65, 0x99, 0x63, 0x05, 0xba, 0x75, 0x1d, 0x77, 0x6f, 0x56, 0x61, 0x59, 0x0a, 0x61, 0xcf, 0xe8, 0x27, 0x7c, 0xe4, 0xd0, 0x5e, 0x7c, 0xa2, 0x6c, 0x27, 0x7e, 0xd3, 0x54, 0x8f, 0x27, 0x5c, 0xcf, 0xb0, 0x6f, 0xc8, 0x89, 0x2f, 0x5a, 0x4e, 0x0a, 0xeb, 0xf3, 0x36, 0xb0, 0x66, 0xb3, 0x39, 0x99, 0x47, 0x35, 0xd9, 0x82, 0x26, 0x87, 0x2f, 0x2b, 0xd1, 0x6f, 0x31, 0xed, 0x30, 0x16, 0xc1, 0xc8, 0x87, 0x56, 0x00, 0xa4, 0x84, 0xca, 0x8a, 0xdd, 0x10, 0x8c, 0xaa, 0x41, 0xa3, 0xd5, 0x42, 0x3c, 0x91, 0x80, 0x70, 0x64, 0x19, 0xce, 0x57, 0x56, 0x94, 0x08, 0x33, 0xf3, 0xd7, 0x37, 0x17, 0x14, 0x34, 0x65, 0xb5, 0xc0, 0x30, 0x0c, 0x47, 0xde, 0x4b, 0xaf, 0x5e, 0x38, 0xd3, 0x7f, 0xeb, 0x8a, 0x25, 0x7f, 0x61, 0x71, 0x09, 0x18, 0x16, 0xc1, 0xb4, 0x5f, 0x06, 0xdd, 0xda, 0x1c, 0x50, 0xa9, 0x38, 0x60, 0x48, 0x80, 0x4a, 0xc9, 0x81, 0xa3, 0x73, 0x10, 0x1c, 0x6d, 0x3d, 0x8d, 0xf3, 0x52, 0xa8, 0x8e, 0x02, 0xd8, 0x15, 0x50, 0x94, 0xe8, 0xd8, 0xdb, 0xf7, 0x43, 0x1d, 0x41, 0x39, 0x4c, 0xb0, 0xa4, 0xef, 0x78, 0x02, 0x8a, 0x37, 0xe6, 0x26, 0x93, 0x02, 0x52, 0x38, 0x09, 0xa3, 0x92, 0xa7, 0x51, 0xc2, 0x82, 0x2c, 0xf5, 0xfd, 0xa9, 0x80, 0xcd, 0x9c, 0xe8, 0x5c, 0x50, 0xbe, 0xf3, 0xc4, 0xd9, 0x33, 0xc9, 0xab, 0x94, 0x29, 0x2a, 0x81, 0x90, 0xf9, 0x80, 0x77, 0x4a, 0x04, 0x61, 0x46, 0x82, 0x68, 0x2c, 0x06, 0xba, 0xfc, 0x5c, 0xea, 0x0a, 0xfc, 0x17, 0x40, 0x44, 0x7a, 0xd5, 0xe5, 0xb2, 0xf9, 0xa6, 0x45, 0x40, 0x28, 0xe5, 0x8a, 0xc6, 0xe2, 0xb0, 0x6f, 0x7b, 0x31, 0x98, 0x76, 0x15, 0x26, 0xc3, 0x57, 0xe0, 0xea, 0xd5, 0x00, 0x10, 0x8b, 0xc7, 0x5d, 0xee, 0xd1, 0xf1, 0x25, 0x5a, 0x7a, 0x7a, 0x50, 0x2c, 0x4b, 0x1f, 0x69, 0x20, 0x0d, 0x5b, 0x15, 0x40, 0x44, 0x16, 0xe7, 0x82, 0x0b, 0x2c, 0xfb, 0xaf, 0x4b, 0xa1, 0x40, 0xf0, 0xc3, 0x1f, 0xa0, 0x04, 0x7f, 0xd6, 0x4d, 0x34, 0x18, 0x0c, 0x29, 0x1a, 0x49, 0xfa, 0xee, 0x9b, 0x04, 0x44, 0x56, 0xe6, 0xaf, 0x64, 0x6a, 0x63, 0x01, 0x43, 0x30, 0x82, 0x91, 0x5a, 0xb3, 0xe6, 0x34, 0x31, 0x35, 0xa7, 0x01, 0x1e, 0x8f, 0x27, 0x19, 0xa4, 0x25, 0x67, 0x6e, 0xab, 0xab, 0x57, 0x7b, 0x06, 0x7b, 0x79, 0xba, 0x1b, 0x47, 0x14, 0x21, 0xb2, 0x72, 0x0a, 0xa0, 0x47, 0xfb, 0xb8, 0xb5, 0xef, 0xd7, 0xc7, 0x51, 0xe1, 0xe5, 0xc1, 0x03, 0xfb, 0x67, 0xb3, 0x2a, 0x28, 0x2f, 0x2f, 0x4f, 0x57, 0x20, 0x8a, 0x62, 0x42, 0x92, 0xa4, 0xda, 0xa7, 0xed, 0xfd, 0x0f, 0x4d, 0x87, 0xf7, 0xe4, 0xce, 0xce, 0x4c, 0xc3, 0xb8, 0x30, 0x15, 0x78, 0x37, 0x30, 0xdc, 0x8b, 0x11, 0x7f, 0xaf, 0xba, 0xba, 0x7a, 0xd2, 0x6a, 0xb5, 0x66, 0xff, 0x4c, 0x82, 0x20, 0x64, 0x56, 0xbb, 0x48, 0xf4, 0xb9, 0xcb, 0x33, 0x61, 0x1d, 0xfb, 0xe6, 0x8f, 0xf0, 0x3c, 0xff, 0xa0, 0xbb, 0xbb, 0xfb, 0x33, 0xb1, 0x85, 0xf4, 0x7a, 0x3d, 0xbd, 0x74, 0x59, 0xad, 0xfd, 0x16, 0x60, 0x00, 0xa8, 0x08, 0x0d, 0x8b, 0x03, 0xe7, 0x62, 0xea, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x81, 0x61, 0x25, 0x3d, 0xc0, 0xd7, 0xed, 0xc3, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, 0x05, 0x00, 0x03, 0x71, 0xfc, 0x82, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x7e, 0x25, 0x3d, 0xfe, 0x31, 0xd5, 0x54, 0x11, 0x03, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x14, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x5b, 0x00, 0x00, 0x00, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x31, 0x36, 0x78, 0x31, 0x36, 0x2e, 0x70, 0x6e, 0x67, 0x55, 0x54, 0x05, 0x00, 0x03, 0x3a, 0x30, 0x83, 0x4c, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xf5, 0x01, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xba, 0x03, 0x00, 0x00, 0x1a, 0x00, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x7a, 0x69, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x2e, }
Output: ./test.txt ./gophercolor16x16.png
Example (CreateAndUnzip) ¶
package main import ( "archive/zip" "bytes" "fmt" "io/ioutil" "os" "strings" "moul.io/u" ) func main() { // create a custom zip buf := new(bytes.Buffer) { w := zip.NewWriter(buf) // a.txt { hdr := zip.FileHeader{ Name: "a.txt", Method: zip.Deflate, } hdr.SetMode(0o755) f, err := w.CreateHeader(&hdr) if err != nil { panic(err) } _, err = f.Write([]byte("hello world!")) if err != nil { panic(err) } } // b.txt -> a.txt { hdr := zip.FileHeader{ Name: "b.txt", Comment: "c", Method: zip.Deflate, } hdr.SetMode(0o755 | os.ModeSymlink) f, err := w.CreateHeader(&hdr) if err != nil { panic(err) } _, err = f.Write([]byte("a.txt")) if err != nil { panic(err) } } err := w.Close() if err != nil { panic(err) } } // unzip it { // create tempdir for dest tempdir, err := ioutil.TempDir("", "u") if err != nil { panic(err) } defer os.RemoveAll(tempdir) // unzip to dest files, err := u.UnzipBytes(buf.Bytes(), tempdir) if err != nil { panic(err) } for _, file := range files { relPath := "." + strings.TrimPrefix(file, tempdir) stat, err := os.Lstat(file) if err != nil { panic(err) } fmt.Println(relPath, stat.Mode()&os.ModeSymlink != 0) } } }
Output: ./a.txt false ./b.txt true
Example (CreateAndUnzipZipSlip) ¶
package main import ( "archive/zip" "bytes" "fmt" "io/ioutil" "os" "strings" "moul.io/u" ) func main() { // create second temp dir var victim string { var err error victim, err = ioutil.TempDir("", "u") if err != nil { panic(err) } defer os.RemoveAll(victim) } // create a custom zip buf := new(bytes.Buffer) { w := zip.NewWriter(buf) // a.txt { hdr := zip.FileHeader{ Name: "a", Method: zip.Deflate, } hdr.SetMode(0o755 | os.ModeSymlink) f, err := w.CreateHeader(&hdr) if err != nil { panic(err) } _, err = f.Write([]byte(victim)) if err != nil { panic(err) } } // b.txt -> a.txt { hdr := zip.FileHeader{ Name: "a/b.txt", Method: zip.Deflate, } hdr.SetMode(0o755) f, err := w.CreateHeader(&hdr) if err != nil { panic(err) } _, err = f.Write([]byte("hello world!")) if err != nil { panic(err) } } err := w.Close() if err != nil { panic(err) } } // unzip it { // create tempdir for dest tempdir, err := ioutil.TempDir("", "u") if err != nil { panic(err) } defer os.RemoveAll(tempdir) // unzip to dest _, err = u.UnzipBytes(buf.Bytes(), tempdir) errStr := err.Error() errStr = strings.Replace(errStr, tempdir, "TEMPDIR", -1) fmt.Println(errStr) } }
Output: TEMPDIR/a/b.txt: illegal file path
func WaitForCtrlC ¶ added in v1.10.0
func WaitForCtrlC()
Example ¶
package main import ( "context" "moul.io/u" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() go func() { // do your stuff <-ctx.Done() }() u.WaitForCtrlC() }
Output:
Types ¶
type FutureRet ¶ added in v1.20.0
type FutureRet struct { Ret interface{} Err error }
FutureRet is a generic struct returned by Future.
type MutexMap ¶ added in v1.18.0
type MutexMap struct {
// contains filtered or unexported fields
}
MutexMap manages a pool of mutexes that can be get by key. MutexMap is thread-safe.
Example ¶
package main import ( "fmt" "sync" "time" "moul.io/u" ) func main() { var wg sync.WaitGroup var m u.MutexMap for i := 0; i < 10; i++ { name := fmt.Sprintf("abc%d", i) wg.Add(1) go func(i int) { fmt.Printf("init %s\n", name) defer m.Lock("abc-X")() sleep := time.Duration(100/(i+1)) * time.Millisecond time.Sleep(sleep) fmt.Printf("run %s (after sleep of %s)\n", name, sleep) wg.Done() }(i) time.Sleep(1 * time.Millisecond) } wg.Wait() }
Output: init abc0 init abc1 init abc2 init abc3 init abc4 init abc5 init abc6 init abc7 init abc8 init abc9 run abc0 (after sleep of 100ms) run abc1 (after sleep of 50ms) run abc2 (after sleep of 33ms) run abc3 (after sleep of 25ms) run abc4 (after sleep of 20ms) run abc5 (after sleep of 16ms) run abc6 (after sleep of 14ms) run abc7 (after sleep of 12ms) run abc8 (after sleep of 11ms) run abc9 (after sleep of 10ms)
type UniqueChild ¶ added in v1.6.0
UniqueChild is a goroutine manager (parent) that can only have one child at a time. When you call UniqueChild.SetChild(), UniqueChild cancels the previous child context (if any), then run a new child. The child needs to auto-kill itself when its context is done.
Example ¶
package main import ( "context" "fmt" "time" "moul.io/u" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() parent := u.NewUniqueChild(ctx) parent.SetChild(func(ctx context.Context) { select { case <-time.After(50 * time.Millisecond): fmt.Print("A") case <-ctx.Done(): } }) time.Sleep(100 * time.Millisecond) parent.SetChild(func(ctx context.Context) { select { case <-time.After(50 * time.Millisecond): fmt.Print("B") case <-ctx.Done(): } }) parent.SetChild(func(ctx context.Context) { select { case <-time.After(50 * time.Millisecond): fmt.Print("C") case <-ctx.Done(): } }) time.Sleep(100 * time.Millisecond) }
Output: AC
func NewUniqueChild ¶ added in v1.6.0
func NewUniqueChild(ctx context.Context) UniqueChild
NewUniqueChild instantiates and returns a UniqueChild manager.