...

Source file src/github.com/Microsoft/go-winio/ea.go

Documentation: github.com/Microsoft/go-winio

     1  package winio
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  )
     8  
     9  type fileFullEaInformation struct {
    10  	NextEntryOffset uint32
    11  	Flags           uint8
    12  	NameLength      uint8
    13  	ValueLength     uint16
    14  }
    15  
    16  var (
    17  	fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
    18  
    19  	errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
    20  	errEaNameTooLarge  = errors.New("extended attribute name too large")
    21  	errEaValueTooLarge = errors.New("extended attribute value too large")
    22  )
    23  
    24  // ExtendedAttribute represents a single Windows EA.
    25  type ExtendedAttribute struct {
    26  	Name  string
    27  	Value []byte
    28  	Flags uint8
    29  }
    30  
    31  func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
    32  	var info fileFullEaInformation
    33  	err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
    34  	if err != nil {
    35  		err = errInvalidEaBuffer
    36  		return ea, nb, err
    37  	}
    38  
    39  	nameOffset := fileFullEaInformationSize
    40  	nameLen := int(info.NameLength)
    41  	valueOffset := nameOffset + int(info.NameLength) + 1
    42  	valueLen := int(info.ValueLength)
    43  	nextOffset := int(info.NextEntryOffset)
    44  	if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
    45  		err = errInvalidEaBuffer
    46  		return ea, nb, err
    47  	}
    48  
    49  	ea.Name = string(b[nameOffset : nameOffset+nameLen])
    50  	ea.Value = b[valueOffset : valueOffset+valueLen]
    51  	ea.Flags = info.Flags
    52  	if info.NextEntryOffset != 0 {
    53  		nb = b[info.NextEntryOffset:]
    54  	}
    55  	return ea, nb, err
    56  }
    57  
    58  // DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
    59  // buffer retrieved from BackupRead, ZwQueryEaFile, etc.
    60  func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
    61  	for len(b) != 0 {
    62  		ea, nb, err := parseEa(b)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  
    67  		eas = append(eas, ea)
    68  		b = nb
    69  	}
    70  	return eas, err
    71  }
    72  
    73  func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
    74  	if int(uint8(len(ea.Name))) != len(ea.Name) {
    75  		return errEaNameTooLarge
    76  	}
    77  	if int(uint16(len(ea.Value))) != len(ea.Value) {
    78  		return errEaValueTooLarge
    79  	}
    80  	entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
    81  	withPadding := (entrySize + 3) &^ 3
    82  	nextOffset := uint32(0)
    83  	if !last {
    84  		nextOffset = withPadding
    85  	}
    86  	info := fileFullEaInformation{
    87  		NextEntryOffset: nextOffset,
    88  		Flags:           ea.Flags,
    89  		NameLength:      uint8(len(ea.Name)),
    90  		ValueLength:     uint16(len(ea.Value)),
    91  	}
    92  
    93  	err := binary.Write(buf, binary.LittleEndian, &info)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	_, err = buf.Write([]byte(ea.Name))
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	err = buf.WriteByte(0)
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	_, err = buf.Write(ea.Value)
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	return nil
   119  }
   120  
   121  // EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
   122  // buffer for use with BackupWrite, ZwSetEaFile, etc.
   123  func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
   124  	var buf bytes.Buffer
   125  	for i := range eas {
   126  		last := false
   127  		if i == len(eas)-1 {
   128  			last = true
   129  		}
   130  
   131  		err := writeEa(&buf, &eas[i], last)
   132  		if err != nil {
   133  			return nil, err
   134  		}
   135  	}
   136  	return buf.Bytes(), nil
   137  }
   138  

View as plain text