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 }