...

Source file src/pkg/syscall/dir_plan9.go

     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