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 7package syscall 8 9import "errors" 10 11var ( 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. 18type 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. 25type 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 42var 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. 58func (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. 63func (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. 98func 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. 139func 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. 145func 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. 152func 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. 161func 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.. 175func 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. 182func 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 188func 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. 193func 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. 198func 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. 207func 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