minikube/third_party/go9p/unpack.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
}