Gibheer
fa05045d31
This is the import from the separate monfront repository. The history could not be imported, but this should suffice.
213 lines
5.6 KiB
Go
213 lines
5.6 KiB
Go
// Copyright 2012 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Plan 9 directory marshalling. See intro(5).
|
|
|
|
package plan9
|
|
|
|
import "errors"
|
|
|
|
var (
|
|
ErrShortStat = errors.New("stat buffer too short")
|
|
ErrBadStat = errors.New("malformed stat buffer")
|
|
ErrBadName = errors.New("bad character in file name")
|
|
)
|
|
|
|
// A Qid represents a 9P server's unique identification for a file.
|
|
type Qid struct {
|
|
Path uint64 // the file server's unique identification for the file
|
|
Vers uint32 // version number for given Path
|
|
Type uint8 // the type of the file (plan9.QTDIR for example)
|
|
}
|
|
|
|
// A Dir contains the metadata for a file.
|
|
type Dir struct {
|
|
// system-modified data
|
|
Type uint16 // server type
|
|
Dev uint32 // server subtype
|
|
|
|
// file data
|
|
Qid Qid // unique id from server
|
|
Mode uint32 // permissions
|
|
Atime uint32 // last read time
|
|
Mtime uint32 // last write time
|
|
Length int64 // file length
|
|
Name string // last element of path
|
|
Uid string // owner name
|
|
Gid string // group name
|
|
Muid string // last modifier name
|
|
}
|
|
|
|
var nullDir = Dir{
|
|
Type: ^uint16(0),
|
|
Dev: ^uint32(0),
|
|
Qid: Qid{
|
|
Path: ^uint64(0),
|
|
Vers: ^uint32(0),
|
|
Type: ^uint8(0),
|
|
},
|
|
Mode: ^uint32(0),
|
|
Atime: ^uint32(0),
|
|
Mtime: ^uint32(0),
|
|
Length: ^int64(0),
|
|
}
|
|
|
|
// Null assigns special "don't touch" values to members of d to
|
|
// avoid modifying them during plan9.Wstat.
|
|
func (d *Dir) Null() { *d = nullDir }
|
|
|
|
// Marshal encodes a 9P stat message corresponding to d into b
|
|
//
|
|
// If there isn't enough space in b for a stat message, ErrShortStat is returned.
|
|
func (d *Dir) Marshal(b []byte) (n int, err error) {
|
|
n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
|
|
if n > len(b) {
|
|
return n, ErrShortStat
|
|
}
|
|
|
|
for _, c := range d.Name {
|
|
if c == '/' {
|
|
return n, ErrBadName
|
|
}
|
|
}
|
|
|
|
b = pbit16(b, uint16(n)-2)
|
|
b = pbit16(b, d.Type)
|
|
b = pbit32(b, d.Dev)
|
|
b = pbit8(b, d.Qid.Type)
|
|
b = pbit32(b, d.Qid.Vers)
|
|
b = pbit64(b, d.Qid.Path)
|
|
b = pbit32(b, d.Mode)
|
|
b = pbit32(b, d.Atime)
|
|
b = pbit32(b, d.Mtime)
|
|
b = pbit64(b, uint64(d.Length))
|
|
b = pstring(b, d.Name)
|
|
b = pstring(b, d.Uid)
|
|
b = pstring(b, d.Gid)
|
|
b = pstring(b, d.Muid)
|
|
|
|
return n, nil
|
|
}
|
|
|
|
// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
|
|
//
|
|
// If b is too small to hold a valid stat message, ErrShortStat is returned.
|
|
//
|
|
// If the stat message itself is invalid, ErrBadStat is returned.
|
|
func UnmarshalDir(b []byte) (*Dir, error) {
|
|
if len(b) < STATFIXLEN {
|
|
return nil, ErrShortStat
|
|
}
|
|
size, buf := gbit16(b)
|
|
if len(b) != int(size)+2 {
|
|
return nil, ErrBadStat
|
|
}
|
|
b = buf
|
|
|
|
var d Dir
|
|
d.Type, b = gbit16(b)
|
|
d.Dev, b = gbit32(b)
|
|
d.Qid.Type, b = gbit8(b)
|
|
d.Qid.Vers, b = gbit32(b)
|
|
d.Qid.Path, b = gbit64(b)
|
|
d.Mode, b = gbit32(b)
|
|
d.Atime, b = gbit32(b)
|
|
d.Mtime, b = gbit32(b)
|
|
|
|
n, b := gbit64(b)
|
|
d.Length = int64(n)
|
|
|
|
var ok bool
|
|
if d.Name, b, ok = gstring(b); !ok {
|
|
return nil, ErrBadStat
|
|
}
|
|
if d.Uid, b, ok = gstring(b); !ok {
|
|
return nil, ErrBadStat
|
|
}
|
|
if d.Gid, b, ok = gstring(b); !ok {
|
|
return nil, ErrBadStat
|
|
}
|
|
if d.Muid, b, ok = gstring(b); !ok {
|
|
return nil, ErrBadStat
|
|
}
|
|
|
|
return &d, nil
|
|
}
|
|
|
|
// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
|
|
func pbit8(b []byte, v uint8) []byte {
|
|
b[0] = byte(v)
|
|
return b[1:]
|
|
}
|
|
|
|
// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
|
|
func pbit16(b []byte, v uint16) []byte {
|
|
b[0] = byte(v)
|
|
b[1] = byte(v >> 8)
|
|
return b[2:]
|
|
}
|
|
|
|
// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
|
|
func pbit32(b []byte, v uint32) []byte {
|
|
b[0] = byte(v)
|
|
b[1] = byte(v >> 8)
|
|
b[2] = byte(v >> 16)
|
|
b[3] = byte(v >> 24)
|
|
return b[4:]
|
|
}
|
|
|
|
// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
|
|
func pbit64(b []byte, v uint64) []byte {
|
|
b[0] = byte(v)
|
|
b[1] = byte(v >> 8)
|
|
b[2] = byte(v >> 16)
|
|
b[3] = byte(v >> 24)
|
|
b[4] = byte(v >> 32)
|
|
b[5] = byte(v >> 40)
|
|
b[6] = byte(v >> 48)
|
|
b[7] = byte(v >> 56)
|
|
return b[8:]
|
|
}
|
|
|
|
// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
|
|
// returning the remaining slice of b..
|
|
func pstring(b []byte, s string) []byte {
|
|
b = pbit16(b, uint16(len(s)))
|
|
n := copy(b, s)
|
|
return b[n:]
|
|
}
|
|
|
|
// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
|
|
func gbit8(b []byte) (uint8, []byte) {
|
|
return uint8(b[0]), b[1:]
|
|
}
|
|
|
|
// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
|
|
func gbit16(b []byte) (uint16, []byte) {
|
|
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
|
|
}
|
|
|
|
// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
|
|
func gbit32(b []byte) (uint32, []byte) {
|
|
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
|
|
}
|
|
|
|
// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
|
|
func gbit64(b []byte) (uint64, []byte) {
|
|
lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
|
hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
|
|
return uint64(lo) | uint64(hi)<<32, b[8:]
|
|
}
|
|
|
|
// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
|
|
// It returns the string with the remaining slice of b and a boolean. If the length is
|
|
// greater than the number of bytes in b, the boolean will be false.
|
|
func gstring(b []byte) (string, []byte, bool) {
|
|
n, b := gbit16(b)
|
|
if int(n) > len(b) {
|
|
return "", b, false
|
|
}
|
|
return string(b[:n]), b[n:], true
|
|
}
|