github.com/nilium/gitlab-runner@v12.5.0+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  }