github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/syscall/dir_plan9.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Plan 9 directory marshalling. See intro(5).
     6  
     7  package syscall
     8  
     9  import "errors"
    10  
    11  var (
    12  	ErrShortStat = errors.New("stat buffer too short")
    13  	ErrBadStat   = errors.New("malformed stat buffer")
    14  )
    15  
    16  // A Qid represents a 9P server's unique identification for a file.
    17  type Qid struct {
    18  	Path uint64 // the file server's unique identification for the file
    19  	Vers uint32 // version number for given Path
    20  	Type uint8  // the type of the file (syscall.QTDIR for example)
    21  }
    22  
    23  // A Dir contains the metadata for a file.
    24  type Dir struct {
    25  	// system-modified data
    26  	Type uint16 // server type
    27  	Dev  uint32 // server subtype
    28  
    29  	// file data
    30  	Qid    Qid    // unique id from server
    31  	Mode   uint32 // permissions
    32  	Atime  uint32 // last read time
    33  	Mtime  uint32 // last write time
    34  	Length int64  // file length
    35  	Name   string // last element of path
    36  	Uid    string // owner name
    37  	Gid    string // group name
    38  	Muid   string // last modifier name
    39  }
    40  
    41  var nullDir = Dir{
    42  	Type: ^uint16(0),
    43  	Dev:  ^uint32(0),
    44  	Qid: Qid{
    45  		Path: ^uint64(0),
    46  		Vers: ^uint32(0),
    47  		Type: ^uint8(0),
    48  	},
    49  	Mode:   ^uint32(0),
    50  	Atime:  ^uint32(0),
    51  	Mtime:  ^uint32(0),
    52  	Length: ^int64(0),
    53  }
    54  
    55  // Null assigns special "don't touch" values to members of d to
    56  // avoid modifiying them during syscall.Wstat.
    57  func (d *Dir) Null() { *d = nullDir }
    58  
    59  // Marshal encodes a 9P stat message corresponding to d into b
    60  //
    61  // If there isn't enough space in b for a stat message, ErrShortStat is returned.
    62  func (d *Dir) Marshal(b []byte) (n int, err error) {
    63  	n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
    64  	if n > len(b) {
    65  		return n, ErrShortStat
    66  	}
    67  
    68  	b = pbit16(b, uint16(n)-2)
    69  	b = pbit16(b, d.Type)
    70  	b = pbit32(b, d.Dev)
    71  	b = pbit8(b, d.Qid.Type)
    72  	b = pbit32(b, d.Qid.Vers)
    73  	b = pbit64(b, d.Qid.Path)
    74  	b = pbit32(b, d.Mode)
    75  	b = pbit32(b, d.Atime)
    76  	b = pbit32(b, d.Mtime)
    77  	b = pbit64(b, uint64(d.Length))
    78  	b = pstring(b, d.Name)
    79  	b = pstring(b, d.Uid)
    80  	b = pstring(b, d.Gid)
    81  	b = pstring(b, d.Muid)
    82  
    83  	return n, nil
    84  }
    85  
    86  // UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
    87  //
    88  // If b is too small to hold a valid stat message, ErrShortStat is returned.
    89  //
    90  // If the stat message itself is invalid, ErrBadStat is returned.
    91  func UnmarshalDir(b []byte) (*Dir, error) {
    92  	if len(b) < STATFIXLEN {
    93  		return nil, ErrShortStat
    94  	}
    95  	size, buf := gbit16(b)
    96  	if len(b) != int(size)+2 {
    97  		return nil, ErrBadStat
    98  	}
    99  	b = buf
   100  
   101  	var d Dir
   102  	d.Type, b = gbit16(b)
   103  	d.Dev, b = gbit32(b)
   104  	d.Qid.Type, b = gbit8(b)
   105  	d.Qid.Vers, b = gbit32(b)
   106  	d.Qid.Path, b = gbit64(b)
   107  	d.Mode, b = gbit32(b)
   108  	d.Atime, b = gbit32(b)
   109  	d.Mtime, b = gbit32(b)
   110  
   111  	n, b := gbit64(b)
   112  	d.Length = int64(n)
   113  
   114  	var ok bool
   115  	if d.Name, b, ok = gstring(b); !ok {
   116  		return nil, ErrBadStat
   117  	}
   118  	if d.Uid, b, ok = gstring(b); !ok {
   119  		return nil, ErrBadStat
   120  	}
   121  	if d.Gid, b, ok = gstring(b); !ok {
   122  		return nil, ErrBadStat
   123  	}
   124  	if d.Muid, b, ok = gstring(b); !ok {
   125  		return nil, ErrBadStat
   126  	}
   127  
   128  	return &d, nil
   129  }
   130  
   131  // pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
   132  func pbit8(b []byte, v uint8) []byte {
   133  	b[0] = byte(v)
   134  	return b[1:]
   135  }
   136  
   137  // pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
   138  func pbit16(b []byte, v uint16) []byte {
   139  	b[0] = byte(v)
   140  	b[1] = byte(v >> 8)
   141  	return b[2:]
   142  }
   143  
   144  // pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
   145  func pbit32(b []byte, v uint32) []byte {
   146  	b[0] = byte(v)
   147  	b[1] = byte(v >> 8)
   148  	b[2] = byte(v >> 16)
   149  	b[3] = byte(v >> 24)
   150  	return b[4:]
   151  }
   152  
   153  // pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
   154  func pbit64(b []byte, v uint64) []byte {
   155  	b[0] = byte(v)
   156  	b[1] = byte(v >> 8)
   157  	b[2] = byte(v >> 16)
   158  	b[3] = byte(v >> 24)
   159  	b[4] = byte(v >> 32)
   160  	b[5] = byte(v >> 40)
   161  	b[6] = byte(v >> 48)
   162  	b[7] = byte(v >> 56)
   163  	return b[8:]
   164  }
   165  
   166  // pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
   167  // returning the remaining slice of b..
   168  func pstring(b []byte, s string) []byte {
   169  	b = pbit16(b, uint16(len(s)))
   170  	n := copy(b, s)
   171  	return b[n:]
   172  }
   173  
   174  // gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
   175  func gbit8(b []byte) (uint8, []byte) {
   176  	return uint8(b[0]), b[1:]
   177  }
   178  
   179  // gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
   180  func gbit16(b []byte) (uint16, []byte) {
   181  	return uint16(b[0]) | uint16(b[1])<<8, b[2:]
   182  }
   183  
   184  // gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
   185  func gbit32(b []byte) (uint32, []byte) {
   186  	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
   187  }
   188  
   189  // gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
   190  func gbit64(b []byte) (uint64, []byte) {
   191  	lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
   192  	hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
   193  	return uint64(lo) | uint64(hi)<<32, b[8:]
   194  }
   195  
   196  // gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
   197  // It returns the string with the remaining slice of b and a boolean. If the length is
   198  // greater than the number of bytes in b, the boolean will be false.
   199  func gstring(b []byte) (string, []byte, bool) {
   200  	n, b := gbit16(b)
   201  	if int(n) > len(b) {
   202  		return "", b, false
   203  	}
   204  	return string(b[:n]), b[n:], true
   205  }