gitlab.com/jfprevost/gitlab-runner-notlscheck@v11.11.4+incompatible/helpers/archives/zip_extra.go (about) 1 package archives 2 3 import ( 4 "archive/zip" 5 "bytes" 6 "encoding/binary" 7 "io" 8 "os" 9 "time" 10 ) 11 12 const ZipUIDGidFieldType = 0x7875 13 const ZipTimestampFieldType = 0x5455 14 15 // ZipExtraField is taken from https://github.com/LuaDist/zip/blob/master/proginfo/extrafld.txt 16 type ZipExtraField struct { 17 Type uint16 18 Size uint16 19 } 20 21 type ZipUIDGidField struct { 22 Version uint8 23 UIDSize uint8 24 UID uint32 25 GIDSize uint8 26 Gid uint32 27 } 28 29 type ZipTimestampField struct { 30 Flags uint8 31 ModTime uint32 32 } 33 34 func createZipTimestampField(w io.Writer, fi os.FileInfo) (err error) { 35 tsField := ZipTimestampField{ 36 1, 37 uint32(fi.ModTime().Unix()), 38 } 39 tsFieldType := ZipExtraField{ 40 Type: ZipTimestampFieldType, 41 Size: uint16(binary.Size(&tsField)), 42 } 43 err = binary.Write(w, binary.LittleEndian, &tsFieldType) 44 if err == nil { 45 err = binary.Write(w, binary.LittleEndian, &tsField) 46 } 47 return 48 } 49 50 func processZipTimestampField(data []byte, file *zip.FileHeader) error { 51 if !file.Mode().IsDir() && !file.Mode().IsRegular() { 52 return nil 53 } 54 55 var tsField ZipTimestampField 56 err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &tsField) 57 if err != nil { 58 return err 59 } 60 61 if (tsField.Flags & 1) == 1 { 62 modTime := time.Unix(int64(tsField.ModTime), 0) 63 acTime := time.Now() 64 return os.Chtimes(file.Name, acTime, modTime) 65 } 66 67 return nil 68 } 69 70 func createZipExtra(fi os.FileInfo) []byte { 71 var buffer bytes.Buffer 72 err := createZipUIDGidField(&buffer, fi) 73 if err == nil { 74 err = createZipTimestampField(&buffer, fi) 75 } 76 if err == nil { 77 return buffer.Bytes() 78 } 79 return nil 80 } 81 82 func readZipExtraField(r io.Reader) (field ZipExtraField, data []byte, err error) { 83 err = binary.Read(r, binary.LittleEndian, &field) 84 if err != nil { 85 return 86 } 87 88 data = make([]byte, field.Size) 89 _, err = r.Read(data) 90 if err != nil { 91 return 92 } 93 return 94 } 95 96 func processZipExtra(file *zip.FileHeader) error { 97 if len(file.Extra) == 0 { 98 return nil 99 } 100 101 r := bytes.NewReader(file.Extra) 102 for { 103 field, data, err := readZipExtraField(r) 104 if err == io.EOF { 105 break 106 } else if err != nil { 107 return err 108 } 109 110 switch field.Type { 111 case ZipUIDGidFieldType: 112 err = processZipUIDGidField(data, file) 113 case ZipTimestampFieldType: 114 err = processZipTimestampField(data, file) 115 } 116 if err != nil { 117 return err 118 } 119 } 120 121 return nil 122 }