├── .gitignore ├── .mention-bot ├── .pullapprove.yml ├── .travis.yml ├── AUTHORS ├── CONTRIBUTORS ├── LICENSE ├── README.md ├── cmd └── ufs │ ├── .gitignore │ └── ufs.go ├── filesystem ├── filesystem.go ├── filesystem_test.go ├── filesystem_unix.go ├── filesystem_windows.go ├── ninep.go ├── ninep_unix.go └── ninep_windows.go ├── pkg └── debugfs │ └── debug.go └── protocol ├── client.go ├── gen.go ├── genout.go ├── pprof.go ├── protocol.go ├── protocol_test.go ├── server.go └── types.go /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.test 3 | *.swp 4 | -------------------------------------------------------------------------------- /.mention-bot: -------------------------------------------------------------------------------- 1 | { 2 | "requiredOrgs": ["Harvey-OS"], // mention-bot will only mention user who are a member of one of these organizations 3 | "actions": ["opened"] // List of PR actions that mention-bot will listen to, default is "opened" 4 | } 5 | -------------------------------------------------------------------------------- /.pullapprove.yml: -------------------------------------------------------------------------------- 1 | approve_by_comment: true 2 | approve_regex: '^(LGTM|:\+1:|\+1)' 3 | reject_regex: '^(NMW|:-1:|-1)' 4 | reset_on_push: false 5 | reviewers: 6 | members: 7 | - 0intro 8 | - aki5 9 | - dancrossnyc 10 | - elbing 11 | - floren 12 | - fuchicar 13 | - hdonnay 14 | - keedon 15 | - rminnich 16 | - sevki 17 | - hagna 18 | name: Harvey-OS/core 19 | required: 1 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.7.x 4 | - 1.8.x 5 | - 1.9.x 6 | - 1.10.x 7 | install: 8 | - export GOPATH="$HOME/gopath" 9 | - mkdir -p "$GOPATH/src/github.com/Harvey-OS/ninep" 10 | - go get -v -t -d github.com/Harvey-OS/ninep/... 11 | script: 12 | - go test github.com/Harvey-OS/ninep/... 13 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of Ninep authors for copyright purposes. 2 | # This file is distinct from the CONTRIBUTORS files. 3 | # See the latter for an explanation. 4 | 5 | # Names should be added to this file as 6 | # Name or Organization 7 | # The email address is not required for organizations. 8 | 9 | # Please keep the list sorted. 10 | 11 | Andrey Mirtchovski 12 | Latchesar Ionkov 13 | Roger Peppe 14 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This is the official list of people who can contribute 2 | # (and typically have contributed) code to the Ninep repository. 3 | # The AUTHORS file lists the copyright holders; this file 4 | # lists people. For example, Google employees are listed here 5 | # but not in AUTHORS, because Google holds the copyright. 6 | # 7 | # The submission process automatically checks to make sure 8 | # that people submitting code are listed in this file (by email address). 9 | # XXX more bumph here? 10 | # Names should be added to this file like so: 11 | # Name 12 | 13 | # Please keep the list sorted. 14 | 15 | Andrey Mirtchovski 16 | Latchesar Ionkov 17 | Akshat Kumar 18 | Roger Peppe 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 The Ninep Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * The names of Ninep's contributors may not be used to endorse 14 | or promote products derived from this software without specific prior 15 | written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ninep 2 | Package for implementing clients and servers of the 9P and 9P2000 distributed resource protocols in Go. 3 | 4 | -------------------------------------------------------------------------------- /cmd/ufs/.gitignore: -------------------------------------------------------------------------------- 1 | /ufs 2 | 3 | -------------------------------------------------------------------------------- /cmd/ufs/ufs.go: -------------------------------------------------------------------------------- 1 | // UFS is a userspace server which exports a filesystem over 9p2000. 2 | // 3 | // By default, it will export / over a TCP on port 5640 under the username 4 | // of "harvey". 5 | package main 6 | 7 | import ( 8 | "flag" 9 | "log" 10 | "net" 11 | 12 | ufs "github.com/Harvey-OS/ninep/filesystem" 13 | "github.com/Harvey-OS/ninep/protocol" 14 | ) 15 | 16 | var ( 17 | ntype = flag.String("ntype", "tcp4", "Default network type") 18 | naddr = flag.String("addr", ":5640", "Network address") 19 | ) 20 | 21 | func main() { 22 | flag.Parse() 23 | 24 | ln, err := net.Listen(*ntype, *naddr) 25 | if err != nil { 26 | log.Fatalf("Listen failed: %v", err) 27 | } 28 | 29 | ufslistener, err := ufs.NewUFS(func(l *protocol.Listener) error { 30 | l.Trace = nil // log.Printf 31 | return nil 32 | }) 33 | 34 | if err := ufslistener.Serve(ln); err != nil { 35 | log.Fatal(err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /filesystem/filesystem.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Ninep 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 | package ufs 6 | 7 | import ( 8 | "bytes" 9 | "flag" 10 | "fmt" 11 | "io" 12 | "log" 13 | "os" 14 | "path" 15 | "path/filepath" 16 | "sync" 17 | "time" 18 | 19 | "github.com/Harvey-OS/ninep/pkg/debugfs" 20 | "github.com/Harvey-OS/ninep/protocol" 21 | ) 22 | 23 | type file struct { 24 | protocol.QID 25 | fullName string 26 | file *os.File 27 | // We can't know how big a serialized dentry is until we serialize it. 28 | // At that point it might be too big. We save it here if that happens, 29 | // and on the next directory read we start with that. 30 | oflow []byte 31 | } 32 | 33 | type FileServer struct { 34 | root *file 35 | rootPath string 36 | Versioned bool 37 | IOunit protocol.MaxSize 38 | 39 | // mu guards below 40 | mu sync.Mutex 41 | files map[protocol.FID]*file 42 | } 43 | 44 | var ( 45 | debug = flag.Int("debug", 0, "print debug messages") 46 | root = flag.String("root", "/", "Set the root for all attaches") 47 | ) 48 | 49 | func stat(s string) (*protocol.Dir, protocol.QID, error) { 50 | var q protocol.QID 51 | st, err := os.Lstat(s) 52 | if err != nil { 53 | return nil, q, fmt.Errorf("does not exist") 54 | } 55 | d, err := dirTo9p2000Dir(st) 56 | if err != nil { 57 | return nil, q, nil 58 | } 59 | q = fileInfoToQID(st) 60 | return d, q, nil 61 | } 62 | 63 | func (e *FileServer) Rversion(msize protocol.MaxSize, version string) (protocol.MaxSize, string, error) { 64 | if version != "9P2000" { 65 | return 0, "", fmt.Errorf("%v not supported; only 9P2000", version) 66 | } 67 | e.Versioned = true 68 | return msize, version, nil 69 | } 70 | 71 | func (e *FileServer) getFile(fid protocol.FID) (*file, error) { 72 | e.mu.Lock() 73 | defer e.mu.Unlock() 74 | f, ok := e.files[fid] 75 | if !ok { 76 | return nil, fmt.Errorf("does not exist") 77 | } 78 | 79 | return f, nil 80 | } 81 | 82 | func (e *FileServer) Rattach(fid protocol.FID, afid protocol.FID, uname string, aname string) (protocol.QID, error) { 83 | if afid != protocol.NOFID { 84 | return protocol.QID{}, fmt.Errorf("We don't do auth attach") 85 | } 86 | // There should be no .. or other such junk in the Aname. Clean it up anyway. 87 | aname = path.Join("/", aname) 88 | aname = path.Join(e.rootPath, aname) 89 | st, err := os.Stat(aname) 90 | if err != nil { 91 | return protocol.QID{}, err 92 | } 93 | r := &file{fullName: aname} 94 | r.QID = fileInfoToQID(st) 95 | e.files[fid] = r 96 | e.root = r 97 | return r.QID, nil 98 | } 99 | 100 | func (e *FileServer) Rflush(o protocol.Tag) error { 101 | return nil 102 | } 103 | 104 | func (e *FileServer) Rwalk(fid protocol.FID, newfid protocol.FID, paths []string) ([]protocol.QID, error) { 105 | e.mu.Lock() 106 | f, ok := e.files[fid] 107 | e.mu.Unlock() 108 | if !ok { 109 | return nil, fmt.Errorf("does not exist") 110 | } 111 | if len(paths) == 0 { 112 | e.mu.Lock() 113 | defer e.mu.Unlock() 114 | _, ok := e.files[newfid] 115 | if ok { 116 | return nil, fmt.Errorf("FID in use: clone walk, fid %d newfid %d", fid, newfid) 117 | } 118 | nf := *f 119 | e.files[newfid] = &nf 120 | return []protocol.QID{}, nil 121 | } 122 | p := f.fullName 123 | q := make([]protocol.QID, len(paths)) 124 | 125 | var i int 126 | for i = range paths { 127 | p = path.Join(p, paths[i]) 128 | st, err := os.Lstat(p) 129 | if err != nil { 130 | // From the RFC: If the first element cannot be walked for any 131 | // reason, Rerror is returned. Otherwise, the walk will return an 132 | // Rwalk message containing nwqid qids corresponding, in order, to 133 | // the files that are visited by the nwqid successful elementwise 134 | // walks; nwqid is therefore either nwname or the index of the 135 | // first elementwise walk that failed. The value of nwqid cannot be 136 | // zero unless nwname is zero. Also, nwqid will always be less than 137 | // or equal to nwname. Only if it is equal, however, will newfid be 138 | // affected, in which case newfid will represent the file reached 139 | // by the final elementwise walk requested in the message. 140 | // 141 | // to sum up: if any walks have succeeded, you return the QIDS for 142 | // one more than the last successful walk 143 | if i == 0 { 144 | return nil, fmt.Errorf("file does not exist") 145 | } 146 | // we only get here if i is > 0 and less than nwname, 147 | // so the i should be safe. 148 | return q[:i], nil 149 | } 150 | q[i] = fileInfoToQID(st) 151 | } 152 | e.mu.Lock() 153 | defer e.mu.Unlock() 154 | // this is quite unlikely, which is why we don't bother checking for it first. 155 | if fid != newfid { 156 | if _, ok := e.files[newfid]; ok { 157 | return nil, fmt.Errorf("FID in use: walk to %v, fid %v, newfid %v", paths, fid, newfid) 158 | } 159 | } 160 | e.files[newfid] = &file{fullName: p, QID: q[i]} 161 | return q, nil 162 | } 163 | 164 | func (e *FileServer) Ropen(fid protocol.FID, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { 165 | e.mu.Lock() 166 | f, ok := e.files[fid] 167 | e.mu.Unlock() 168 | if !ok { 169 | return protocol.QID{}, 0, fmt.Errorf("does not exist") 170 | } 171 | 172 | var err error 173 | f.file, err = os.OpenFile(f.fullName, modeToUnixFlags(mode), 0) 174 | if err != nil { 175 | return protocol.QID{}, 0, err 176 | } 177 | 178 | return f.QID, e.IOunit, nil 179 | } 180 | func (e *FileServer) Rcreate(fid protocol.FID, name string, perm protocol.Perm, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { 181 | f, err := e.getFile(fid) 182 | if err != nil { 183 | return protocol.QID{}, 0, err 184 | } 185 | if f.file != nil { 186 | return protocol.QID{}, 0, fmt.Errorf("FID already open") 187 | } 188 | n := path.Join(f.fullName, name) 189 | if perm&protocol.Perm(protocol.DMDIR) != 0 { 190 | p := os.FileMode(int(perm) & 0777) 191 | err := os.Mkdir(n, p) 192 | _, q, err := stat(n) 193 | if err != nil { 194 | return protocol.QID{}, 0, err 195 | } 196 | f.fullName = n 197 | f.QID = q 198 | return q, 8000, err 199 | } 200 | 201 | m := modeToUnixFlags(mode) | os.O_CREATE | os.O_TRUNC 202 | p := os.FileMode(perm) & 0777 203 | of, err := os.OpenFile(n, m, p) 204 | if err != nil { 205 | return protocol.QID{}, 0, err 206 | } 207 | _, q, err := stat(n) 208 | if err != nil { 209 | return protocol.QID{}, 0, err 210 | } 211 | f.fullName = n 212 | f.QID = q 213 | f.file = of 214 | return q, 8000, err 215 | } 216 | func (e *FileServer) Rclunk(fid protocol.FID) error { 217 | _, err := e.clunk(fid) 218 | return err 219 | } 220 | 221 | func (e *FileServer) Rstat(fid protocol.FID) ([]byte, error) { 222 | f, err := e.getFile(fid) 223 | if err != nil { 224 | return []byte{}, err 225 | } 226 | st, err := os.Lstat(f.fullName) 227 | if err != nil { 228 | return []byte{}, fmt.Errorf("ENOENT") 229 | } 230 | d, err := dirTo9p2000Dir(st) 231 | if err != nil { 232 | return []byte{}, nil 233 | } 234 | var b bytes.Buffer 235 | protocol.Marshaldir(&b, *d) 236 | return b.Bytes(), nil 237 | } 238 | func (e *FileServer) Rwstat(fid protocol.FID, b []byte) error { 239 | var changed bool 240 | f, err := e.getFile(fid) 241 | if err != nil { 242 | return err 243 | } 244 | dir, err := protocol.Unmarshaldir(bytes.NewBuffer(b)) 245 | if err != nil { 246 | return err 247 | } 248 | if dir.Mode != 0xFFFFFFFF { 249 | changed = true 250 | mode := dir.Mode & 0777 251 | if err := os.Chmod(f.fullName, os.FileMode(mode)); err != nil { 252 | return err 253 | } 254 | } 255 | 256 | // Try to find local uid, gid by name. 257 | if dir.User != "" || dir.Group != "" { 258 | return fmt.Errorf("Permission denied") 259 | changed = true 260 | } 261 | 262 | /* 263 | if uid != ninep.NOUID || gid != ninep.NOUID { 264 | changed = true 265 | e := os.Chown(fid.path, int(uid), int(gid)) 266 | if e != nil { 267 | req.RespondError(toError(e)) 268 | return 269 | } 270 | } 271 | */ 272 | 273 | if dir.Name != "" { 274 | changed = true 275 | // If we path.Join dir.Name to / before adding it to 276 | // the fid path, that ensures nobody gets to walk out of the 277 | // root of this server. 278 | newname := path.Join(path.Dir(f.fullName), path.Join("/", dir.Name)) 279 | 280 | // absolute renaming. Ufs can do this, so let's support it. 281 | // We'll allow an absolute path in the Name and, if it is, 282 | // we will make it relative to root. This is a gigantic performance 283 | // improvement in systems that allow it. 284 | if filepath.IsAbs(dir.Name) { 285 | newname = path.Join(e.rootPath, dir.Name) 286 | } 287 | 288 | // If to exists, and to is a directory, we can't do the 289 | // rename, since os.Rename will move from into to. 290 | 291 | st, err := os.Stat(newname) 292 | if err == nil && st.IsDir() { 293 | return fmt.Errorf("is a directory") 294 | } 295 | if err := os.Rename(f.fullName, newname); err != nil { 296 | return err 297 | } 298 | f.fullName = newname 299 | } 300 | 301 | if dir.Length != 0xFFFFFFFFFFFFFFFF { 302 | changed = true 303 | if err := os.Truncate(f.fullName, int64(dir.Length)); err != nil { 304 | return err 305 | } 306 | } 307 | 308 | // If either mtime or atime need to be changed, then 309 | // we must change both. 310 | if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { 311 | changed = true 312 | mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0) 313 | if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat { 314 | st, err := os.Stat(f.fullName) 315 | if err != nil { 316 | return err 317 | } 318 | switch cmt { 319 | case true: 320 | mt = st.ModTime() 321 | default: 322 | //at = atime(st.Sys().(*syscall.Stat_t)) 323 | } 324 | } 325 | if err := os.Chtimes(f.fullName, at, mt); err != nil { 326 | return err 327 | } 328 | } 329 | 330 | if !changed && f.file != nil { 331 | f.file.Sync() 332 | } 333 | return nil 334 | } 335 | 336 | func (e *FileServer) clunk(fid protocol.FID) (*file, error) { 337 | e.mu.Lock() 338 | defer e.mu.Unlock() 339 | f, ok := e.files[fid] 340 | if !ok { 341 | return nil, fmt.Errorf("does not exist") 342 | } 343 | delete(e.files, fid) 344 | // What do we do if we can't close it? 345 | // All I can think of is to log it. 346 | if f.file != nil { 347 | if err := f.file.Close(); err != nil { 348 | log.Printf("Close of %v failed: %v", f.fullName, err) 349 | } 350 | } 351 | return f, nil 352 | } 353 | 354 | // Rremove removes the file. The question of whether the file continues to be accessible 355 | // is system dependent. 356 | func (e *FileServer) Rremove(fid protocol.FID) error { 357 | f, err := e.clunk(fid) 358 | if err != nil { 359 | return err 360 | } 361 | return os.Remove(f.fullName) 362 | } 363 | 364 | func (e *FileServer) Rread(fid protocol.FID, o protocol.Offset, c protocol.Count) ([]byte, error) { 365 | f, err := e.getFile(fid) 366 | if err != nil { 367 | return nil, err 368 | } 369 | if f.file == nil { 370 | return nil, fmt.Errorf("FID not open") 371 | } 372 | if f.QID.Type&protocol.QTDIR != 0 { 373 | if o == 0 { 374 | f.oflow = nil 375 | if err := resetDir(f); err != nil { 376 | return nil, err 377 | } 378 | } 379 | 380 | // We make the assumption that they can always fit at least one 381 | // directory entry into a read. If that assumption does not hold 382 | // so many things are broken that we can't fix them here. 383 | // But we'll drop out of the loop below having returned nothing 384 | // anyway. 385 | b := bytes.NewBuffer(f.oflow) 386 | f.oflow = nil 387 | pos := 0 388 | 389 | for { 390 | if b.Len() > int(c) { 391 | f.oflow = b.Bytes()[pos:] 392 | return b.Bytes()[:pos], nil 393 | } 394 | pos += b.Len() 395 | st, err := f.file.Readdir(1) 396 | if err == io.EOF { 397 | return b.Bytes(), nil 398 | } 399 | if err != nil { 400 | return nil, err 401 | } 402 | 403 | d9p, err := dirTo9p2000Dir(st[0]) 404 | if err != nil { 405 | return nil, err 406 | } 407 | protocol.Marshaldir(b, *d9p) 408 | // Seen on linux clients: sometimes the math is wrong and 409 | // they end up asking for the last element with not enough data. 410 | // Linux bug or bug with this server? Not sure yet. 411 | if b.Len() > int(c) { 412 | log.Printf("Warning: Server bug? %v, need %d bytes;count is %d: skipping", d9p, b.Len(), c) 413 | return nil, nil 414 | } 415 | // We're not quite doing the array right. 416 | // What does work is returning one thing so, for now, do that. 417 | return b.Bytes(), nil 418 | } 419 | return b.Bytes(), nil 420 | } 421 | 422 | // N.B. even if they ask for 0 bytes on some file systems it is important to pass 423 | // through a zero byte read (not Unix, of course). 424 | b := make([]byte, c) 425 | n, err := f.file.ReadAt(b, int64(o)) 426 | if err != nil && err != io.EOF { 427 | return nil, err 428 | } 429 | return b[:n], nil 430 | } 431 | 432 | func (e *FileServer) Rwrite(fid protocol.FID, o protocol.Offset, b []byte) (protocol.Count, error) { 433 | f, err := e.getFile(fid) 434 | if err != nil { 435 | return -1, err 436 | } 437 | if f.file == nil { 438 | return -1, fmt.Errorf("FID not open") 439 | } 440 | 441 | // N.B. even if they ask for 0 bytes on some file systems it is important to pass 442 | // through a zero byte write (not Unix, of course). Also, let the underlying file system 443 | // manage the error if the open mode was wrong. No need to duplicate the logic. 444 | 445 | n, err := f.file.WriteAt(b, int64(o)) 446 | return protocol.Count(n), err 447 | } 448 | 449 | func NewUFS(opts ...protocol.ListenerOpt) (*protocol.Listener, error) { 450 | nsCreator := func() protocol.NineServer { 451 | f := &FileServer{} 452 | f.files = make(map[protocol.FID]*file) 453 | f.rootPath = *root // for now. 454 | f.IOunit = 8192 455 | // any opts for the ufs layer can be added here too ... 456 | var d protocol.NineServer = f 457 | if *debug != 0 { 458 | d = &debugfs.DebugFileServer{FileServer: f} 459 | } 460 | return d 461 | } 462 | 463 | l, err := protocol.NewListener(nsCreator, opts...) 464 | if err != nil { 465 | return nil, err 466 | } 467 | return l, nil 468 | } 469 | -------------------------------------------------------------------------------- /filesystem/filesystem_test.go: -------------------------------------------------------------------------------- 1 | package ufs 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net" 8 | "os" 9 | "path" 10 | "strings" 11 | "testing" 12 | 13 | "github.com/Harvey-OS/ninep/protocol" 14 | ) 15 | 16 | func print(f string, args ...interface{}) { 17 | fmt.Printf(f+"\n", args...) 18 | } 19 | 20 | func TestNew(t *testing.T) { 21 | n, err := NewUFS() 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | t.Logf("n is %v", n) 26 | } 27 | 28 | // a simple prototype file system. 29 | type makeit struct { 30 | n string // name 31 | m os.FileMode // mode 32 | s string // for symlinks or content 33 | } 34 | 35 | var tests = []makeit{ 36 | { 37 | n: "ro", 38 | m: 0444, 39 | s: "", 40 | }, 41 | { 42 | n: "rw", 43 | m: 0666, 44 | s: "", 45 | }, 46 | { 47 | n: "wo", 48 | m: 0222, 49 | s: "", 50 | }, 51 | } 52 | 53 | func TestMount(t *testing.T) { 54 | /* Create the simple file system. */ 55 | tmpdir, err := ioutil.TempDir(os.TempDir(), "hi.dir") 56 | if err != nil { 57 | t.Fatalf("%v", err) 58 | } 59 | 60 | for i := range tests { 61 | if err := ioutil.WriteFile(path.Join(tmpdir, tests[i].n), []byte("hi"), tests[i].m); err != nil { 62 | t.Fatalf("%v", err) 63 | } 64 | } 65 | 66 | p, p2 := net.Pipe() 67 | 68 | c, err := protocol.NewClient(func(c *protocol.Client) error { 69 | c.FromNet, c.ToNet = p, p 70 | return nil 71 | }, 72 | func(c *protocol.Client) error { 73 | c.Msize = 8192 74 | c.Trace = print //t.Logf 75 | return nil 76 | }) 77 | if err != nil { 78 | t.Fatalf("%v", err) 79 | } 80 | t.Logf("Client is %v", c.String()) 81 | 82 | n, err := NewUFS(func(l *protocol.Listener) error { 83 | l.Trace = print //t.Logf 84 | return nil 85 | }) 86 | if err != nil { 87 | t.Fatal(err) 88 | } 89 | 90 | if err := n.Accept(p2); err != nil { 91 | t.Fatalf("Accept: want nil, got %v", err) 92 | } 93 | 94 | t.Logf("n is %v", n) 95 | 96 | m, v, err := c.CallTversion(8000, "9P2000") 97 | if err != nil { 98 | t.Fatalf("CallTversion: want nil, got %v", err) 99 | } 100 | t.Logf("CallTversion: msize %v version %v", m, v) 101 | 102 | t.Logf("Server is %v", n.String()) 103 | 104 | a, err := c.CallTattach(0, protocol.NOFID, "/", "") 105 | if err != nil { 106 | t.Fatalf("CallTattach: want nil, got %v", err) 107 | } 108 | 109 | t.Logf("Attach is %v", a) 110 | w, err := c.CallTwalk(0, 1, []string{"hi", "there"}) 111 | if err == nil { 112 | t.Fatalf("CallTwalk(0,1,[\"hi\", \"there\"]): want err, got nil") 113 | } 114 | if len(w) > 0 { 115 | t.Fatalf("CallTwalk(0,1,[\"hi\", \"there\"]): want 0 QIDs, got %v", w) 116 | } 117 | t.Logf("Walk is %v", w) 118 | ro := strings.Split(path.Join(tmpdir, "ro"), "/") 119 | 120 | w, err = c.CallTwalk(0, 1, ro) 121 | if err != nil { 122 | t.Fatalf("CallTwalk(0,1,%v): want nil, got %v", ro, err) 123 | } 124 | t.Logf("Walk is %v", w) 125 | 126 | of, _, err := c.CallTopen(22, protocol.OREAD) 127 | if err == nil { 128 | t.Fatalf("CallTopen(22, protocol.OREAD): want err, got nil") 129 | } 130 | of, _, err = c.CallTopen(1, protocol.OWRITE) 131 | if err == nil { 132 | t.Fatalf("CallTopen(0, protocol.OWRITE): want err, got nil") 133 | } 134 | of, _, err = c.CallTopen(1, protocol.OREAD) 135 | if err != nil { 136 | t.Fatalf("CallTopen(1, protocol.OREAD): want nil, got %v", nil) 137 | } 138 | t.Logf("Open is %v", of) 139 | 140 | b, err := c.CallTread(22, 0, 0) 141 | if err == nil { 142 | t.Fatalf("CallTread(22, 0, 0): want err, got nil") 143 | } 144 | b, err = c.CallTread(1, 1, 1) 145 | if err != nil { 146 | t.Fatalf("CallTread(1, 1, 1): want nil, got %v", err) 147 | } 148 | t.Logf("read is %v", string(b)) 149 | 150 | /* make sure Twrite fails */ 151 | if _, err = c.CallTwrite(1, 0, b); err == nil { 152 | t.Fatalf("CallTwrite(1, 0, b): want err, got nil") 153 | } 154 | 155 | d, err := c.CallTstat(1) 156 | if err != nil { 157 | t.Fatalf("CallTstat(1): want nil, got %v", err) 158 | } 159 | t.Logf("stat is %v", d) 160 | 161 | d, err = c.CallTstat(22) 162 | if err == nil { 163 | t.Fatalf("CallTstat(22): want err, got nil)") 164 | } 165 | t.Logf("stat is %v", d) 166 | 167 | if err := c.CallTclunk(22); err == nil { 168 | t.Fatalf("CallTclunk(22): want err, got nil") 169 | } 170 | if err := c.CallTclunk(1); err != nil { 171 | t.Fatalf("CallTclunk(1): want nil, got %v", err) 172 | } 173 | if _, err := c.CallTread(1, 1, 22); err == nil { 174 | t.Fatalf("CallTread(1, 1, 22) after clunk: want err, got nil") 175 | } 176 | 177 | d, err = c.CallTstat(1) 178 | if err == nil { 179 | t.Fatalf("CallTstat(1): after clunk: want err, got nil") 180 | } 181 | t.Logf("stat is %v", d) 182 | 183 | // fun with write 184 | rw := strings.Split(path.Join(tmpdir, "rw"), "/") 185 | w, err = c.CallTwalk(0, 1, rw) 186 | if err != nil { 187 | t.Fatalf("CallTwalk(0,1,%v): want nil, got %v", rw, err) 188 | } 189 | t.Logf("Walk is %v", w) 190 | 191 | of, _, err = c.CallTopen(1, protocol.OREAD) 192 | if err != nil { 193 | t.Fatalf("CallTopen(1, protocol.OREAD): want nil, got %v", nil) 194 | } 195 | if err := c.CallTclunk(1); err != nil { 196 | t.Fatalf("CallTclunk(1): want nil, got %v", err) 197 | } 198 | w, err = c.CallTwalk(0, 1, rw) 199 | if err != nil { 200 | t.Fatalf("CallTwalk(0,1,%v): want nil, got %v", rw, err) 201 | } 202 | t.Logf("Walk is %v", w) 203 | 204 | of, _, err = c.CallTopen(1, protocol.OWRITE) 205 | if err != nil { 206 | t.Fatalf("CallTopen(0, protocol.OWRITE): want nil, got %v", err) 207 | } 208 | t.Logf("open OWRITE of is %v", of) 209 | if _, err = c.CallTwrite(1, 1, []byte("there")); err != nil { 210 | t.Fatalf("CallTwrite(1, 0, \"there\"): want nil, got %v", err) 211 | } 212 | if _, err = c.CallTwrite(22, 1, []byte("there")); err == nil { 213 | t.Fatalf("CallTwrite(22, 1, \"there\"): want err, got nil") 214 | } 215 | 216 | // readdir test. 217 | w, err = c.CallTwalk(0, 2, strings.Split(tmpdir, "/")) 218 | if err != nil { 219 | t.Fatalf("CallTwalk(0,2,strings.Split(tmpdir, \"/\")): want nil, got %v", err) 220 | } 221 | t.Logf("Walk is %v", w) 222 | of, _, err = c.CallTopen(2, protocol.OWRITE) 223 | if err == nil { 224 | t.Fatalf("CallTopen(2, protocol.OWRITE) on /: want err, got nil") 225 | } 226 | of, _, err = c.CallTopen(2, protocol.ORDWR) 227 | if err == nil { 228 | t.Fatalf("CallTopen(2, protocol.ORDWR) on /: want err, got nil") 229 | } 230 | of, _, err = c.CallTopen(2, protocol.OREAD) 231 | if err != nil { 232 | t.Fatalf("CallTopen(1, protocol.OREAD): want nil, got %v", nil) 233 | } 234 | var o protocol.Offset 235 | var iter int 236 | for iter < 10 { 237 | iter++ 238 | b, err = c.CallTread(2, o, 256) 239 | // EOF is indicated by a zero length read, not an actual error 240 | if len(b) == 0 { 241 | break 242 | } 243 | if err != nil { 244 | t.Fatalf("CallTread(2, 0, 256): want nil, got %v", err) 245 | } 246 | 247 | dent, err := protocol.Unmarshaldir(bytes.NewBuffer(b)) 248 | if err != nil { 249 | t.Errorf("Unmarshalldir: want nil, got %v", err) 250 | } 251 | t.Logf("dir read is %v", dent) 252 | o += protocol.Offset(len(b)) 253 | } 254 | 255 | if iter > 9 { 256 | t.Errorf("Too many reads from the directory: want 3, got %v", iter) 257 | } 258 | if err := c.CallTclunk(2); err != nil { 259 | t.Fatalf("CallTclunk(1): want nil, got %v", err) 260 | } 261 | // Create tests 262 | w, err = c.CallTwalk(0, 3, []string{}) 263 | if err != nil { 264 | t.Fatalf("CallTwalk(0,3,[]string{}): want nil, got %v", err) 265 | } 266 | w, err = c.CallTwalk(3, 3, strings.Split(tmpdir, "/")) 267 | if err != nil { 268 | t.Fatalf("CallTwalk(0,3,[]string{}): want nil, got %v", err) 269 | } 270 | t.Logf("Walk is %v", w) 271 | of, _, err = c.CallTcreate(3, "xxx", 077, 0) 272 | if err != nil { 273 | t.Fatalf("CallTcreate(\"xxx\", 077, 0): want nil, got %v", err) 274 | } 275 | xxx := path.Join(tmpdir, "xxx") 276 | fi, err := os.Stat(xxx) 277 | if err != nil { 278 | t.Fatalf("After create, check %v: want nil, got %v", xxx, err) 279 | } 280 | t.Logf("Stat of created file: %v", fi) 281 | 282 | // Test mkdir 283 | w, err = c.CallTwalk(0, 4, strings.Split(tmpdir, "/")) 284 | if err != nil { 285 | t.Fatalf("CallTwalk(0,4,%v): want nil, got %v", tmpdir, err) 286 | } 287 | of, _, err = c.CallTcreate(4, "yyy", protocol.DMDIR|0777, 0) 288 | if err != nil { 289 | t.Fatalf("CallTcreate(\"yyy\", 0777, 0): want nil, got %v", err) 290 | } 291 | yyy := path.Join(tmpdir, "yyy") 292 | fi, err = os.Stat(yyy) 293 | if err != nil { 294 | t.Fatalf("After create, check %v: want nil, got %v", yyy, err) 295 | } 296 | if !fi.IsDir() { 297 | t.Fatalf("After mkdir, %v, not a directory", yyy) 298 | } 299 | t.Logf("Stat of created file: %v", fi) 300 | 301 | // test remove 302 | if err = c.CallTremove(3); err != nil { 303 | t.Fatalf("CallTremove(3) failed: want nil, got %v", err) 304 | } 305 | if err = c.CallTclunk(3); err == nil { 306 | t.Errorf("CallTclunk(3) failed: want err, got nil") 307 | } 308 | if _, err := os.Stat(xxx); err == nil { 309 | t.Fatalf("After remove(%v); stat returns nil, not err", xxx) 310 | } 311 | if err = c.CallTremove(4); err != nil { 312 | t.Fatalf("CallTremove(4) failed: want nil, got %v", err) 313 | } 314 | if _, err := os.Stat(yyy); err == nil { 315 | t.Fatalf("After remove(%v); stat returns nil, not err", yyy) 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /filesystem/filesystem_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | // +build !windows 8 | 9 | package ufs 10 | 11 | import "io" 12 | 13 | // resetDir seeks to the beginning of the file so that the file list can be 14 | // read again. 15 | func resetDir(f *file) error { 16 | _, err := f.file.Seek(0, io.SeekStart) 17 | return err 18 | } 19 | -------------------------------------------------------------------------------- /filesystem/filesystem_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | // +build windows 8 | 9 | package ufs 10 | 11 | import "os" 12 | 13 | // resetDir closes the underlying file and reopens it so it can be read again. 14 | // This is because Windows doesn't seem to support calling Seek on a directory 15 | // handle. 16 | func resetDir(f *File) error { 17 | f2, err := os.OpenFile(f.fullName, os.O_RDONLY, 0) 18 | if err != nil { 19 | return err 20 | } 21 | 22 | f.File.Close() 23 | f.File = f2 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /filesystem/ninep.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | package ufs 8 | 9 | import ( 10 | "flag" 11 | "os" 12 | 13 | "github.com/Harvey-OS/ninep/protocol" 14 | ) 15 | 16 | var ( 17 | user = flag.String("user", "harvey", "Default user name") 18 | ) 19 | 20 | func modeToUnixFlags(mode protocol.Mode) int { 21 | ret := int(0) 22 | switch mode & 3 { 23 | case protocol.OREAD: 24 | ret = os.O_RDONLY 25 | break 26 | 27 | case protocol.ORDWR: 28 | ret = os.O_RDWR 29 | break 30 | 31 | case protocol.OWRITE: 32 | ret = os.O_WRONLY 33 | break 34 | 35 | case protocol.OEXEC: 36 | ret = os.O_RDONLY 37 | break 38 | } 39 | 40 | if mode&protocol.OTRUNC != 0 { 41 | ret |= os.O_TRUNC 42 | } 43 | 44 | return ret 45 | } 46 | 47 | func dirToQIDType(d os.FileInfo) uint8 { 48 | ret := uint8(0) 49 | if d.IsDir() { 50 | ret |= protocol.QTDIR 51 | } 52 | 53 | if d.Mode()&os.ModeSymlink != 0 { 54 | ret |= protocol.QTSYMLINK 55 | } 56 | 57 | return ret 58 | } 59 | 60 | func dirTo9p2000Mode(d os.FileInfo) uint32 { 61 | ret := uint32(d.Mode() & 0777) 62 | if d.IsDir() { 63 | ret |= protocol.DMDIR 64 | } 65 | return ret 66 | } 67 | 68 | func dirTo9p2000Dir(fi os.FileInfo) (*protocol.Dir, error) { 69 | d := &protocol.Dir{} 70 | d.QID = fileInfoToQID(fi) 71 | d.Mode = dirTo9p2000Mode(fi) 72 | // TODO: use info on systems that have it. 73 | d.Atime = uint32(fi.ModTime().Unix()) // uint32(atime(sysMode).Unix()) 74 | d.Mtime = uint32(fi.ModTime().Unix()) 75 | d.Length = uint64(fi.Size()) 76 | d.Name = fi.Name() 77 | d.User = *user 78 | d.Group = *user 79 | 80 | return d, nil 81 | } 82 | -------------------------------------------------------------------------------- /filesystem/ninep_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | // +build !windows 8 | 9 | package ufs 10 | 11 | import ( 12 | "os" 13 | "syscall" 14 | 15 | "github.com/Harvey-OS/ninep/protocol" 16 | ) 17 | 18 | func fileInfoToQID(d os.FileInfo) protocol.QID { 19 | var qid protocol.QID 20 | sysif := d.Sys() 21 | 22 | // on systems with inodes, use it. 23 | if sysif != nil { 24 | stat := sysif.(*syscall.Stat_t) 25 | qid.Path = uint64(stat.Ino) 26 | } else { 27 | qid.Path = uint64(d.ModTime().UnixNano()) 28 | } 29 | 30 | qid.Version = uint32(d.ModTime().UnixNano() / 1000000) 31 | qid.Type = dirToQIDType(d) 32 | 33 | return qid 34 | } 35 | -------------------------------------------------------------------------------- /filesystem/ninep_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | // +build windows 8 | 9 | package ufs 10 | 11 | import ( 12 | "os" 13 | 14 | "github.com/Harvey-OS/ninep/protocol" 15 | ) 16 | 17 | func fileInfoToQID(d os.FileInfo) protocol.QID { 18 | var qid protocol.QID 19 | 20 | qid.Path = uint64(d.ModTime().UnixNano()) 21 | qid.Version = uint32(d.ModTime().UnixNano() / 1000000) 22 | qid.Type = dirToQIDType(d) 23 | 24 | return qid 25 | } 26 | -------------------------------------------------------------------------------- /pkg/debugfs/debug.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Ninep 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 | package debugfs 6 | 7 | import ( 8 | "bytes" 9 | "log" 10 | 11 | "github.com/Harvey-OS/ninep/protocol" 12 | ) 13 | 14 | type DebugFileServer struct { 15 | FileServer protocol.NineServer 16 | } 17 | 18 | func (dfs *DebugFileServer) Rversion(msize protocol.MaxSize, version string) (protocol.MaxSize, string, error) { 19 | log.Printf(">>> Tversion %v %v\n", msize, version) 20 | msize, version, err := dfs.FileServer.Rversion(msize, version) 21 | if err == nil { 22 | log.Printf("<<< Rversion %v %v\n", msize, version) 23 | } else { 24 | log.Printf("<<< Error %v\n", err) 25 | } 26 | return msize, version, err 27 | } 28 | 29 | func (dfs *DebugFileServer) Rattach(fid protocol.FID, afid protocol.FID, uname string, aname string) (protocol.QID, error) { 30 | log.Printf(">>> Tattach fid %v, afid %v, uname %v, aname %v\n", fid, afid, 31 | uname, aname) 32 | qid, err := dfs.FileServer.Rattach(fid, afid, uname, aname) 33 | if err == nil { 34 | log.Printf("<<< Rattach %v\n", qid) 35 | } else { 36 | log.Printf("<<< Error %v\n", err) 37 | } 38 | return qid, err 39 | } 40 | 41 | func (dfs *DebugFileServer) Rflush(o protocol.Tag) error { 42 | log.Printf(">>> Tflush tag %v\n", o) 43 | err := dfs.FileServer.Rflush(o) 44 | if err == nil { 45 | log.Printf("<<< Rflush\n") 46 | } else { 47 | log.Printf("<<< Error %v\n", err) 48 | } 49 | return err 50 | } 51 | 52 | func (dfs *DebugFileServer) Rwalk(fid protocol.FID, newfid protocol.FID, paths []string) ([]protocol.QID, error) { 53 | log.Printf(">>> Twalk fid %v, newfid %v, paths %v\n", fid, newfid, paths) 54 | qid, err := dfs.FileServer.Rwalk(fid, newfid, paths) 55 | if err == nil { 56 | log.Printf("<<< Rwalk %v\n", qid) 57 | } else { 58 | log.Printf("<<< Error %v\n", err) 59 | } 60 | return qid, err 61 | } 62 | 63 | func (dfs *DebugFileServer) Ropen(fid protocol.FID, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { 64 | log.Printf(">>> Topen fid %v, mode %v\n", fid, mode) 65 | qid, iounit, err := dfs.FileServer.Ropen(fid, mode) 66 | if err == nil { 67 | log.Printf("<<< Ropen %v %v\n", qid, iounit) 68 | } else { 69 | log.Printf("<<< Error %v\n", err) 70 | } 71 | return qid, iounit, err 72 | } 73 | 74 | func (dfs *DebugFileServer) Rcreate(fid protocol.FID, name string, perm protocol.Perm, mode protocol.Mode) (protocol.QID, protocol.MaxSize, error) { 75 | log.Printf(">>> Tcreate fid %v, name %v, perm %v, mode %v\n", fid, name, 76 | perm, mode) 77 | qid, iounit, err := dfs.FileServer.Rcreate(fid, name, perm, mode) 78 | if err == nil { 79 | log.Printf("<<< Rcreate %v %v\n", qid, iounit) 80 | } else { 81 | log.Printf("<<< Error %v\n", err) 82 | } 83 | return qid, iounit, err 84 | } 85 | 86 | func (dfs *DebugFileServer) Rclunk(fid protocol.FID) error { 87 | log.Printf(">>> Tclunk fid %v\n", fid) 88 | err := dfs.FileServer.Rclunk(fid) 89 | if err == nil { 90 | log.Printf("<<< Rclunk\n") 91 | } else { 92 | log.Printf("<<< Error %v\n", err) 93 | } 94 | return err 95 | } 96 | 97 | func (dfs *DebugFileServer) Rstat(fid protocol.FID) ([]byte, error) { 98 | log.Printf(">>> Tstat fid %v\n", fid) 99 | b, err := dfs.FileServer.Rstat(fid) 100 | if err == nil { 101 | dir, _ := protocol.Unmarshaldir(bytes.NewBuffer(b)) 102 | log.Printf("<<< Rstat %v\n", dir) 103 | } else { 104 | log.Printf("<<< Error %v\n", err) 105 | } 106 | return b, err 107 | } 108 | 109 | func (dfs *DebugFileServer) Rwstat(fid protocol.FID, b []byte) error { 110 | dir, _ := protocol.Unmarshaldir(bytes.NewBuffer(b)) 111 | log.Printf(">>> Twstat fid %v, %v\n", fid, dir) 112 | err := dfs.FileServer.Rwstat(fid, b) 113 | if err == nil { 114 | log.Printf("<<< Rwstat\n") 115 | } else { 116 | log.Printf("<<< Error %v\n", err) 117 | } 118 | return err 119 | } 120 | 121 | func (dfs *DebugFileServer) Rremove(fid protocol.FID) error { 122 | log.Printf(">>> Tremove fid %v\n", fid) 123 | err := dfs.FileServer.Rremove(fid) 124 | if err == nil { 125 | log.Printf("<<< Rremove\n") 126 | } else { 127 | log.Printf("<<< Error %v\n", err) 128 | } 129 | return err 130 | } 131 | 132 | func (dfs *DebugFileServer) Rread(fid protocol.FID, o protocol.Offset, c protocol.Count) ([]byte, error) { 133 | log.Printf(">>> Tread fid %v, off %v, count %v\n", fid, o, c) 134 | b, err := dfs.FileServer.Rread(fid, o, c) 135 | if err == nil { 136 | log.Printf("<<< Rread %v\n", len(b)) 137 | } else { 138 | log.Printf("<<< Error %v\n", err) 139 | } 140 | return b, err 141 | } 142 | 143 | func (dfs *DebugFileServer) Rwrite(fid protocol.FID, o protocol.Offset, b []byte) (protocol.Count, error) { 144 | log.Printf(">>> Twrite fid %v, off %v, count %v\n", fid, o, len(b)) 145 | c, err := dfs.FileServer.Rwrite(fid, o, b) 146 | if err == nil { 147 | log.Printf("<<< Rwrite %v\n", c) 148 | } else { 149 | log.Printf("<<< Error %v\n", err) 150 | } 151 | return c, err 152 | } 153 | -------------------------------------------------------------------------------- /protocol/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | package protocol 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io" 13 | "log" 14 | "runtime" 15 | "sync/atomic" 16 | ) 17 | 18 | // Client implements a 9p client. It has a chan containing all tags, 19 | // a scalar FID which is incremented to provide new FIDS (all FIDS for a given 20 | // client are unique), an array of MaxTag-2 RPC structs, a ReadWriteCloser 21 | // for IO, and two channels for a server goroutine: one down which RPCalls are 22 | // pushed and another from which RPCReplys return. 23 | // Once a client is marked Dead all further requests to it will fail. 24 | // The ToNet/FromNet are separate so we can use io.Pipe for testing. 25 | type Client struct { 26 | Tags chan Tag 27 | FID uint64 28 | RPC []*RPCCall 29 | ToNet io.WriteCloser 30 | FromNet io.ReadCloser 31 | FromClient chan *RPCCall 32 | FromServer chan *RPCReply 33 | Msize uint32 34 | Dead bool 35 | Trace Tracer 36 | } 37 | 38 | func NewClient(opts ...ClientOpt) (*Client, error) { 39 | var c = &Client{} 40 | 41 | c.Tags = make(chan Tag, NumTags) 42 | for i := 1; i < int(NOTAG); i++ { 43 | c.Tags <- Tag(i) 44 | } 45 | c.FID = 1 46 | c.RPC = make([]*RPCCall, NumTags) 47 | for _, o := range opts { 48 | if err := o(c); err != nil { 49 | return nil, err 50 | } 51 | } 52 | c.FromClient = make(chan *RPCCall, NumTags) 53 | c.FromServer = make(chan *RPCReply) 54 | go c.IO() 55 | go c.readNetPackets() 56 | return c, nil 57 | } 58 | 59 | // GetTag gets a tag to be used to identify a message. 60 | func (c *Client) GetTag() Tag { 61 | t := <-c.Tags 62 | if false { 63 | runtime.SetFinalizer(&t, func(t *Tag) { 64 | c.Tags <- *t 65 | }) 66 | } 67 | return t 68 | } 69 | 70 | // GetFID gets a fid to be used to identify a resource for a 9p client. 71 | // For a given lifetime of a 9p client, FIDS are unique (i.e. not reused as in 72 | // many 9p client libraries). 73 | func (c *Client) GetFID() FID { 74 | return FID(atomic.AddUint64(&c.FID, 1)) 75 | } 76 | 77 | func (c *Client) readNetPackets() { 78 | if c.FromNet == nil { 79 | if c.Trace != nil { 80 | c.Trace("c.FromNet is nil, marking dead") 81 | } 82 | c.Dead = true 83 | return 84 | } 85 | defer c.FromNet.Close() 86 | defer close(c.FromServer) 87 | if c.Trace != nil { 88 | c.Trace("Starting readNetPackets") 89 | } 90 | for !c.Dead { 91 | l := make([]byte, 7) 92 | if c.Trace != nil { 93 | c.Trace("Before read") 94 | } 95 | 96 | if n, err := c.FromNet.Read(l); err != nil || n < 7 { 97 | log.Printf("readNetPackets: short read: %v", err) 98 | c.Dead = true 99 | return 100 | } 101 | if c.Trace != nil { 102 | c.Trace("Server reads %v", l) 103 | } 104 | s := int64(l[0]) + int64(l[1])<<8 + int64(l[2])<<16 + int64(l[3])<<24 105 | b := bytes.NewBuffer(l) 106 | r := io.LimitReader(c.FromNet, s-7) 107 | if _, err := io.Copy(b, r); err != nil { 108 | log.Printf("readNetPackets: short read: %v", err) 109 | c.Dead = true 110 | return 111 | } 112 | if c.Trace != nil { 113 | c.Trace("readNetPackets: got %v, len %d, sending to IO", RPCNames[MType(l[4])], b.Len()) 114 | } 115 | c.FromServer <- &RPCReply{b: b.Bytes()} 116 | } 117 | if c.Trace != nil { 118 | c.Trace("Client %v is all done", c) 119 | } 120 | 121 | } 122 | 123 | func (c *Client) IO() { 124 | go func() { 125 | for { 126 | r := <-c.FromClient 127 | t := <-c.Tags 128 | if c.Trace != nil { 129 | c.Trace(fmt.Sprintf("Tag for request is %v", t)) 130 | } 131 | r.b[5] = uint8(t) 132 | r.b[6] = uint8(t >> 8) 133 | if c.Trace != nil { 134 | c.Trace(fmt.Sprintf("Tag for request is %v", t)) 135 | } 136 | c.RPC[int(t)-1] = r 137 | if c.Trace != nil { 138 | c.Trace("Write %v to ToNet", r.b) 139 | } 140 | if _, err := c.ToNet.Write(r.b); err != nil { 141 | c.Dead = true 142 | log.Fatalf("Write to server: %v", err) 143 | return 144 | } 145 | } 146 | }() 147 | 148 | for { 149 | r := <-c.FromServer 150 | if c.Trace != nil { 151 | c.Trace("Read %v FromServer", r.b) 152 | } 153 | t := Tag(r.b[5]) | Tag(r.b[6])<<8 154 | if c.Trace != nil { 155 | c.Trace(fmt.Sprintf("Tag for reply is %v", t)) 156 | } 157 | if t < 1 { 158 | panic(fmt.Sprintf("tag %d < 1", t)) 159 | } 160 | if int(t-1) >= len(c.RPC) { 161 | panic(fmt.Sprintf("tag %d >= len(c.RPC) %d", t, len(c.RPC))) 162 | } 163 | c.Trace("RPC %v ", c.RPC[t-1]) 164 | rrr := c.RPC[t-1] 165 | c.Trace("rrr %v ", rrr) 166 | rrr.Reply <- r.b 167 | c.Tags <- t 168 | } 169 | } 170 | 171 | func (c *Client) String() string { 172 | z := map[bool]string{false: "Alive", true: "Dead"} 173 | return fmt.Sprintf("%v tags available, Msize %v, %v FromNet %v ToNet %v", len(c.Tags), c.Msize, z[c.Dead], 174 | c.FromNet, c.ToNet) 175 | } 176 | -------------------------------------------------------------------------------- /protocol/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Ninep 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 | // +build ignore 6 | 7 | // gen is an rpc generator for the Plan 9 style XDR. It uses the types and structs 8 | // defined in types. go. A core function, gen, creates the needed lists of 9 | // parameters, code, and variable list for calling a Marshall function; and the 10 | // return declaration, code, and return value list for an unmarshall function. 11 | // You can think of an RPC as a pipline: 12 | // marshal(parms) -> b[]byte over a network -> unmarshal -> dispatch -> reply(parms) -> unmarshal 13 | // Since we have T messages and R messages in 9p, we adopt the following naming convention for, e.g., Version: 14 | // MarshalTPktVersion 15 | // UnmarshalTpktVersion 16 | // MarshalRPktVersion 17 | // UnmarshalRPktVersion 18 | // 19 | // A caller uses the MarshalT* and UnmarshallR* information. A dispatcher 20 | // uses the UnmarshalT* and MarshalR* information. 21 | // Hence the caller needs the call MarshalT params, and UnmarshalR* returns; 22 | // a dispatcher needs the UnmarshalT returns, and the MarshalR params. 23 | package main 24 | 25 | import ( 26 | "bytes" 27 | "flag" 28 | "fmt" 29 | "io" 30 | "io/ioutil" 31 | "log" 32 | "reflect" 33 | "text/template" 34 | 35 | "github.com/Harvey-OS/ninep/protocol" 36 | ) 37 | 38 | const ( 39 | header = ` 40 | package protocol 41 | import ( 42 | "bytes" 43 | "fmt" 44 | _ "log" 45 | ) 46 | ` 47 | ) 48 | 49 | type emitter struct { 50 | Name string 51 | MFunc string 52 | // Encoders always return []byte 53 | MParms *bytes.Buffer 54 | MList *bytes.Buffer 55 | MLsep string 56 | MCode *bytes.Buffer 57 | 58 | // Decoders always take []byte as parms. 59 | UFunc string 60 | UList *bytes.Buffer 61 | UCode *bytes.Buffer 62 | URet *bytes.Buffer 63 | inBWrite bool 64 | } 65 | 66 | type call struct { 67 | T *emitter 68 | R *emitter 69 | } 70 | 71 | type pack struct { 72 | n string 73 | t interface{} 74 | tn string 75 | r interface{} 76 | rn string 77 | } 78 | 79 | const ( 80 | serverError = `func ServerError (b *bytes.Buffer, s string) { 81 | var u [8]byte 82 | // This can't really happen. 83 | if _, err := b.Read(u[:2]); err != nil { 84 | return 85 | } 86 | t := Tag(uint16(u[0])|uint16(u[1])<<8) 87 | MarshalRerrorPkt (b, t, s) 88 | } 89 | ` 90 | ) 91 | 92 | var ( 93 | doDebug = flag.Bool("d", false, "Debug prints") 94 | debug = nodebug //log.Printf 95 | packages = []*pack{ 96 | {n: "error", t: protocol.RerrorPkt{}, tn: "Rerror", r: protocol.RerrorPkt{}, rn: "Rerror"}, 97 | {n: "version", t: protocol.TversionPkt{}, tn: "Tversion", r: protocol.RversionPkt{}, rn: "Rversion"}, 98 | {n: "attach", t: protocol.TattachPkt{}, tn: "Tattach", r: protocol.RattachPkt{}, rn: "Rattach"}, 99 | {n: "flush", t: protocol.TflushPkt{}, tn: "Tflush", r: protocol.RflushPkt{}, rn: "Rflush"}, 100 | {n: "walk", t: protocol.TwalkPkt{}, tn: "Twalk", r: protocol.RwalkPkt{}, rn: "Rwalk"}, 101 | {n: "open", t: protocol.TopenPkt{}, tn: "Topen", r: protocol.RopenPkt{}, rn: "Ropen"}, 102 | {n: "create", t: protocol.TcreatePkt{}, tn: "Tcreate", r: protocol.RcreatePkt{}, rn: "Rcreate"}, 103 | {n: "stat", t: protocol.TstatPkt{}, tn: "Tstat", r: protocol.RstatPkt{}, rn: "Rstat"}, 104 | {n: "wstat", t: protocol.TwstatPkt{}, tn: "Twstat", r: protocol.RwstatPkt{}, rn: "Rwstat"}, 105 | {n: "clunk", t: protocol.TclunkPkt{}, tn: "Tclunk", r: protocol.RclunkPkt{}, rn: "Rclunk"}, 106 | {n: "remove", t: protocol.TremovePkt{}, tn: "Tremove", r: protocol.RremovePkt{}, rn: "Rremove"}, 107 | {n: "read", t: protocol.TreadPkt{}, tn: "Tread", r: protocol.RreadPkt{}, rn: "Rread"}, 108 | {n: "write", t: protocol.TwritePkt{}, tn: "Twrite", r: protocol.RwritePkt{}, rn: "Rwrite"}, 109 | } 110 | msfunc = template.Must(template.New("ms").Parse(`func Marshal{{.MFunc}} (b *bytes.Buffer, {{.MParms}}) { 111 | var l uint64 112 | b.Reset() 113 | b.Write([]byte{0,0,}) 114 | {{.MCode}} 115 | l = uint64(b.Len()) - 2 116 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8)}) 117 | return 118 | } 119 | `)) 120 | usfunc = template.Must(template.New("us").Parse(`func Unmarshal{{.UFunc}} (b *bytes.Buffer) ({{.URet}} err error) { 121 | var u [8]uint8 122 | var l uint64 123 | _ = b.Next(2) // eat the length too 124 | {{.UCode}} 125 | return 126 | } 127 | `)) 128 | 129 | mfunc = template.Must(template.New("mt").Parse(`func Marshal{{.MFunc}}Pkt (b *bytes.Buffer, t Tag, {{.MParms}}) { 130 | var l uint64 131 | b.Reset() 132 | b.Write([]byte{0,0,0,0, 133 | uint8({{.Name}}), 134 | byte(t), byte(t>>8), 135 | {{.MCode}} 136 | { 137 | l = uint64(b.Len()) 138 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 139 | } 140 | return 141 | } 142 | `)) 143 | ufunc = template.Must(template.New("mr").Parse(`func Unmarshal{{.UFunc}}Pkt (b *bytes.Buffer) ({{.URet}} t Tag, err error) { 144 | var u [8]uint8 145 | var l uint64 146 | if _, err = b.Read(u[:2]); err != nil { 147 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 148 | return 149 | } 150 | l = uint64(u[0]) | uint64(u[1])<<8 151 | t = Tag(l) 152 | {{.UCode}} 153 | if b.Len() > 0 { 154 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 155 | } 156 | return 157 | } 158 | `)) 159 | sfunc = template.Must(template.New("s").Parse(`func (s *Server) Srv{{.R.UFunc}}(b*bytes.Buffer) (err error) { 160 | {{.T.MList}}{{.T.MLsep}} t, err := Unmarshal{{.T.MFunc}}Pkt(b) 161 | //if err != nil { 162 | //} 163 | if {{.R.MList}}{{.R.MLsep}} err := s.NS.{{.R.MFunc}}({{.T.MList}}); err != nil { 164 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 165 | } else { 166 | Marshal{{.R.MFunc}}Pkt(b, t, {{.R.MList}}) 167 | } 168 | return nil 169 | } 170 | `)) 171 | cfunc = template.Must(template.New("s").Parse(` 172 | func (c *Client)Call{{.T.MFunc}} ({{.T.MParms}}) ({{.R.URet}} err error) { 173 | var b = bytes.Buffer{} 174 | if c.Trace != nil {c.Trace("%v", {{.T.MFunc}})} 175 | t := Tag(0) 176 | r := make (chan []byte) 177 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 178 | Marshal{{.T.MFunc}}Pkt(&b, t, {{.T.MList}}) 179 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 180 | bb := <-r 181 | if MType(bb[4]) == Rerror { 182 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 183 | if err != nil { 184 | return {{.R.UList}} err 185 | } 186 | return {{.R.UList}} fmt.Errorf("%v", s) 187 | } else { 188 | {{.R.MList}}{{.R.MLsep}} _, err = Unmarshal{{.R.UFunc}}Pkt(bytes.NewBuffer(bb[5:])) 189 | } 190 | return {{.R.UList}} err 191 | } 192 | `)) 193 | ) 194 | 195 | func nodebug(string, ...interface{}) { 196 | } 197 | 198 | func newCall(p *pack) *call { 199 | c := &call{} 200 | // We set inBWrite to true because the prologue marshal code sets up some default writes to b 201 | c.T = &emitter{"T" + p.n, p.tn, &bytes.Buffer{}, &bytes.Buffer{}, "", &bytes.Buffer{}, p.tn, &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}, true} 202 | c.R = &emitter{"R" + p.n, p.rn, &bytes.Buffer{}, &bytes.Buffer{}, "", &bytes.Buffer{}, p.rn, &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}, true} 203 | return c 204 | } 205 | 206 | func emitEncodeInt(v interface{}, n string, l int, e *emitter) { 207 | debug("emit %v, %v", n, l) 208 | for i := 0; i < l; i++ { 209 | if !e.inBWrite { 210 | e.MCode.WriteString("\tb.Write([]byte{") 211 | e.inBWrite = true 212 | } 213 | e.MCode.WriteString(fmt.Sprintf("\tuint8(%v>>%v),\n", n, i*8)) 214 | } 215 | } 216 | 217 | func emitDecodeInt(v interface{}, n string, l int, e *emitter) { 218 | t := reflect.ValueOf(v).Type().Name() 219 | debug("emit reflect.ValueOf(v) %s %v, %v", t, n, l) 220 | e.UCode.WriteString(fmt.Sprintf("\tif _, err = b.Read(u[:%v]); err != nil {\n\t\terr = fmt.Errorf(\"pkt too short for uint%v: need %v, have %%d\", b.Len())\n\treturn\n\t}\n", l, l*8, l)) 221 | e.UCode.WriteString(fmt.Sprintf("\t%v = %s(u[0])\n", n, t)) 222 | for i := 1; i < l; i++ { 223 | e.UCode.WriteString(fmt.Sprintf("\t%v |= %s(u[%d])<<%v\n", n, t, i, i*8)) 224 | } 225 | } 226 | 227 | // TODO: templates. 228 | func emitEncodeString(v interface{}, n string, e *emitter) { 229 | if !e.inBWrite { 230 | e.MCode.WriteString("\tb.Write([]byte{") 231 | e.inBWrite = true 232 | } 233 | e.MCode.WriteString(fmt.Sprintf("\tuint8(len(%v)),uint8(len(%v)>>8),\n", n, n)) 234 | e.MCode.WriteString("\t})\n") 235 | e.inBWrite = false 236 | e.MCode.WriteString(fmt.Sprintf("\tb.Write([]byte(%v))\n", n)) 237 | } 238 | 239 | func emitDecodeString(n string, e *emitter) { 240 | var l uint64 241 | emitDecodeInt(l, "l", 2, e) 242 | e.UCode.WriteString(fmt.Sprintf("\tif b.Len() < int(l) {\n\t\terr = fmt.Errorf(\"pkt too short for string: need %%d, have %%d\", l, b.Len())\n\treturn\n\t}\n")) 243 | e.UCode.WriteString(fmt.Sprintf("\t%v = string(b.Bytes()[:l])\n", n)) 244 | e.UCode.WriteString("\t_ = b.Next(int(l))\n") 245 | } 246 | 247 | func genEncodeStruct(v interface{}, n string, e *emitter) error { 248 | debug("genEncodeStruct(%T, %v, %v)", v, n, e) 249 | t := reflect.ValueOf(v) 250 | for i := 0; i < t.NumField(); i++ { 251 | f := t.Field(i) 252 | fn := t.Type().Field(i).Name 253 | debug("genEncodeStruct %T n %v field %d %v %v\n", t, n, i, f.Type(), f.Type().Name()) 254 | genEncodeData(f.Interface(), n+fn, e) 255 | } 256 | return nil 257 | } 258 | 259 | func genDecodeStruct(v interface{}, n string, e *emitter) error { 260 | debug("genDecodeStruct(%T, %v, %v)", v, n, "") 261 | t := reflect.ValueOf(v) 262 | for i := 0; i < t.NumField(); i++ { 263 | f := t.Field(i) 264 | fn := t.Type().Field(i).Name 265 | debug("genDecodeStruct %T n %v field %d %v %v\n", t, n, i, f.Type(), f.Type().Name()) 266 | genDecodeData(f.Interface(), n+fn, e) 267 | } 268 | return nil 269 | } 270 | 271 | // TODO: there has to be a smarter way to do slices. 272 | func genEncodeSlice(v interface{}, n string, e *emitter) error { 273 | t := fmt.Sprintf("%T", v) 274 | switch t { 275 | case "[]string": 276 | var u uint16 277 | emitEncodeInt(u, fmt.Sprintf("len(%v)", n), 2, e) 278 | if e.inBWrite { 279 | e.MCode.WriteString("\t})\n") 280 | e.inBWrite = false 281 | } 282 | e.MCode.WriteString(fmt.Sprintf("for i := range %v {\n", n)) 283 | var s string 284 | genEncodeData(s, n+"[i]", e) 285 | e.MCode.WriteString("}\n") 286 | case "[]protocol.QID": 287 | var u uint16 288 | emitEncodeInt(u, fmt.Sprintf("len(%v)", n), 2, e) 289 | if e.inBWrite { 290 | e.MCode.WriteString("\t})\n") 291 | e.inBWrite = false 292 | } 293 | e.MCode.WriteString(fmt.Sprintf("for i := range %v {\n", n)) 294 | genEncodeData(protocol.QID{}, n+"[i]", e) 295 | e.MCode.WriteString("\t})\n") 296 | e.inBWrite = false 297 | e.MCode.WriteString("}\n") 298 | case "[]byte", "[]uint8": 299 | var u uint32 300 | emitEncodeInt(u, fmt.Sprintf("len(%v)", n), 4, e) 301 | if e.inBWrite { 302 | e.MCode.WriteString("\t})\n") 303 | e.inBWrite = false 304 | } 305 | e.MCode.WriteString(fmt.Sprintf("\tb.Write(%v)\n", n)) 306 | case "[]protocol.DataCnt16": 307 | var u uint16 308 | emitEncodeInt(u, fmt.Sprintf("len(%v)", n), 2, e) 309 | if e.inBWrite { 310 | e.MCode.WriteString("\t})\n") 311 | e.inBWrite = false 312 | } 313 | e.MCode.WriteString(fmt.Sprintf("\tb.Write(%v)\n", n)) 314 | default: 315 | log.Printf("genEncodeSlice: Can't handle slice of %s", t) 316 | } 317 | return nil 318 | } 319 | 320 | func genDecodeSlice(v interface{}, n string, e *emitter) error { 321 | // Sadly, []byte is not encoded like []everything else. 322 | t := fmt.Sprintf("%T", v) 323 | switch t { 324 | case "[]string": 325 | var u uint64 326 | emitDecodeInt(u, "l", 2, e) 327 | e.UCode.WriteString(fmt.Sprintf("\t%v = make([]string, l)\n", n)) 328 | e.UCode.WriteString(fmt.Sprintf("for i := range %v {\n", n)) 329 | var s string 330 | genDecodeData(s, n+"[i]", e) 331 | e.UCode.WriteString("}\n") 332 | case "[]protocol.QID": 333 | var u uint64 334 | emitDecodeInt(u, "l", 2, e) 335 | e.UCode.WriteString(fmt.Sprintf("\t%v = make([]QID, l)\n", n)) 336 | e.UCode.WriteString(fmt.Sprintf("for i := range %v {\n", n)) 337 | genDecodeData(protocol.QID{}, n+"[i]", e) 338 | e.UCode.WriteString("}\n") 339 | case "[]byte", "[]uint8": 340 | var u uint64 341 | emitDecodeInt(u, "l", 4, e) 342 | e.UCode.WriteString(fmt.Sprintf("\t%v = b.Bytes()[:l]\n", n)) 343 | e.UCode.WriteString("\t_ = b.Next(int(l))\n") 344 | case "[]protocol.DataCnt16": 345 | var u uint64 346 | emitDecodeInt(u, "l", 2, e) 347 | e.UCode.WriteString(fmt.Sprintf("\t%v = b.Bytes()[:l]\n", n)) 348 | e.UCode.WriteString("\t_ = b.Next(int(l))\n") 349 | default: 350 | log.Printf("genDecodeSlice: Can't handle slice of %v", t) 351 | } 352 | return nil 353 | } 354 | 355 | func genEncodeData(v interface{}, n string, e *emitter) error { 356 | debug("genEncodeData(%T, %v, %v)", v, n, e) 357 | s := reflect.ValueOf(v).Kind() 358 | switch s { 359 | case reflect.Uint8: 360 | emitEncodeInt(v, n, 1, e) 361 | case reflect.Uint16: 362 | emitEncodeInt(v, n, 2, e) 363 | case reflect.Uint32, reflect.Int32: 364 | emitEncodeInt(v, n, 4, e) 365 | case reflect.Uint64: 366 | emitEncodeInt(v, n, 8, e) 367 | case reflect.String: 368 | emitEncodeString(v, n, e) 369 | case reflect.Struct: 370 | if n != "" { 371 | n = n + "." 372 | } 373 | return genEncodeStruct(v, n, e) 374 | case reflect.Slice: 375 | return genEncodeSlice(v, n, e) 376 | default: 377 | log.Printf("genEncodeData: Can't handle type %T", v) 378 | } 379 | return nil 380 | } 381 | 382 | func genDecodeData(v interface{}, n string, e *emitter) error { 383 | debug("genEncodeData(%T, %v, %v)", v, n, "") //e) 384 | s := reflect.ValueOf(v).Kind() 385 | switch s { 386 | case reflect.Uint8: 387 | emitDecodeInt(v, n, 1, e) 388 | case reflect.Uint16: 389 | emitDecodeInt(v, n, 2, e) 390 | case reflect.Uint32, reflect.Int32: 391 | emitDecodeInt(v, n, 4, e) 392 | case reflect.Uint64: 393 | emitDecodeInt(v, n, 8, e) 394 | case reflect.String: 395 | emitDecodeString(n, e) 396 | case reflect.Struct: 397 | if n != "" { 398 | n = n + "." 399 | } 400 | debug("----------> call gendecodstruct(%v, %v, e)", v, n) 401 | return genDecodeStruct(v, n, e) 402 | case reflect.Slice: 403 | return genDecodeSlice(v, n, e) 404 | default: 405 | log.Printf("genDecodeData: Can't handle type %T", v) 406 | } 407 | return nil 408 | } 409 | 410 | // Well, it's odd, but Name sometimes comes back empty. 411 | // I don't know why. 412 | func tn(f reflect.Value) string { 413 | n := f.Type().Name() 414 | if n == "" { 415 | t := f.Type().String() 416 | switch t { 417 | case "[]protocol.QID": 418 | n = "[]QID" 419 | case "[]protocol.DataCnt16": 420 | n = "[]byte" 421 | default: 422 | n = t 423 | } 424 | } 425 | return n 426 | } 427 | 428 | // genParms writes the parameters for declarations (name and type) 429 | // a list of names (for calling the encoder) 430 | func genParms(v interface{}, n string, e *emitter) error { 431 | t := reflect.ValueOf(v) 432 | for i := 0; i < t.NumField(); i++ { 433 | f := t.Field(i) 434 | fn := t.Type().Field(i).Name 435 | e.MList.WriteString(e.MLsep + fn) 436 | e.MParms.WriteString(e.MLsep + fn + " " + tn(f)) 437 | e.MLsep = ", " 438 | } 439 | return nil 440 | } 441 | 442 | // genRets writes the rets for declarations (name and type) 443 | // a list of names 444 | func genRets(v interface{}, n string, e *emitter) error { 445 | t := reflect.ValueOf(v) 446 | for i := 0; i < t.NumField(); i++ { 447 | f := t.Field(i) 448 | fn := t.Type().Field(i).Name 449 | e.UList.WriteString(fn + ", ") 450 | e.URet.WriteString(fn + " " + tn(f) + ", ") 451 | } 452 | return nil 453 | } 454 | 455 | // genMsgRPC generates the call and reply declarations and marshalers. We don't think of encoders as too separate 456 | // because the 9p encoding is so simple. 457 | func genMsgRPC(b io.Writer, p *pack) (*call, error) { 458 | 459 | c := newCall(p) 460 | 461 | if err := genEncodeStruct(p.r, "", c.R); err != nil { 462 | log.Fatalf("%v", err) 463 | } 464 | if c.R.inBWrite { 465 | c.R.MCode.WriteString("\t})\n") 466 | c.R.inBWrite = false 467 | } 468 | if err := genDecodeStruct(p.r, "", c.R); err != nil { 469 | log.Fatalf("%v", err) 470 | } 471 | 472 | if err := genEncodeStruct(p.t, "", c.T); err != nil { 473 | log.Fatalf("%v", err) 474 | } 475 | if c.T.inBWrite { 476 | c.T.MCode.WriteString("\t})\n") 477 | c.T.inBWrite = false 478 | } 479 | 480 | if err := genDecodeStruct(p.t, "", c.T); err != nil { 481 | log.Fatalf("%v", err) 482 | } 483 | 484 | if err := genParms(p.t, p.tn, c.T); err != nil { 485 | log.Fatalf("%v", err) 486 | } 487 | 488 | if err := genRets(p.t, p.tn, c.T); err != nil { 489 | log.Fatalf("%v", err) 490 | } 491 | 492 | if err := genParms(p.r, p.rn, c.R); err != nil { 493 | log.Fatalf("%v", err) 494 | } 495 | 496 | if err := genRets(p.r, p.rn, c.R); err != nil { 497 | log.Fatalf("%v", err) 498 | } 499 | 500 | //log.Print("e %v d %v", c.T, c.R) 501 | 502 | // log.Print("------------------", c.T.MParms, "0", c.T.MList, "1", c.R.URet, "2", c.R.UList) 503 | // log.Print("------------------", c.T.MCode) 504 | mfunc.Execute(b, c.R) 505 | ufunc.Execute(b, c.R) 506 | 507 | if p.n == "error" { 508 | return c, nil 509 | } 510 | 511 | mfunc.Execute(b, c.T) 512 | ufunc.Execute(b, c.T) 513 | sfunc.Execute(b, c) 514 | cfunc.Execute(b, c) 515 | return nil, nil 516 | 517 | } 518 | 519 | func main() { 520 | flag.Parse() 521 | if *doDebug { 522 | debug = log.Printf 523 | } 524 | var b = bytes.NewBufferString(header) 525 | for _, p := range packages { 526 | _, err := genMsgRPC(b, p) 527 | if err != nil { 528 | log.Fatalf("%v", err) 529 | } 530 | } 531 | b.WriteString(serverError) 532 | 533 | // yeah, it's a hack. 534 | dir := &emitter{"dir", "dir", &bytes.Buffer{}, &bytes.Buffer{}, "", &bytes.Buffer{}, "dir", &bytes.Buffer{}, &bytes.Buffer{}, &bytes.Buffer{}, false} 535 | if err := genEncodeStruct(protocol.DirPkt{}, "", dir); err != nil { 536 | log.Fatalf("%v", err) 537 | } 538 | if err := genDecodeStruct(protocol.DirPkt{}, "", dir); err != nil { 539 | log.Fatalf("%v", err) 540 | } 541 | if err := genParms(protocol.DirPkt{}, "dir", dir); err != nil { 542 | log.Fatalf("%v", err) 543 | } 544 | 545 | if err := genRets(protocol.DirPkt{}, "dir", dir); err != nil { 546 | log.Fatalf("%v", err) 547 | } 548 | 549 | msfunc.Execute(b, dir) 550 | usfunc.Execute(b, dir) 551 | 552 | if err := ioutil.WriteFile("genout.go", b.Bytes(), 0600); err != nil { 553 | log.Fatalf("%v", err) 554 | } 555 | 556 | } 557 | -------------------------------------------------------------------------------- /protocol/genout.go: -------------------------------------------------------------------------------- 1 | 2 | package protocol 3 | import ( 4 | "bytes" 5 | "fmt" 6 | _ "log" 7 | ) 8 | func MarshalRerrorPkt (b *bytes.Buffer, t Tag, Error string) { 9 | var l uint64 10 | b.Reset() 11 | b.Write([]byte{0,0,0,0, 12 | uint8(Rerror), 13 | byte(t), byte(t>>8), 14 | uint8(len(Error)),uint8(len(Error)>>8), 15 | }) 16 | b.Write([]byte(Error)) 17 | 18 | { 19 | l = uint64(b.Len()) 20 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 21 | } 22 | return 23 | } 24 | func UnmarshalRerrorPkt (b *bytes.Buffer) (Error string, t Tag, err error) { 25 | var u [8]uint8 26 | var l uint64 27 | if _, err = b.Read(u[:2]); err != nil { 28 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 29 | return 30 | } 31 | l = uint64(u[0]) | uint64(u[1])<<8 32 | t = Tag(l) 33 | if _, err = b.Read(u[:2]); err != nil { 34 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 35 | return 36 | } 37 | l = uint64(u[0]) 38 | l |= uint64(u[1])<<8 39 | if b.Len() < int(l) { 40 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 41 | return 42 | } 43 | Error = string(b.Bytes()[:l]) 44 | _ = b.Next(int(l)) 45 | 46 | if b.Len() > 0 { 47 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 48 | } 49 | return 50 | } 51 | func MarshalRversionPkt (b *bytes.Buffer, t Tag, RMsize MaxSize, RVersion string) { 52 | var l uint64 53 | b.Reset() 54 | b.Write([]byte{0,0,0,0, 55 | uint8(Rversion), 56 | byte(t), byte(t>>8), 57 | uint8(RMsize>>0), 58 | uint8(RMsize>>8), 59 | uint8(RMsize>>16), 60 | uint8(RMsize>>24), 61 | uint8(len(RVersion)),uint8(len(RVersion)>>8), 62 | }) 63 | b.Write([]byte(RVersion)) 64 | 65 | { 66 | l = uint64(b.Len()) 67 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 68 | } 69 | return 70 | } 71 | func UnmarshalRversionPkt (b *bytes.Buffer) (RMsize MaxSize, RVersion string, t Tag, err error) { 72 | var u [8]uint8 73 | var l uint64 74 | if _, err = b.Read(u[:2]); err != nil { 75 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 76 | return 77 | } 78 | l = uint64(u[0]) | uint64(u[1])<<8 79 | t = Tag(l) 80 | if _, err = b.Read(u[:4]); err != nil { 81 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 82 | return 83 | } 84 | RMsize = MaxSize(u[0]) 85 | RMsize |= MaxSize(u[1])<<8 86 | RMsize |= MaxSize(u[2])<<16 87 | RMsize |= MaxSize(u[3])<<24 88 | if _, err = b.Read(u[:2]); err != nil { 89 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 90 | return 91 | } 92 | l = uint64(u[0]) 93 | l |= uint64(u[1])<<8 94 | if b.Len() < int(l) { 95 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 96 | return 97 | } 98 | RVersion = string(b.Bytes()[:l]) 99 | _ = b.Next(int(l)) 100 | 101 | if b.Len() > 0 { 102 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 103 | } 104 | return 105 | } 106 | func MarshalTversionPkt (b *bytes.Buffer, t Tag, TMsize MaxSize, TVersion string) { 107 | var l uint64 108 | b.Reset() 109 | b.Write([]byte{0,0,0,0, 110 | uint8(Tversion), 111 | byte(t), byte(t>>8), 112 | uint8(TMsize>>0), 113 | uint8(TMsize>>8), 114 | uint8(TMsize>>16), 115 | uint8(TMsize>>24), 116 | uint8(len(TVersion)),uint8(len(TVersion)>>8), 117 | }) 118 | b.Write([]byte(TVersion)) 119 | 120 | { 121 | l = uint64(b.Len()) 122 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 123 | } 124 | return 125 | } 126 | func UnmarshalTversionPkt (b *bytes.Buffer) (TMsize MaxSize, TVersion string, t Tag, err error) { 127 | var u [8]uint8 128 | var l uint64 129 | if _, err = b.Read(u[:2]); err != nil { 130 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 131 | return 132 | } 133 | l = uint64(u[0]) | uint64(u[1])<<8 134 | t = Tag(l) 135 | if _, err = b.Read(u[:4]); err != nil { 136 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 137 | return 138 | } 139 | TMsize = MaxSize(u[0]) 140 | TMsize |= MaxSize(u[1])<<8 141 | TMsize |= MaxSize(u[2])<<16 142 | TMsize |= MaxSize(u[3])<<24 143 | if _, err = b.Read(u[:2]); err != nil { 144 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 145 | return 146 | } 147 | l = uint64(u[0]) 148 | l |= uint64(u[1])<<8 149 | if b.Len() < int(l) { 150 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 151 | return 152 | } 153 | TVersion = string(b.Bytes()[:l]) 154 | _ = b.Next(int(l)) 155 | 156 | if b.Len() > 0 { 157 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 158 | } 159 | return 160 | } 161 | func (s *Server) SrvRversion(b*bytes.Buffer) (err error) { 162 | TMsize, TVersion, t, err := UnmarshalTversionPkt(b) 163 | //if err != nil { 164 | //} 165 | if RMsize, RVersion, err := s.NS.Rversion(TMsize, TVersion); err != nil { 166 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 167 | } else { 168 | MarshalRversionPkt(b, t, RMsize, RVersion) 169 | } 170 | return nil 171 | } 172 | 173 | func (c *Client)CallTversion (TMsize MaxSize, TVersion string) (RMsize MaxSize, RVersion string, err error) { 174 | var b = bytes.Buffer{} 175 | if c.Trace != nil {c.Trace("%v", Tversion)} 176 | t := Tag(0) 177 | r := make (chan []byte) 178 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 179 | MarshalTversionPkt(&b, t, TMsize, TVersion) 180 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 181 | bb := <-r 182 | if MType(bb[4]) == Rerror { 183 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 184 | if err != nil { 185 | return RMsize, RVersion, err 186 | } 187 | return RMsize, RVersion, fmt.Errorf("%v", s) 188 | } else { 189 | RMsize, RVersion, _, err = UnmarshalRversionPkt(bytes.NewBuffer(bb[5:])) 190 | } 191 | return RMsize, RVersion, err 192 | } 193 | func MarshalRattachPkt (b *bytes.Buffer, t Tag, QID QID) { 194 | var l uint64 195 | b.Reset() 196 | b.Write([]byte{0,0,0,0, 197 | uint8(Rattach), 198 | byte(t), byte(t>>8), 199 | uint8(QID.Type>>0), 200 | uint8(QID.Version>>0), 201 | uint8(QID.Version>>8), 202 | uint8(QID.Version>>16), 203 | uint8(QID.Version>>24), 204 | uint8(QID.Path>>0), 205 | uint8(QID.Path>>8), 206 | uint8(QID.Path>>16), 207 | uint8(QID.Path>>24), 208 | uint8(QID.Path>>32), 209 | uint8(QID.Path>>40), 210 | uint8(QID.Path>>48), 211 | uint8(QID.Path>>56), 212 | }) 213 | 214 | { 215 | l = uint64(b.Len()) 216 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 217 | } 218 | return 219 | } 220 | func UnmarshalRattachPkt (b *bytes.Buffer) (QID QID, t Tag, err error) { 221 | var u [8]uint8 222 | var l uint64 223 | if _, err = b.Read(u[:2]); err != nil { 224 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 225 | return 226 | } 227 | l = uint64(u[0]) | uint64(u[1])<<8 228 | t = Tag(l) 229 | if _, err = b.Read(u[:1]); err != nil { 230 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 231 | return 232 | } 233 | QID.Type = uint8(u[0]) 234 | if _, err = b.Read(u[:4]); err != nil { 235 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 236 | return 237 | } 238 | QID.Version = uint32(u[0]) 239 | QID.Version |= uint32(u[1])<<8 240 | QID.Version |= uint32(u[2])<<16 241 | QID.Version |= uint32(u[3])<<24 242 | if _, err = b.Read(u[:8]); err != nil { 243 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 244 | return 245 | } 246 | QID.Path = uint64(u[0]) 247 | QID.Path |= uint64(u[1])<<8 248 | QID.Path |= uint64(u[2])<<16 249 | QID.Path |= uint64(u[3])<<24 250 | QID.Path |= uint64(u[4])<<32 251 | QID.Path |= uint64(u[5])<<40 252 | QID.Path |= uint64(u[6])<<48 253 | QID.Path |= uint64(u[7])<<56 254 | 255 | if b.Len() > 0 { 256 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 257 | } 258 | return 259 | } 260 | func MarshalTattachPkt (b *bytes.Buffer, t Tag, SFID FID, AFID FID, Uname string, Aname string) { 261 | var l uint64 262 | b.Reset() 263 | b.Write([]byte{0,0,0,0, 264 | uint8(Tattach), 265 | byte(t), byte(t>>8), 266 | uint8(SFID>>0), 267 | uint8(SFID>>8), 268 | uint8(SFID>>16), 269 | uint8(SFID>>24), 270 | uint8(AFID>>0), 271 | uint8(AFID>>8), 272 | uint8(AFID>>16), 273 | uint8(AFID>>24), 274 | uint8(len(Uname)),uint8(len(Uname)>>8), 275 | }) 276 | b.Write([]byte(Uname)) 277 | b.Write([]byte{ uint8(len(Aname)),uint8(len(Aname)>>8), 278 | }) 279 | b.Write([]byte(Aname)) 280 | 281 | { 282 | l = uint64(b.Len()) 283 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 284 | } 285 | return 286 | } 287 | func UnmarshalTattachPkt (b *bytes.Buffer) (SFID FID, AFID FID, Uname string, Aname string, t Tag, err error) { 288 | var u [8]uint8 289 | var l uint64 290 | if _, err = b.Read(u[:2]); err != nil { 291 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 292 | return 293 | } 294 | l = uint64(u[0]) | uint64(u[1])<<8 295 | t = Tag(l) 296 | if _, err = b.Read(u[:4]); err != nil { 297 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 298 | return 299 | } 300 | SFID = FID(u[0]) 301 | SFID |= FID(u[1])<<8 302 | SFID |= FID(u[2])<<16 303 | SFID |= FID(u[3])<<24 304 | if _, err = b.Read(u[:4]); err != nil { 305 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 306 | return 307 | } 308 | AFID = FID(u[0]) 309 | AFID |= FID(u[1])<<8 310 | AFID |= FID(u[2])<<16 311 | AFID |= FID(u[3])<<24 312 | if _, err = b.Read(u[:2]); err != nil { 313 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 314 | return 315 | } 316 | l = uint64(u[0]) 317 | l |= uint64(u[1])<<8 318 | if b.Len() < int(l) { 319 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 320 | return 321 | } 322 | Uname = string(b.Bytes()[:l]) 323 | _ = b.Next(int(l)) 324 | if _, err = b.Read(u[:2]); err != nil { 325 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 326 | return 327 | } 328 | l = uint64(u[0]) 329 | l |= uint64(u[1])<<8 330 | if b.Len() < int(l) { 331 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 332 | return 333 | } 334 | Aname = string(b.Bytes()[:l]) 335 | _ = b.Next(int(l)) 336 | 337 | if b.Len() > 0 { 338 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 339 | } 340 | return 341 | } 342 | func (s *Server) SrvRattach(b*bytes.Buffer) (err error) { 343 | SFID, AFID, Uname, Aname, t, err := UnmarshalTattachPkt(b) 344 | //if err != nil { 345 | //} 346 | if QID, err := s.NS.Rattach(SFID, AFID, Uname, Aname); err != nil { 347 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 348 | } else { 349 | MarshalRattachPkt(b, t, QID) 350 | } 351 | return nil 352 | } 353 | 354 | func (c *Client)CallTattach (SFID FID, AFID FID, Uname string, Aname string) (QID QID, err error) { 355 | var b = bytes.Buffer{} 356 | if c.Trace != nil {c.Trace("%v", Tattach)} 357 | t := Tag(0) 358 | r := make (chan []byte) 359 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 360 | MarshalTattachPkt(&b, t, SFID, AFID, Uname, Aname) 361 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 362 | bb := <-r 363 | if MType(bb[4]) == Rerror { 364 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 365 | if err != nil { 366 | return QID, err 367 | } 368 | return QID, fmt.Errorf("%v", s) 369 | } else { 370 | QID, _, err = UnmarshalRattachPkt(bytes.NewBuffer(bb[5:])) 371 | } 372 | return QID, err 373 | } 374 | func MarshalRflushPkt (b *bytes.Buffer, t Tag, ) { 375 | var l uint64 376 | b.Reset() 377 | b.Write([]byte{0,0,0,0, 378 | uint8(Rflush), 379 | byte(t), byte(t>>8), 380 | }) 381 | 382 | { 383 | l = uint64(b.Len()) 384 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 385 | } 386 | return 387 | } 388 | func UnmarshalRflushPkt (b *bytes.Buffer) ( t Tag, err error) { 389 | var u [8]uint8 390 | var l uint64 391 | if _, err = b.Read(u[:2]); err != nil { 392 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 393 | return 394 | } 395 | l = uint64(u[0]) | uint64(u[1])<<8 396 | t = Tag(l) 397 | 398 | if b.Len() > 0 { 399 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 400 | } 401 | return 402 | } 403 | func MarshalTflushPkt (b *bytes.Buffer, t Tag, OTag Tag) { 404 | var l uint64 405 | b.Reset() 406 | b.Write([]byte{0,0,0,0, 407 | uint8(Tflush), 408 | byte(t), byte(t>>8), 409 | uint8(OTag>>0), 410 | uint8(OTag>>8), 411 | }) 412 | 413 | { 414 | l = uint64(b.Len()) 415 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 416 | } 417 | return 418 | } 419 | func UnmarshalTflushPkt (b *bytes.Buffer) (OTag Tag, t Tag, err error) { 420 | var u [8]uint8 421 | var l uint64 422 | if _, err = b.Read(u[:2]); err != nil { 423 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 424 | return 425 | } 426 | l = uint64(u[0]) | uint64(u[1])<<8 427 | t = Tag(l) 428 | if _, err = b.Read(u[:2]); err != nil { 429 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 430 | return 431 | } 432 | OTag = Tag(u[0]) 433 | OTag |= Tag(u[1])<<8 434 | 435 | if b.Len() > 0 { 436 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 437 | } 438 | return 439 | } 440 | func (s *Server) SrvRflush(b*bytes.Buffer) (err error) { 441 | OTag, t, err := UnmarshalTflushPkt(b) 442 | //if err != nil { 443 | //} 444 | if err := s.NS.Rflush(OTag); err != nil { 445 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 446 | } else { 447 | MarshalRflushPkt(b, t, ) 448 | } 449 | return nil 450 | } 451 | 452 | func (c *Client)CallTflush (OTag Tag) ( err error) { 453 | var b = bytes.Buffer{} 454 | if c.Trace != nil {c.Trace("%v", Tflush)} 455 | t := Tag(0) 456 | r := make (chan []byte) 457 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 458 | MarshalTflushPkt(&b, t, OTag) 459 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 460 | bb := <-r 461 | if MType(bb[4]) == Rerror { 462 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 463 | if err != nil { 464 | return err 465 | } 466 | return fmt.Errorf("%v", s) 467 | } else { 468 | _, err = UnmarshalRflushPkt(bytes.NewBuffer(bb[5:])) 469 | } 470 | return err 471 | } 472 | func MarshalRwalkPkt (b *bytes.Buffer, t Tag, QIDs []QID) { 473 | var l uint64 474 | b.Reset() 475 | b.Write([]byte{0,0,0,0, 476 | uint8(Rwalk), 477 | byte(t), byte(t>>8), 478 | uint8(len(QIDs)>>0), 479 | uint8(len(QIDs)>>8), 480 | }) 481 | for i := range QIDs { 482 | b.Write([]byte{ uint8(QIDs[i].Type>>0), 483 | uint8(QIDs[i].Version>>0), 484 | uint8(QIDs[i].Version>>8), 485 | uint8(QIDs[i].Version>>16), 486 | uint8(QIDs[i].Version>>24), 487 | uint8(QIDs[i].Path>>0), 488 | uint8(QIDs[i].Path>>8), 489 | uint8(QIDs[i].Path>>16), 490 | uint8(QIDs[i].Path>>24), 491 | uint8(QIDs[i].Path>>32), 492 | uint8(QIDs[i].Path>>40), 493 | uint8(QIDs[i].Path>>48), 494 | uint8(QIDs[i].Path>>56), 495 | }) 496 | } 497 | 498 | { 499 | l = uint64(b.Len()) 500 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 501 | } 502 | return 503 | } 504 | func UnmarshalRwalkPkt (b *bytes.Buffer) (QIDs []QID, t Tag, err error) { 505 | var u [8]uint8 506 | var l uint64 507 | if _, err = b.Read(u[:2]); err != nil { 508 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 509 | return 510 | } 511 | l = uint64(u[0]) | uint64(u[1])<<8 512 | t = Tag(l) 513 | if _, err = b.Read(u[:2]); err != nil { 514 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 515 | return 516 | } 517 | l = uint64(u[0]) 518 | l |= uint64(u[1])<<8 519 | QIDs = make([]QID, l) 520 | for i := range QIDs { 521 | if _, err = b.Read(u[:1]); err != nil { 522 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 523 | return 524 | } 525 | QIDs[i].Type = uint8(u[0]) 526 | if _, err = b.Read(u[:4]); err != nil { 527 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 528 | return 529 | } 530 | QIDs[i].Version = uint32(u[0]) 531 | QIDs[i].Version |= uint32(u[1])<<8 532 | QIDs[i].Version |= uint32(u[2])<<16 533 | QIDs[i].Version |= uint32(u[3])<<24 534 | if _, err = b.Read(u[:8]); err != nil { 535 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 536 | return 537 | } 538 | QIDs[i].Path = uint64(u[0]) 539 | QIDs[i].Path |= uint64(u[1])<<8 540 | QIDs[i].Path |= uint64(u[2])<<16 541 | QIDs[i].Path |= uint64(u[3])<<24 542 | QIDs[i].Path |= uint64(u[4])<<32 543 | QIDs[i].Path |= uint64(u[5])<<40 544 | QIDs[i].Path |= uint64(u[6])<<48 545 | QIDs[i].Path |= uint64(u[7])<<56 546 | } 547 | 548 | if b.Len() > 0 { 549 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 550 | } 551 | return 552 | } 553 | func MarshalTwalkPkt (b *bytes.Buffer, t Tag, SFID FID, NewFID FID, Paths []string) { 554 | var l uint64 555 | b.Reset() 556 | b.Write([]byte{0,0,0,0, 557 | uint8(Twalk), 558 | byte(t), byte(t>>8), 559 | uint8(SFID>>0), 560 | uint8(SFID>>8), 561 | uint8(SFID>>16), 562 | uint8(SFID>>24), 563 | uint8(NewFID>>0), 564 | uint8(NewFID>>8), 565 | uint8(NewFID>>16), 566 | uint8(NewFID>>24), 567 | uint8(len(Paths)>>0), 568 | uint8(len(Paths)>>8), 569 | }) 570 | for i := range Paths { 571 | b.Write([]byte{ uint8(len(Paths[i])),uint8(len(Paths[i])>>8), 572 | }) 573 | b.Write([]byte(Paths[i])) 574 | } 575 | 576 | { 577 | l = uint64(b.Len()) 578 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 579 | } 580 | return 581 | } 582 | func UnmarshalTwalkPkt (b *bytes.Buffer) (SFID FID, NewFID FID, Paths []string, t Tag, err error) { 583 | var u [8]uint8 584 | var l uint64 585 | if _, err = b.Read(u[:2]); err != nil { 586 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 587 | return 588 | } 589 | l = uint64(u[0]) | uint64(u[1])<<8 590 | t = Tag(l) 591 | if _, err = b.Read(u[:4]); err != nil { 592 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 593 | return 594 | } 595 | SFID = FID(u[0]) 596 | SFID |= FID(u[1])<<8 597 | SFID |= FID(u[2])<<16 598 | SFID |= FID(u[3])<<24 599 | if _, err = b.Read(u[:4]); err != nil { 600 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 601 | return 602 | } 603 | NewFID = FID(u[0]) 604 | NewFID |= FID(u[1])<<8 605 | NewFID |= FID(u[2])<<16 606 | NewFID |= FID(u[3])<<24 607 | if _, err = b.Read(u[:2]); err != nil { 608 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 609 | return 610 | } 611 | l = uint64(u[0]) 612 | l |= uint64(u[1])<<8 613 | Paths = make([]string, l) 614 | for i := range Paths { 615 | if _, err = b.Read(u[:2]); err != nil { 616 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 617 | return 618 | } 619 | l = uint64(u[0]) 620 | l |= uint64(u[1])<<8 621 | if b.Len() < int(l) { 622 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 623 | return 624 | } 625 | Paths[i] = string(b.Bytes()[:l]) 626 | _ = b.Next(int(l)) 627 | } 628 | 629 | if b.Len() > 0 { 630 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 631 | } 632 | return 633 | } 634 | func (s *Server) SrvRwalk(b*bytes.Buffer) (err error) { 635 | SFID, NewFID, Paths, t, err := UnmarshalTwalkPkt(b) 636 | //if err != nil { 637 | //} 638 | if QIDs, err := s.NS.Rwalk(SFID, NewFID, Paths); err != nil { 639 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 640 | } else { 641 | MarshalRwalkPkt(b, t, QIDs) 642 | } 643 | return nil 644 | } 645 | 646 | func (c *Client)CallTwalk (SFID FID, NewFID FID, Paths []string) (QIDs []QID, err error) { 647 | var b = bytes.Buffer{} 648 | if c.Trace != nil {c.Trace("%v", Twalk)} 649 | t := Tag(0) 650 | r := make (chan []byte) 651 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 652 | MarshalTwalkPkt(&b, t, SFID, NewFID, Paths) 653 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 654 | bb := <-r 655 | if MType(bb[4]) == Rerror { 656 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 657 | if err != nil { 658 | return QIDs, err 659 | } 660 | return QIDs, fmt.Errorf("%v", s) 661 | } else { 662 | QIDs, _, err = UnmarshalRwalkPkt(bytes.NewBuffer(bb[5:])) 663 | } 664 | return QIDs, err 665 | } 666 | func MarshalRopenPkt (b *bytes.Buffer, t Tag, OQID QID, IOUnit MaxSize) { 667 | var l uint64 668 | b.Reset() 669 | b.Write([]byte{0,0,0,0, 670 | uint8(Ropen), 671 | byte(t), byte(t>>8), 672 | uint8(OQID.Type>>0), 673 | uint8(OQID.Version>>0), 674 | uint8(OQID.Version>>8), 675 | uint8(OQID.Version>>16), 676 | uint8(OQID.Version>>24), 677 | uint8(OQID.Path>>0), 678 | uint8(OQID.Path>>8), 679 | uint8(OQID.Path>>16), 680 | uint8(OQID.Path>>24), 681 | uint8(OQID.Path>>32), 682 | uint8(OQID.Path>>40), 683 | uint8(OQID.Path>>48), 684 | uint8(OQID.Path>>56), 685 | uint8(IOUnit>>0), 686 | uint8(IOUnit>>8), 687 | uint8(IOUnit>>16), 688 | uint8(IOUnit>>24), 689 | }) 690 | 691 | { 692 | l = uint64(b.Len()) 693 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 694 | } 695 | return 696 | } 697 | func UnmarshalRopenPkt (b *bytes.Buffer) (OQID QID, IOUnit MaxSize, t Tag, err error) { 698 | var u [8]uint8 699 | var l uint64 700 | if _, err = b.Read(u[:2]); err != nil { 701 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 702 | return 703 | } 704 | l = uint64(u[0]) | uint64(u[1])<<8 705 | t = Tag(l) 706 | if _, err = b.Read(u[:1]); err != nil { 707 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 708 | return 709 | } 710 | OQID.Type = uint8(u[0]) 711 | if _, err = b.Read(u[:4]); err != nil { 712 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 713 | return 714 | } 715 | OQID.Version = uint32(u[0]) 716 | OQID.Version |= uint32(u[1])<<8 717 | OQID.Version |= uint32(u[2])<<16 718 | OQID.Version |= uint32(u[3])<<24 719 | if _, err = b.Read(u[:8]); err != nil { 720 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 721 | return 722 | } 723 | OQID.Path = uint64(u[0]) 724 | OQID.Path |= uint64(u[1])<<8 725 | OQID.Path |= uint64(u[2])<<16 726 | OQID.Path |= uint64(u[3])<<24 727 | OQID.Path |= uint64(u[4])<<32 728 | OQID.Path |= uint64(u[5])<<40 729 | OQID.Path |= uint64(u[6])<<48 730 | OQID.Path |= uint64(u[7])<<56 731 | if _, err = b.Read(u[:4]); err != nil { 732 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 733 | return 734 | } 735 | IOUnit = MaxSize(u[0]) 736 | IOUnit |= MaxSize(u[1])<<8 737 | IOUnit |= MaxSize(u[2])<<16 738 | IOUnit |= MaxSize(u[3])<<24 739 | 740 | if b.Len() > 0 { 741 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 742 | } 743 | return 744 | } 745 | func MarshalTopenPkt (b *bytes.Buffer, t Tag, OFID FID, Omode Mode) { 746 | var l uint64 747 | b.Reset() 748 | b.Write([]byte{0,0,0,0, 749 | uint8(Topen), 750 | byte(t), byte(t>>8), 751 | uint8(OFID>>0), 752 | uint8(OFID>>8), 753 | uint8(OFID>>16), 754 | uint8(OFID>>24), 755 | uint8(Omode>>0), 756 | }) 757 | 758 | { 759 | l = uint64(b.Len()) 760 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 761 | } 762 | return 763 | } 764 | func UnmarshalTopenPkt (b *bytes.Buffer) (OFID FID, Omode Mode, t Tag, err error) { 765 | var u [8]uint8 766 | var l uint64 767 | if _, err = b.Read(u[:2]); err != nil { 768 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 769 | return 770 | } 771 | l = uint64(u[0]) | uint64(u[1])<<8 772 | t = Tag(l) 773 | if _, err = b.Read(u[:4]); err != nil { 774 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 775 | return 776 | } 777 | OFID = FID(u[0]) 778 | OFID |= FID(u[1])<<8 779 | OFID |= FID(u[2])<<16 780 | OFID |= FID(u[3])<<24 781 | if _, err = b.Read(u[:1]); err != nil { 782 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 783 | return 784 | } 785 | Omode = Mode(u[0]) 786 | 787 | if b.Len() > 0 { 788 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 789 | } 790 | return 791 | } 792 | func (s *Server) SrvRopen(b*bytes.Buffer) (err error) { 793 | OFID, Omode, t, err := UnmarshalTopenPkt(b) 794 | //if err != nil { 795 | //} 796 | if OQID, IOUnit, err := s.NS.Ropen(OFID, Omode); err != nil { 797 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 798 | } else { 799 | MarshalRopenPkt(b, t, OQID, IOUnit) 800 | } 801 | return nil 802 | } 803 | 804 | func (c *Client)CallTopen (OFID FID, Omode Mode) (OQID QID, IOUnit MaxSize, err error) { 805 | var b = bytes.Buffer{} 806 | if c.Trace != nil {c.Trace("%v", Topen)} 807 | t := Tag(0) 808 | r := make (chan []byte) 809 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 810 | MarshalTopenPkt(&b, t, OFID, Omode) 811 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 812 | bb := <-r 813 | if MType(bb[4]) == Rerror { 814 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 815 | if err != nil { 816 | return OQID, IOUnit, err 817 | } 818 | return OQID, IOUnit, fmt.Errorf("%v", s) 819 | } else { 820 | OQID, IOUnit, _, err = UnmarshalRopenPkt(bytes.NewBuffer(bb[5:])) 821 | } 822 | return OQID, IOUnit, err 823 | } 824 | func MarshalRcreatePkt (b *bytes.Buffer, t Tag, OQID QID, IOUnit MaxSize) { 825 | var l uint64 826 | b.Reset() 827 | b.Write([]byte{0,0,0,0, 828 | uint8(Rcreate), 829 | byte(t), byte(t>>8), 830 | uint8(OQID.Type>>0), 831 | uint8(OQID.Version>>0), 832 | uint8(OQID.Version>>8), 833 | uint8(OQID.Version>>16), 834 | uint8(OQID.Version>>24), 835 | uint8(OQID.Path>>0), 836 | uint8(OQID.Path>>8), 837 | uint8(OQID.Path>>16), 838 | uint8(OQID.Path>>24), 839 | uint8(OQID.Path>>32), 840 | uint8(OQID.Path>>40), 841 | uint8(OQID.Path>>48), 842 | uint8(OQID.Path>>56), 843 | uint8(IOUnit>>0), 844 | uint8(IOUnit>>8), 845 | uint8(IOUnit>>16), 846 | uint8(IOUnit>>24), 847 | }) 848 | 849 | { 850 | l = uint64(b.Len()) 851 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 852 | } 853 | return 854 | } 855 | func UnmarshalRcreatePkt (b *bytes.Buffer) (OQID QID, IOUnit MaxSize, t Tag, err error) { 856 | var u [8]uint8 857 | var l uint64 858 | if _, err = b.Read(u[:2]); err != nil { 859 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 860 | return 861 | } 862 | l = uint64(u[0]) | uint64(u[1])<<8 863 | t = Tag(l) 864 | if _, err = b.Read(u[:1]); err != nil { 865 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 866 | return 867 | } 868 | OQID.Type = uint8(u[0]) 869 | if _, err = b.Read(u[:4]); err != nil { 870 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 871 | return 872 | } 873 | OQID.Version = uint32(u[0]) 874 | OQID.Version |= uint32(u[1])<<8 875 | OQID.Version |= uint32(u[2])<<16 876 | OQID.Version |= uint32(u[3])<<24 877 | if _, err = b.Read(u[:8]); err != nil { 878 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 879 | return 880 | } 881 | OQID.Path = uint64(u[0]) 882 | OQID.Path |= uint64(u[1])<<8 883 | OQID.Path |= uint64(u[2])<<16 884 | OQID.Path |= uint64(u[3])<<24 885 | OQID.Path |= uint64(u[4])<<32 886 | OQID.Path |= uint64(u[5])<<40 887 | OQID.Path |= uint64(u[6])<<48 888 | OQID.Path |= uint64(u[7])<<56 889 | if _, err = b.Read(u[:4]); err != nil { 890 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 891 | return 892 | } 893 | IOUnit = MaxSize(u[0]) 894 | IOUnit |= MaxSize(u[1])<<8 895 | IOUnit |= MaxSize(u[2])<<16 896 | IOUnit |= MaxSize(u[3])<<24 897 | 898 | if b.Len() > 0 { 899 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 900 | } 901 | return 902 | } 903 | func MarshalTcreatePkt (b *bytes.Buffer, t Tag, OFID FID, Name string, CreatePerm Perm, Omode Mode) { 904 | var l uint64 905 | b.Reset() 906 | b.Write([]byte{0,0,0,0, 907 | uint8(Tcreate), 908 | byte(t), byte(t>>8), 909 | uint8(OFID>>0), 910 | uint8(OFID>>8), 911 | uint8(OFID>>16), 912 | uint8(OFID>>24), 913 | uint8(len(Name)),uint8(len(Name)>>8), 914 | }) 915 | b.Write([]byte(Name)) 916 | b.Write([]byte{ uint8(CreatePerm>>0), 917 | uint8(CreatePerm>>8), 918 | uint8(CreatePerm>>16), 919 | uint8(CreatePerm>>24), 920 | uint8(Omode>>0), 921 | }) 922 | 923 | { 924 | l = uint64(b.Len()) 925 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 926 | } 927 | return 928 | } 929 | func UnmarshalTcreatePkt (b *bytes.Buffer) (OFID FID, Name string, CreatePerm Perm, Omode Mode, t Tag, err error) { 930 | var u [8]uint8 931 | var l uint64 932 | if _, err = b.Read(u[:2]); err != nil { 933 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 934 | return 935 | } 936 | l = uint64(u[0]) | uint64(u[1])<<8 937 | t = Tag(l) 938 | if _, err = b.Read(u[:4]); err != nil { 939 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 940 | return 941 | } 942 | OFID = FID(u[0]) 943 | OFID |= FID(u[1])<<8 944 | OFID |= FID(u[2])<<16 945 | OFID |= FID(u[3])<<24 946 | if _, err = b.Read(u[:2]); err != nil { 947 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 948 | return 949 | } 950 | l = uint64(u[0]) 951 | l |= uint64(u[1])<<8 952 | if b.Len() < int(l) { 953 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 954 | return 955 | } 956 | Name = string(b.Bytes()[:l]) 957 | _ = b.Next(int(l)) 958 | if _, err = b.Read(u[:4]); err != nil { 959 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 960 | return 961 | } 962 | CreatePerm = Perm(u[0]) 963 | CreatePerm |= Perm(u[1])<<8 964 | CreatePerm |= Perm(u[2])<<16 965 | CreatePerm |= Perm(u[3])<<24 966 | if _, err = b.Read(u[:1]); err != nil { 967 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 968 | return 969 | } 970 | Omode = Mode(u[0]) 971 | 972 | if b.Len() > 0 { 973 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 974 | } 975 | return 976 | } 977 | func (s *Server) SrvRcreate(b*bytes.Buffer) (err error) { 978 | OFID, Name, CreatePerm, Omode, t, err := UnmarshalTcreatePkt(b) 979 | //if err != nil { 980 | //} 981 | if OQID, IOUnit, err := s.NS.Rcreate(OFID, Name, CreatePerm, Omode); err != nil { 982 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 983 | } else { 984 | MarshalRcreatePkt(b, t, OQID, IOUnit) 985 | } 986 | return nil 987 | } 988 | 989 | func (c *Client)CallTcreate (OFID FID, Name string, CreatePerm Perm, Omode Mode) (OQID QID, IOUnit MaxSize, err error) { 990 | var b = bytes.Buffer{} 991 | if c.Trace != nil {c.Trace("%v", Tcreate)} 992 | t := Tag(0) 993 | r := make (chan []byte) 994 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 995 | MarshalTcreatePkt(&b, t, OFID, Name, CreatePerm, Omode) 996 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 997 | bb := <-r 998 | if MType(bb[4]) == Rerror { 999 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1000 | if err != nil { 1001 | return OQID, IOUnit, err 1002 | } 1003 | return OQID, IOUnit, fmt.Errorf("%v", s) 1004 | } else { 1005 | OQID, IOUnit, _, err = UnmarshalRcreatePkt(bytes.NewBuffer(bb[5:])) 1006 | } 1007 | return OQID, IOUnit, err 1008 | } 1009 | func MarshalRstatPkt (b *bytes.Buffer, t Tag, B []byte) { 1010 | var l uint64 1011 | b.Reset() 1012 | b.Write([]byte{0,0,0,0, 1013 | uint8(Rstat), 1014 | byte(t), byte(t>>8), 1015 | uint8(len(B)>>0), 1016 | uint8(len(B)>>8), 1017 | }) 1018 | b.Write(B) 1019 | 1020 | { 1021 | l = uint64(b.Len()) 1022 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1023 | } 1024 | return 1025 | } 1026 | func UnmarshalRstatPkt (b *bytes.Buffer) (B []byte, t Tag, err error) { 1027 | var u [8]uint8 1028 | var l uint64 1029 | if _, err = b.Read(u[:2]); err != nil { 1030 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1031 | return 1032 | } 1033 | l = uint64(u[0]) | uint64(u[1])<<8 1034 | t = Tag(l) 1035 | if _, err = b.Read(u[:2]); err != nil { 1036 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1037 | return 1038 | } 1039 | l = uint64(u[0]) 1040 | l |= uint64(u[1])<<8 1041 | B = b.Bytes()[:l] 1042 | _ = b.Next(int(l)) 1043 | 1044 | if b.Len() > 0 { 1045 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1046 | } 1047 | return 1048 | } 1049 | func MarshalTstatPkt (b *bytes.Buffer, t Tag, OFID FID) { 1050 | var l uint64 1051 | b.Reset() 1052 | b.Write([]byte{0,0,0,0, 1053 | uint8(Tstat), 1054 | byte(t), byte(t>>8), 1055 | uint8(OFID>>0), 1056 | uint8(OFID>>8), 1057 | uint8(OFID>>16), 1058 | uint8(OFID>>24), 1059 | }) 1060 | 1061 | { 1062 | l = uint64(b.Len()) 1063 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1064 | } 1065 | return 1066 | } 1067 | func UnmarshalTstatPkt (b *bytes.Buffer) (OFID FID, t Tag, err error) { 1068 | var u [8]uint8 1069 | var l uint64 1070 | if _, err = b.Read(u[:2]); err != nil { 1071 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1072 | return 1073 | } 1074 | l = uint64(u[0]) | uint64(u[1])<<8 1075 | t = Tag(l) 1076 | if _, err = b.Read(u[:4]); err != nil { 1077 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1078 | return 1079 | } 1080 | OFID = FID(u[0]) 1081 | OFID |= FID(u[1])<<8 1082 | OFID |= FID(u[2])<<16 1083 | OFID |= FID(u[3])<<24 1084 | 1085 | if b.Len() > 0 { 1086 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1087 | } 1088 | return 1089 | } 1090 | func (s *Server) SrvRstat(b*bytes.Buffer) (err error) { 1091 | OFID, t, err := UnmarshalTstatPkt(b) 1092 | //if err != nil { 1093 | //} 1094 | if B, err := s.NS.Rstat(OFID); err != nil { 1095 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 1096 | } else { 1097 | MarshalRstatPkt(b, t, B) 1098 | } 1099 | return nil 1100 | } 1101 | 1102 | func (c *Client)CallTstat (OFID FID) (B []byte, err error) { 1103 | var b = bytes.Buffer{} 1104 | if c.Trace != nil {c.Trace("%v", Tstat)} 1105 | t := Tag(0) 1106 | r := make (chan []byte) 1107 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 1108 | MarshalTstatPkt(&b, t, OFID) 1109 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 1110 | bb := <-r 1111 | if MType(bb[4]) == Rerror { 1112 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1113 | if err != nil { 1114 | return B, err 1115 | } 1116 | return B, fmt.Errorf("%v", s) 1117 | } else { 1118 | B, _, err = UnmarshalRstatPkt(bytes.NewBuffer(bb[5:])) 1119 | } 1120 | return B, err 1121 | } 1122 | func MarshalRwstatPkt (b *bytes.Buffer, t Tag, ) { 1123 | var l uint64 1124 | b.Reset() 1125 | b.Write([]byte{0,0,0,0, 1126 | uint8(Rwstat), 1127 | byte(t), byte(t>>8), 1128 | }) 1129 | 1130 | { 1131 | l = uint64(b.Len()) 1132 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1133 | } 1134 | return 1135 | } 1136 | func UnmarshalRwstatPkt (b *bytes.Buffer) ( t Tag, err error) { 1137 | var u [8]uint8 1138 | var l uint64 1139 | if _, err = b.Read(u[:2]); err != nil { 1140 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1141 | return 1142 | } 1143 | l = uint64(u[0]) | uint64(u[1])<<8 1144 | t = Tag(l) 1145 | 1146 | if b.Len() > 0 { 1147 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1148 | } 1149 | return 1150 | } 1151 | func MarshalTwstatPkt (b *bytes.Buffer, t Tag, OFID FID, B []byte) { 1152 | var l uint64 1153 | b.Reset() 1154 | b.Write([]byte{0,0,0,0, 1155 | uint8(Twstat), 1156 | byte(t), byte(t>>8), 1157 | uint8(OFID>>0), 1158 | uint8(OFID>>8), 1159 | uint8(OFID>>16), 1160 | uint8(OFID>>24), 1161 | uint8(len(B)>>0), 1162 | uint8(len(B)>>8), 1163 | }) 1164 | b.Write(B) 1165 | 1166 | { 1167 | l = uint64(b.Len()) 1168 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1169 | } 1170 | return 1171 | } 1172 | func UnmarshalTwstatPkt (b *bytes.Buffer) (OFID FID, B []byte, t Tag, err error) { 1173 | var u [8]uint8 1174 | var l uint64 1175 | if _, err = b.Read(u[:2]); err != nil { 1176 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1177 | return 1178 | } 1179 | l = uint64(u[0]) | uint64(u[1])<<8 1180 | t = Tag(l) 1181 | if _, err = b.Read(u[:4]); err != nil { 1182 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1183 | return 1184 | } 1185 | OFID = FID(u[0]) 1186 | OFID |= FID(u[1])<<8 1187 | OFID |= FID(u[2])<<16 1188 | OFID |= FID(u[3])<<24 1189 | if _, err = b.Read(u[:2]); err != nil { 1190 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1191 | return 1192 | } 1193 | l = uint64(u[0]) 1194 | l |= uint64(u[1])<<8 1195 | B = b.Bytes()[:l] 1196 | _ = b.Next(int(l)) 1197 | 1198 | if b.Len() > 0 { 1199 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1200 | } 1201 | return 1202 | } 1203 | func (s *Server) SrvRwstat(b*bytes.Buffer) (err error) { 1204 | OFID, B, t, err := UnmarshalTwstatPkt(b) 1205 | //if err != nil { 1206 | //} 1207 | if err := s.NS.Rwstat(OFID, B); err != nil { 1208 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 1209 | } else { 1210 | MarshalRwstatPkt(b, t, ) 1211 | } 1212 | return nil 1213 | } 1214 | 1215 | func (c *Client)CallTwstat (OFID FID, B []byte) ( err error) { 1216 | var b = bytes.Buffer{} 1217 | if c.Trace != nil {c.Trace("%v", Twstat)} 1218 | t := Tag(0) 1219 | r := make (chan []byte) 1220 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 1221 | MarshalTwstatPkt(&b, t, OFID, B) 1222 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 1223 | bb := <-r 1224 | if MType(bb[4]) == Rerror { 1225 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1226 | if err != nil { 1227 | return err 1228 | } 1229 | return fmt.Errorf("%v", s) 1230 | } else { 1231 | _, err = UnmarshalRwstatPkt(bytes.NewBuffer(bb[5:])) 1232 | } 1233 | return err 1234 | } 1235 | func MarshalRclunkPkt (b *bytes.Buffer, t Tag, ) { 1236 | var l uint64 1237 | b.Reset() 1238 | b.Write([]byte{0,0,0,0, 1239 | uint8(Rclunk), 1240 | byte(t), byte(t>>8), 1241 | }) 1242 | 1243 | { 1244 | l = uint64(b.Len()) 1245 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1246 | } 1247 | return 1248 | } 1249 | func UnmarshalRclunkPkt (b *bytes.Buffer) ( t Tag, err error) { 1250 | var u [8]uint8 1251 | var l uint64 1252 | if _, err = b.Read(u[:2]); err != nil { 1253 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1254 | return 1255 | } 1256 | l = uint64(u[0]) | uint64(u[1])<<8 1257 | t = Tag(l) 1258 | 1259 | if b.Len() > 0 { 1260 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1261 | } 1262 | return 1263 | } 1264 | func MarshalTclunkPkt (b *bytes.Buffer, t Tag, OFID FID) { 1265 | var l uint64 1266 | b.Reset() 1267 | b.Write([]byte{0,0,0,0, 1268 | uint8(Tclunk), 1269 | byte(t), byte(t>>8), 1270 | uint8(OFID>>0), 1271 | uint8(OFID>>8), 1272 | uint8(OFID>>16), 1273 | uint8(OFID>>24), 1274 | }) 1275 | 1276 | { 1277 | l = uint64(b.Len()) 1278 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1279 | } 1280 | return 1281 | } 1282 | func UnmarshalTclunkPkt (b *bytes.Buffer) (OFID FID, t Tag, err error) { 1283 | var u [8]uint8 1284 | var l uint64 1285 | if _, err = b.Read(u[:2]); err != nil { 1286 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1287 | return 1288 | } 1289 | l = uint64(u[0]) | uint64(u[1])<<8 1290 | t = Tag(l) 1291 | if _, err = b.Read(u[:4]); err != nil { 1292 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1293 | return 1294 | } 1295 | OFID = FID(u[0]) 1296 | OFID |= FID(u[1])<<8 1297 | OFID |= FID(u[2])<<16 1298 | OFID |= FID(u[3])<<24 1299 | 1300 | if b.Len() > 0 { 1301 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1302 | } 1303 | return 1304 | } 1305 | func (s *Server) SrvRclunk(b*bytes.Buffer) (err error) { 1306 | OFID, t, err := UnmarshalTclunkPkt(b) 1307 | //if err != nil { 1308 | //} 1309 | if err := s.NS.Rclunk(OFID); err != nil { 1310 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 1311 | } else { 1312 | MarshalRclunkPkt(b, t, ) 1313 | } 1314 | return nil 1315 | } 1316 | 1317 | func (c *Client)CallTclunk (OFID FID) ( err error) { 1318 | var b = bytes.Buffer{} 1319 | if c.Trace != nil {c.Trace("%v", Tclunk)} 1320 | t := Tag(0) 1321 | r := make (chan []byte) 1322 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 1323 | MarshalTclunkPkt(&b, t, OFID) 1324 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 1325 | bb := <-r 1326 | if MType(bb[4]) == Rerror { 1327 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1328 | if err != nil { 1329 | return err 1330 | } 1331 | return fmt.Errorf("%v", s) 1332 | } else { 1333 | _, err = UnmarshalRclunkPkt(bytes.NewBuffer(bb[5:])) 1334 | } 1335 | return err 1336 | } 1337 | func MarshalRremovePkt (b *bytes.Buffer, t Tag, ) { 1338 | var l uint64 1339 | b.Reset() 1340 | b.Write([]byte{0,0,0,0, 1341 | uint8(Rremove), 1342 | byte(t), byte(t>>8), 1343 | }) 1344 | 1345 | { 1346 | l = uint64(b.Len()) 1347 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1348 | } 1349 | return 1350 | } 1351 | func UnmarshalRremovePkt (b *bytes.Buffer) ( t Tag, err error) { 1352 | var u [8]uint8 1353 | var l uint64 1354 | if _, err = b.Read(u[:2]); err != nil { 1355 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1356 | return 1357 | } 1358 | l = uint64(u[0]) | uint64(u[1])<<8 1359 | t = Tag(l) 1360 | 1361 | if b.Len() > 0 { 1362 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1363 | } 1364 | return 1365 | } 1366 | func MarshalTremovePkt (b *bytes.Buffer, t Tag, OFID FID) { 1367 | var l uint64 1368 | b.Reset() 1369 | b.Write([]byte{0,0,0,0, 1370 | uint8(Tremove), 1371 | byte(t), byte(t>>8), 1372 | uint8(OFID>>0), 1373 | uint8(OFID>>8), 1374 | uint8(OFID>>16), 1375 | uint8(OFID>>24), 1376 | }) 1377 | 1378 | { 1379 | l = uint64(b.Len()) 1380 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1381 | } 1382 | return 1383 | } 1384 | func UnmarshalTremovePkt (b *bytes.Buffer) (OFID FID, t Tag, err error) { 1385 | var u [8]uint8 1386 | var l uint64 1387 | if _, err = b.Read(u[:2]); err != nil { 1388 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1389 | return 1390 | } 1391 | l = uint64(u[0]) | uint64(u[1])<<8 1392 | t = Tag(l) 1393 | if _, err = b.Read(u[:4]); err != nil { 1394 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1395 | return 1396 | } 1397 | OFID = FID(u[0]) 1398 | OFID |= FID(u[1])<<8 1399 | OFID |= FID(u[2])<<16 1400 | OFID |= FID(u[3])<<24 1401 | 1402 | if b.Len() > 0 { 1403 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1404 | } 1405 | return 1406 | } 1407 | func (s *Server) SrvRremove(b*bytes.Buffer) (err error) { 1408 | OFID, t, err := UnmarshalTremovePkt(b) 1409 | //if err != nil { 1410 | //} 1411 | if err := s.NS.Rremove(OFID); err != nil { 1412 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 1413 | } else { 1414 | MarshalRremovePkt(b, t, ) 1415 | } 1416 | return nil 1417 | } 1418 | 1419 | func (c *Client)CallTremove (OFID FID) ( err error) { 1420 | var b = bytes.Buffer{} 1421 | if c.Trace != nil {c.Trace("%v", Tremove)} 1422 | t := Tag(0) 1423 | r := make (chan []byte) 1424 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 1425 | MarshalTremovePkt(&b, t, OFID) 1426 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 1427 | bb := <-r 1428 | if MType(bb[4]) == Rerror { 1429 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1430 | if err != nil { 1431 | return err 1432 | } 1433 | return fmt.Errorf("%v", s) 1434 | } else { 1435 | _, err = UnmarshalRremovePkt(bytes.NewBuffer(bb[5:])) 1436 | } 1437 | return err 1438 | } 1439 | func MarshalRreadPkt (b *bytes.Buffer, t Tag, Data []uint8) { 1440 | var l uint64 1441 | b.Reset() 1442 | b.Write([]byte{0,0,0,0, 1443 | uint8(Rread), 1444 | byte(t), byte(t>>8), 1445 | uint8(len(Data)>>0), 1446 | uint8(len(Data)>>8), 1447 | uint8(len(Data)>>16), 1448 | uint8(len(Data)>>24), 1449 | }) 1450 | b.Write(Data) 1451 | 1452 | { 1453 | l = uint64(b.Len()) 1454 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1455 | } 1456 | return 1457 | } 1458 | func UnmarshalRreadPkt (b *bytes.Buffer) (Data []uint8, t Tag, err error) { 1459 | var u [8]uint8 1460 | var l uint64 1461 | if _, err = b.Read(u[:2]); err != nil { 1462 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1463 | return 1464 | } 1465 | l = uint64(u[0]) | uint64(u[1])<<8 1466 | t = Tag(l) 1467 | if _, err = b.Read(u[:4]); err != nil { 1468 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1469 | return 1470 | } 1471 | l = uint64(u[0]) 1472 | l |= uint64(u[1])<<8 1473 | l |= uint64(u[2])<<16 1474 | l |= uint64(u[3])<<24 1475 | Data = b.Bytes()[:l] 1476 | _ = b.Next(int(l)) 1477 | 1478 | if b.Len() > 0 { 1479 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1480 | } 1481 | return 1482 | } 1483 | func MarshalTreadPkt (b *bytes.Buffer, t Tag, OFID FID, Off Offset, Len Count) { 1484 | var l uint64 1485 | b.Reset() 1486 | b.Write([]byte{0,0,0,0, 1487 | uint8(Tread), 1488 | byte(t), byte(t>>8), 1489 | uint8(OFID>>0), 1490 | uint8(OFID>>8), 1491 | uint8(OFID>>16), 1492 | uint8(OFID>>24), 1493 | uint8(Off>>0), 1494 | uint8(Off>>8), 1495 | uint8(Off>>16), 1496 | uint8(Off>>24), 1497 | uint8(Off>>32), 1498 | uint8(Off>>40), 1499 | uint8(Off>>48), 1500 | uint8(Off>>56), 1501 | uint8(Len>>0), 1502 | uint8(Len>>8), 1503 | uint8(Len>>16), 1504 | uint8(Len>>24), 1505 | }) 1506 | 1507 | { 1508 | l = uint64(b.Len()) 1509 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1510 | } 1511 | return 1512 | } 1513 | func UnmarshalTreadPkt (b *bytes.Buffer) (OFID FID, Off Offset, Len Count, t Tag, err error) { 1514 | var u [8]uint8 1515 | var l uint64 1516 | if _, err = b.Read(u[:2]); err != nil { 1517 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1518 | return 1519 | } 1520 | l = uint64(u[0]) | uint64(u[1])<<8 1521 | t = Tag(l) 1522 | if _, err = b.Read(u[:4]); err != nil { 1523 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1524 | return 1525 | } 1526 | OFID = FID(u[0]) 1527 | OFID |= FID(u[1])<<8 1528 | OFID |= FID(u[2])<<16 1529 | OFID |= FID(u[3])<<24 1530 | if _, err = b.Read(u[:8]); err != nil { 1531 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 1532 | return 1533 | } 1534 | Off = Offset(u[0]) 1535 | Off |= Offset(u[1])<<8 1536 | Off |= Offset(u[2])<<16 1537 | Off |= Offset(u[3])<<24 1538 | Off |= Offset(u[4])<<32 1539 | Off |= Offset(u[5])<<40 1540 | Off |= Offset(u[6])<<48 1541 | Off |= Offset(u[7])<<56 1542 | if _, err = b.Read(u[:4]); err != nil { 1543 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1544 | return 1545 | } 1546 | Len = Count(u[0]) 1547 | Len |= Count(u[1])<<8 1548 | Len |= Count(u[2])<<16 1549 | Len |= Count(u[3])<<24 1550 | 1551 | if b.Len() > 0 { 1552 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1553 | } 1554 | return 1555 | } 1556 | func (s *Server) SrvRread(b*bytes.Buffer) (err error) { 1557 | OFID, Off, Len, t, err := UnmarshalTreadPkt(b) 1558 | //if err != nil { 1559 | //} 1560 | if Data, err := s.NS.Rread(OFID, Off, Len); err != nil { 1561 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 1562 | } else { 1563 | MarshalRreadPkt(b, t, Data) 1564 | } 1565 | return nil 1566 | } 1567 | 1568 | func (c *Client)CallTread (OFID FID, Off Offset, Len Count) (Data []uint8, err error) { 1569 | var b = bytes.Buffer{} 1570 | if c.Trace != nil {c.Trace("%v", Tread)} 1571 | t := Tag(0) 1572 | r := make (chan []byte) 1573 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 1574 | MarshalTreadPkt(&b, t, OFID, Off, Len) 1575 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 1576 | bb := <-r 1577 | if MType(bb[4]) == Rerror { 1578 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1579 | if err != nil { 1580 | return Data, err 1581 | } 1582 | return Data, fmt.Errorf("%v", s) 1583 | } else { 1584 | Data, _, err = UnmarshalRreadPkt(bytes.NewBuffer(bb[5:])) 1585 | } 1586 | return Data, err 1587 | } 1588 | func MarshalRwritePkt (b *bytes.Buffer, t Tag, RLen Count) { 1589 | var l uint64 1590 | b.Reset() 1591 | b.Write([]byte{0,0,0,0, 1592 | uint8(Rwrite), 1593 | byte(t), byte(t>>8), 1594 | uint8(RLen>>0), 1595 | uint8(RLen>>8), 1596 | uint8(RLen>>16), 1597 | uint8(RLen>>24), 1598 | }) 1599 | 1600 | { 1601 | l = uint64(b.Len()) 1602 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1603 | } 1604 | return 1605 | } 1606 | func UnmarshalRwritePkt (b *bytes.Buffer) (RLen Count, t Tag, err error) { 1607 | var u [8]uint8 1608 | var l uint64 1609 | if _, err = b.Read(u[:2]); err != nil { 1610 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1611 | return 1612 | } 1613 | l = uint64(u[0]) | uint64(u[1])<<8 1614 | t = Tag(l) 1615 | if _, err = b.Read(u[:4]); err != nil { 1616 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1617 | return 1618 | } 1619 | RLen = Count(u[0]) 1620 | RLen |= Count(u[1])<<8 1621 | RLen |= Count(u[2])<<16 1622 | RLen |= Count(u[3])<<24 1623 | 1624 | if b.Len() > 0 { 1625 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1626 | } 1627 | return 1628 | } 1629 | func MarshalTwritePkt (b *bytes.Buffer, t Tag, OFID FID, Off Offset, Data []uint8) { 1630 | var l uint64 1631 | b.Reset() 1632 | b.Write([]byte{0,0,0,0, 1633 | uint8(Twrite), 1634 | byte(t), byte(t>>8), 1635 | uint8(OFID>>0), 1636 | uint8(OFID>>8), 1637 | uint8(OFID>>16), 1638 | uint8(OFID>>24), 1639 | uint8(Off>>0), 1640 | uint8(Off>>8), 1641 | uint8(Off>>16), 1642 | uint8(Off>>24), 1643 | uint8(Off>>32), 1644 | uint8(Off>>40), 1645 | uint8(Off>>48), 1646 | uint8(Off>>56), 1647 | uint8(len(Data)>>0), 1648 | uint8(len(Data)>>8), 1649 | uint8(len(Data)>>16), 1650 | uint8(len(Data)>>24), 1651 | }) 1652 | b.Write(Data) 1653 | 1654 | { 1655 | l = uint64(b.Len()) 1656 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8), uint8(l>>16), uint8(l>>24)}) 1657 | } 1658 | return 1659 | } 1660 | func UnmarshalTwritePkt (b *bytes.Buffer) (OFID FID, Off Offset, Data []uint8, t Tag, err error) { 1661 | var u [8]uint8 1662 | var l uint64 1663 | if _, err = b.Read(u[:2]); err != nil { 1664 | err = fmt.Errorf("pkt too short for Tag; need 2, have %d", b.Len()) 1665 | return 1666 | } 1667 | l = uint64(u[0]) | uint64(u[1])<<8 1668 | t = Tag(l) 1669 | if _, err = b.Read(u[:4]); err != nil { 1670 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1671 | return 1672 | } 1673 | OFID = FID(u[0]) 1674 | OFID |= FID(u[1])<<8 1675 | OFID |= FID(u[2])<<16 1676 | OFID |= FID(u[3])<<24 1677 | if _, err = b.Read(u[:8]); err != nil { 1678 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 1679 | return 1680 | } 1681 | Off = Offset(u[0]) 1682 | Off |= Offset(u[1])<<8 1683 | Off |= Offset(u[2])<<16 1684 | Off |= Offset(u[3])<<24 1685 | Off |= Offset(u[4])<<32 1686 | Off |= Offset(u[5])<<40 1687 | Off |= Offset(u[6])<<48 1688 | Off |= Offset(u[7])<<56 1689 | if _, err = b.Read(u[:4]); err != nil { 1690 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1691 | return 1692 | } 1693 | l = uint64(u[0]) 1694 | l |= uint64(u[1])<<8 1695 | l |= uint64(u[2])<<16 1696 | l |= uint64(u[3])<<24 1697 | Data = b.Bytes()[:l] 1698 | _ = b.Next(int(l)) 1699 | 1700 | if b.Len() > 0 { 1701 | err = fmt.Errorf("Packet too long: %d bytes left over after decode", b.Len()) 1702 | } 1703 | return 1704 | } 1705 | func (s *Server) SrvRwrite(b*bytes.Buffer) (err error) { 1706 | OFID, Off, Data, t, err := UnmarshalTwritePkt(b) 1707 | //if err != nil { 1708 | //} 1709 | if RLen, err := s.NS.Rwrite(OFID, Off, Data); err != nil { 1710 | MarshalRerrorPkt(b, t, fmt.Sprintf("%v", err)) 1711 | } else { 1712 | MarshalRwritePkt(b, t, RLen) 1713 | } 1714 | return nil 1715 | } 1716 | 1717 | func (c *Client)CallTwrite (OFID FID, Off Offset, Data []uint8) (RLen Count, err error) { 1718 | var b = bytes.Buffer{} 1719 | if c.Trace != nil {c.Trace("%v", Twrite)} 1720 | t := Tag(0) 1721 | r := make (chan []byte) 1722 | if c.Trace != nil { c.Trace(":tag %v, FID %v", t, c.FID)} 1723 | MarshalTwritePkt(&b, t, OFID, Off, Data) 1724 | c.FromClient <- &RPCCall{b: b.Bytes(), Reply: r} 1725 | bb := <-r 1726 | if MType(bb[4]) == Rerror { 1727 | s, _, err := UnmarshalRerrorPkt(bytes.NewBuffer(bb[5:])) 1728 | if err != nil { 1729 | return RLen, err 1730 | } 1731 | return RLen, fmt.Errorf("%v", s) 1732 | } else { 1733 | RLen, _, err = UnmarshalRwritePkt(bytes.NewBuffer(bb[5:])) 1734 | } 1735 | return RLen, err 1736 | } 1737 | func ServerError (b *bytes.Buffer, s string) { 1738 | var u [8]byte 1739 | // This can't really happen. 1740 | if _, err := b.Read(u[:2]); err != nil { 1741 | return 1742 | } 1743 | t := Tag(uint16(u[0])|uint16(u[1])<<8) 1744 | MarshalRerrorPkt (b, t, s) 1745 | } 1746 | func Marshaldir (b *bytes.Buffer, D Dir) { 1747 | var l uint64 1748 | b.Reset() 1749 | b.Write([]byte{0,0,}) 1750 | b.Write([]byte{ uint8(D.Type>>0), 1751 | uint8(D.Type>>8), 1752 | uint8(D.Dev>>0), 1753 | uint8(D.Dev>>8), 1754 | uint8(D.Dev>>16), 1755 | uint8(D.Dev>>24), 1756 | uint8(D.QID.Type>>0), 1757 | uint8(D.QID.Version>>0), 1758 | uint8(D.QID.Version>>8), 1759 | uint8(D.QID.Version>>16), 1760 | uint8(D.QID.Version>>24), 1761 | uint8(D.QID.Path>>0), 1762 | uint8(D.QID.Path>>8), 1763 | uint8(D.QID.Path>>16), 1764 | uint8(D.QID.Path>>24), 1765 | uint8(D.QID.Path>>32), 1766 | uint8(D.QID.Path>>40), 1767 | uint8(D.QID.Path>>48), 1768 | uint8(D.QID.Path>>56), 1769 | uint8(D.Mode>>0), 1770 | uint8(D.Mode>>8), 1771 | uint8(D.Mode>>16), 1772 | uint8(D.Mode>>24), 1773 | uint8(D.Atime>>0), 1774 | uint8(D.Atime>>8), 1775 | uint8(D.Atime>>16), 1776 | uint8(D.Atime>>24), 1777 | uint8(D.Mtime>>0), 1778 | uint8(D.Mtime>>8), 1779 | uint8(D.Mtime>>16), 1780 | uint8(D.Mtime>>24), 1781 | uint8(D.Length>>0), 1782 | uint8(D.Length>>8), 1783 | uint8(D.Length>>16), 1784 | uint8(D.Length>>24), 1785 | uint8(D.Length>>32), 1786 | uint8(D.Length>>40), 1787 | uint8(D.Length>>48), 1788 | uint8(D.Length>>56), 1789 | uint8(len(D.Name)),uint8(len(D.Name)>>8), 1790 | }) 1791 | b.Write([]byte(D.Name)) 1792 | b.Write([]byte{ uint8(len(D.User)),uint8(len(D.User)>>8), 1793 | }) 1794 | b.Write([]byte(D.User)) 1795 | b.Write([]byte{ uint8(len(D.Group)),uint8(len(D.Group)>>8), 1796 | }) 1797 | b.Write([]byte(D.Group)) 1798 | b.Write([]byte{ uint8(len(D.ModUser)),uint8(len(D.ModUser)>>8), 1799 | }) 1800 | b.Write([]byte(D.ModUser)) 1801 | 1802 | l = uint64(b.Len()) - 2 1803 | copy(b.Bytes(), []byte{uint8(l), uint8(l>>8)}) 1804 | return 1805 | } 1806 | func Unmarshaldir (b *bytes.Buffer) (D Dir, err error) { 1807 | var u [8]uint8 1808 | var l uint64 1809 | _ = b.Next(2) // eat the length too 1810 | if _, err = b.Read(u[:2]); err != nil { 1811 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1812 | return 1813 | } 1814 | D.Type = uint16(u[0]) 1815 | D.Type |= uint16(u[1])<<8 1816 | if _, err = b.Read(u[:4]); err != nil { 1817 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1818 | return 1819 | } 1820 | D.Dev = uint32(u[0]) 1821 | D.Dev |= uint32(u[1])<<8 1822 | D.Dev |= uint32(u[2])<<16 1823 | D.Dev |= uint32(u[3])<<24 1824 | if _, err = b.Read(u[:1]); err != nil { 1825 | err = fmt.Errorf("pkt too short for uint8: need 1, have %d", b.Len()) 1826 | return 1827 | } 1828 | D.QID.Type = uint8(u[0]) 1829 | if _, err = b.Read(u[:4]); err != nil { 1830 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1831 | return 1832 | } 1833 | D.QID.Version = uint32(u[0]) 1834 | D.QID.Version |= uint32(u[1])<<8 1835 | D.QID.Version |= uint32(u[2])<<16 1836 | D.QID.Version |= uint32(u[3])<<24 1837 | if _, err = b.Read(u[:8]); err != nil { 1838 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 1839 | return 1840 | } 1841 | D.QID.Path = uint64(u[0]) 1842 | D.QID.Path |= uint64(u[1])<<8 1843 | D.QID.Path |= uint64(u[2])<<16 1844 | D.QID.Path |= uint64(u[3])<<24 1845 | D.QID.Path |= uint64(u[4])<<32 1846 | D.QID.Path |= uint64(u[5])<<40 1847 | D.QID.Path |= uint64(u[6])<<48 1848 | D.QID.Path |= uint64(u[7])<<56 1849 | if _, err = b.Read(u[:4]); err != nil { 1850 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1851 | return 1852 | } 1853 | D.Mode = uint32(u[0]) 1854 | D.Mode |= uint32(u[1])<<8 1855 | D.Mode |= uint32(u[2])<<16 1856 | D.Mode |= uint32(u[3])<<24 1857 | if _, err = b.Read(u[:4]); err != nil { 1858 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1859 | return 1860 | } 1861 | D.Atime = uint32(u[0]) 1862 | D.Atime |= uint32(u[1])<<8 1863 | D.Atime |= uint32(u[2])<<16 1864 | D.Atime |= uint32(u[3])<<24 1865 | if _, err = b.Read(u[:4]); err != nil { 1866 | err = fmt.Errorf("pkt too short for uint32: need 4, have %d", b.Len()) 1867 | return 1868 | } 1869 | D.Mtime = uint32(u[0]) 1870 | D.Mtime |= uint32(u[1])<<8 1871 | D.Mtime |= uint32(u[2])<<16 1872 | D.Mtime |= uint32(u[3])<<24 1873 | if _, err = b.Read(u[:8]); err != nil { 1874 | err = fmt.Errorf("pkt too short for uint64: need 8, have %d", b.Len()) 1875 | return 1876 | } 1877 | D.Length = uint64(u[0]) 1878 | D.Length |= uint64(u[1])<<8 1879 | D.Length |= uint64(u[2])<<16 1880 | D.Length |= uint64(u[3])<<24 1881 | D.Length |= uint64(u[4])<<32 1882 | D.Length |= uint64(u[5])<<40 1883 | D.Length |= uint64(u[6])<<48 1884 | D.Length |= uint64(u[7])<<56 1885 | if _, err = b.Read(u[:2]); err != nil { 1886 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1887 | return 1888 | } 1889 | l = uint64(u[0]) 1890 | l |= uint64(u[1])<<8 1891 | if b.Len() < int(l) { 1892 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 1893 | return 1894 | } 1895 | D.Name = string(b.Bytes()[:l]) 1896 | _ = b.Next(int(l)) 1897 | if _, err = b.Read(u[:2]); err != nil { 1898 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1899 | return 1900 | } 1901 | l = uint64(u[0]) 1902 | l |= uint64(u[1])<<8 1903 | if b.Len() < int(l) { 1904 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 1905 | return 1906 | } 1907 | D.User = string(b.Bytes()[:l]) 1908 | _ = b.Next(int(l)) 1909 | if _, err = b.Read(u[:2]); err != nil { 1910 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1911 | return 1912 | } 1913 | l = uint64(u[0]) 1914 | l |= uint64(u[1])<<8 1915 | if b.Len() < int(l) { 1916 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 1917 | return 1918 | } 1919 | D.Group = string(b.Bytes()[:l]) 1920 | _ = b.Next(int(l)) 1921 | if _, err = b.Read(u[:2]); err != nil { 1922 | err = fmt.Errorf("pkt too short for uint16: need 2, have %d", b.Len()) 1923 | return 1924 | } 1925 | l = uint64(u[0]) 1926 | l |= uint64(u[1])<<8 1927 | if b.Len() < int(l) { 1928 | err = fmt.Errorf("pkt too short for string: need %d, have %d", l, b.Len()) 1929 | return 1930 | } 1931 | D.ModUser = string(b.Bytes()[:l]) 1932 | _ = b.Next(int(l)) 1933 | 1934 | return 1935 | } 1936 | -------------------------------------------------------------------------------- /protocol/pprof.go: -------------------------------------------------------------------------------- 1 | // +build pprof 2 | 3 | package protocol 4 | 5 | import ( 6 | "log" 7 | "net/http" 8 | _ "net/http/pprof" 9 | 10 | ) 11 | 12 | 13 | func init() { 14 | go func() { 15 | log.Println(http.ListenAndServe(":6060", nil)) 16 | }() 17 | } 18 | -------------------------------------------------------------------------------- /protocol/protocol.go: -------------------------------------------------------------------------------- 1 | // Package protocol implements the 9p protocol using the stubs. 2 | 3 | //go:generate go run gen.go 4 | 5 | package protocol 6 | 7 | import "bytes" 8 | 9 | // 9P2000 message types 10 | const ( 11 | Tversion MType = 100 + iota 12 | Rversion 13 | Tauth 14 | Rauth 15 | Tattach 16 | Rattach 17 | Terror 18 | Rerror 19 | Tflush 20 | Rflush 21 | Twalk 22 | Rwalk 23 | Topen 24 | Ropen 25 | Tcreate 26 | Rcreate 27 | Tread 28 | Rread 29 | Twrite 30 | Rwrite 31 | Tclunk 32 | Rclunk 33 | Tremove 34 | Rremove 35 | Tstat 36 | Rstat 37 | Twstat 38 | Rwstat 39 | Tlast 40 | ) 41 | 42 | const ( 43 | MSIZE = 2*1048576 + IOHDRSZ // default message size (1048576+IOHdrSz) 44 | IOHDRSZ = 24 // the non-data size of the Twrite messages 45 | PORT = 564 // default port for 9P file servers 46 | NumFID = 1 << 16 47 | QIDLen = 13 48 | ) 49 | 50 | // QID types 51 | const ( 52 | QTDIR = 0x80 // directories 53 | QTAPPEND = 0x40 // append only files 54 | QTEXCL = 0x20 // exclusive use files 55 | QTMOUNT = 0x10 // mounted channel 56 | QTAUTH = 0x08 // authentication file 57 | QTTMP = 0x04 // non-backed-up file 58 | QTSYMLINK = 0x02 // symbolic link (Unix, 9P2000.u) 59 | QTLINK = 0x01 // hard link (Unix, 9P2000.u) 60 | QTFILE = 0x00 61 | ) 62 | 63 | // Flags for the mode field in Topen and Tcreate messages 64 | const ( 65 | OREAD = 0x0 // open read-only 66 | OWRITE = 0x1 // open write-only 67 | ORDWR = 0x2 // open read-write 68 | OEXEC = 0x3 // execute (== read but check execute permission) 69 | OTRUNC = 0x10 // or'ed in (except for exec), truncate file first 70 | OCEXEC = 0x20 // or'ed in, close on exec 71 | ORCLOSE = 0x40 // or'ed in, remove on close 72 | OAPPEND = 0x80 // or'ed in, append only 73 | OEXCL = 0x1000 // or'ed in, exclusive client use 74 | ) 75 | 76 | // File modes 77 | const ( 78 | DMDIR = 0x80000000 // mode bit for directories 79 | DMAPPEND = 0x40000000 // mode bit for append only files 80 | DMEXCL = 0x20000000 // mode bit for exclusive use files 81 | DMMOUNT = 0x10000000 // mode bit for mounted channel 82 | DMAUTH = 0x08000000 // mode bit for authentication file 83 | DMTMP = 0x04000000 // mode bit for non-backed-up file 84 | DMREAD = 0x4 // mode bit for read permission 85 | DMWRITE = 0x2 // mode bit for write permission 86 | DMEXEC = 0x1 // mode bit for execute permission 87 | ) 88 | 89 | const ( 90 | NOTAG Tag = 0xFFFF // no tag specified 91 | NOFID FID = 0xFFFFFFFF // no fid specified 92 | // We reserve tag NOTAG and tag 0. 0 is a troublesome value to pass 93 | // around, since it is also a default value and using it can hide errors 94 | // in the code. 95 | NumTags = 1<<16 - 2 96 | ) 97 | 98 | // Error values 99 | const ( 100 | EPERM = 1 101 | ENOENT = 2 102 | EIO = 5 103 | EACCES = 13 104 | EEXIST = 17 105 | ENOTDIR = 20 106 | EINVAL = 22 107 | ) 108 | 109 | // Types contained in 9p messages. 110 | type ( 111 | MType uint8 112 | Mode uint8 113 | NumEntries uint16 114 | Tag uint16 115 | FID uint32 116 | MaxSize uint32 117 | Count int32 118 | Perm uint32 119 | Offset uint64 120 | Data []byte 121 | // Some []byte fields are encoded with a 16-bit length, e.g. stat data. 122 | // We use this type to tag such fields. The parameters are still []byte, 123 | // this was just the only way I could think of to make the stub generator do the right 124 | // thing. 125 | DataCnt16 byte // []byte with a 16-bit count. 126 | ) 127 | 128 | // Error represents a 9P2000 error 129 | type Error struct { 130 | Err string 131 | } 132 | 133 | // File identifier 134 | type QID struct { 135 | Type uint8 // type of the file (high 8 bits of the mode) 136 | Version uint32 // version number for the path 137 | Path uint64 // server's unique identification of the file 138 | } 139 | 140 | // Dir describes a file 141 | type Dir struct { 142 | Type uint16 143 | Dev uint32 144 | QID QID // file's QID 145 | Mode uint32 // permissions and flags 146 | Atime uint32 // last access time in seconds 147 | Mtime uint32 // last modified time in seconds 148 | Length uint64 // file length in bytes 149 | Name string // file name 150 | User string // owner name 151 | Group string // group name 152 | ModUser string // name of the last user that modified the file 153 | } 154 | 155 | type Dispatcher func(s *Server, b *bytes.Buffer, t MType) error 156 | 157 | // N.B. In all packets, the wire order is assumed to be the order in which you 158 | // put struct members. 159 | // In an earlier version of this code we got really fancy and made it so you 160 | // could have identically named fields in the R and T packets. It's only an issue 161 | // in a trivial number of packets so we place the burden on you, the user, to make 162 | // the names different. Also, you can't name struct members with the same names as the 163 | // type. Sorry. But it keeps gen.go so much simpler. 164 | 165 | type TversionPkt struct { 166 | TMsize MaxSize 167 | TVersion string 168 | } 169 | 170 | type RversionPkt struct { 171 | RMsize MaxSize 172 | RVersion string 173 | } 174 | 175 | type TattachPkt struct { 176 | SFID FID 177 | AFID FID 178 | Uname string 179 | Aname string 180 | } 181 | 182 | type RattachPkt struct { 183 | QID QID 184 | } 185 | 186 | type TflushPkt struct { 187 | OTag Tag 188 | } 189 | 190 | type RflushPkt struct { 191 | } 192 | 193 | type TwalkPkt struct { 194 | SFID FID 195 | NewFID FID 196 | Paths []string 197 | } 198 | 199 | type RwalkPkt struct { 200 | QIDs []QID 201 | } 202 | 203 | type TopenPkt struct { 204 | OFID FID 205 | Omode Mode 206 | } 207 | 208 | type RopenPkt struct { 209 | OQID QID 210 | IOUnit MaxSize 211 | } 212 | 213 | type TcreatePkt struct { 214 | OFID FID 215 | Name string 216 | CreatePerm Perm 217 | Omode Mode 218 | } 219 | 220 | type RcreatePkt struct { 221 | OQID QID 222 | IOUnit MaxSize 223 | } 224 | 225 | type TclunkPkt struct { 226 | OFID FID 227 | } 228 | 229 | type RclunkPkt struct { 230 | } 231 | 232 | type TremovePkt struct { 233 | OFID FID 234 | } 235 | 236 | type RremovePkt struct { 237 | } 238 | 239 | type TstatPkt struct { 240 | OFID FID 241 | } 242 | 243 | type RstatPkt struct { 244 | B []DataCnt16 245 | } 246 | 247 | type TwstatPkt struct { 248 | OFID FID 249 | B []DataCnt16 250 | } 251 | 252 | type RwstatPkt struct { 253 | } 254 | 255 | type TreadPkt struct { 256 | OFID FID 257 | Off Offset 258 | Len Count 259 | } 260 | 261 | type RreadPkt struct { 262 | Data []byte 263 | } 264 | 265 | type TwritePkt struct { 266 | OFID FID 267 | Off Offset 268 | Data []byte 269 | } 270 | 271 | type RwritePkt struct { 272 | RLen Count 273 | } 274 | 275 | type RerrorPkt struct { 276 | Error string 277 | } 278 | 279 | type DirPkt struct { 280 | D Dir 281 | } 282 | 283 | type RPCCall struct { 284 | b []byte 285 | Reply chan []byte 286 | } 287 | 288 | type RPCReply struct { 289 | b []byte 290 | } 291 | 292 | /* rpc servers */ 293 | type ClientOpt func(*Client) error 294 | type ListenerOpt func(*Listener) error 295 | type Tracer func(string, ...interface{}) 296 | 297 | type NineServer interface { 298 | Rversion(MaxSize, string) (MaxSize, string, error) 299 | Rattach(FID, FID, string, string) (QID, error) 300 | Rwalk(FID, FID, []string) ([]QID, error) 301 | Ropen(FID, Mode) (QID, MaxSize, error) 302 | Rcreate(FID, string, Perm, Mode) (QID, MaxSize, error) 303 | Rstat(FID) ([]byte, error) 304 | Rwstat(FID, []byte) error 305 | Rclunk(FID) error 306 | Rremove(FID) error 307 | Rread(FID, Offset, Count) ([]byte, error) 308 | Rwrite(FID, Offset, []byte) (Count, error) 309 | Rflush(Otag Tag) error 310 | } 311 | 312 | var ( 313 | RPCNames = map[MType]string{ 314 | Tversion: "Tversion", 315 | Rversion: "Rversion", 316 | Tauth: "Tauth", 317 | Rauth: "Rauth", 318 | Tattach: "Tattach", 319 | Rattach: "Rattach", 320 | Terror: "Terror", 321 | Rerror: "Rerror", 322 | Tflush: "Tflush", 323 | Rflush: "Rflush", 324 | Twalk: "Twalk", 325 | Rwalk: "Rwalk", 326 | Topen: "Topen", 327 | Ropen: "Ropen", 328 | Tcreate: "Tcreate", 329 | Rcreate: "Rcreate", 330 | Tread: "Tread", 331 | Rread: "Rread", 332 | Twrite: "Twrite", 333 | Rwrite: "Rwrite", 334 | Tclunk: "Tclunk", 335 | Rclunk: "Rclunk", 336 | Tremove: "Tremove", 337 | Rremove: "Rremove", 338 | Tstat: "Tstat", 339 | Rstat: "Rstat", 340 | Twstat: "Twstat", 341 | Rwstat: "Rwstat", 342 | } 343 | ) 344 | -------------------------------------------------------------------------------- /protocol/protocol_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Ninep 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 | package protocol 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "net" 11 | "os" 12 | "reflect" 13 | "testing" 14 | ) 15 | 16 | var ( 17 | removedFID2 bool 18 | ) 19 | 20 | func print(f string, args ...interface{}) { 21 | fmt.Fprintf(os.Stderr, f+"\n", args...) 22 | } 23 | 24 | func newEcho() *echo { 25 | return &echo{ 26 | qids: make(map[FID]QID), 27 | } 28 | } 29 | 30 | // Two files, dotu was true. 31 | var testunpackbytes = []byte{ 32 | 79, 0, 0, 0, 0, 0, 0, 0, 0, 228, 193, 233, 248, 44, 145, 3, 0, 0, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0, 47, 117, 180, 83, 102, 3, 0, 0, 0, 0, 0, 0, 6, 0, 112, 97, 115, 115, 119, 100, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 0, 0, 232, 3, 0, 0, 232, 3, 0, 0, 255, 255, 255, 255, 78, 0, 0, 0, 0, 0, 0, 0, 0, 123, 171, 233, 248, 42, 145, 3, 0, 0, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0, 41, 117, 180, 83, 195, 0, 0, 0, 0, 0, 0, 0, 5, 0, 104, 111, 115, 116, 115, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 0, 0, 232, 3, 0, 0, 232, 3, 0, 0, 255, 255, 255, 255, 33 | } 34 | 35 | /* 36 | func testUnpackDir(t *testing.T) { 37 | b := testunpackbytes 38 | for len(b) > 0 { 39 | var err error 40 | if _, b, _, err = UnpackDir(b, true); err != nil { 41 | t.Fatalf("Unpackdir: %v", err) 42 | } 43 | } 44 | } 45 | */ 46 | func TestEncode(t *testing.T) { 47 | // The traces used in this array came from running 9p servers and clients. 48 | // Except for flush, which we made up. 49 | // TODO: put the replies in, then the decode testing when we get decode done. 50 | var tests = []struct { 51 | n string 52 | b []byte 53 | f func(b *bytes.Buffer) 54 | }{ 55 | { 56 | "TVersion test with 8192 byte msize and 9P2000", 57 | []byte{19, 0, 0, 0, 100, 0x55, 0xaa, 0, 32, 0, 0, 6, 0, 57, 80, 50, 48, 48, 48}, 58 | func(b *bytes.Buffer) { MarshalTversionPkt(b, Tag(0xaa55), 8192, "9P2000") }, 59 | }, 60 | { 61 | "RVersion test with 8192 byte msize and 9P2000", 62 | []byte{19, 0, 0, 0, 101, 0xaa, 0x55, 0, 32, 0, 0, 6, 0, 57, 80, 50, 48, 48, 48}, 63 | func(b *bytes.Buffer) { MarshalRversionPkt(b, Tag(0x55aa), 8192, "9P2000") }, 64 | }, 65 | /* 66 | { 67 | "Twalk tag 0 fid 0 newfid 1 to null", 68 | []byte{23, 0, 0, 0, 110, 0xaa, 0x55, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 0, 110, 117, 108, 108}, 69 | func(b *bytes.Buffer) { MarshalTwalkPkt(b, Tag(0x55aa), 0, 1, []string{"null",}) }, 70 | }, 71 | { 72 | "Flush test with tag 1 and oldtag 2", 73 | []byte{9, 0, 0, 0, 108, 1, 0, 2, 0}, 74 | []interface{}{Tflush, Tag(1), Tag(2)}, 75 | }, 76 | { 77 | "Auth test with tag 0, fid 0,uname rminnich", 78 | []byte{21, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 8, 0, 114, 109, 105, 110, 110, 105, 99, 104}, 79 | []interface{}{Tauth, Tag(0), FID(0), "rminnich"}, 80 | }, 81 | { 82 | "Attach test with tag 0, fid 0, afid -1, uname rminnich", 83 | []byte{28, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 8, 0, 114, 109, 105, 110, 110, 105, 99, 104, 1, 0, 47}, 84 | []interface{}{Tattach, Tag(0), FID(0), NOFID, "rminnich", "/"}, 85 | }, 86 | { 87 | "Tauth with an rerror of no user required", 88 | //Tauth tag 1 afid 45 uname 'rminnich' nuname 4294967295 aname '' 89 | []byte{23,0,0,0,102,1,0,45,0,0,0,8,0,114,109,105,110,110,105,99,104,0,0}, 90 | []interface{}{Tauth, Tag(1), FID(45), "rminnich", ""}, 91 | // [39 0 0 0 107 1 0 30 0 110 111 32 97 117 116 104 101 110 116 105 99 97 116 105 111 110 32 114 101 113 117 105 114 101 100 58 32 50 50] 92 | //Rerror tag 1 ename 'no authentication required: 22' ecode 0 93 | }, 94 | { 95 | "Tattach from Harvey to ninep: Tattach tag 1 fid 48 afid 4294967295 uname 'rminnich' nuname 4294967295 aname ''", 96 | []byte{27,0,0,0,104,1,0,48,0,0,0,255,255,255,255,8,0,114,109,105,110,110,105,99,104,0,0}, 97 | []interface{}{Tattach, Tag(1), FID(48), NOFID, "rminnich", ""}, 98 | // 20 0 0 0 105 1 0 128 99 207 44 145 115 221 96 0 0 0 0 0] 99 | // Rattach tag 1 aqid (60dd73 912ccf63 'd') 100 | }, 101 | { 102 | "Topen tag 0 fid 1 mode 2", 103 | []byte{12, 0, 0, 0, 112, 0, 0, 1, 0, 0, 0, 2}, 104 | []interface{}{Topen, Tag(0), FID(1), Mode(2)}, 105 | }, 106 | { 107 | "Tread tag 0 fid 1 offset 0 count 8192", 108 | []byte{23, 0, 0, 0, 116, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0}, 109 | []interface{}{Tread, Tag(0), FID(1), Offset(0), Count(8192)}, 110 | }, 111 | { 112 | "Tstat tag 1 fid 49", 113 | []byte{11, 0, 0, 0, 124, 1, 0, 49, 0, 0, 0}, 114 | // Rstat 115 | // 116 | //[84,0,0,0,125,1,0,75,0,73,0,0,0,0,0,0,0,128,99,207,44,145,115,221,96,0,0,0,0,0,253,1,0,128,109,185,47,86,196,66,41,86,0,16,0,0,0,0,0,0,6,0,104,97,114,118,101,121,8,0,114,109,105,110,110,105,99,104,8,0,114,109,105,110,110,105,99,104,4,0,110,111,110,101] 117 | 118 | //Rstat tag 1 st ('harvey' 'rminnich' 'rminnich' 'none' q (60dd73 912ccf63 'd') m d775 at 1445968237 mt 1445544644 l 4096 t 0 d 0 ext ) 119 | []interface{}{Tstat, Tag(1), FID(49)}, 120 | }, 121 | { 122 | "Twrite tag 3 fid 139 offset 0 count 3", 123 | []byte{26, 0, 0, 0, 118, 3, 0, 139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 104, 105, 10}, 124 | // rwrite []byte{11,0,0,0,119,3,0,3,0,0,0} 125 | []interface{}{Twrite, Tag(3), FID(139), Offset(0), Count(3), []byte("hi\n")}, 126 | }, 127 | { 128 | "Tclunk tag 1 fid 49", 129 | []byte{11, 0, 0, 0, 120, 1, 0, 49, 0, 0, 0}, 130 | // rclunk 7 0 0 0 121 1 0] 131 | []interface{}{Tclunk, Tag(1), FID(49)}, 132 | }, 133 | { 134 | "Tremove tag 1 fid 49", 135 | []byte{11, 0, 0, 0, 122, 1, 0, 49, 0, 0, 0}, 136 | // rclunk 7 0 0 0 121 1 0] 137 | []interface{}{Tremove, Tag(1), FID(49)}, 138 | }, 139 | { 140 | "Twstat tag 3 fid 49 ", 141 | //Twstat tag 3 fid 49 st ('' '' '' '' q (ffffffffffffffff ffffffff 'daAltL') m daAltDSPL777 at 4294967295 mt 1445968327 l 18446744073709551615 t 65535 d 4294967295 ext ) 142 | []byte{62, 0, 0, 0, 126, 3, 0, 49, 0, 0, 0, 49, 0, 47, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 199, 185, 47, 86, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, 143 | // Rwstat [11 0 0 0 120 3 0 49 0 0 0] 144 | []interface{}{Twstat, Tag(3), FID(49), &Dir{ /* TODO: remove this size 145 | Size: 47, 146 | Type: math.MaxUint16, 147 | Dev: math.MaxUint32, 148 | Qid: Qid{Type: math.MaxUint8, Version: math.MaxUint32, Path: math.MaxUint64}, 149 | Mode: math.MaxUint32, 150 | Atime: 4294967295, 151 | Mtime: 1445968327, 152 | Length: 18446744073709551615, 153 | Name: "", 154 | Uid: "", 155 | Gid: "", 156 | Muid: "", 157 | }, 158 | }, 159 | }, 160 | { 161 | "Tcreate tag 3 fid 74 name 'y' perm 666 mode 0", 162 | []byte{19,0,0,0,114,3,0,74,0,0,0,1,0,121,182,1,0,0,0}, 163 | []interface{}{Tcreate, Tag(3), FID(74), "y", Perm(0666), Mode(0)}, 164 | /// rcreate [24 0 0 0 115 3 0 0 226 200 71 172 45 166 98 0 0 0 0 0 0 0 0 0] 165 | // Rcreate tag 3 qid (62a62d ac47c8e2 '') iounit 0 166 | },*/ 167 | } 168 | 169 | for _, v := range tests { 170 | var b bytes.Buffer 171 | v.f(&b) 172 | if !reflect.DeepEqual(v.b, b.Bytes()) { 173 | t.Errorf("Mismatch on %v: Got\n%v[%v], want\n%v[%v]", v.n, b.Bytes(), len(b.Bytes()), v.b, len(v.b)) 174 | } 175 | } 176 | 177 | } 178 | 179 | /* 180 | func testDecode(t *testing.T) { 181 | var tests = []struct { 182 | n string 183 | b []byte 184 | f func(b *bytes.Buffer) error 185 | }{ 186 | { 187 | "TVersion test with 8192 byte msize and 9P2000", 188 | []byte{19, 0, 0, 0, 100, 255, 255, 0, 32, 0, 0, 6, 0, 57, 80, 50, 48, 48, 48}, 189 | func (b *bytes.Buffer){ MarshalTversionPkt(b, NOTAG, 8192, "9P2000")}, 190 | }, 191 | 192 | for _, v := range tests { 193 | var b bytes.Buffer 194 | v.f(&b) 195 | if !reflect.DeepEqual(v.b, b.Bytes()) { 196 | t.Errorf("Mismatch on %v: Got %v[%v], want %v[%v]", v.n, b.Bytes(), len(b.Bytes()), v.b, len(v.b)) 197 | } 198 | } 199 | 200 | } 201 | */ 202 | 203 | func TestTags(t *testing.T) { 204 | c, err := NewClient() 205 | if err != nil { 206 | t.Fatalf("%v", err) 207 | } 208 | _ = c.GetTag() 209 | if len(c.Tags) != NumTags-1 { 210 | t.Errorf("Got one tag, len(tags) is %d, want %d", len(c.Tags), NumTags-1) 211 | } 212 | } 213 | 214 | type echo struct { 215 | qids map[FID]QID 216 | } 217 | 218 | func (e *echo) Rversion(msize MaxSize, version string) (MaxSize, string, error) { 219 | if version != "9P2000" { 220 | return 0, "", fmt.Errorf("%v not supported; only 9P2000", version) 221 | } 222 | return msize, version, nil 223 | } 224 | 225 | func (e *echo) Rattach(FID, FID, string, string) (QID, error) { 226 | return QID{}, nil 227 | } 228 | 229 | func (e *echo) Rflush(o Tag) error { 230 | switch o { 231 | case 3: 232 | // Make it fancier, later. 233 | return nil 234 | } 235 | return fmt.Errorf("Rflush: bad Tag %v", o) 236 | } 237 | 238 | func (e *echo) Rwalk(fid FID, newfid FID, paths []string) ([]QID, error) { 239 | //fmt.Printf("walk(%d, %d, %d, %v\n", fid, newfid, len(paths), paths) 240 | if len(paths) > 1 { 241 | return nil, nil 242 | } 243 | switch paths[0] { 244 | case "null": 245 | return []QID{{Type: 0, Version: 0, Path: 0xaa55}}, nil 246 | } 247 | return nil, nil 248 | } 249 | 250 | func (e *echo) Ropen(fid FID, mode Mode) (QID, MaxSize, error) { 251 | //fmt.Printf("open(%v, %v\n", fid, mode) 252 | return QID{}, 4000, nil 253 | } 254 | func (e *echo) Rcreate(fid FID, name string, perm Perm, mode Mode) (QID, MaxSize, error) { 255 | //fmt.Printf("open(%v, %v\n", fid, mode) 256 | return QID{}, 5000, nil 257 | } 258 | func (e *echo) Rclunk(f FID) error { 259 | switch int(f) { 260 | case 2: 261 | // Make it fancier, later. 262 | if removedFID2 { 263 | return fmt.Errorf("Clunk: bad FID %v", f) 264 | } 265 | return nil 266 | } 267 | //fmt.Printf("clunk(%v)\n", f) 268 | return fmt.Errorf("Clunk: bad FID %v", f) 269 | } 270 | func (e *echo) Rstat(f FID) ([]byte, error) { 271 | switch int(f) { 272 | case 2: 273 | // Make it fancier, later. 274 | return []byte{}, nil 275 | } 276 | //fmt.Printf("stat(%v)\n", f) 277 | return []byte{}, fmt.Errorf("Stat: bad FID %v", f) 278 | } 279 | func (e *echo) Rwstat(f FID, s []byte) error { 280 | switch int(f) { 281 | case 2: 282 | // Make it fancier, later. 283 | return nil 284 | } 285 | //fmt.Printf("stat(%v)\n", f)y 286 | return fmt.Errorf("Wstat: bad FID %v", f) 287 | } 288 | func (e *echo) Rremove(f FID) error { 289 | switch int(f) { 290 | case 2: 291 | // Make it fancier, later. 292 | removedFID2 = true 293 | return nil 294 | } 295 | //fmt.Printf("remove(%v)\n", f) 296 | return fmt.Errorf("Remove: bad FID %v", f) 297 | } 298 | func (e *echo) Rread(f FID, o Offset, c Count) ([]byte, error) { 299 | switch int(f) { 300 | case 2: 301 | // Make it fancier, later. 302 | return []byte("HI"), nil 303 | } 304 | return nil, fmt.Errorf("Read: bad FID %v", f) 305 | } 306 | 307 | func (e *echo) Rwrite(f FID, o Offset, b []byte) (Count, error) { 308 | switch int(f) { 309 | case 2: 310 | // Make it fancier, later. 311 | return Count(len(b)), nil 312 | } 313 | return -1, fmt.Errorf("Write: bad FID %v", f) 314 | } 315 | func TestTManyRPCs(t *testing.T) { 316 | p, p2 := net.Pipe() 317 | 318 | c, err := NewClient(func(c *Client) error { 319 | c.FromNet, c.ToNet = p, p 320 | return nil 321 | }, 322 | func(c *Client) error { 323 | c.Msize = 8192 324 | c.Trace = print // t.Logf 325 | return nil 326 | }) 327 | if err != nil { 328 | t.Fatalf("%v", err) 329 | } 330 | t.Logf("Client is %v", c.String()) 331 | 332 | s, err := NewListener( 333 | func() NineServer { return newEcho() }, 334 | func(l *Listener) error { 335 | l.Trace = print 336 | return nil 337 | }) 338 | if err != nil { 339 | t.Fatalf("NewServer: want nil, got %v", err) 340 | } 341 | 342 | if err := s.Accept(p2); err != nil { 343 | t.Fatalf("Accept: want nil, got %v", err) 344 | } 345 | 346 | for i := 0; i < 256*1024; i++ { 347 | _, _, err := c.CallTversion(8000, "9P2000") 348 | if err != nil { 349 | t.Fatalf("CallTversion: want nil, got %v", err) 350 | } 351 | } 352 | } 353 | 354 | func TestTMessages(t *testing.T) { 355 | p, p2 := net.Pipe() 356 | 357 | c, err := NewClient(func(c *Client) error { 358 | c.FromNet, c.ToNet = p, p 359 | return nil 360 | }, 361 | func(c *Client) error { 362 | c.Msize = 8192 363 | c.Trace = print // t.Logf 364 | return nil 365 | }) 366 | if err != nil { 367 | t.Fatalf("%v", err) 368 | } 369 | t.Logf("Client is %v", c.String()) 370 | 371 | s, err := NewListener( 372 | func() NineServer { return newEcho() }, 373 | func(l *Listener) error { 374 | l.Trace = print // t.Logf 375 | return nil 376 | }) 377 | 378 | if err != nil { 379 | t.Fatalf("NewServer: want nil, got %v", err) 380 | } 381 | 382 | if err := s.Accept(p2); err != nil { 383 | t.Fatalf("Accept: want nil, got %v", err) 384 | } 385 | 386 | // If things really go to hell, change this to true. 387 | if false { 388 | m, v, err := c.CallTversion(8000, "9P2000") 389 | if err != nil { 390 | t.Fatalf("CallTversion: want nil, got %v", err) 391 | } 392 | t.Logf("CallTversion: msize %v version %v", m, v) 393 | t.Fatalf("Quit early") 394 | } 395 | 396 | // make sure server rejects requests until the first Tversion 397 | t.Logf("Server is %v", s.String()) 398 | if _, err = c.CallTattach(0, 0, "", ""); err == nil { 399 | t.Fatalf("CallTattach: want err, got nil") 400 | } 401 | t.Logf("CallTattach: wanted an error and got %v", err) 402 | 403 | m, v, err := c.CallTversion(8000, "9p3000") 404 | if err == nil { 405 | t.Fatalf("CallTversion: want err, got nil") 406 | } 407 | t.Logf("CallTversion: wanted an error and got %v", err) 408 | 409 | m, v, err = c.CallTversion(8000, "9P2000") 410 | if err != nil { 411 | t.Fatalf("CallTversion: want nil, got %v", err) 412 | } 413 | t.Logf("CallTversion: msize %v version %v", m, v) 414 | 415 | t.Logf("Server is %v", s.String()) 416 | a, err := c.CallTattach(0, 0, "", "") 417 | if err != nil { 418 | t.Fatalf("CallTattach: want nil, got %v", err) 419 | } 420 | t.Logf("Attach is %v", a) 421 | w, err := c.CallTwalk(0, 1, []string{"hi", "there"}) 422 | // There should never be an error. The indication of a failed walk is that 423 | // the number of QIDS does not match. 424 | if err != nil { 425 | t.Fatalf("CallTwalk(0,1,[\"hi\", \"there\"]): want nil, got %v", err) 426 | } 427 | if len(w) != 0 { 428 | t.Fatalf("CallTwalk(0,1,[\"hi\", \"there\"]): want 0 QIDS, got back %d", len(w)) 429 | } 430 | t.Logf("Walk is %v", w) 431 | 432 | w, err = c.CallTwalk(0, 1, []string{"null"}) 433 | if err != nil { 434 | t.Errorf("CallTwalk(0,1,\"null\"): want nil, got err %v", err) 435 | } 436 | if len(w) != 1 { 437 | t.Errorf("CallTwalk(0,1,\"null\"): want 1 QIDs, got back %d", len(w)) 438 | } 439 | t.Logf("Walk is %v", w) 440 | 441 | q, iounit, err := c.CallTopen(1, 1) 442 | if err != nil { 443 | t.Fatalf("CallTopen: want nil, got %v", err) 444 | } 445 | t.Logf("Open is %v %v", q, iounit) 446 | 447 | d, err := c.CallTread(FID(2), 0, 5) 448 | if err != nil { 449 | t.Fatalf("CallTread: want nil, got %v", err) 450 | } 451 | t.Logf("Read is %v", d) 452 | 453 | _, err = c.CallTwrite(FID(2), 0, d) 454 | if err != nil { 455 | t.Fatalf("CallTread: want nil, got %v", err) 456 | } 457 | t.Logf("Read is %v", s) 458 | 459 | if err := c.CallTclunk(FID(2)); err != nil { 460 | t.Fatalf("CallTclunk: want nil, got %v", err) 461 | } 462 | if err := c.CallTremove(FID(1)); err == nil { 463 | t.Fatalf("CallTremove: want err, got nil") 464 | } 465 | if err := c.CallTremove(FID(2)); err != nil { 466 | t.Fatalf("CallTremove: want nil, got %v", err) 467 | } 468 | if err := c.CallTclunk(FID(2)); err == nil { 469 | t.Fatalf("Callclunk on removed file: want err, got nil") 470 | } 471 | if err := c.CallTremove(FID(1)); err == nil { 472 | t.Fatalf("CallTremove: want err, got nil") 473 | } 474 | st, err := c.CallTstat(FID(2)) 475 | if err != nil { 476 | t.Fatalf("CallTstat: want nil, got %v", err) 477 | } 478 | t.Logf("Stat: Got %v", st) 479 | 480 | if _, err := c.CallTstat(FID(1)); err == nil { 481 | t.Fatalf("CallTstat: want err, got nil") 482 | } 483 | if err := c.CallTwstat(FID(2), []byte{}); err != nil { 484 | t.Fatalf("CallTwstat: want nil, got %v", err) 485 | } 486 | 487 | if err := c.CallTwstat(FID(1), []byte{}); err == nil { 488 | t.Fatalf("CallTwstat: want err, got nil") 489 | } 490 | if err := c.CallTflush(3); err != nil { 491 | t.Fatalf("CallTflush: want nil, got %v", err) 492 | } 493 | 494 | if err := c.CallTflush(2); err == nil { 495 | t.Fatalf("CallTflush: want err, got nil") 496 | } 497 | } 498 | 499 | func BenchmarkNull(b *testing.B) { 500 | p, p2 := net.Pipe() 501 | 502 | c, err := NewClient(func(c *Client) error { 503 | c.FromNet, c.ToNet = p, p 504 | return nil 505 | }, 506 | func(c *Client) error { 507 | c.Msize = 8192 508 | return nil 509 | }) 510 | if err != nil { 511 | b.Fatalf("%v", err) 512 | } 513 | b.Logf("Client is %v", c.String()) 514 | 515 | s, err := NewListener( 516 | func() NineServer { 517 | return newEcho() 518 | }) 519 | 520 | if err != nil { 521 | b.Fatalf("NewServer: want nil, got %v", err) 522 | } 523 | 524 | if err := s.Accept(p2); err != nil { 525 | b.Fatalf("Accept: want nil, got %v", err) 526 | } 527 | 528 | b.Logf("%d iterations", b.N) 529 | for i := 0; i < b.N; i++ { 530 | if _, err := c.CallTread(FID(2), 0, 5); err != nil { 531 | b.Fatalf("CallTread: want nil, got %v", err) 532 | } 533 | } 534 | 535 | } 536 | -------------------------------------------------------------------------------- /protocol/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Ninep 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 | // This code is imported from the old ninep repo, 5 | // with some changes. 6 | 7 | package protocol 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io" 13 | "net" 14 | "sync" 15 | "time" 16 | ) 17 | 18 | const DefaultAddr = ":5640" 19 | 20 | type NsCreator func() NineServer 21 | 22 | type Listener struct { 23 | nsCreator NsCreator 24 | 25 | // TCP address to listen on, default is DefaultAddr 26 | Addr string 27 | 28 | // Trace function for logging 29 | Trace Tracer 30 | 31 | // mu guards below 32 | mu sync.Mutex 33 | 34 | listeners map[net.Listener]struct{} 35 | } 36 | 37 | // Server is a 9p server. 38 | // For now it's extremely serial. But we will use a chan for replies to ensure that 39 | // we can go to a more concurrent one later. 40 | type Server struct { 41 | NS NineServer 42 | D Dispatcher 43 | 44 | // Versioned is set to true on the first call to Tversion 45 | Versioned bool 46 | } 47 | 48 | type conn struct { 49 | listener *Listener 50 | 51 | // server on which the connection arrived. 52 | server *Server 53 | 54 | // rwc is the underlying network connection. 55 | rwc net.Conn 56 | 57 | // remoteAddr is rwc.RemoteAddr().String(). See note in net/http/server.go. 58 | remoteAddr string 59 | 60 | // replies 61 | replies chan RPCReply 62 | 63 | // dead is set to true when we finish reading packets. 64 | dead bool 65 | } 66 | 67 | func NewListener(nsCreator NsCreator, opts ...ListenerOpt) (*Listener, error) { 68 | l := &Listener{ 69 | nsCreator: nsCreator, 70 | } 71 | 72 | for _, o := range opts { 73 | if err := o(l); err != nil { 74 | return nil, err 75 | } 76 | } 77 | 78 | return l, nil 79 | } 80 | 81 | func (l *Listener) newConn(rwc net.Conn) (*conn, error) { 82 | ns := l.nsCreator() 83 | server := &Server{NS: ns, D: Dispatch} 84 | 85 | c := &conn{ 86 | server: server, 87 | listener: l, 88 | rwc: rwc, 89 | replies: make(chan RPCReply, NumTags), 90 | } 91 | 92 | return c, nil 93 | } 94 | 95 | // trackListener from http.Server 96 | func (l *Listener) trackListener(ln net.Listener, add bool) { 97 | l.mu.Lock() 98 | defer l.mu.Unlock() 99 | 100 | if l.listeners == nil { 101 | l.listeners = make(map[net.Listener]struct{}) 102 | } 103 | 104 | if add { 105 | l.listeners[ln] = struct{}{} 106 | } else { 107 | delete(l.listeners, ln) 108 | } 109 | } 110 | 111 | // closeListenersLocked from http.Server 112 | func (l *Listener) closeListenersLocked() error { 113 | var err error 114 | for ln := range l.listeners { 115 | if cerr := ln.Close(); cerr != nil && err == nil { 116 | err = cerr 117 | } 118 | delete(l.listeners, ln) 119 | } 120 | return err 121 | } 122 | 123 | // Serve accepts incoming connections on the Listener and calls e.Accept on 124 | // each connection. 125 | func (l *Listener) Serve(ln net.Listener) error { 126 | defer ln.Close() 127 | 128 | var tempDelay time.Duration // how long to sleep on accept failure 129 | 130 | l.trackListener(ln, true) 131 | defer l.trackListener(ln, false) 132 | 133 | // from http.Server.Serve 134 | for { 135 | conn, err := ln.Accept() 136 | if err != nil { 137 | if ne, ok := err.(net.Error); ok && ne.Temporary() { 138 | if tempDelay == 0 { 139 | tempDelay = 5 * time.Millisecond 140 | } else { 141 | tempDelay *= 2 142 | } 143 | if max := 1 * time.Second; tempDelay > max { 144 | tempDelay = max 145 | } 146 | l.logf("ufs: Accept error: %v; retrying in %v", err, tempDelay) 147 | time.Sleep(tempDelay) 148 | continue 149 | } 150 | return err 151 | } 152 | tempDelay = 0 153 | 154 | if err := l.Accept(conn); err != nil { 155 | return err 156 | } 157 | } 158 | } 159 | 160 | // Accept a new connection, typically called via Serve but may be called 161 | // directly if there's a connection from an exotic listener. 162 | func (l *Listener) Accept(conn net.Conn) error { 163 | c, err := l.newConn(conn) 164 | if err != nil { 165 | return err 166 | } 167 | 168 | go c.serve() 169 | return nil 170 | } 171 | 172 | // Shutdown closes all active listeners. It does not close all active 173 | // connections but probably should. 174 | func (l *Listener) Shutdown() error { 175 | l.mu.Lock() 176 | defer l.mu.Unlock() 177 | 178 | return l.closeListenersLocked() 179 | } 180 | 181 | func (l *Listener) String() string { 182 | // TODO 183 | return "" 184 | } 185 | 186 | func (l *Listener) logf(format string, args ...interface{}) { 187 | if l.Trace != nil { 188 | l.Trace(format, args...) 189 | } 190 | } 191 | 192 | func (c *conn) String() string { 193 | return fmt.Sprintf("Dead %v %d replies pending", c.dead, len(c.replies)) 194 | } 195 | 196 | func (c *conn) logf(format string, args ...interface{}) { 197 | // prepend some info about the conn 198 | c.listener.logf("[%v] "+format, append([]interface{}{c.remoteAddr}, args...)...) 199 | } 200 | 201 | func (c *conn) serve() { 202 | if c.rwc == nil { 203 | c.dead = true 204 | return 205 | } 206 | 207 | c.remoteAddr = c.rwc.RemoteAddr().String() 208 | 209 | defer c.rwc.Close() 210 | 211 | c.logf("Starting readNetPackets") 212 | 213 | for !c.dead { 214 | l := make([]byte, 7) 215 | if n, err := c.rwc.Read(l); err != nil || n < 7 { 216 | c.logf("readNetPackets: short read: %v", err) 217 | c.dead = true 218 | return 219 | } 220 | sz := int64(l[0]) + int64(l[1])<<8 + int64(l[2])<<16 + int64(l[3])<<24 221 | t := MType(l[4]) 222 | b := bytes.NewBuffer(l[5:]) 223 | r := io.LimitReader(c.rwc, sz-7) 224 | if _, err := io.Copy(b, r); err != nil { 225 | c.logf("readNetPackets: short read: %v", err) 226 | c.dead = true 227 | return 228 | } 229 | c.logf("readNetPackets: got %v, len %d, sending to IO", RPCNames[MType(l[4])], b.Len()) 230 | //panic(fmt.Sprintf("packet is %v", b.Bytes()[:])) 231 | //panic(fmt.Sprintf("s is %v", s)) 232 | if err := c.server.D(c.server, b, t); err != nil { 233 | c.logf("%v: %v", RPCNames[MType(l[4])], err) 234 | } 235 | c.logf("readNetPackets: Write %v back", b) 236 | amt, err := c.rwc.Write(b.Bytes()) 237 | if err != nil { 238 | c.logf("readNetPackets: write error: %v", err) 239 | c.dead = true 240 | return 241 | } 242 | c.logf("Returned %v amt %v", b, amt) 243 | } 244 | } 245 | 246 | // Dispatch dispatches request to different functions. 247 | // It's also the the first place we try to establish server semantics. 248 | // We could do this with interface assertions and such a la rsc/fuse 249 | // but most people I talked do disliked that. So we don't. If you want 250 | // to make things optional, just define the ones you want to implement in this case. 251 | func Dispatch(s *Server, b *bytes.Buffer, t MType) error { 252 | switch t { 253 | case Tversion: 254 | s.Versioned = true 255 | default: 256 | if !s.Versioned { 257 | m := fmt.Sprintf("Dispatch: %v not allowed before Tversion", RPCNames[t]) 258 | // Yuck. Provide helper. 259 | d := b.Bytes() 260 | MarshalRerrorPkt(b, Tag(d[0])|Tag(d[1])<<8, m) 261 | return fmt.Errorf("Dispatch: %v not allowed before Tversion", RPCNames[t]) 262 | } 263 | } 264 | 265 | switch t { 266 | case Tversion: 267 | return s.SrvRversion(b) 268 | case Tattach: 269 | return s.SrvRattach(b) 270 | case Tflush: 271 | return s.SrvRflush(b) 272 | case Twalk: 273 | return s.SrvRwalk(b) 274 | case Topen: 275 | return s.SrvRopen(b) 276 | case Tcreate: 277 | return s.SrvRcreate(b) 278 | case Tclunk: 279 | return s.SrvRclunk(b) 280 | case Tstat: 281 | return s.SrvRstat(b) 282 | case Twstat: 283 | return s.SrvRwstat(b) 284 | case Tremove: 285 | return s.SrvRremove(b) 286 | case Tread: 287 | return s.SrvRread(b) 288 | case Twrite: 289 | return s.SrvRwrite(b) 290 | } 291 | 292 | // This has been tested by removing Attach from the switch. 293 | ServerError(b, fmt.Sprintf("Dispatch: %v not supported", RPCNames[t])) 294 | return nil 295 | } 296 | -------------------------------------------------------------------------------- /protocol/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Ninep 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 | package protocol 6 | 7 | 8 | // A File is defined by a QID. File Servers never see a FID. 9 | // There are two channels. The first is for normal requests. 10 | // The second is for Flushes. File server code always 11 | // checks the flush channel first. At the same time, server code 12 | // puts the flush into both channels, so the server code has some 13 | // idea when the flush entered the queue. This is very similar 14 | // to how MSI-X works on PCIe ... 15 | type File struct { 16 | } 17 | 18 | /* 19 | // A FileOp is a function to call, an abort channel, and a reply channel 20 | type FileOp struct { 21 | f func() error 22 | abort chan abort 23 | reply chan 24 | } 25 | */ 26 | 27 | // A service is a closure which returns an error or nil. 28 | // It writes its result down the provided channel. 29 | // It looks for flushes on the flushchan before doing its 30 | // function, and will respond to all flushes while any are pending. 31 | type Service func(func() error, chan FID) 32 | 33 | // Server maintains file system server state. This is inclusive of RPC 34 | // server state plus more. In our case when we walk to a fid we kick 35 | // off a goroutine to manage it. As a result we need a map of Tag to FID 36 | // so we know what to do about Tflush. 37 | type FileServer struct { 38 | Server 39 | Versioned bool 40 | } 41 | --------------------------------------------------------------------------------