123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- package winio
- import (
- "bytes"
- "encoding/binary"
- "errors"
- )
- type fileFullEaInformation struct {
- NextEntryOffset uint32
- Flags uint8
- NameLength uint8
- ValueLength uint16
- }
- var (
- fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
- errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
- errEaNameTooLarge = errors.New("extended attribute name too large")
- errEaValueTooLarge = errors.New("extended attribute value too large")
- )
- // ExtendedAttribute represents a single Windows EA.
- type ExtendedAttribute struct {
- Name string
- Value []byte
- Flags uint8
- }
- func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
- var info fileFullEaInformation
- err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
- if err != nil {
- err = errInvalidEaBuffer
- return
- }
- nameOffset := fileFullEaInformationSize
- nameLen := int(info.NameLength)
- valueOffset := nameOffset + int(info.NameLength) + 1
- valueLen := int(info.ValueLength)
- nextOffset := int(info.NextEntryOffset)
- if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
- err = errInvalidEaBuffer
- return
- }
- ea.Name = string(b[nameOffset : nameOffset+nameLen])
- ea.Value = b[valueOffset : valueOffset+valueLen]
- ea.Flags = info.Flags
- if info.NextEntryOffset != 0 {
- nb = b[info.NextEntryOffset:]
- }
- return
- }
- // DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
- // buffer retrieved from BackupRead, ZwQueryEaFile, etc.
- func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
- for len(b) != 0 {
- ea, nb, err := parseEa(b)
- if err != nil {
- return nil, err
- }
- eas = append(eas, ea)
- b = nb
- }
- return
- }
- func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
- if int(uint8(len(ea.Name))) != len(ea.Name) {
- return errEaNameTooLarge
- }
- if int(uint16(len(ea.Value))) != len(ea.Value) {
- return errEaValueTooLarge
- }
- entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
- withPadding := (entrySize + 3) &^ 3
- nextOffset := uint32(0)
- if !last {
- nextOffset = withPadding
- }
- info := fileFullEaInformation{
- NextEntryOffset: nextOffset,
- Flags: ea.Flags,
- NameLength: uint8(len(ea.Name)),
- ValueLength: uint16(len(ea.Value)),
- }
- err := binary.Write(buf, binary.LittleEndian, &info)
- if err != nil {
- return err
- }
- _, err = buf.Write([]byte(ea.Name))
- if err != nil {
- return err
- }
- err = buf.WriteByte(0)
- if err != nil {
- return err
- }
- _, err = buf.Write(ea.Value)
- if err != nil {
- return err
- }
- _, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
- if err != nil {
- return err
- }
- return nil
- }
- // EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
- // buffer for use with BackupWrite, ZwSetEaFile, etc.
- func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
- var buf bytes.Buffer
- for i := range eas {
- last := false
- if i == len(eas)-1 {
- last = true
- }
- err := writeEa(&buf, &eas[i], last)
- if err != nil {
- return nil, err
- }
- }
- return buf.Bytes(), nil
- }
|