Black Lives Matter. Support the Equal Justice Initiative.

Source file src/syscall/dir_plan9.go

Documentation: syscall

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

View as plain text