226 lines
3.8 KiB
Go
226 lines
3.8 KiB
Go
// Copyright 2009 The Go9p Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package go9p
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// Creates a Fcall value from the on-the-wire representation. If
|
|
// dotu is true, reads 9P2000.u messages. Returns the unpacked message,
|
|
// error and how many bytes from the buffer were used by the message.
|
|
func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
|
|
var m uint16
|
|
|
|
if len(buf) < 7 {
|
|
return nil, &Error{"buffer too short", EINVAL}, 0
|
|
}
|
|
|
|
fc = new(Fcall)
|
|
fc.Fid = NOFID
|
|
fc.Afid = NOFID
|
|
fc.Newfid = NOFID
|
|
|
|
p := buf
|
|
fc.Size, p = gint32(p)
|
|
fc.Type, p = gint8(p)
|
|
fc.Tag, p = gint16(p)
|
|
|
|
if int(fc.Size) > len(buf) || fc.Size < 7 {
|
|
return nil, &Error{fmt.Sprintf("buffer too short: %d expected %d",
|
|
len(buf), fc.Size),
|
|
EINVAL},
|
|
0
|
|
}
|
|
|
|
p = p[0 : fc.Size-7]
|
|
fc.Pkt = buf[0:fc.Size]
|
|
fcsz = int(fc.Size)
|
|
if fc.Type < Tversion || fc.Type >= Tlast {
|
|
return nil, &Error{"invalid id", EINVAL}, 0
|
|
}
|
|
|
|
var sz uint32
|
|
if dotu {
|
|
sz = minFcsize[fc.Type-Tversion]
|
|
} else {
|
|
sz = minFcusize[fc.Type-Tversion]
|
|
}
|
|
|
|
if fc.Size < sz {
|
|
goto szerror
|
|
}
|
|
|
|
err = nil
|
|
switch fc.Type {
|
|
default:
|
|
return nil, &Error{"invalid message id", EINVAL}, 0
|
|
|
|
case Tversion, Rversion:
|
|
fc.Msize, p = gint32(p)
|
|
fc.Version, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
|
|
case Tauth:
|
|
fc.Afid, p = gint32(p)
|
|
fc.Uname, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
|
|
fc.Aname, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
|
|
if dotu {
|
|
if len(p) > 0 {
|
|
fc.Unamenum, p = gint32(p)
|
|
} else {
|
|
fc.Unamenum = NOUID
|
|
}
|
|
} else {
|
|
fc.Unamenum = NOUID
|
|
}
|
|
|
|
case Rauth, Rattach:
|
|
p = gqid(p, &fc.Qid)
|
|
|
|
case Tflush:
|
|
fc.Oldtag, p = gint16(p)
|
|
|
|
case Tattach:
|
|
fc.Fid, p = gint32(p)
|
|
fc.Afid, p = gint32(p)
|
|
fc.Uname, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
|
|
fc.Aname, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
|
|
if dotu {
|
|
if len(p) > 0 {
|
|
fc.Unamenum, p = gint32(p)
|
|
} else {
|
|
fc.Unamenum = NOUID
|
|
}
|
|
}
|
|
|
|
case Rerror:
|
|
fc.Error, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
if dotu {
|
|
fc.Errornum, p = gint32(p)
|
|
} else {
|
|
fc.Errornum = 0
|
|
}
|
|
|
|
case Twalk:
|
|
fc.Fid, p = gint32(p)
|
|
fc.Newfid, p = gint32(p)
|
|
m, p = gint16(p)
|
|
fc.Wname = make([]string, m)
|
|
for i := 0; i < int(m); i++ {
|
|
fc.Wname[i], p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
}
|
|
|
|
case Rwalk:
|
|
m, p = gint16(p)
|
|
fc.Wqid = make([]Qid, m)
|
|
for i := 0; i < int(m); i++ {
|
|
p = gqid(p, &fc.Wqid[i])
|
|
}
|
|
|
|
case Topen:
|
|
fc.Fid, p = gint32(p)
|
|
fc.Mode, p = gint8(p)
|
|
|
|
case Ropen, Rcreate:
|
|
p = gqid(p, &fc.Qid)
|
|
fc.Iounit, p = gint32(p)
|
|
|
|
case Tcreate:
|
|
fc.Fid, p = gint32(p)
|
|
fc.Name, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
fc.Perm, p = gint32(p)
|
|
fc.Mode, p = gint8(p)
|
|
if dotu {
|
|
fc.Ext, p = gstr(p)
|
|
if p == nil {
|
|
goto szerror
|
|
}
|
|
}
|
|
|
|
case Tread:
|
|
fc.Fid, p = gint32(p)
|
|
fc.Offset, p = gint64(p)
|
|
fc.Count, p = gint32(p)
|
|
|
|
case Rread:
|
|
fc.Count, p = gint32(p)
|
|
if len(p) < int(fc.Count) {
|
|
goto szerror
|
|
}
|
|
fc.Data = p
|
|
p = p[fc.Count:]
|
|
|
|
case Twrite:
|
|
fc.Fid, p = gint32(p)
|
|
fc.Offset, p = gint64(p)
|
|
fc.Count, p = gint32(p)
|
|
if len(p) != int(fc.Count) {
|
|
fc.Data = make([]byte, fc.Count)
|
|
copy(fc.Data, p)
|
|
p = p[len(p):]
|
|
} else {
|
|
fc.Data = p
|
|
p = p[fc.Count:]
|
|
}
|
|
|
|
case Rwrite:
|
|
fc.Count, p = gint32(p)
|
|
|
|
case Tclunk, Tremove, Tstat:
|
|
fc.Fid, p = gint32(p)
|
|
|
|
case Rstat:
|
|
m, p = gint16(p)
|
|
p, err = gstat(p, &fc.Dir, dotu)
|
|
if err != nil {
|
|
return nil, err, 0
|
|
}
|
|
|
|
case Twstat:
|
|
fc.Fid, p = gint32(p)
|
|
m, p = gint16(p)
|
|
p, _ = gstat(p, &fc.Dir, dotu)
|
|
|
|
case Rflush, Rclunk, Rremove, Rwstat:
|
|
}
|
|
|
|
if len(p) > 0 {
|
|
goto szerror
|
|
}
|
|
|
|
return //NOSONAR
|
|
|
|
szerror:
|
|
return nil, &Error{"invalid size", EINVAL}, 0
|
|
}
|