Update mount implementation, add mount integration tests, and check that path exists.

pull/1293/head
Aaron Prindle 2017-03-23 08:26:21 -07:00
parent 12e41aeaba
commit 8e801e3975
60 changed files with 1602 additions and 2610 deletions

View File

@ -26,7 +26,7 @@ import (
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/third_party/go9p/p/srv/examples/ufs"
"k8s.io/minikube/third_party/go9p/ufs"
)
// mountCmd represents the mount command
@ -42,6 +42,15 @@ var mountCmd = &cobra.Command{
fmt.Fprintln(os.Stderr, errText)
os.Exit(1)
}
if _, err := os.Stat(args[0]); err != nil {
if os.IsNotExist(err) {
errText := fmt.Sprintf("Cannot find directory %s for mount", args[0])
fmt.Fprintln(os.Stderr, errText)
} else {
errText := fmt.Sprintf("Error accesssing directory %s for mount", args[0])
fmt.Fprintln(os.Stderr, errText)
}
}
var debugVal int
if glog.V(1) {
debugVal = 1 // ufs.StartServer takes int debug param

View File

@ -30,6 +30,7 @@ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH} out/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH} out/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox.yaml testdata/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/pvc.yaml testdata/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox-mount-test.yaml testdata/
# Set the executable bit on the e2e binary and out binary
chmod +x out/e2e-${OS_ARCH}
@ -63,4 +64,4 @@ curl "https://api.github.com/repos/kubernetes/minikube/statuses/${COMMIT}?access
-d "{\"state\": \"$status\", \"description\": \"Jenkins\", \"target_url\": \"$target_url\", \"context\": \"${JOB_NAME}\"}"
set -x
exit $result
exit $result

View File

@ -408,6 +408,7 @@ func Mount9pHost(api libmachine.API) error {
if err != nil {
return errors.Wrap(err, "Error getting the host IP address to use from within the VM")
}
host.RunSSHCommand(GetMount9pCleanupCommand())
_, err = host.RunSSHCommand(GetMount9pCommand(ip))
if err != nil {
return err

View File

@ -77,7 +77,7 @@ func getVMHostIP(host *host.Host) (net.IP, error) {
case "virtualbox":
return net.ParseIP("10.0.2.2"), nil
case "xhyve":
return net.ParseIP("10.0.2.2"), nil
return net.ParseIP("192.168.64.1"), nil
default:
return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver")
}

View File

@ -154,7 +154,7 @@ func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) {
flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates)
}
if kubernetesConfig.APIServerName != "" {
if kubernetesConfig.APIServerName != constants.APIServerName {
flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName)
}
@ -226,9 +226,16 @@ else
fi
`, constants.LocalkubePIDPath)
func GetMount9pCleanupCommand() string {
return `
sudo umount /mount-9p;
sudo rm -rf /mount-9p;
`
}
func GetMount9pCommand(ip net.IP) string {
return fmt.Sprintf(`
sudo mkdir /mount-9p;
sudo mount -t 9p -o trans=tcp -o port=5640 %s /mount-9p;
sudo mount -t 9p -o trans=tcp -o port=5640 -o uid=1001 -o gid=1001 %s /mount-9p;
sudo chmod 775 /mount-9p;`, ip)
}

View File

@ -41,4 +41,5 @@ func TestFunctional(t *testing.T) {
t.Run("Dashboard", testDashboard)
t.Run("ServicesList", testServicesList)
t.Run("Provisioning", testProvisioning)
t.Run("Mounting", testMounting)
}

View File

@ -0,0 +1,112 @@
// +build integration
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package integration
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
"k8s.io/kubernetes/pkg/api"
commonutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/test/integration/util"
)
func testMounting(t *testing.T) {
t.Parallel()
minikubeRunner := util.MinikubeRunner{
Args: *args,
BinaryPath: *binaryPath,
T: t}
tempDir, err := ioutil.TempDir("", "mounttest")
if err != nil {
t.Fatalf("Unexpected error while creating tempDir: %s", err)
}
defer os.RemoveAll(tempDir)
mountCmd := fmt.Sprintf("mount %s", tempDir)
cmd := minikubeRunner.RunDaemon(mountCmd)
defer cmd.Process.Kill()
kubectlRunner := util.NewKubectlRunner(t)
podName := "busybox"
podPath, _ := filepath.Abs("testdata/busybox-mount-test.yaml")
// Write file in mounted dir from host
expected := "test\n"
files := []string{"fromhost", "fromhostremove"}
for _, file := range files {
path := filepath.Join(tempDir, file)
err = ioutil.WriteFile(path, []byte(expected), 0644)
if err != nil {
t.Fatalf("Unexpected error while writing file %s: %s.", path, err)
}
}
mountTest := func() error {
if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil {
return err
}
defer kubectlRunner.RunCommand([]string{"delete", "-f", podPath})
p := &api.Pod{}
for p.Status.Phase != "Running" {
p = kubectlRunner.GetPod(podName, "default")
}
path := filepath.Join(tempDir, "frompod")
out, err := ioutil.ReadFile(path)
if err != nil {
return &commonutil.RetriableError{Err: err}
}
// test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod
if string(out) != expected {
t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
}
// test that file written from host was read in by the pod via cat /mount-9p/fromhost;
if out, err = kubectlRunner.RunCommand([]string{"logs", podName}); err != nil {
return &commonutil.RetriableError{Err: err}
}
if string(out) != expected {
t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
}
// test that fromhostremove was deleted by the pod from the mount via rm /mount-9p/fromhostremove
path = filepath.Join(tempDir, "fromhostremove")
if _, err := os.Stat(path); err == nil {
t.Fatalf("Expected file %s to be removed", path, expected, out)
}
// test that frompodremove can be deleted on the host
path = filepath.Join(tempDir, "frompodremove")
if err := os.Remove(path); err != nil {
t.Fatalf("Unexpected error removing file %s: %s", path, err)
}
return nil
}
if err := commonutil.RetryAfter(40, mountTest, 5*time.Second); err != nil {
t.Fatal("mountTest failed with error:", err)
}
}

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: busybox
spec:
containers:
- image: busybox:glibc
command: [ "/bin/sh", "-c", "--" ]
args: [ "cat /mount-9p/fromhost; echo test > /mount-9p/frompod; rm /mount-9p/fromhostremove; echo test > /mount-9p/frompodremove;" ]
name: busybox
volumeMounts:
- mountPath: /mount-9p
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /mount-9p

View File

@ -69,6 +69,17 @@ func (m *MinikubeRunner) RunCommand(command string, checkError bool) string {
return string(stdout)
}
func (m *MinikubeRunner) RunDaemon(command string) *exec.Cmd {
commandArr := strings.Split(command, " ")
path, _ := filepath.Abs(m.BinaryPath)
cmd := exec.Command(path, commandArr...)
err := cmd.Start()
if err != nil {
m.T.Fatalf("Error running command: %s %s", command, err)
}
return cmd
}
func (m *MinikubeRunner) SSH(command string) (string, error) {
path, _ := filepath.Abs(m.BinaryPath)
cmd := exec.Command(path, "ssh", command)

2
third_party/go9p/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.orig
*.rej

View File

@ -1,13 +0,0 @@
# This is the official list of Go9p authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Andrey Mirtchovski <mirtchovski@gmail.com>
Latchesar Ionkov <lionkov@gmail.com>
Roger Peppe <rogpeppe@gmail.com>

View File

@ -1,18 +0,0 @@
# This is the official list of people who can contribute
# (and typically have contributed) code to the Go9p repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# The submission process automatically checks to make sure
# that people submitting code are listed in this file (by email address).
# XXX more bumph here?
# Names should be added to this file like so:
# Name <email address>
# Please keep the list sorted.
Andrey Mirtchovski <mirtchovski@gmail.com>
Latchesar Ionkov <lionkov@gmail.com>
Akshat Kumar <seed@mail.nanosouffle.net>
Roger Peppe <rogpeppe@gmail.com>

11
third_party/go9p/README.md vendored Normal file
View File

@ -0,0 +1,11 @@
This is go9p done in a way that I can understand.
To install:
export GOPATH=~rminnich/go
go get -a /k8s.io/minikube/third_party/go9p
go get -a /k8s.io/minikube/third_party/go9p/ufs
go install -a /k8s.io/minikube/third_party/go9p/ufs
~/go/bin/ufs

121
third_party/go9p/p/clnt/clnt.go → third_party/go9p/clnt_clnt.go vendored Executable file → Normal file
View File

@ -2,31 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The clnt package provides definitions and functions used to implement
// The clnt package go9provides definitions and functions used to implement
// a 9P2000 file client.
package clnt
package go9p
import (
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"log"
"net"
"sync"
"sync/atomic"
)
// Debug flags
const (
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr
DbgPrintPackets // print the raw packets on stderr
DbgLogFcalls // keep the last N 9P messages (can be accessed over http)
DbgLogPackets // keep the last N 9P messages (can be accessed over http)
)
type StatsOps interface {
statsRegister()
statsUnregister()
}
// The Clnt type represents a 9P2000 client. The client is connected to
// a 9P2000 file server and its methods can be used to access and manipulate
// the files exported by the server.
@ -37,7 +24,7 @@ type Clnt struct {
Dotu bool // If true, 9P2000.u protocol is spoken
Root *Fid // Fid that points to the rood directory
Id string // Used when printing debug messages
Log *p.Logger
Log *Logger
conn net.Conn
tagpool *pool
@ -49,7 +36,7 @@ type Clnt struct {
err error
reqchan chan *Req
tchan chan *p.Fcall
tchan chan *Fcall
next, prev *Clnt
}
@ -60,33 +47,26 @@ type Fid struct {
sync.Mutex
Clnt *Clnt // Client the fid belongs to
Iounit uint32
p.Qid // The Qid description for the file
Mode uint8 // Open mode (one of p.O* values) (if file is open)
Qid // The Qid description for the file
Mode uint8 // Open mode (one of O* values) (if file is open)
Fid uint32 // Fid number
p.User // The user the fid belongs to
User // The user the fid belongs to
walked bool // true if the fid points to a walked file on the server
}
// The file is similar to the Fid, but is used in the high-level client
// interface.
// interface. We expose the Fid so that client code can use Remove
// on a fid, the same way a kernel can.
type File struct {
fid *Fid
Fid *Fid
offset uint64
}
type pool struct {
sync.Mutex
need int
nchan chan uint32
maxid uint32
imap []byte
}
type Req struct {
sync.Mutex
Clnt *Clnt
Tc *p.Fcall
Rc *p.Fcall
Tc *Fcall
Rc *Fcall
Err error
Done chan *Req
tag uint16
@ -101,18 +81,18 @@ type ClntList struct {
var clnts *ClntList
var DefaultDebuglevel int
var DefaultLogger *p.Logger
var DefaultLogger *Logger
func (clnt *Clnt) Rpcnb(r *Req) error {
var tag uint16
if r.Tc.Type == p.Tversion {
tag = p.NOTAG
if r.Tc.Type == Tversion {
tag = NOTAG
} else {
tag = r.tag
}
p.SetTag(r.Tc, tag)
SetTag(r.Tc, tag)
clnt.Lock()
if clnt.err != nil {
clnt.Unlock()
@ -133,7 +113,7 @@ func (clnt *Clnt) Rpcnb(r *Req) error {
return nil
}
func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
func (clnt *Clnt) Rpc(tc *Fcall) (rc *Fcall, err error) {
r := clnt.ReqAlloc()
r.Tc = tc
r.Done = make(chan *Req)
@ -151,13 +131,15 @@ func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
func (clnt *Clnt) recv() {
var err error
var buf []byte
err = nil
buf := make([]byte, clnt.Msize*8)
pos := 0
for {
if len(buf) < int(clnt.Msize) {
b := make([]byte, clnt.Msize*8)
// Connect can change the client Msize.
clntmsize := int(atomic.LoadUint32(&clnt.Msize))
if len(buf) < clntmsize {
b := make([]byte, clntmsize*8)
copy(b, buf[0:pos])
buf = b
b = nil
@ -165,7 +147,7 @@ func (clnt *Clnt) recv() {
n, oerr := clnt.conn.Read(buf[pos:])
if oerr != nil || n == 0 {
err = &p.Error{oerr.Error(), p.EIO}
err = &Error{oerr.Error(), EIO}
clnt.Lock()
clnt.err = err
clnt.Unlock()
@ -174,10 +156,10 @@ func (clnt *Clnt) recv() {
pos += n
for pos > 4 {
sz, _ := p.Gint32(buf)
sz, _ := Gint32(buf)
if pos < int(sz) {
if len(buf) < int(sz) {
b := make([]byte, clnt.Msize*8)
b := make([]byte, atomic.LoadUint32(&clnt.Msize)*8)
copy(b, buf[0:pos])
buf = b
b = nil
@ -186,7 +168,7 @@ func (clnt *Clnt) recv() {
break
}
fc, err, fcsize := p.Unpack(buf, clnt.Dotu)
fc, err, fcsize := Unpack(buf, clnt.Dotu)
clnt.Lock()
if err != nil {
clnt.err = err
@ -214,7 +196,7 @@ func (clnt *Clnt) recv() {
}
if r == nil {
clnt.err = &p.Error{"unexpected response", p.EINVAL}
clnt.err = &Error{"unexpected response", EINVAL}
clnt.conn.Close()
clnt.Unlock()
goto closed
@ -235,13 +217,13 @@ func (clnt *Clnt) recv() {
clnt.Unlock()
if r.Tc.Type != r.Rc.Type-1 {
if r.Rc.Type != p.Rerror {
r.Err = &p.Error{"invalid response", p.EINVAL}
if r.Rc.Type != Rerror {
r.Err = &Error{"invalid response", EINVAL}
log.Println(fmt.Sprintf("TTT %v", r.Tc))
log.Println(fmt.Sprintf("RRR %v", r.Rc))
} else {
if r.Err == nil {
r.Err = &p.Error{r.Rc.Error, r.Rc.Errornum}
r.Err = &Error{r.Rc.Error, r.Rc.Errornum}
}
}
}
@ -335,12 +317,12 @@ func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt {
clnt.Debuglevel = DefaultDebuglevel
clnt.Log = DefaultLogger
clnt.Id = c.RemoteAddr().String() + ":"
clnt.tagpool = newPool(uint32(p.NOTAG))
clnt.fidpool = newPool(p.NOFID)
clnt.tagpool = newPool(uint32(NOTAG))
clnt.fidpool = newPool(NOFID)
clnt.reqout = make(chan *Req)
clnt.done = make(chan bool)
clnt.reqchan = make(chan *Req, 16)
clnt.tchan = make(chan *p.Fcall, 16)
clnt.tchan = make(chan *Fcall, 16)
go clnt.recv()
go clnt.send()
@ -373,8 +355,9 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
ver = "9P2000.u"
}
tc := p.NewFcall(clnt.Msize)
err := p.PackTversion(tc, clnt.Msize, ver)
clntmsize := atomic.LoadUint32(&clnt.Msize)
tc := NewFcall(clntmsize)
err := PackTversion(tc, clntmsize, ver)
if err != nil {
return nil, err
}
@ -384,8 +367,8 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
return nil, err
}
if rc.Msize < clnt.Msize {
clnt.Msize = rc.Msize
if rc.Msize < atomic.LoadUint32(&clnt.Msize) {
atomic.StoreUint32(&clnt.Msize, rc.Msize)
}
clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
@ -401,17 +384,17 @@ func (clnt *Clnt) FidAlloc() *Fid {
return fid
}
func (clnt *Clnt) NewFcall() *p.Fcall {
func (clnt *Clnt) NewFcall() *Fcall {
select {
case tc := <-clnt.tchan:
return tc
default:
}
return p.NewFcall(clnt.Msize)
return NewFcall(atomic.LoadUint32(&clnt.Msize))
}
func (clnt *Clnt) FreeFcall(fc *p.Fcall) {
if fc != nil && len(fc.Buf) >= int(clnt.Msize) {
func (clnt *Clnt) FreeFcall(fc *Fcall) {
if fc != nil && len(fc.Buf) >= int(atomic.LoadUint32(&clnt.Msize)) {
select {
case clnt.tchan <- fc:
break
@ -450,15 +433,7 @@ func (clnt *Clnt) ReqFree(req *Req) {
}
}
func NewFile(f *Fid, offset uint64) *File {
return &File{f, offset}
}
func (f *File) Fid() *Fid {
return f.fid
}
func (clnt *Clnt) logFcall(fc *p.Fcall) {
func (clnt *Clnt) logFcall(fc *Fcall) {
if clnt.Debuglevel&DbgLogPackets != 0 {
pkt := make([]byte, len(fc.Pkt))
copy(pkt, fc.Pkt)
@ -466,13 +441,19 @@ func (clnt *Clnt) logFcall(fc *p.Fcall) {
}
if clnt.Debuglevel&DbgLogFcalls != 0 {
f := new(p.Fcall)
f := new(Fcall)
*f = *fc
f.Pkt = nil
clnt.Log.Log(f, clnt, DbgLogFcalls)
}
}
// FidFile returns a File that represents the given Fid, initially at the given
// offset.
func FidFile(fid *Fid, offset uint64) *File {
return &File{fid, offset}
}
func init() {
clnts = new(ClntList)
if sop, ok := (interface{}(clnts)).(StatsOps); ok {

View File

@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Clunks a fid. Returns nil if successful.
func (clnt *Clnt) Clunk(fid *Fid) (err error) {
err = nil
if fid.walked {
tc := clnt.NewFcall()
err := p.PackTclunk(tc, fid.Fid)
err := PackTclunk(tc, fid.Fid)
if err != nil {
return err
}
@ -21,12 +19,12 @@ func (clnt *Clnt) Clunk(fid *Fid) (err error) {
clnt.fidpool.putId(fid.Fid)
fid.walked = false
fid.Fid = p.NOFID
fid.Fid = NOFID
return
}
// Closes a file. Returns nil if successful.
func (file *File) Close() error {
// Should we cancel all pending requests for the File
return file.fid.Clnt.Clunk(file.fid)
return file.Fid.Clnt.Clunk(file.Fid)
}

View File

@ -2,19 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"net"
)
// Creates an authentication fid for the specified user. Returns the fid, if
// successful, or an Error.
func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
func (clnt *Clnt) Auth(user User, aname string) (*Fid, error) {
fid := clnt.FidAlloc()
tc := clnt.NewFcall()
err := p.PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
err := PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
if err != nil {
return nil, err
}
@ -24,7 +23,6 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
return nil, err
}
fid.Iounit = clnt.Msize - p.IOHDRSZ
fid.User = user
fid.walked = true
return fid, nil
@ -33,18 +31,18 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
// Creates a fid for the specified user that points to the root
// of the file server's file tree. Returns a Fid pointing to the root,
// if successful, or an Error.
func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) {
func (clnt *Clnt) Attach(afid *Fid, user User, aname string) (*Fid, error) {
var afno uint32
if afid != nil {
afno = afid.Fid
} else {
afno = p.NOFID
afno = NOFID
}
fid := clnt.FidAlloc()
tc := clnt.NewFcall()
err := p.PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
err := PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
if err != nil {
return nil, err
}
@ -61,17 +59,17 @@ func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) {
}
// Connects to a file server and attaches to it as the specified user.
func Mount(ntype, addr, aname string, user p.User) (*Clnt, error) {
func Mount(ntype, addr, aname string, msize uint32, user User) (*Clnt, error) {
c, e := net.Dial(ntype, addr)
if e != nil {
return nil, &p.Error{e.Error(), p.EIO}
return nil, &Error{e.Error(), EIO}
}
return MountConn(c, aname, user)
return MountConn(c, aname, msize, user)
}
func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
clnt, err := Connect(c, 8192+p.IOHDRSZ, true)
func MountConn(c net.Conn, aname string, msize uint32, user User) (*Clnt, error) {
clnt, err := Connect(c, msize+IOHDRSZ, true)
if err != nil {
return nil, err
}
@ -89,7 +87,7 @@ func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
// Closes the connection to the file sever.
func (clnt *Clnt) Unmount() {
clnt.Lock()
clnt.err = &p.Error{"connection closed", p.EIO}
clnt.err = &Error{"connection closed", EIO}
clnt.conn.Close()
clnt.Unlock()
}

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"strings"
)
@ -13,7 +12,7 @@ import (
// the operation is successful.
func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
tc := clnt.NewFcall()
err := p.PackTopen(tc, fid.Fid, mode)
err := PackTopen(tc, fid.Fid, mode)
if err != nil {
return err
}
@ -25,8 +24,8 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
fid.Qid = rc.Qid
fid.Iounit = rc.Iounit
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ {
fid.Iounit = clnt.Msize - p.IOHDRSZ
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
fid.Iounit = clnt.Msize - IOHDRSZ
}
fid.Mode = mode
return nil
@ -36,7 +35,7 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
// if the operation is successful.
func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
tc := clnt.NewFcall()
err := p.PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu)
err := PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu)
if err != nil {
return err
}
@ -48,8 +47,8 @@ func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext str
fid.Qid = rc.Qid
fid.Iounit = rc.Iounit
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ {
fid.Iounit = clnt.Msize - p.IOHDRSZ
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
fid.Iounit = clnt.Msize - IOHDRSZ
}
fid.Mode = mode
return nil

View File

@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import "sync"
var m2id = [...]uint8{
0, 1, 0, 2, 0, 1, 0, 3,
@ -39,6 +41,14 @@ var m2id = [...]uint8{
0, 1, 0, 2, 0, 1, 0, 0,
}
type pool struct {
sync.Mutex
need int
nchan chan uint32
maxid uint32
imap []byte
}
func newPool(maxid uint32) *pool {
p := new(pool)
p.maxid = maxid

View File

@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"io"
"k8s.io/minikube/third_party/go9p/p"
)
// Reads count bytes starting from offset from the file associated with the fid.
@ -18,7 +17,7 @@ func (clnt *Clnt) Read(fid *Fid, offset uint64, count uint32) ([]byte, error) {
}
tc := clnt.NewFcall()
err := p.PackTread(tc, fid.Fid, offset, count)
err := PackTread(tc, fid.Fid, offset, count)
if err != nil {
return nil, err
}
@ -45,7 +44,7 @@ func (file *File) Read(buf []byte) (int, error) {
// Reads up to len(buf) bytes from the file starting from offset.
// Returns the number of bytes read, or an Error.
func (file *File) ReadAt(buf []byte, offset int64) (int, error) {
b, err := file.fid.Clnt.Read(file.fid, uint64(offset), uint32(len(buf)))
b, err := file.Fid.Clnt.Read(file.Fid, uint64(offset), uint32(len(buf)))
if err != nil {
return 0, err
}
@ -85,10 +84,14 @@ func (file *File) Readn(buf []byte, offset uint64) (int, error) {
// Returns an array of maximum num entries (if num is 0, returns
// all entries from the directory). If the operation fails, returns
// an Error.
func (file *File) Readdir(num int) ([]*p.Dir, error) {
buf := make([]byte, file.fid.Clnt.Msize-p.IOHDRSZ)
dirs := make([]*p.Dir, 32)
func (file *File) Readdir(num int) ([]*Dir, error) {
buf := make([]byte, file.Fid.Clnt.Msize-IOHDRSZ)
dirs := make([]*Dir, 32)
pos := 0
offset := file.offset
defer func() {
file.offset = offset
}()
for {
n, err := file.Read(buf)
if err != nil && err != io.EOF {
@ -100,14 +103,20 @@ func (file *File) Readdir(num int) ([]*p.Dir, error) {
}
for b := buf[0:n]; len(b) > 0; {
d, perr := p.UnpackDir(b, file.fid.Clnt.Dotu)
d, _, _, perr := UnpackDir(b, file.Fid.Clnt.Dotu)
if perr != nil {
// If we have unpacked anything, it is almost certainly
// a too-short buffer. So return what we got.
if pos > 0 {
return dirs[0:pos], nil
}
return nil, perr
}
b = b[d.Size+2:]
offset += uint64(d.Size + 2)
if pos >= len(dirs) {
s := make([]*p.Dir, len(dirs)+32)
s := make([]*Dir, len(dirs)+32)
copy(s, dirs)
dirs = s
}

View File

@ -2,22 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Removes the file associated with the Fid. Returns nil if the
// operation is successful.
func (clnt *Clnt) Remove(fid *Fid) error {
tc := clnt.NewFcall()
err := p.PackTremove(tc, fid.Fid)
err := PackTremove(tc, fid.Fid)
if err != nil {
return err
}
_, err = clnt.Rpc(tc)
clnt.fidpool.putId(fid.Fid)
fid.Fid = p.NOFID
fid.Fid = NOFID
return err
}

View File

@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Returns the metadata for the file associated with the Fid, or an Error.
func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
func (clnt *Clnt) Stat(fid *Fid) (*Dir, error) {
tc := clnt.NewFcall()
err := p.PackTstat(tc, fid.Fid)
err := PackTstat(tc, fid.Fid)
if err != nil {
return nil, err
}
@ -23,7 +21,7 @@ func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
}
// Returns the metadata for a named file, or an Error.
func (clnt *Clnt) FStat(path string) (*p.Dir, error) {
func (clnt *Clnt) FStat(path string) (*Dir, error) {
fid, err := clnt.FWalk(path)
if err != nil {
return nil, err
@ -35,9 +33,9 @@ func (clnt *Clnt) FStat(path string) (*p.Dir, error) {
}
// Modifies the data of the file associated with the Fid, or an Error.
func (clnt *Clnt) Wstat(fid *Fid, dir *p.Dir) error {
func (clnt *Clnt) Wstat(fid *Fid, dir *Dir) error {
tc := clnt.NewFcall()
err := p.PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
err := PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
if err != nil {
return err
}

View File

@ -1,11 +1,10 @@
// +build httpstats
package clnt
package go9p
import (
"fmt"
"io"
"k8s.io/minikube/third_party/go9p/p"
"net/http"
)
@ -18,7 +17,7 @@ func (clnt *Clnt) ServeHTTP(c http.ResponseWriter, r *http.Request) {
fs := clnt.Log.Filter(clnt, DbgLogFcalls)
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
for _, l := range fs {
fc := l.Data.(*p.Fcall)
fc := l.Data.(*Fcall)
if fc.Type != 0 {
io.WriteString(c, fmt.Sprintf("<br>%s", fc))
}

View File

@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
type Tag struct {
clnt *Clnt
@ -54,22 +52,22 @@ func (tag *Tag) reqproc() {
case r := <-tag.respchan:
rc := r.Rc
fid := r.fid
err := r.Rc.Type == p.Rerror
err := r.Rc.Type == Rerror
switch r.Tc.Type {
case p.Tauth:
case Tauth:
if err {
fid.User = nil
}
case p.Tattach:
case Tattach:
if !err {
fid.Qid = rc.Qid
} else {
fid.User = nil
}
case p.Twalk:
case Twalk:
if !err {
fid.walked = true
if len(rc.Wqid) > 0 {
@ -79,8 +77,8 @@ func (tag *Tag) reqproc() {
fid.User = nil
}
case p.Topen:
case p.Tcreate:
case Topen:
case Tcreate:
if !err {
fid.Iounit = rc.Iounit
fid.Qid = rc.Qid
@ -88,8 +86,8 @@ func (tag *Tag) reqproc() {
fid.Mode = 0
}
case p.Tclunk:
case p.Tremove:
case Tclunk:
case Tremove:
tag.clnt.fidpool.putId(fid.Fid)
}
@ -98,10 +96,10 @@ func (tag *Tag) reqproc() {
}
}
func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
func (tag *Tag) Auth(afid *Fid, user User, aname string) error {
req := tag.reqAlloc()
req.fid = afid
err := p.PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
err := PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
if err != nil {
return err
}
@ -110,18 +108,18 @@ func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
return tag.clnt.Rpcnb(req)
}
func (tag *Tag) Attach(fid, afid *Fid, user p.User, aname string) error {
func (tag *Tag) Attach(fid, afid *Fid, user User, aname string) error {
var afno uint32
if afid != nil {
afno = afid.Fid
} else {
afno = p.NOFID
afno = NOFID
}
req := tag.reqAlloc()
req.fid = fid
err := p.PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
err := PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
if err != nil {
return err
}
@ -137,7 +135,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
newfid.Qid = fid.Qid
}
err := p.PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames)
err := PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames)
if err != nil {
return err
}
@ -149,7 +147,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
func (tag *Tag) Open(fid *Fid, mode uint8) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTopen(req.Tc, fid.Fid, mode)
err := PackTopen(req.Tc, fid.Fid, mode)
if err != nil {
return err
}
@ -161,7 +159,7 @@ func (tag *Tag) Open(fid *Fid, mode uint8) error {
func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu)
err := PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu)
if err != nil {
return err
}
@ -173,7 +171,7 @@ func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext strin
func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTread(req.Tc, fid.Fid, offset, count)
err := PackTread(req.Tc, fid.Fid, offset, count)
if err != nil {
return err
}
@ -184,7 +182,7 @@ func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data)
err := PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data)
if err != nil {
return err
}
@ -195,7 +193,7 @@ func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
func (tag *Tag) Clunk(fid *Fid) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTclunk(req.Tc, fid.Fid)
err := PackTclunk(req.Tc, fid.Fid)
if err != nil {
return err
}
@ -206,7 +204,7 @@ func (tag *Tag) Clunk(fid *Fid) error {
func (tag *Tag) Remove(fid *Fid) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTremove(req.Tc, fid.Fid)
err := PackTremove(req.Tc, fid.Fid)
if err != nil {
return err
}
@ -217,7 +215,7 @@ func (tag *Tag) Remove(fid *Fid) error {
func (tag *Tag) Stat(fid *Fid) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTstat(req.Tc, fid.Fid)
err := PackTstat(req.Tc, fid.Fid)
if err != nil {
return err
}
@ -225,10 +223,10 @@ func (tag *Tag) Stat(fid *Fid) error {
return tag.clnt.Rpcnb(req)
}
func (tag *Tag) Wstat(fid *Fid, dir *p.Dir) error {
func (tag *Tag) Wstat(fid *Fid, dir *Dir) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu)
err := PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu)
if err != nil {
return err
}

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"strings"
)
@ -13,9 +12,9 @@ import (
// sequence and associates the resulting file with newfid. If no wnames
// were walked successfully, an Error is returned. Otherwise a slice with a
// Qid for each walked name is returned.
func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]p.Qid, error) {
func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]Qid, error) {
tc := clnt.NewFcall()
err := p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
err := PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
if err != nil {
return nil, err
}
@ -66,12 +65,12 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
}
tc := clnt.NewFcall()
err = p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n])
err = PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n])
if err != nil {
goto error
}
var rc *p.Fcall
var rc *Fcall
rc, err = clnt.Rpc(tc)
if err != nil {
goto error
@ -79,7 +78,7 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
newfid.walked = true
if len(rc.Wqid) != n {
err = &p.Error{"file not found", p.ENOENT}
err = &Error{"file not found", ENOENT}
goto error
}

View File

@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Write up to len(data) bytes starting from offset. Returns the
// number of bytes written, or an Error.
@ -14,7 +12,7 @@ func (clnt *Clnt) Write(fid *Fid, data []byte, offset uint64) (int, error) {
}
tc := clnt.NewFcall()
err := p.PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data)
err := PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data)
if err != nil {
return 0, err
}
@ -41,7 +39,7 @@ func (file *File) Write(buf []byte) (int, error) {
// Writes up to len(buf) bytes starting from offset. Returns the number
// of bytes written, or an Error.
func (file *File) WriteAt(buf []byte, offset int64) (int, error) {
return file.fid.Clnt.Write(file.fid, buf, uint64(offset))
return file.Fid.Clnt.Write(file.Fid, buf, uint64(offset))
}
// Writes exactly len(buf) bytes starting from offset. Returns the number of

9
third_party/go9p/debug.go vendored Normal file
View File

@ -0,0 +1,9 @@
package go9p
// Debug flags
const (
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr
DbgPrintPackets // print the raw packets on stderr
DbgLogFcalls // keep the last N 9P messages (can be accessed over http)
DbgLogPackets // keep the last N 9P messages (can be accessed over http)
)

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
import "fmt"

View File

@ -1,4 +1,4 @@
package p
package go9p
type Log struct {
Data interface{}

View File

@ -2,38 +2,33 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
import (
"os/user"
"strconv"
"sync"
)
import "sync"
var once sync.Once
type osUser struct {
*user.User
uid int
gid int
}
type osUsers struct {
users map[int]*osUser
groups map[int]*osGroup
sync.Mutex
}
// Simple Users implementation that defers to os/user and fakes
// looking up groups by gid only.
// Simple Users implementation that fakes looking up users and groups
// by uid only. The names and groups memberships are empty
var OsUsers *osUsers
func (u *osUser) Name() string { return u.Username }
func (u *osUser) Name() string { return "" }
func (u *osUser) Id() int { return u.uid }
func (u *osUser) Groups() []Group { return []Group{OsUsers.Gid2Group(u.gid)} }
func (u *osUser) Groups() []Group { return nil }
func (u *osUser) IsMember(g Group) bool { return u.gid == g.Id() }
func (u *osUser) IsMember(g Group) bool { return false }
type osGroup struct {
gid int
@ -47,33 +42,28 @@ func (g *osGroup) Members() []User { return nil }
func initOsusers() {
OsUsers = new(osUsers)
OsUsers.users = make(map[int]*osUser)
OsUsers.groups = make(map[int]*osGroup)
}
func newUser(u *user.User) *osUser {
uid, uerr := strconv.Atoi(u.Uid)
gid, gerr := strconv.Atoi(u.Gid)
if uerr != nil || gerr != nil {
/* non-numeric uid/gid => unsupported system */
return nil
}
return &osUser{u, uid, gid}
}
func (up *osUsers) Uid2User(uid int) User {
u, err := user.LookupId(strconv.Itoa(uid))
if err != nil {
return nil
once.Do(initOsusers)
OsUsers.Lock()
defer OsUsers.Unlock()
user, present := OsUsers.users[uid]
if present {
return user
}
return newUser(u)
user = new(osUser)
user.uid = uid
OsUsers.users[uid] = user
return user
}
func (up *osUsers) Uname2User(uname string) User {
u, err := user.Lookup(uname)
if err != nil {
return nil
}
return newUser(u)
// unimplemented
return nil
}
func (up *osUsers) Gid2Group(gid int) Group {

View File

@ -1,489 +0,0 @@
package main
// An interactive client for 9P servers.
import (
"bufio"
"flag"
"fmt"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"os"
"path"
"strings"
)
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
var ouser = flag.String("user", "", "user to connect as")
var cmdfile = flag.String("file", "", "read commands from file")
var prompt = flag.String("prompt", "9p> ", "prompt for interactive client")
var debug = flag.Bool("d", false, "enable debugging (fcalls)")
var debugall = flag.Bool("D", false, "enable debugging (raw packets)")
var cwd = "/"
var cfid *clnt.Fid
type Cmd struct {
fun func(c *clnt.Clnt, s []string)
help string
}
var cmds map[string]*Cmd
func init() {
cmds = make(map[string]*Cmd)
cmds["write"] = &Cmd{cmdwrite, "write file string [...]\t«write the unmodified string to file, create file if necessary»"}
cmds["echo"] = &Cmd{cmdecho, "echo file string [...]\t«echo string to file (newline appended)»"}
cmds["stat"] = &Cmd{cmdstat, "stat file [...]\t«stat file»"}
cmds["ls"] = &Cmd{cmdls, "ls [-l] file [...]\t«list contents of directory or file»"}
cmds["cd"] = &Cmd{cmdcd, "cd dir\t«change working directory»"}
cmds["cat"] = &Cmd{cmdcat, "cat file [...]\t«print the contents of file»"}
cmds["mkdir"] = &Cmd{cmdmkdir, "mkdir dir [...]\t«create dir on remote server»"}
cmds["get"] = &Cmd{cmdget, "get file [local]\t«get file from remote server»"}
cmds["put"] = &Cmd{cmdput, "put file [remote]\t«put file on the remote server as 'file'»"}
cmds["pwd"] = &Cmd{cmdpwd, "pwd\t«print working directory»"}
cmds["rm"] = &Cmd{cmdrm, "rm file [...]\t«remove file from remote server»"}
cmds["help"] = &Cmd{cmdhelp, "help [cmd]\t«print available commands or help on cmd»"}
cmds["quit"] = &Cmd{cmdquit, "quit\t«exit»"}
cmds["exit"] = &Cmd{cmdquit, "exit\t«quit»"}
}
// normalize user-supplied path. path starting with '/' is left untouched, otherwise is considered
// local from cwd
func normpath(s string) string {
if len(s) > 0 {
if s[0] == '/' {
return path.Clean(s)
}
return path.Clean(cwd + "/" + s)
}
return "/"
}
func b(mode uint32, s uint8) string {
var bits = []string{"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}
return bits[(mode>>s)&7]
}
// Convert file mode bits to string representation
func modetostr(mode uint32) string {
d := "-"
if mode&p.DMDIR != 0 {
d = "d"
} else if mode&p.DMAPPEND != 0 {
d = "a"
}
return fmt.Sprintf("%s%s%s%s", d, b(mode, 6), b(mode, 3), b(mode, 0))
}
// Write the string s to remote file f. Create f if it doesn't exist
func writeone(c *clnt.Clnt, f, s string) {
fname := normpath(f)
file, oserr := c.FCreate(fname, 0666, p.OWRITE)
if oserr != nil {
file, oserr = c.FOpen(fname, p.OWRITE|p.OTRUNC)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error opening %s: %v\n", fname, oserr)
return
}
}
defer file.Close()
m, oserr := file.Write([]byte(s))
if oserr != nil {
fmt.Fprintf(os.Stderr, "error writing to %s: %v\n", fname, oserr)
return
}
if m != len(s) {
fmt.Fprintf(os.Stderr, "short write %s\n", fname)
return
}
}
// Write s[1:] (with appended spaces) to the file s[0]
func cmdwrite(c *clnt.Clnt, s []string) {
fname := normpath(s[0])
str := strings.Join(s[1:], " ")
writeone(c, fname, str)
}
// Echo (append newline) s[1:] to s[0]
func cmdecho(c *clnt.Clnt, s []string) {
fname := normpath(s[0])
str := strings.Join(s[1:], " ") + "\n"
writeone(c, fname, str)
}
// Stat the remote file f
func statone(c *clnt.Clnt, f string) {
fname := normpath(f)
stat, oserr := c.FStat(fname)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error in stat %s: %v\n", fname, oserr)
return
}
fmt.Fprintf(os.Stdout, "%s\n", stat)
}
func cmdstat(c *clnt.Clnt, s []string) {
for _, f := range s {
statone(c, normpath(f))
}
}
func dirtostr(d *p.Dir) string {
return fmt.Sprintf("%s %s %s %-8d\t\t%s", modetostr(d.Mode), d.Uid, d.Gid, d.Length, d.Name)
}
func lsone(c *clnt.Clnt, s string, long bool) {
st, oserr := c.FStat(normpath(s))
if oserr != nil {
fmt.Fprintf(os.Stderr, "error stat: %v\n", oserr)
return
}
if st.Mode&p.DMDIR != 0 {
file, oserr := c.FOpen(s, p.OREAD)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error opening dir: %s\n", oserr)
return
}
defer file.Close()
for {
d, oserr := file.Readdir(0)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error reading dir: %v\n", oserr)
}
if d == nil || len(d) == 0 {
break
}
for _, dir := range d {
if long {
fmt.Fprintf(os.Stdout, "%s\n", dirtostr(dir))
} else {
os.Stdout.WriteString(dir.Name + "\n")
}
}
}
} else {
fmt.Fprintf(os.Stdout, "%s\n", dirtostr(st))
}
}
func cmdls(c *clnt.Clnt, s []string) {
long := false
if len(s) > 0 && s[0] == "-l" {
long = true
s = s[1:]
}
if len(s) == 0 {
lsone(c, cwd, long)
} else {
for _, d := range s {
lsone(c, cwd+d, long)
}
}
}
func walkone(c *clnt.Clnt, s string, fileok bool) {
ncwd := normpath(s)
fid, err := c.FWalk(ncwd)
defer c.Clunk(fid)
if err != nil {
fmt.Fprintf(os.Stderr, "walk error: %s\n", err)
return
}
if fileok != true && (fid.Type&p.QTDIR == 0) {
fmt.Fprintf(os.Stderr, "can't cd to file [%s]\n", ncwd)
return
}
cwd = ncwd
}
func cmdcd(c *clnt.Clnt, s []string) {
if s != nil {
walkone(c, strings.Join(s, "/"), false)
}
}
// Print the contents of f
func cmdcat(c *clnt.Clnt, s []string) {
buf := make([]byte, 8192)
Outer:
for _, f := range s {
fname := normpath(f)
file, oserr := c.FOpen(fname, p.OREAD)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error opening %s: %v\n", f, oserr)
continue Outer
}
defer file.Close()
for {
n, oserr := file.Read(buf)
if oserr != nil && oserr != io.EOF {
fmt.Fprintf(os.Stderr, "error reading %s: %v\n", f, oserr)
}
if n == 0 {
break
}
os.Stdout.Write(buf[0:n])
}
}
}
// Create a single directory on remote server
func mkone(c *clnt.Clnt, s string) {
fname := normpath(s)
file, oserr := c.FCreate(fname, 0777|p.DMDIR, p.OWRITE)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error creating directory %s: %v\n", fname, oserr)
return
}
file.Close()
}
// Create directories on remote server
func cmdmkdir(c *clnt.Clnt, s []string) {
for _, f := range s {
mkone(c, f)
}
}
// Copy a remote file to local filesystem
func cmdget(c *clnt.Clnt, s []string) {
var from, to string
switch len(s) {
case 1:
from = normpath(s[0])
_, to = path.Split(s[0])
case 2:
from, to = normpath(s[0]), s[1]
default:
fmt.Fprintf(os.Stderr, "from arguments; usage: get from to\n")
}
tofile, err := os.Create(to)
if err != nil {
fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err)
return
}
defer tofile.Close()
file, ferr := c.FOpen(from, p.OREAD)
if ferr != nil {
fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err)
return
}
defer file.Close()
buf := make([]byte, 8192)
for {
n, oserr := file.Read(buf)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error reading %s: %s\n", from, oserr)
return
}
if n == 0 {
break
}
m, err := tofile.Write(buf[0:n])
if err != nil {
fmt.Fprintf(os.Stderr, "error writing %s: %s\n", to, err)
return
}
if m != n {
fmt.Fprintf(os.Stderr, "short write %s\n", to)
return
}
}
}
// Copy a local file to remote server
func cmdput(c *clnt.Clnt, s []string) {
var from, to string
switch len(s) {
case 1:
_, to = path.Split(s[0])
to = normpath(to)
from = s[0]
case 2:
from, to = s[0], normpath(s[1])
default:
fmt.Fprintf(os.Stderr, "incorrect arguments; usage: put local [remote]\n")
}
fromfile, err := os.Open(from)
if err != nil {
fmt.Fprintf(os.Stderr, "error opening %s for reading: %s\n", from, err)
return
}
defer fromfile.Close()
file, ferr := c.FOpen(to, p.OWRITE|p.OTRUNC)
if ferr != nil {
file, ferr = c.FCreate(to, 0666, p.OWRITE)
if ferr != nil {
fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err)
return
}
}
defer file.Close()
buf := make([]byte, 8192)
for {
n, oserr := fromfile.Read(buf)
if oserr != nil && oserr != io.EOF {
fmt.Fprintf(os.Stderr, "error reading %s: %s\n", from, oserr)
return
}
if n == 0 {
break
}
m, oserr := file.Write(buf[0:n])
if oserr != nil {
fmt.Fprintf(os.Stderr, "error writing %s: %v\n", to, oserr)
return
}
if m != n {
fmt.Fprintf(os.Stderr, "short write %s\n", to)
return
}
}
}
func cmdpwd(c *clnt.Clnt, s []string) { fmt.Fprintf(os.Stdout, cwd+"\n") }
// Remove f from remote server
func rmone(c *clnt.Clnt, f string) {
fname := normpath(f)
err := c.FRemove(fname)
if err != nil {
fmt.Fprintf(os.Stderr, "error in stat %s", err)
return
}
}
// Remove one or more files from the server
func cmdrm(c *clnt.Clnt, s []string) {
for _, f := range s {
rmone(c, normpath(f))
}
}
// Print available commands
func cmdhelp(c *clnt.Clnt, s []string) {
cmdstr := ""
if len(s) > 0 {
for _, h := range s {
v, ok := cmds[h]
if ok {
cmdstr = cmdstr + v.help + "\n"
} else {
cmdstr = cmdstr + "unknown command: " + h + "\n"
}
}
} else {
cmdstr = "available commands: "
for k := range cmds {
cmdstr = cmdstr + " " + k
}
cmdstr = cmdstr + "\n"
}
fmt.Fprintf(os.Stdout, "%s", cmdstr)
}
func cmdquit(c *clnt.Clnt, s []string) { os.Exit(0) }
func cmd(c *clnt.Clnt, cmd string) {
ncmd := strings.Fields(cmd)
if len(ncmd) <= 0 {
return
}
v, ok := cmds[ncmd[0]]
if ok == false {
fmt.Fprintf(os.Stderr, "unknown command: %s\n", ncmd[0])
return
}
v.fun(c, ncmd[1:])
return
}
func interactive(c *clnt.Clnt) {
reader := bufio.NewReaderSize(os.Stdin, 8192)
for {
fmt.Print(*prompt)
line, err := reader.ReadSlice('\n')
if err != nil {
fmt.Fprintf(os.Stderr, "exiting...\n")
break
}
str := strings.TrimSpace(string(line))
// TODO: handle larger input lines by doubling buffer
in := strings.Split(str, "\n")
for i := range in {
if len(in[i]) > 0 {
cmd(c, in[i])
}
}
}
}
func main() {
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
flag.Parse()
if *ouser == "" {
user = p.OsUsers.Uid2User(os.Geteuid())
} else {
user = p.OsUsers.Uname2User(*ouser)
}
naddr := *addr
if strings.LastIndex(naddr, ":") == -1 {
naddr = naddr + ":5640"
}
c, err = clnt.Mount("tcp", naddr, "", user)
if err != nil {
fmt.Fprintf(os.Stderr, "error mounting %s: %s\n", naddr, err)
os.Exit(1)
}
if *debug {
c.Debuglevel = 1
}
if *debugall {
c.Debuglevel = 2
}
walkone(c, "/", false)
if file != nil {
//process(c)
fmt.Sprint(os.Stderr, "file reading unimplemented\n")
} else if flag.NArg() > 0 {
flags := flag.Args()
for _, uc := range flags {
cmd(c, uc)
}
} else {
interactive(c)
}
return
}

View File

@ -1,59 +0,0 @@
package main
import (
"flag"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
var d []*p.Dir
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err = clnt.Mount("tcp", *addr, "", user)
if err != nil {
log.Fatal(err)
}
lsarg := "/"
if flag.NArg() == 1 {
lsarg = flag.Arg(0)
} else if flag.NArg() > 1 {
log.Fatal("error: only one argument expected")
}
file, err = c.FOpen(lsarg, p.OREAD)
if err != nil {
log.Fatal(err)
}
for {
d, err = file.Readdir(0)
if d == nil || len(d) == 0 || err != nil {
break
}
for i := 0; i < len(d); i++ {
os.Stdout.WriteString(d[i].Name + "\n")
}
}
file.Close()
if err != nil && err != io.EOF {
log.Fatal(err)
}
return
}

View File

@ -1,61 +0,0 @@
package main
import (
"flag"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var n int
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
var buf []byte
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err = clnt.Mount("tcp", *addr, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
file, err = c.FOpen(flag.Arg(0), p.OREAD)
if err != nil {
goto error
}
buf = make([]byte, 8192)
for {
n, err = file.Read(buf)
if n == 0 {
break
}
os.Stdout.Write(buf[0:n])
}
file.Close()
if err != nil && err != io.EOF {
goto error
}
return
error:
log.Println("Error", err)
}

View File

@ -1,101 +0,0 @@
package main
import (
"flag"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
"strings"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var user p.User
var ba [][]byte
var nreqs int
var rchan chan *clnt.Req
var tag *clnt.Tag
var fid *clnt.Fid
var wnames []string
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err := clnt.Mount("tcp", *addr, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
ba = make([][]byte, 100)
for i := 0; i < len(ba); i++ {
ba[i] = make([]byte, 8192)
}
nreqs = 0
rchan = make(chan *clnt.Req)
tag = c.TagAlloc(rchan)
// walk the file
wnames = strings.Split(flag.Arg(0), "/")
for wnames[0] == "" {
wnames = wnames[1:]
}
fid = c.FidAlloc()
for root := c.Root; len(wnames) > 0; root = fid {
n := len(wnames)
if n > 8 {
n = 8
}
err = tag.Walk(root, fid, wnames[0:n])
if err != nil {
goto error
}
nreqs++
wnames = wnames[n:]
}
err = tag.Open(fid, p.OREAD)
if err != nil {
goto error
}
for i := 0; i < len(ba); i++ {
err = tag.Read(fid, uint64(i*8192), 8192)
if err != nil {
goto error
}
nreqs++
}
err = tag.Clunk(fid)
// now start reading...
for nreqs > 0 {
r := <-rchan
if r.Tc.Type == p.Tread {
i := r.Tc.Offset / 8192
copy(ba[i], r.Rc.Data)
ba[i] = ba[i][0:r.Rc.Count]
}
nreqs--
}
for i := 0; i < len(ba); i++ {
os.Stdout.Write(ba[i])
}
return
error:
log.Println("error: ", err)
}

View File

@ -1,74 +0,0 @@
// Connects to a server over TLS and lists the specified directory
package main
import (
"crypto/rand"
"crypto/tls"
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var user p.User
var file *clnt.File
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, oerr := tls.Dial("tcp", *addr, &tls.Config{
Rand: rand.Reader,
InsecureSkipVerify: true,
})
if oerr != nil {
log.Println("can't dial", oerr)
return
}
clnt, err := clnt.MountConn(c, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
file, oerr = clnt.FOpen(flag.Arg(0), p.OREAD)
if oerr != nil {
goto oerror
}
for {
d, oerr := file.Readdir(0)
if oerr != nil {
goto oerror
}
if d == nil || len(d) == 0 {
break
}
for i := 0; i < len(d); i++ {
os.Stdout.WriteString(d[i].Name + "\n")
}
}
file.Close()
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
return
oerror:
log.Println("Error", oerr)
}

View File

@ -1,71 +0,0 @@
package main
import (
"flag"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var n, m int
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
var buf []byte
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err = clnt.Mount("tcp", *addr, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
file, err = c.FOpen(flag.Arg(0), p.OWRITE|p.OTRUNC)
if err != nil {
file, err = c.FCreate(flag.Arg(0), 0666, p.OWRITE)
if err != nil {
goto error
}
}
buf = make([]byte, 8192)
for {
n, err = os.Stdin.Read(buf)
if err != nil && err != io.EOF {
goto error
}
if n == 0 {
break
}
m, err = file.Write(buf[0:n])
if err != nil {
goto error
}
if m != n {
err = &p.Error{"short write", 0}
goto error
}
}
file.Close()
return
error:
log.Println("Error", err)
}

View File

@ -1,63 +0,0 @@
// 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 clnt
import (
"k8s.io/minikube/third_party/go9p/p"
)
var Eisdir = &p.Error{"file is a directory", p.EIO}
var Enegoff = &p.Error{"negative i/o offset", p.EIO}
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence: 0 means relative to the origin of
// the file, 1 means relative to the current offset, and 2 means
// relative to the end. Seek returns the new offset and an error, if
// any.
//
// Seeking to a negative offset is an error, and results in Enegoff.
// Seeking to 0 in a directory is only valid if whence is 0. Seek returns
// Eisdir otherwise.
func (f *File) Seek(offset int64, whence int) (int64, error) {
var off int64
switch whence {
case 0:
// origin
off = offset
if f.fid.Qid.Type&p.QTDIR > 0 && off != 0 {
return 0, Eisdir
}
case 1:
// current
if f.fid.Qid.Type&p.QTDIR > 0 {
return 0, Eisdir
}
off = offset + int64(f.offset)
case 2:
// end
if f.fid.Qid.Type&p.QTDIR > 0 {
return 0, Eisdir
}
dir, err := f.fid.Clnt.Stat(f.fid)
if err != nil {
return 0, &p.Error{"stat error in seek: " + err.Error(), p.EIO}
}
off = int64(dir.Length) + offset
default:
return 0, &p.Error{"bad whence in seek", p.EIO}
}
if off < 0 {
return 0, Enegoff
}
f.offset = uint64(off)
return off, nil
}

View File

@ -1,147 +0,0 @@
// 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.
// A synthetic filesystem emulating a persistent cloning interface
// from Plan 9. Reading the /clone file creates new entries in the filesystem
// each containing unique information/data. Clone files remember what it written
// to them. Removing a clone file does what is expected.
package main
import (
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"os"
"strconv"
"time"
)
type ClFile struct {
srv.File
created string
id int
data []byte
}
type Clone struct {
srv.File
clones int
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Bool("d", false, "print debug messages")
var root *srv.File
func (cl *ClFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
var b []byte
if len(cl.data) == 0 {
str := strconv.Itoa(cl.id) + " created on:" + cl.created
b = []byte(str)
} else {
b = cl.data
}
n := len(b)
if offset >= uint64(n) {
return 0, nil
}
b = b[int(offset):n]
n -= int(offset)
if len(buf) < n {
n = len(buf)
}
copy(buf[offset:int(offset)+n], b[offset:])
return n, nil
}
func (cl *ClFile) Write(fid *srv.FFid, data []byte, offset uint64) (int, error) {
n := uint64(len(cl.data))
nlen := offset + uint64(len(data))
if nlen > n {
ndata := make([]byte, nlen)
copy(ndata, cl.data[0:n])
cl.data = ndata
}
copy(cl.data[offset:], data[offset:])
return len(data), nil
}
func (cl *ClFile) Wstat(fid *srv.FFid, dir *p.Dir) error {
return nil
}
func (cl *ClFile) Remove(fid *srv.FFid) error {
return nil
}
func (cl *Clone) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
// we only allow a single read from us, change the offset and we're done
if offset > uint64(0) {
return 0, nil
}
cl.clones += 1
ncl := new(ClFile)
ncl.id = cl.clones
ncl.created = time.Now().String()
name := strconv.Itoa(ncl.id)
err := ncl.Add(root, name, p.OsUsers.Uid2User(os.Geteuid()), nil, 0666, ncl)
if err != nil {
return 0, &p.Error{"can not create file", 0}
}
b := []byte(name)
if len(buf) < len(b) {
// cleanup
ncl.File.Remove()
return 0, &p.Error{"not enough buffer space for result", 0}
}
copy(buf, b)
return len(b), nil
}
func main() {
var err error
var cl *Clone
var s *srv.Fsrv
flag.Parse()
user := p.OsUsers.Uid2User(os.Geteuid())
root = new(srv.File)
err = root.Add(nil, "/", user, nil, p.DMDIR|0777, nil)
if err != nil {
goto error
}
cl = new(Clone)
err = cl.Add(root, "clone", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, cl)
if err != nil {
goto error
}
s = srv.NewFileSrv(root)
s.Dotu = true
if *debug {
s.Debuglevel = 1
}
s.Start(s)
err = s.StartNetListener("tcp", *addr)
if err != nil {
goto error
}
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
}

View File

@ -1,251 +0,0 @@
// 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 main
import (
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"os"
)
type Ramfs struct {
srv *srv.Fsrv
user p.User
group p.Group
blksz int
blkchan chan []byte
zero []byte // blksz array of zeroes
}
type RFile struct {
srv.File
data [][]byte
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Int("d", 0, "debuglevel")
var blksize = flag.Int("b", 8192, "block size")
var logsz = flag.Int("l", 2048, "log size")
var rsrv Ramfs
func (f *RFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
if offset > f.Length {
return 0, nil
}
count := uint32(len(buf))
if offset+uint64(count) > f.Length {
count = uint32(f.Length - offset)
}
for n, off, b := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz), buf[0:count]; len(b) > 0; n++ {
m := rsrv.blksz - int(off)
if m > len(b) {
m = len(b)
}
blk := rsrv.zero
if len(f.data[n]) != 0 {
blk = f.data[n]
}
// log.Stderr("read block", n, "off", off, "len", m, "l", len(blk), "ll", len(b))
copy(b, blk[off:off+uint64(m)])
b = b[m:]
off = 0
}
return int(count), nil
}
func (f *RFile) Write(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
// make sure the data array is big enough
sz := offset + uint64(len(buf))
if f.Length < sz {
f.expand(sz)
}
count := 0
for n, off := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz); len(buf) > 0; n++ {
blk := f.data[n]
if len(blk) == 0 {
select {
case blk = <-rsrv.blkchan:
break
default:
blk = make([]byte, rsrv.blksz)
}
// if off>0 {
copy(blk, rsrv.zero /*[0:off]*/)
// }
f.data[n] = blk
}
m := copy(blk[off:], buf)
buf = buf[m:]
count += m
off = 0
}
return count, nil
}
func (f *RFile) Create(fid *srv.FFid, name string, perm uint32) (*srv.File, error) {
ff := new(RFile)
err := ff.Add(&f.File, name, rsrv.user, rsrv.group, perm, ff)
return &ff.File, err
}
func (f *RFile) Remove(fid *srv.FFid) error {
f.trunc(0)
return nil
}
func (f *RFile) Wstat(fid *srv.FFid, dir *p.Dir) error {
var uid, gid uint32
f.Lock()
defer f.Unlock()
up := rsrv.srv.Upool
uid = dir.Uidnum
gid = dir.Gidnum
if uid == p.NOUID && dir.Uid != "" {
user := up.Uname2User(dir.Uid)
if user == nil {
return srv.Enouser
}
f.Uidnum = uint32(user.Id())
}
if gid == p.NOUID && dir.Gid != "" {
group := up.Gname2Group(dir.Gid)
if group == nil {
return srv.Enouser
}
f.Gidnum = uint32(group.Id())
}
if dir.Mode != 0xFFFFFFFF {
f.Mode = (f.Mode &^ 0777) | (dir.Mode & 0777)
}
if dir.Name != "" {
if err := f.Rename(dir.Name); err != nil {
return err
}
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
f.trunc(dir.Length)
}
return nil
}
// called with f locked
func (f *RFile) trunc(sz uint64) {
if f.Length == sz {
return
}
if f.Length > sz {
f.shrink(sz)
} else {
f.expand(sz)
}
}
// called with f lock held
func (f *RFile) shrink(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
off := sz % uint64(rsrv.blksz)
if off > 0 {
if len(f.data[blknum]) > 0 {
copy(f.data[blknum][off:], rsrv.zero)
}
blknum++
}
for i := blknum; i < uint64(len(f.data)); i++ {
if len(f.data[i]) == 0 {
continue
}
select {
case rsrv.blkchan <- f.data[i]:
break
default:
}
}
f.data = f.data[0:blknum]
f.Length = sz
}
func (f *RFile) expand(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
if sz%uint64(rsrv.blksz) != 0 {
blknum++
}
data := make([][]byte, blknum)
if f.data != nil {
copy(data, f.data)
}
f.data = data
f.Length = sz
}
func main() {
var err error
var l *p.Logger
flag.Parse()
rsrv.user = p.OsUsers.Uid2User(os.Geteuid())
rsrv.group = p.OsUsers.Gid2Group(os.Getegid())
rsrv.blksz = *blksize
rsrv.blkchan = make(chan []byte, 2048)
rsrv.zero = make([]byte, rsrv.blksz)
root := new(RFile)
err = root.Add(nil, "/", rsrv.user, nil, p.DMDIR|0777, root)
if err != nil {
goto error
}
l = p.NewLogger(*logsz)
rsrv.srv = srv.NewFileSrv(&root.File)
rsrv.srv.Dotu = true
rsrv.srv.Debuglevel = *debug
rsrv.srv.Start(rsrv.srv)
rsrv.srv.Id = "ramfs"
rsrv.srv.Log = l
err = rsrv.srv.StartNetListener("tcp", *addr)
if err != nil {
goto error
}
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
}

View File

@ -1,98 +0,0 @@
// 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 main
import (
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"os"
"time"
)
type Time struct {
srv.File
}
type InfTime struct {
srv.File
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Bool("d", false, "print debug messages")
var debugall = flag.Bool("D", false, "print packets as well as debug messages")
func (*InfTime) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
// push out time ignoring offset (infinite read)
t := time.Now().String() + "\n"
b := []byte(t)
ml := len(b)
if ml > len(buf) {
ml = len(buf)
}
copy(buf, b[0:ml])
return ml, nil
}
func (*Time) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
b := []byte(time.Now().String())
have := len(b)
off := int(offset)
if off >= have {
return 0, nil
}
return copy(buf, b[off:]), nil
}
func main() {
var err error
var tm *Time
var ntm *InfTime
var s *srv.Fsrv
flag.Parse()
user := p.OsUsers.Uid2User(os.Geteuid())
root := new(srv.File)
err = root.Add(nil, "/", user, nil, p.DMDIR|0555, nil)
if err != nil {
goto error
}
tm = new(Time)
err = tm.Add(root, "time", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, tm)
if err != nil {
goto error
}
ntm = new(InfTime)
err = ntm.Add(root, "inftime", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, ntm)
if err != nil {
goto error
}
s = srv.NewFileSrv(root)
s.Dotu = true
if *debug {
s.Debuglevel = 1
}
if *debugall {
s.Debuglevel = 2
}
s.Start(s)
err = s.StartNetListener("tcp", *addr)
if err != nil {
goto error
}
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
}

View File

@ -1,297 +0,0 @@
// 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.
// Listen on SSL connection, can be used as an example with p/clnt/examples/tls.go
// Sample certificate was copied from the Go source code
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"encoding/hex"
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"math/big"
"os"
)
type Ramfs struct {
srv *srv.Fsrv
user p.User
group p.Group
blksz int
blkchan chan []byte
zero []byte // blksz array of zeroes
}
type RFile struct {
srv.File
data [][]byte
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Int("d", 0, "debuglevel")
var blksize = flag.Int("b", 8192, "block size")
var logsz = flag.Int("l", 2048, "log size")
var rsrv Ramfs
func (f *RFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
if offset > f.Length {
return 0, nil
}
count := uint32(len(buf))
if offset+uint64(count) > f.Length {
count = uint32(f.Length - offset)
}
for n, off, b := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz), buf[0:count]; len(b) > 0; n++ {
m := rsrv.blksz - int(off)
if m > len(b) {
m = len(b)
}
blk := rsrv.zero
if len(f.data[n]) != 0 {
blk = f.data[n]
}
// log.Stderr("read block", n, "off", off, "len", m, "l", len(blk), "ll", len(b))
copy(b, blk[off:off+uint64(m)])
b = b[m:]
off = 0
}
return int(count), nil
}
func (f *RFile) Write(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
// make sure the data array is big enough
sz := offset + uint64(len(buf))
if f.Length < sz {
f.expand(sz)
}
count := 0
for n, off := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz); len(buf) > 0; n++ {
blk := f.data[n]
if len(blk) == 0 {
select {
case blk = <-rsrv.blkchan:
break
default:
blk = make([]byte, rsrv.blksz)
}
// if off>0 {
copy(blk, rsrv.zero /*[0:off]*/)
// }
f.data[n] = blk
}
m := copy(blk[off:], buf)
buf = buf[m:]
count += m
off = 0
}
return count, nil
}
func (f *RFile) Create(fid *srv.FFid, name string, perm uint32) (*srv.File, error) {
ff := new(RFile)
err := ff.Add(&f.File, name, rsrv.user, rsrv.group, perm, ff)
return &ff.File, err
}
func (f *RFile) Remove(fid *srv.FFid) error {
f.trunc(0)
return nil
}
func (f *RFile) Wstat(fid *srv.FFid, dir *p.Dir) error {
var uid, gid uint32
f.Lock()
defer f.Unlock()
up := rsrv.srv.Upool
uid = dir.Uidnum
gid = dir.Gidnum
if uid == p.NOUID && dir.Uid != "" {
user := up.Uname2User(dir.Uid)
if user == nil {
return srv.Enouser
}
f.Uidnum = uint32(user.Id())
}
if gid == p.NOUID && dir.Gid != "" {
group := up.Gname2Group(dir.Gid)
if group == nil {
return srv.Enouser
}
f.Gidnum = uint32(group.Id())
}
if dir.Mode != 0xFFFFFFFF {
f.Mode = (f.Mode &^ 0777) | (dir.Mode & 0777)
}
if dir.Name != "" {
if err := f.Rename(dir.Name); err != nil {
return err
}
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
f.trunc(dir.Length)
}
return nil
}
// called with f locked
func (f *RFile) trunc(sz uint64) {
if f.Length == sz {
return
}
if f.Length > sz {
f.shrink(sz)
} else {
f.expand(sz)
}
}
// called with f lock held
func (f *RFile) shrink(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
off := sz % uint64(rsrv.blksz)
if off > 0 {
if len(f.data[blknum]) > 0 {
copy(f.data[blknum][off:], rsrv.zero)
}
blknum++
}
for i := blknum; i < uint64(len(f.data)); i++ {
if len(f.data[i]) == 0 {
continue
}
select {
case rsrv.blkchan <- f.data[i]:
break
default:
}
}
f.data = f.data[0:blknum]
f.Length = sz
}
func (f *RFile) expand(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
if sz%uint64(rsrv.blksz) != 0 {
blknum++
}
data := make([][]byte, blknum)
if f.data != nil {
copy(data, f.data)
}
f.data = data
f.Length = sz
}
func main() {
var err error
flag.Parse()
rsrv.user = p.OsUsers.Uid2User(os.Geteuid())
rsrv.group = p.OsUsers.Gid2Group(os.Getegid())
rsrv.blksz = *blksize
rsrv.blkchan = make(chan []byte, 2048)
rsrv.zero = make([]byte, rsrv.blksz)
root := new(RFile)
err = root.Add(nil, "/", rsrv.user, nil, p.DMDIR|0777, root)
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}
l := p.NewLogger(*logsz)
rsrv.srv = srv.NewFileSrv(&root.File)
rsrv.srv.Dotu = true
rsrv.srv.Debuglevel = *debug
rsrv.srv.Start(rsrv.srv)
rsrv.srv.Id = "ramfs"
rsrv.srv.Log = l
cert := make([]tls.Certificate, 1)
cert[0].Certificate = [][]byte{testCertificate}
cert[0].PrivateKey = testPrivateKey
ls, oerr := tls.Listen("tcp", *addr, &tls.Config{
Rand: rand.Reader,
Certificates: cert,
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA},
InsecureSkipVerify: true,
})
if oerr != nil {
log.Println("can't listen:", oerr)
return
}
err = rsrv.srv.StartListener(ls)
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}
return
}
// Copied from crypto/tls/handshake_server_test.go from the Go repository
func bigFromString(s string) *big.Int {
ret := new(big.Int)
ret.SetString(s, 10)
return ret
}
func fromHex(s string) []byte {
b, _ := hex.DecodeString(s)
return b
}
var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
var testPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
E: 65537,
},
D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
Primes: []*big.Int{
bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
},
}

View File

@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The p9 package provides the definitions and functions used to implement
// The p9 package go9provides the definitions and functions used to implement
// the 9P2000 protocol.
package p
// TODO.
// All the packet conversion code in this file is crap and needs a rewrite.
package go9p
import (
"fmt"
@ -44,9 +46,9 @@ const (
)
const (
MSIZE = 8192 + IOHDRSZ // default message size (8192+IOHdrSz)
IOHDRSZ = 24 // the non-data size of the Twrite messages
PORT = 564 // default port for 9P file servers
MSIZE = 1048576 + IOHDRSZ // default message size (1048576+IOHdrSz)
IOHDRSZ = 24 // the non-data size of the Twrite messages
PORT = 564 // default port for 9P file servers
)
// Qid types
@ -301,11 +303,12 @@ func gint64(buf []byte) (uint64, []byte) {
func gstr(buf []byte) (string, []byte) {
var n uint16
if buf == nil {
if buf == nil || len(buf) < 2 {
return "", nil
}
n, buf = gint16(buf)
if int(n) > len(buf) {
return "", nil
}
@ -321,7 +324,8 @@ func gqid(buf []byte, qid *Qid) []byte {
return buf
}
func gstat(buf []byte, d *Dir, dotu bool) []byte {
func gstat(buf []byte, d *Dir, dotu bool) ([]byte, error) {
sz := len(buf)
d.Size, buf = gint16(buf)
d.Type, buf = gint16(buf)
d.Dev, buf = gint32(buf)
@ -332,27 +336,29 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
d.Length, buf = gint64(buf)
d.Name, buf = gstr(buf)
if buf == nil {
return nil
s := fmt.Sprintf("Buffer too short for basic 9p: need %d, have %d",
49, sz)
return nil, &Error{s, EINVAL}
}
d.Uid, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Uid failed", EINVAL}
}
d.Gid, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Gid failed", EINVAL}
}
d.Muid, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Muid failed", EINVAL}
}
if dotu {
d.Ext, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Ext failed", EINVAL}
}
d.Uidnum, buf = gint32(buf)
@ -364,7 +370,7 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
d.Muidnum = NOUID
}
return buf
return buf, nil
}
func pint8(val uint8, buf []byte) []byte {
@ -449,20 +455,17 @@ func pstat(d *Dir, buf []byte, dotu bool) []byte {
// Converts a Dir value to its on-the-wire representation and writes it to
// the buf. Returns the number of bytes written, 0 if there is not enough space.
func PackDir(d *Dir, buf []byte, dotu bool) int {
func PackDir(d *Dir, dotu bool) []byte {
sz := statsz(d, dotu)
if sz > len(buf) {
return 0
}
buf = pstat(d, buf, dotu)
return sz
buf := make([]byte, sz)
pstat(d, buf, dotu)
return buf
}
// Converts the on-the-wire representation of a stat to Stat value.
// Returns an error if the conversion is impossible, otherwise
// a pointer to a Stat value.
func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
func UnpackDir(buf []byte, dotu bool) (d *Dir, b []byte, amt int, err error) {
sz := 2 + 2 + 4 + 13 + 4 + /* size[2] type[2] dev[4] qid[13] mode[4] */
4 + 4 + 8 + /* atime[4] mtime[4] length[8] */
2 + 2 + 2 + 2 /* name[s] uid[s] gid[s] muid[s] */
@ -472,19 +475,17 @@ func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
}
if len(buf) < sz {
goto szerror
s := fmt.Sprintf("short buffer: Need %d and have %v", sz, len(buf))
return nil, nil, 0, &Error{s, EINVAL}
}
d = new(Dir)
buf = gstat(buf, d, dotu)
if buf == nil {
goto szerror
b, err = gstat(buf, d, dotu)
if err != nil {
return nil, nil, 0, err
}
return d, nil
szerror:
return nil, &Error{"short buffer", EINVAL}
return d, b, len(buf) - len(b), nil
}
@ -522,7 +523,7 @@ func packCommon(fc *Fcall, size int, id uint8) ([]byte, error) {
func (err *Error) Error() string {
if err != nil {
return fmt.Sprintf("%s: %d", err.Err, err.Errornum)
return err.Err
}
return ""

View File

@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
import "fmt"
// Create a Rversion message in the specified Fcall.
func PackRversion(fc *Fcall, msize uint32, version string) error {
@ -34,9 +36,17 @@ func PackRauth(fc *Fcall, aqid *Qid) error {
}
// Create a Rerror message in the specified Fcall. If dotu is true,
// the function will create a 9P2000.u message. If false, nerror is
// the function will create a 9P2000.u message. If false, errornum is
// ignored.
// The Akaros global is hurl-inducing but this whole blob of code
// needs a redo. dotu is even worse, since it bakes in ONE PARTICULAR
// EXTENSION ...
func PackRerror(fc *Fcall, error string, errornum uint32, dotu bool) error {
if *Akaros {
error = fmt.Sprintf("%04X %v", errornum, error)
}
size := 2 + len(error) /* ename[s] */
if dotu {
size += 4 /* ecode[4] */

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
// Create a Tversion message in the specified Fcall.
func PackTversion(fc *Fcall, msize uint32, version string) error {

View File

@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import (
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"log"
"net"
)
@ -18,11 +17,11 @@ func (srv *Srv) NewConn(c net.Conn) {
conn.Dotu = srv.Dotu
conn.Debuglevel = srv.Debuglevel
conn.conn = c
conn.fidpool = make(map[uint32]*Fid)
conn.reqs = make(map[uint16]*Req)
conn.reqout = make(chan *Req, srv.Maxpend)
conn.fidpool = make(map[uint32]*SrvFid)
conn.reqs = make(map[uint16]*SrvReq)
conn.reqout = make(chan *SrvReq, srv.Maxpend)
conn.done = make(chan bool)
conn.rchan = make(chan *p.Fcall, 64)
conn.rchan = make(chan *Fcall, 64)
srv.Lock()
if srv.conns == nil {
@ -58,7 +57,7 @@ func (conn *Conn) close() {
}
/* call FidDestroy for all remaining fids */
if op, ok := (conn.Srv.ops).(FidOps); ok {
if op, ok := (conn.Srv.ops).(SrvFidOps); ok {
for _, fid := range conn.fidpool {
op.FidDestroy(fid)
}
@ -87,7 +86,7 @@ func (conn *Conn) recv() {
pos += n
for pos > 4 {
sz, _ := p.Gint32(buf)
sz, _ := Gint32(buf)
if sz > conn.Msize {
log.Println("bad client connection: ", conn.conn.RemoteAddr())
conn.conn.Close()
@ -104,7 +103,7 @@ func (conn *Conn) recv() {
break
}
fc, err, fcsize := p.Unpack(buf, conn.Dotu)
fc, err, fcsize := Unpack(buf, conn.Dotu)
if err != nil {
log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf))
conn.conn.Close()
@ -113,12 +112,12 @@ func (conn *Conn) recv() {
}
tag := fc.Tag
req := new(Req)
req := new(SrvReq)
select {
case req.Rc = <-conn.rchan:
break
default:
req.Rc = p.NewFcall(conn.Msize)
req.Rc = NewFcall(conn.Msize)
}
req.Conn = conn
@ -151,7 +150,15 @@ func (conn *Conn) recv() {
}
conn.Unlock()
if process {
go req.process()
// Tversion may change some attributes of the
// connection, so we block on it. Otherwise,
// we may loop back to reading and that is a race.
// This fix brought to you by the race detector.
if req.Tc.Type == Tversion {
req.process()
} else {
go req.process()
}
}
buf = buf[fcsize:]
@ -159,7 +166,6 @@ func (conn *Conn) recv() {
}
}
panic("unreached")
}
func (conn *Conn) send() {
@ -169,7 +175,7 @@ func (conn *Conn) send() {
return
case req := <-conn.reqout:
p.SetTag(req.Rc, req.Tc.Tag)
SetTag(req.Rc, req.Tc.Tag)
conn.Lock()
conn.rsz += uint64(req.Rc.Size)
conn.npend--
@ -216,7 +222,7 @@ func (conn *Conn) LocalAddr() net.Addr {
return conn.conn.LocalAddr()
}
func (conn *Conn) logFcall(fc *p.Fcall) {
func (conn *Conn) logFcall(fc *Fcall) {
if conn.Debuglevel&DbgLogPackets != 0 {
pkt := make([]byte, len(fc.Pkt))
copy(pkt, fc.Pkt)
@ -224,7 +230,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
}
if conn.Debuglevel&DbgLogFcalls != 0 {
f := new(p.Fcall)
f := new(Fcall)
*f = *fc
f.Pkt = nil
conn.Srv.Log.Log(f, conn, DbgLogFcalls)
@ -234,7 +240,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
func (srv *Srv) StartNetListener(ntype, addr string) error {
l, err := net.Listen(ntype, addr)
if err != nil {
return &p.Error{err.Error(), p.EIO}
return &Error{err.Error(), EIO}
}
return srv.StartListener(l)
@ -248,7 +254,7 @@ func (srv *Srv) StartListener(l net.Listener) error {
for {
c, err := l.Accept()
if err != nil {
return &p.Error{err.Error(), p.EIO}
return &Error{err.Error(), EIO}
}
srv.NewConn(c)

View File

@ -2,20 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import (
"runtime"
import "runtime"
"k8s.io/minikube/third_party/go9p/p"
)
func (srv *Srv) version(req *Req) {
func (srv *Srv) version(req *SrvReq) {
tc := req.Tc
conn := req.Conn
if tc.Msize < p.IOHDRSZ {
req.RespondError(&p.Error{"msize too small", p.EINVAL})
if tc.Msize < IOHDRSZ {
req.RespondError(&Error{"msize too small", EINVAL})
return
}
@ -32,7 +28,7 @@ func (srv *Srv) version(req *Req) {
/* make sure that the responses of all current requests will be ignored */
conn.Lock()
for tag, r := range conn.reqs {
if tag == p.NOTAG {
if tag == NOTAG {
continue
}
@ -47,10 +43,10 @@ func (srv *Srv) version(req *Req) {
req.RespondRversion(conn.Msize, ver)
}
func (srv *Srv) auth(req *Req) {
func (srv *Srv) auth(req *SrvReq) {
tc := req.Tc
conn := req.Conn
if tc.Afid == p.NOFID {
if tc.Afid == NOFID {
req.RespondError(Eunknownfid)
return
}
@ -61,8 +57,8 @@ func (srv *Srv) auth(req *Req) {
return
}
var user p.User = nil
if tc.Unamenum != p.NOUID || conn.Dotu {
var user User = nil
if tc.Unamenum != NOUID || conn.Dotu {
user = srv.Upool.Uid2User(int(tc.Unamenum))
} else if tc.Uname != "" {
user = srv.Upool.Uname2User(tc.Uname)
@ -76,13 +72,13 @@ func (srv *Srv) auth(req *Req) {
}
req.Afid.User = user
req.Afid.Type = p.QTAUTH
req.Afid.Type = QTAUTH
if aop, ok := (srv.ops).(AuthOps); ok {
aqid, err := aop.AuthInit(req.Afid, tc.Aname)
if err != nil {
req.RespondError(err)
} else {
aqid.Type |= p.QTAUTH // just in case
aqid.Type |= QTAUTH // just in case
req.RespondRauth(aqid)
}
} else {
@ -91,16 +87,16 @@ func (srv *Srv) auth(req *Req) {
}
func (srv *Srv) authPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rauth {
func (srv *Srv) authPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rauth {
req.Afid.IncRef()
}
}
func (srv *Srv) attach(req *Req) {
func (srv *Srv) attach(req *SrvReq) {
tc := req.Tc
conn := req.Conn
if tc.Fid == p.NOFID {
if tc.Fid == NOFID {
req.RespondError(Eunknownfid)
return
}
@ -111,15 +107,15 @@ func (srv *Srv) attach(req *Req) {
return
}
if tc.Afid != p.NOFID {
if tc.Afid != NOFID {
req.Afid = conn.FidGet(tc.Afid)
if req.Afid == nil {
req.RespondError(Eunknownfid)
}
}
var user p.User = nil
if tc.Unamenum != p.NOUID || conn.Dotu {
var user User = nil
if tc.Unamenum != NOUID || conn.Dotu {
user = srv.Upool.Uid2User(int(tc.Unamenum))
} else if tc.Uname != "" {
user = srv.Upool.Uname2User(tc.Uname)
@ -141,20 +137,20 @@ func (srv *Srv) attach(req *Req) {
}
}
(srv.ops).(ReqOps).Attach(req)
(srv.ops).(SrvReqOps).Attach(req)
}
func (srv *Srv) attachPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rattach {
func (srv *Srv) attachPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rattach {
req.Fid.Type = req.Rc.Qid.Type
req.Fid.IncRef()
}
}
func (srv *Srv) flush(req *Req) {
func (srv *Srv) flush(req *SrvReq) {
conn := req.Conn
tag := req.Tc.Oldtag
p.PackRflush(req.Rc)
PackRflush(req.Rc)
conn.Lock()
r := conn.reqs[tag]
if r != nil {
@ -186,13 +182,13 @@ func (srv *Srv) flush(req *Req) {
}
}
func (srv *Srv) walk(req *Req) {
func (srv *Srv) walk(req *SrvReq) {
conn := req.Conn
tc := req.Tc
fid := req.Fid
/* we can't walk regular files, only clone them */
if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
if len(tc.Wname) > 0 && (fid.Type&QTDIR) == 0 {
req.RespondError(Enotdir)
return
}
@ -217,12 +213,12 @@ func (srv *Srv) walk(req *Req) {
req.Newfid.IncRef()
}
(req.Conn.Srv.ops).(ReqOps).Walk(req)
(req.Conn.Srv.ops).(SrvReqOps).Walk(req)
}
func (srv *Srv) walkPost(req *Req) {
func (srv *Srv) walkPost(req *SrvReq) {
rc := req.Rc
if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
if rc == nil || rc.Type != Rwalk || req.Newfid == nil {
return
}
@ -243,7 +239,7 @@ func (srv *Srv) walkPost(req *Req) {
}
}
func (srv *Srv) open(req *Req) {
func (srv *Srv) open(req *SrvReq) {
fid := req.Fid
tc := req.Tc
if fid.opened {
@ -251,22 +247,22 @@ func (srv *Srv) open(req *Req) {
return
}
if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
if (fid.Type&QTDIR) != 0 && tc.Mode != OREAD {
req.RespondError(Eperm)
return
}
fid.Omode = tc.Mode
(req.Conn.Srv.ops).(ReqOps).Open(req)
(req.Conn.Srv.ops).(SrvReqOps).Open(req)
}
func (srv *Srv) openPost(req *Req) {
func (srv *Srv) openPost(req *SrvReq) {
if req.Fid != nil {
req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
req.Fid.opened = req.Rc != nil && req.Rc.Type == Ropen
}
}
func (srv *Srv) create(req *Req) {
func (srv *Srv) create(req *SrvReq) {
fid := req.Fid
tc := req.Tc
if fid.opened {
@ -274,47 +270,47 @@ func (srv *Srv) create(req *Req) {
return
}
if (fid.Type & p.QTDIR) == 0 {
if (fid.Type & QTDIR) == 0 {
req.RespondError(Enotdir)
return
}
/* can't open directories for other than reading */
if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
if (tc.Perm&DMDIR) != 0 && tc.Mode != OREAD {
req.RespondError(Eperm)
return
}
/* can't create special files if not 9P2000.u */
if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
if (tc.Perm&(DMNAMEDPIPE|DMSYMLINK|DMLINK|DMDEVICE|DMSOCKET)) != 0 && !req.Conn.Dotu {
req.RespondError(Eperm)
return
}
fid.Omode = tc.Mode
(req.Conn.Srv.ops).(ReqOps).Create(req)
(req.Conn.Srv.ops).(SrvReqOps).Create(req)
}
func (srv *Srv) createPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
func (srv *Srv) createPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rcreate && req.Fid != nil {
req.Fid.Type = req.Rc.Qid.Type
req.Fid.opened = true
}
}
func (srv *Srv) read(req *Req) {
func (srv *Srv) read(req *SrvReq) {
tc := req.Tc
fid := req.Fid
if tc.Count+p.IOHDRSZ > req.Conn.Msize {
if tc.Count+IOHDRSZ > req.Conn.Msize {
req.RespondError(Etoolarge)
return
}
if (fid.Type & p.QTAUTH) != 0 {
if (fid.Type & QTAUTH) != 0 {
var n int
rc := req.Rc
err := p.InitRread(rc, tc.Count)
err := InitRread(rc, tc.Count)
if err != nil {
req.RespondError(err)
return
@ -327,7 +323,7 @@ func (srv *Srv) read(req *Req) {
return
}
p.SetRreadCount(rc, uint32(n))
SetRreadCount(rc, uint32(n))
req.Respond()
} else {
req.RespondError(Enotimpl)
@ -336,28 +332,27 @@ func (srv *Srv) read(req *Req) {
return
}
if (fid.Type & p.QTDIR) != 0 {
if (fid.Type & QTDIR) != 0 {
if tc.Offset == 0 {
fid.Diroffset = 0
} else if tc.Offset != fid.Diroffset {
req.RespondError(Ebadoffset)
return
fid.Diroffset = tc.Offset
}
}
(req.Conn.Srv.ops).(ReqOps).Read(req)
(req.Conn.Srv.ops).(SrvReqOps).Read(req)
}
func (srv *Srv) readPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
func (srv *Srv) readPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rread && (req.Fid.Type&QTDIR) != 0 {
req.Fid.Diroffset += uint64(req.Rc.Count)
}
}
func (srv *Srv) write(req *Req) {
func (srv *Srv) write(req *SrvReq) {
fid := req.Fid
tc := req.Tc
if (fid.Type & p.QTAUTH) != 0 {
if (fid.Type & QTAUTH) != 0 {
tc := req.Tc
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
@ -373,22 +368,22 @@ func (srv *Srv) write(req *Req) {
return
}
if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
if !fid.opened || (fid.Type&QTDIR) != 0 || (fid.Omode&3) == OREAD {
req.RespondError(Ebaduse)
return
}
if tc.Count+p.IOHDRSZ > req.Conn.Msize {
if tc.Count+IOHDRSZ > req.Conn.Msize {
req.RespondError(Etoolarge)
return
}
(req.Conn.Srv.ops).(ReqOps).Write(req)
(req.Conn.Srv.ops).(SrvReqOps).Write(req)
}
func (srv *Srv) clunk(req *Req) {
func (srv *Srv) clunk(req *SrvReq) {
fid := req.Fid
if (fid.Type & p.QTAUTH) != 0 {
if (fid.Type & QTAUTH) != 0 {
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
op.AuthDestroy(fid)
req.RespondRclunk()
@ -399,26 +394,26 @@ func (srv *Srv) clunk(req *Req) {
return
}
(req.Conn.Srv.ops).(ReqOps).Clunk(req)
(req.Conn.Srv.ops).(SrvReqOps).Clunk(req)
}
func (srv *Srv) clunkPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
func (srv *Srv) clunkPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rclunk && req.Fid != nil {
req.Fid.DecRef()
}
}
func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }
func (srv *Srv) remove(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Remove(req) }
func (srv *Srv) removePost(req *Req) {
func (srv *Srv) removePost(req *SrvReq) {
if req.Rc != nil && req.Fid != nil {
req.Fid.DecRef()
}
}
func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }
func (srv *Srv) stat(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Stat(req) }
func (srv *Srv) wstat(req *Req) {
func (srv *Srv) wstat(req *SrvReq) {
/*
fid := req.Fid
d := &req.Tc.Dir
@ -428,12 +423,12 @@ func (srv *Srv) wstat(req *Req) {
return
}
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&QTDIR) != 0 && (d.Mode&DMDIR) == 0) ||
((d.Type&QTDIR) == 0 && (d.Mode&DMDIR) != 0)) {
req.RespondError(Edirchange)
return
}
*/
(req.Conn.Srv.ops).(ReqOps).Wstat(req)
(req.Conn.Srv.ops).(SrvReqOps).Wstat(req)
}

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"log"
"sync"
"time"
@ -13,18 +12,18 @@ import (
// The FStatOp interface provides a single operation (Stat) that will be
// called before a file stat is sent back to the client. If implemented,
// the operation should update the data in the File struct.
// the operation should update the data in the srvFile struct.
type FStatOp interface {
Stat(fid *FFid) error
}
// The FWstatOp interface provides a single operation (Wstat) that will be
// called when the client requests the File metadata to be modified. If
// called when the client requests the srvFile metadata to be modified. If
// implemented, the operation will be called when Twstat message is received.
// If not implemented, "permission denied" error will be sent back. If the
// operation returns an Error, the error is send back to the client.
type FWstatOp interface {
Wstat(*FFid, *p.Dir) error
Wstat(*FFid, *Dir) error
}
// If the FReadOp interface is implemented, the Read operation will be called
@ -44,16 +43,16 @@ type FWriteOp interface {
}
// If the FCreateOp interface is implemented, the Create operation will be called
// when the client attempts to create a file in the File implementing the interface.
// when the client attempts to create a file in the srvFile implementing the interface.
// If not implemented, "permission denied" error will be send back. If successful,
// the operation should call (*File)Add() to add the created file to the directory.
// The operation returns the created file, or the error occured while creating it.
type FCreateOp interface {
Create(fid *FFid, name string, perm uint32) (*File, error)
Create(fid *FFid, name string, perm uint32) (*srvFile, error)
}
// If the FRemoveOp interface is implemented, the Remove operation will be called
// when the client attempts to create a file in the File implementing the interface.
// when the client attempts to create a file in the srvFile implementing the interface.
// If not implemented, "permission denied" error will be send back.
// The operation returns nil if successful, or the error that occured while removing
// the file.
@ -79,39 +78,40 @@ const (
Fremoved FFlags = 1 << iota
)
// The File type represents a file (or directory) served by the file server.
type File struct {
// The srvFile type represents a file (or directory) served by the file server.
type srvFile struct {
sync.Mutex
p.Dir
Dir
flags FFlags
Parent *File // parent
next, prev *File // siblings, guarded by parent.Lock
cfirst, clast *File // children (if directory)
Ops interface{}
Parent *srvFile // parent
next, prev *srvFile // siblings, guarded by parent.Lock
cfirst, clast *srvFile // children (if directory)
ops interface{}
}
type FFid struct {
F *File
Fid *Fid
dirs []*File // used for readdir
F *srvFile
Fid *SrvFid
dirs []*srvFile // used for readdir
dirents []byte // serialized version of dirs
}
// The Fsrv can be used to create file servers that serve
// simple trees of synthetic files.
type Fsrv struct {
Srv
Root *File
Root *srvFile
}
var lock sync.Mutex
var qnext uint64
var Eexist = &p.Error{"file already exists", p.EEXIST}
var Enoent = &p.Error{"file not found", p.ENOENT}
var Enotempty = &p.Error{"directory not empty", p.EPERM}
var Eexist = &Error{"file already exists", EEXIST}
var Enoent = &Error{"file not found", ENOENT}
var Enotempty = &Error{"directory not empty", EPERM}
// Creates a file server with root as root directory
func NewFileSrv(root *File) *Fsrv {
func NewsrvFileSrv(root *srvFile) *Fsrv {
srv := new(Fsrv)
srv.Root = root
root.Parent = root // make sure we can .. in root
@ -121,7 +121,7 @@ func NewFileSrv(root *File) *Fsrv {
// Initializes the fields of a file and add it to a directory.
// Returns nil if successful, or an error.
func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ops interface{}) error {
func (f *srvFile) Add(dir *srvFile, name string, uid User, gid Group, mode uint32, ops interface{}) error {
lock.Lock()
qpath := qnext
@ -141,7 +141,7 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Uidnum = uint32(uid.Id())
} else {
f.Uid = "none"
f.Uidnum = p.NOUID
f.Uidnum = NOUID
}
if gid != nil {
@ -149,11 +149,11 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Gidnum = uint32(gid.Id())
} else {
f.Gid = "none"
f.Gidnum = p.NOUID
f.Gidnum = NOUID
}
f.Muid = ""
f.Muidnum = p.NOUID
f.Muidnum = NOUID
f.Ext = ""
if dir != nil {
@ -180,12 +180,12 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Parent = f
}
f.Ops = ops
f.ops = ops
return nil
}
// Removes a file from its parent directory.
func (f *File) Remove() {
func (f *srvFile) Remove() {
f.Lock()
if (f.flags & Fremoved) != 0 {
f.Unlock()
@ -214,7 +214,7 @@ func (f *File) Remove() {
p.Unlock()
}
func (f *File) Rename(name string) error {
func (f *srvFile) Rename(name string) error {
p := f.Parent
p.Lock()
defer p.Unlock()
@ -229,8 +229,8 @@ func (f *File) Rename(name string) error {
}
// Looks for a file in a directory. Returns nil if the file is not found.
func (p *File) Find(name string) *File {
var f *File
func (p *srvFile) Find(name string) *srvFile {
var f *srvFile
p.Lock()
for f = p.cfirst; f != nil; f = f.next {
@ -244,8 +244,8 @@ func (p *File) Find(name string) *File {
// Checks if the specified user has permission to perform
// certain operation on a file. Perm contains one or more
// of p.DMREAD, p.DMWRITE, and p.DMEXEC.
func (f *File) CheckPerm(user p.User, perm uint32) bool {
// of DMREAD, DMWRITE, and DMEXEC.
func (f *srvFile) CheckPerm(user User, perm uint32) bool {
if user == nil {
return false
}
@ -285,7 +285,7 @@ func (f *File) CheckPerm(user p.User, perm uint32) bool {
return false
}
func (s *Fsrv) Attach(req *Req) {
func (s *Fsrv) Attach(req *SrvReq) {
fid := new(FFid)
fid.F = s.Root
fid.Fid = req.Fid
@ -293,7 +293,7 @@ func (s *Fsrv) Attach(req *Req) {
req.RespondRattach(&s.Root.Qid)
}
func (*Fsrv) Walk(req *Req) {
func (*Fsrv) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
tc := req.Tc
@ -304,7 +304,7 @@ func (*Fsrv) Walk(req *Req) {
}
nfid := req.Newfid.Aux.(*FFid)
wqids := make([]p.Qid, len(tc.Wname))
wqids := make([]Qid, len(tc.Wname))
i := 0
f := fid.F
for ; i < len(tc.Wname); i++ {
@ -314,8 +314,8 @@ func (*Fsrv) Walk(req *Req) {
wqids[i] = f.Qid
continue
}
if (wqids[i].Type & p.QTDIR) > 0 {
if !f.CheckPerm(req.Fid.User, p.DMEXEC) {
if (wqids[i].Type & QTDIR) > 0 {
if !f.CheckPerm(req.Fid.User, DMEXEC) {
break
}
}
@ -342,22 +342,22 @@ func mode2Perm(mode uint8) uint32 {
var perm uint32 = 0
switch mode & 3 {
case p.OREAD:
perm = p.DMREAD
case p.OWRITE:
perm = p.DMWRITE
case p.ORDWR:
perm = p.DMREAD | p.DMWRITE
case OREAD:
perm = DMREAD
case OWRITE:
perm = DMWRITE
case ORDWR:
perm = DMREAD | DMWRITE
}
if (mode & p.OTRUNC) != 0 {
perm |= p.DMWRITE
if (mode & OTRUNC) != 0 {
perm |= DMWRITE
}
return perm
}
func (*Fsrv) Open(req *Req) {
func (*Fsrv) Open(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
tc := req.Tc
@ -366,7 +366,7 @@ func (*Fsrv) Open(req *Req) {
return
}
if op, ok := (fid.F.Ops).(FOpenOp); ok {
if op, ok := (fid.F.ops).(FOpenOp); ok {
err := op.Open(fid, tc.Mode)
if err != nil {
req.RespondError(err)
@ -376,17 +376,17 @@ func (*Fsrv) Open(req *Req) {
req.RespondRopen(&fid.F.Qid, 0)
}
func (*Fsrv) Create(req *Req) {
func (*Fsrv) Create(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
tc := req.Tc
dir := fid.F
if !dir.CheckPerm(req.Fid.User, p.DMWRITE) {
if !dir.CheckPerm(req.Fid.User, DMWRITE) {
req.RespondError(Eperm)
return
}
if cop, ok := (dir.Ops).(FCreateOp); ok {
if cop, ok := (dir.ops).(FCreateOp); ok {
f, err := cop.Create(fid, tc.Name, tc.Perm)
if err != nil {
req.RespondError(err)
@ -399,55 +399,48 @@ func (*Fsrv) Create(req *Req) {
}
}
func (*Fsrv) Read(req *Req) {
var i, n int
func (*Fsrv) Read(req *SrvReq) {
var n int
var err error
fid := req.Fid.Aux.(*FFid)
f := fid.F
tc := req.Tc
rc := req.Rc
p.InitRread(rc, tc.Count)
InitRread(rc, tc.Count)
if f.Mode&p.DMDIR != 0 {
// directory
if f.Mode&DMDIR != 0 {
// Get all the directory entries and
// serialize them all into an output buffer.
// This greatly simplifies the directory read.
if tc.Offset == 0 {
var g *File
var g *srvFile
fid.dirents = nil
f.Lock()
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
}
fid.dirs = make([]*File, n)
fid.dirs = make([]*srvFile, n)
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
fid.dirs[n] = g
fid.dirents = append(fid.dirents,
PackDir(&g.Dir, req.Conn.Dotu)...)
}
f.Unlock()
}
n = 0
b := rc.Data
for i = 0; i < len(fid.dirs); i++ {
g := fid.dirs[i]
g.Lock()
if (g.flags & Fremoved) != 0 {
g.Unlock()
continue
}
sz := p.PackDir(&g.Dir, b, req.Conn.Dotu)
g.Unlock()
if sz == 0 {
break
}
b = b[sz:]
n += sz
switch {
case tc.Offset > uint64(len(fid.dirents)):
n = 0
case len(fid.dirents[tc.Offset:]) > int(tc.Size):
n = int(tc.Size)
default:
n = len(fid.dirents[tc.Offset:])
}
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+1+n])
fid.dirs = fid.dirs[i:]
} else {
// file
if rop, ok := f.Ops.(FReadOp); ok {
if rop, ok := f.ops.(FReadOp); ok {
n, err = rop.Read(fid, rc.Data, tc.Offset)
if err != nil {
req.RespondError(err)
@ -459,16 +452,16 @@ func (*Fsrv) Read(req *Req) {
}
}
p.SetRreadCount(rc, uint32(n))
SetRreadCount(rc, uint32(n))
req.Respond()
}
func (*Fsrv) Write(req *Req) {
func (*Fsrv) Write(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
f := fid.F
tc := req.Tc
if wop, ok := (f.Ops).(FWriteOp); ok {
if wop, ok := (f.ops).(FWriteOp); ok {
n, err := wop.Write(fid, tc.Data, tc.Offset)
if err != nil {
req.RespondError(err)
@ -481,10 +474,10 @@ func (*Fsrv) Write(req *Req) {
}
func (*Fsrv) Clunk(req *Req) {
func (*Fsrv) Clunk(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
if op, ok := (fid.F.Ops).(FClunkOp); ok {
if op, ok := (fid.F.ops).(FClunkOp); ok {
err := op.Clunk(fid)
if err != nil {
req.RespondError(err)
@ -493,7 +486,7 @@ func (*Fsrv) Clunk(req *Req) {
req.RespondRclunk()
}
func (*Fsrv) Remove(req *Req) {
func (*Fsrv) Remove(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
f := fid.F
f.Lock()
@ -504,7 +497,7 @@ func (*Fsrv) Remove(req *Req) {
}
f.Unlock()
if rop, ok := (f.Ops).(FRemoveOp); ok {
if rop, ok := (f.ops).(FRemoveOp); ok {
err := rop.Remove(fid)
if err != nil {
req.RespondError(err)
@ -518,11 +511,11 @@ func (*Fsrv) Remove(req *Req) {
}
}
func (*Fsrv) Stat(req *Req) {
func (*Fsrv) Stat(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
f := fid.F
if sop, ok := (f.Ops).(FStatOp); ok {
if sop, ok := (f.ops).(FStatOp); ok {
err := sop.Stat(fid)
if err != nil {
req.RespondError(err)
@ -534,12 +527,12 @@ func (*Fsrv) Stat(req *Req) {
}
}
func (*Fsrv) Wstat(req *Req) {
func (*Fsrv) Wstat(req *SrvReq) {
tc := req.Tc
fid := req.Fid.Aux.(*FFid)
f := fid.F
if wop, ok := (f.Ops).(FWstatOp); ok {
if wop, ok := (f.ops).(FWstatOp); ok {
err := wop.Wstat(fid, &tc.Dir)
if err != nil {
req.RespondError(err)
@ -551,7 +544,7 @@ func (*Fsrv) Wstat(req *Req) {
}
}
func (*Fsrv) FidDestroy(ffid *Fid) {
func (*Fsrv) FidDestroy(ffid *SrvFid) {
if ffid.Aux == nil {
return
}
@ -562,7 +555,7 @@ func (*Fsrv) FidDestroy(ffid *Fid) {
return // otherwise errs in bad walks
}
if op, ok := (f.Ops).(FDestroyOp); ok {
if op, ok := (f.ops).(FDestroyOp); ok {
op.FidDestroy(fid)
}
}

354
third_party/go9p/srv_pipe.go vendored Normal file
View File

@ -0,0 +1,354 @@
// 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 (
"log"
"os"
"strconv"
"syscall"
)
type pipeFid struct {
path string
file *os.File
dirs []os.FileInfo
dirents []byte
diroffset uint64
st os.FileInfo
data []uint8
eof bool
}
type Pipefs struct {
Srv
Root string
}
func (fid *pipeFid) stat() *Error {
var err error
fid.st, err = os.Lstat(fid.path)
if err != nil {
return toError(err)
}
return nil
}
// Dir is an instantiation of the p.Dir structure
// that can act as a receiver for local methods.
type pipeDir struct {
Dir
}
func (*Pipefs) ConnOpened(conn *Conn) {
if conn.Srv.Debuglevel > 0 {
log.Println("connected")
}
}
func (*Pipefs) ConnClosed(conn *Conn) {
if conn.Srv.Debuglevel > 0 {
log.Println("disconnected")
}
}
func (*Pipefs) FidDestroy(sfid *SrvFid) {
var fid *pipeFid
if sfid.Aux == nil {
return
}
fid = sfid.Aux.(*pipeFid)
if fid.file != nil {
fid.file.Close()
}
}
func (pipe *Pipefs) Attach(req *SrvReq) {
if req.Afid != nil {
req.RespondError(Enoauth)
return
}
tc := req.Tc
fid := new(pipeFid)
if len(tc.Aname) == 0 {
fid.path = pipe.Root
} else {
fid.path = tc.Aname
}
req.Fid.Aux = fid
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
qid := dir2Qid(fid.st)
req.RespondRattach(qid)
}
func (*Pipefs) Flush(req *SrvReq) {}
func (*Pipefs) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
if req.Newfid.Aux == nil {
req.Newfid.Aux = new(pipeFid)
}
nfid := req.Newfid.Aux.(*pipeFid)
wqids := make([]Qid, len(tc.Wname))
path := fid.path
i := 0
for ; i < len(tc.Wname); i++ {
p := path + "/" + tc.Wname[i]
st, err := os.Lstat(p)
if err != nil {
if i == 0 {
req.RespondError(Enoent)
return
}
break
}
wqids[i] = *dir2Qid(st)
path = p
}
nfid.path = path
req.RespondRwalk(wqids[0:i])
}
func (*Pipefs) Open(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
var e error
fid.file, e = os.OpenFile(fid.path, omode2uflags(tc.Mode), 0)
if e != nil {
req.RespondError(toError(e))
return
}
req.RespondRopen(dir2Qid(fid.st), 0)
}
func (*Pipefs) Create(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
path := fid.path + "/" + tc.Name
var e error = nil
var file *os.File = nil
switch {
case tc.Perm&DMDIR != 0:
e = os.Mkdir(path, os.FileMode(tc.Perm&0777))
case tc.Perm&DMSYMLINK != 0:
e = os.Symlink(tc.Ext, path)
case tc.Perm&DMLINK != 0:
n, e := strconv.ParseUint(tc.Ext, 10, 0)
if e != nil {
break
}
ofid := req.Conn.FidGet(uint32(n))
if ofid == nil {
req.RespondError(Eunknownfid)
return
}
e = os.Link(ofid.Aux.(*pipeFid).path, path)
ofid.DecRef()
case tc.Perm&DMNAMEDPIPE != 0:
case tc.Perm&DMDEVICE != 0:
req.RespondError(&Error{"not implemented", EIO})
return
default:
var mode uint32 = tc.Perm & 0777
if req.Conn.Dotu {
if tc.Perm&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if tc.Perm&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
file, e = os.OpenFile(path, omode2uflags(tc.Mode)|os.O_CREATE, os.FileMode(mode))
}
if file == nil && e == nil {
file, e = os.OpenFile(path, omode2uflags(tc.Mode), 0)
}
if e != nil {
req.RespondError(toError(e))
return
}
fid.path = path
fid.file = file
err = fid.stat()
if err != nil {
req.RespondError(err)
return
}
req.RespondRcreate(dir2Qid(fid.st), 0)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func (*Pipefs) Read(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
rc := req.Rc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
InitRread(rc, tc.Count)
var count int
var e error
if fid.st.IsDir() {
if tc.Offset == 0 {
var e error
// If we got here, it was open. Can't really seek
// in most cases, just close and reopen it.
fid.file.Close()
if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil {
req.RespondError(toError(e))
return
}
if fid.dirs, e = fid.file.Readdir(-1); e != nil {
req.RespondError(toError(e))
return
}
fid.dirents = nil
for i := 0; i < len(fid.dirs); i++ {
path := fid.path + "/" + fid.dirs[i].Name()
st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
continue
}
b := PackDir(st, req.Conn.Dotu)
fid.dirents = append(fid.dirents, b...)
count += len(b)
}
}
switch {
case tc.Offset > uint64(len(fid.dirents)):
count = 0
case len(fid.dirents[tc.Offset:]) > int(tc.Count):
count = int(tc.Count)
default:
count = len(fid.dirents[tc.Offset:])
}
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count])
} else {
if fid.eof {
req.RespondError(toError(e))
return
}
length := min(len(rc.Data), len(fid.data))
count = length
copy(rc.Data, fid.data[:length])
fid.data = fid.data[length:]
}
SetRreadCount(rc, uint32(count))
req.Respond()
}
func (*Pipefs) Write(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
fid.data = append(fid.data, tc.Data...)
req.RespondRwrite(uint32(len(tc.Data)))
}
func (*Pipefs) Clunk(req *SrvReq) { req.RespondRclunk() }
func (*Pipefs) Remove(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
e := os.Remove(fid.path)
if e != nil {
req.RespondError(toError(e))
return
}
req.RespondRremove()
}
func (*Pipefs) Stat(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
req.RespondError(derr)
return
}
req.RespondRstat(st)
}
func (*Pipefs) Wstat(req *SrvReq) {
req.RespondError(Eperm)
}

41
third_party/go9p/srv_pipe_darwin.go vendored Normal file
View File

@ -0,0 +1,41 @@
// 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"
"os"
"syscall"
)
func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
if dir.Uid == "" {
dir.Uid = "none"
}
dir.Gid = g.Name()
if dir.Gid == "" {
dir.Gid = "none"
}
dir.Muid = "none"
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
if err != nil {
dir.Ext = ""
}
} else if isBlock(d) {
dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
} else if isChar(d) {
dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
}
}

41
third_party/go9p/srv_pipe_linux.go vendored Normal file
View File

@ -0,0 +1,41 @@
// 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"
"os"
"syscall"
)
func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
if dir.Uid == "" {
dir.Uid = "none"
}
dir.Gid = g.Name()
if dir.Gid == "" {
dir.Gid = "none"
}
dir.Muid = "none"
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
if err != nil {
dir.Ext = ""
}
} else if isBlock(d) {
dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
} else if isChar(d) {
dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
}
}

48
third_party/go9p/srv_pipe_windows.go vendored Normal file
View File

@ -0,0 +1,48 @@
// 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 (
"os"
"syscall"
)
func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) {
// u := upool.Uid2User(int(sysMode.Uid))
// g := upool.Gid2Group(int(sysMode.Gid))
// dir.Uid = u.Name()
// if dir.Uid == "" {
// dir.Uid = "none"
// }
// dir.Gid = g.Name()
// if dir.Gid == "" {
// dir.Gid = "none"
// }
// dir.Muid = "none"
// dir.Ext = ""
// dir.Uidnum = uint32(u.Id())
// dir.Gidnum = uint32(g.Id())
// dir.Muidnum = NOUID
// if d.Mode()&os.ModeSymlink != 0 {
// var err error
// dir.Ext, err = os.Readlink(path)
// if err != nil {
// dir.Ext = ""
// }
// } else if isBlock(d) {
// dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
// } else if isChar(d) {
// dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
// }
dir.Uid = "none"
dir.Gid = "none"
dir.Muid = "none"
dir.Uidnum = 0
dir.Gidnum = 0
dir.Muidnum = NOUID
dir.Ext = ""
}

View File

@ -2,28 +2,42 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import "fmt"
import "k8s.io/minikube/third_party/go9p/p"
// SrvRequest operations. This interface should be implemented by all file servers.
// The operations correspond directly to most of the 9P2000 message types.
type SrvReqOps interface {
Attach(*SrvReq)
Walk(*SrvReq)
Open(*SrvReq)
Create(*SrvReq)
Read(*SrvReq)
Write(*SrvReq)
Clunk(*SrvReq)
Remove(*SrvReq)
Stat(*SrvReq)
Wstat(*SrvReq)
}
// Respond to the request with Rerror message
func (req *Req) RespondError(err interface{}) {
func (req *SrvReq) RespondError(err interface{}) {
switch e := err.(type) {
case *p.Error:
p.PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
case *Error:
PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
case error:
p.PackRerror(req.Rc, e.Error(), uint32(p.EIO), req.Conn.Dotu)
PackRerror(req.Rc, e.Error(), uint32(EIO), req.Conn.Dotu)
default:
p.PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(p.EIO), req.Conn.Dotu)
PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(EIO), req.Conn.Dotu)
}
req.Respond()
}
// Respond to the request with Rversion message
func (req *Req) RespondRversion(msize uint32, version string) {
err := p.PackRversion(req.Rc, msize, version)
func (req *SrvReq) RespondRversion(msize uint32, version string) {
err := PackRversion(req.Rc, msize, version)
if err != nil {
req.RespondError(err)
} else {
@ -32,8 +46,8 @@ func (req *Req) RespondRversion(msize uint32, version string) {
}
// Respond to the request with Rauth message
func (req *Req) RespondRauth(aqid *p.Qid) {
err := p.PackRauth(req.Rc, aqid)
func (req *SrvReq) RespondRauth(aqid *Qid) {
err := PackRauth(req.Rc, aqid)
if err != nil {
req.RespondError(err)
} else {
@ -42,8 +56,8 @@ func (req *Req) RespondRauth(aqid *p.Qid) {
}
// Respond to the request with Rflush message
func (req *Req) RespondRflush() {
err := p.PackRflush(req.Rc)
func (req *SrvReq) RespondRflush() {
err := PackRflush(req.Rc)
if err != nil {
req.RespondError(err)
} else {
@ -52,8 +66,8 @@ func (req *Req) RespondRflush() {
}
// Respond to the request with Rattach message
func (req *Req) RespondRattach(aqid *p.Qid) {
err := p.PackRattach(req.Rc, aqid)
func (req *SrvReq) RespondRattach(aqid *Qid) {
err := PackRattach(req.Rc, aqid)
if err != nil {
req.RespondError(err)
} else {
@ -62,8 +76,8 @@ func (req *Req) RespondRattach(aqid *p.Qid) {
}
// Respond to the request with Rwalk message
func (req *Req) RespondRwalk(wqids []p.Qid) {
err := p.PackRwalk(req.Rc, wqids)
func (req *SrvReq) RespondRwalk(wqids []Qid) {
err := PackRwalk(req.Rc, wqids)
if err != nil {
req.RespondError(err)
} else {
@ -72,8 +86,8 @@ func (req *Req) RespondRwalk(wqids []p.Qid) {
}
// Respond to the request with Ropen message
func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
err := p.PackRopen(req.Rc, qid, iounit)
func (req *SrvReq) RespondRopen(qid *Qid, iounit uint32) {
err := PackRopen(req.Rc, qid, iounit)
if err != nil {
req.RespondError(err)
} else {
@ -82,8 +96,8 @@ func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
}
// Respond to the request with Rcreate message
func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
err := p.PackRcreate(req.Rc, qid, iounit)
func (req *SrvReq) RespondRcreate(qid *Qid, iounit uint32) {
err := PackRcreate(req.Rc, qid, iounit)
if err != nil {
req.RespondError(err)
} else {
@ -92,8 +106,8 @@ func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
}
// Respond to the request with Rread message
func (req *Req) RespondRread(data []byte) {
err := p.PackRread(req.Rc, data)
func (req *SrvReq) RespondRread(data []byte) {
err := PackRread(req.Rc, data)
if err != nil {
req.RespondError(err)
} else {
@ -102,8 +116,8 @@ func (req *Req) RespondRread(data []byte) {
}
// Respond to the request with Rwrite message
func (req *Req) RespondRwrite(count uint32) {
err := p.PackRwrite(req.Rc, count)
func (req *SrvReq) RespondRwrite(count uint32) {
err := PackRwrite(req.Rc, count)
if err != nil {
req.RespondError(err)
} else {
@ -112,8 +126,8 @@ func (req *Req) RespondRwrite(count uint32) {
}
// Respond to the request with Rclunk message
func (req *Req) RespondRclunk() {
err := p.PackRclunk(req.Rc)
func (req *SrvReq) RespondRclunk() {
err := PackRclunk(req.Rc)
if err != nil {
req.RespondError(err)
} else {
@ -122,8 +136,8 @@ func (req *Req) RespondRclunk() {
}
// Respond to the request with Rremove message
func (req *Req) RespondRremove() {
err := p.PackRremove(req.Rc)
func (req *SrvReq) RespondRremove() {
err := PackRremove(req.Rc)
if err != nil {
req.RespondError(err)
} else {
@ -132,8 +146,8 @@ func (req *Req) RespondRremove() {
}
// Respond to the request with Rstat message
func (req *Req) RespondRstat(st *p.Dir) {
err := p.PackRstat(req.Rc, st, req.Conn.Dotu)
func (req *SrvReq) RespondRstat(st *Dir) {
err := PackRstat(req.Rc, st, req.Conn.Dotu)
if err != nil {
req.RespondError(err)
} else {
@ -142,8 +156,8 @@ func (req *Req) RespondRstat(st *p.Dir) {
}
// Respond to the request with Rwstat message
func (req *Req) RespondRwstat() {
err := p.PackRwstat(req.Rc)
func (req *SrvReq) RespondRwstat() {
err := PackRwstat(req.Rc)
if err != nil {
req.RespondError(err)
} else {

View File

@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The srv package provides definitions and functions used to implement
// The srv package go9provides definitions and functions used to implement
// a 9P2000 file server.
package srv
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"net"
"runtime"
"sync"
@ -22,26 +21,18 @@ const (
reqSaved /* no response was produced after the request is worked on */
)
// Debug flags
const (
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr
DbgPrintPackets // print the raw packets on stderr
DbgLogFcalls // keep the last N 9P messages (can be accessed over http)
DbgLogPackets // keep the last N 9P messages (can be accessed over http)
)
var Eunknownfid error = &p.Error{"unknown fid", p.EINVAL}
var Enoauth error = &p.Error{"no authentication required", p.EINVAL}
var Einuse error = &p.Error{"fid already in use", p.EINVAL}
var Ebaduse error = &p.Error{"bad use of fid", p.EINVAL}
var Eopen error = &p.Error{"fid already opened", p.EINVAL}
var Enotdir error = &p.Error{"not a directory", p.ENOTDIR}
var Eperm error = &p.Error{"permission denied", p.EPERM}
var Etoolarge error = &p.Error{"i/o count too large", p.EINVAL}
var Ebadoffset error = &p.Error{"bad offset in directory read", p.EINVAL}
var Edirchange error = &p.Error{"cannot convert between files and directories", p.EINVAL}
var Enouser error = &p.Error{"unknown user", p.EINVAL}
var Enotimpl error = &p.Error{"not implemented", p.EINVAL}
var Eunknownfid error = &Error{"unknown fid", EINVAL}
var Enoauth error = &Error{"no authentication required", EINVAL}
var Einuse error = &Error{"fid already in use", EINVAL}
var Ebaduse error = &Error{"bad use of fid", EINVAL}
var Eopen error = &Error{"fid already opened", EINVAL}
var Enotdir error = &Error{"not a directory", ENOTDIR}
var Eperm error = &Error{"permission denied", EPERM}
var Etoolarge error = &Error{"i/o count too large", EINVAL}
var Ebadoffset error = &Error{"bad offset in directory read", EINVAL}
var Edirchange error = &Error{"cannot convert between files and directories", EINVAL}
var Enouser error = &Error{"unknown user", EINVAL}
var Enotimpl error = &Error{"not implemented", EINVAL}
// Authentication operations. The file server should implement them if
// it requires user authentication. The authentication in 9P2000 is
@ -50,28 +41,28 @@ var Enotimpl error = &p.Error{"not implemented", p.EINVAL}
// fid can be used by the user to get access to the actual files.
type AuthOps interface {
// AuthInit is called when the user starts the authentication
// process on Fid afid. The user that is being authenticated
// process on SrvFid afid. The user that is being authenticated
// is referred by afid.User. The function should return the Qid
// for the authentication file, or an Error if the user can't be
// authenticated
AuthInit(afid *Fid, aname string) (*p.Qid, error)
AuthInit(afid *SrvFid, aname string) (*Qid, error)
// AuthDestroy is called when an authentication fid is destroyed.
AuthDestroy(afid *Fid)
AuthDestroy(afid *SrvFid)
// AuthCheck is called after the authentication process is finished
// when the user tries to attach to the file server. If the function
// returns nil, the authentication was successful and the user has
// permission to access the files.
AuthCheck(fid *Fid, afid *Fid, aname string) error
AuthCheck(fid *SrvFid, afid *SrvFid, aname string) error
// AuthRead is called when the user attempts to read data from an
// authentication fid.
AuthRead(afid *Fid, offset uint64, data []byte) (count int, err error)
AuthRead(afid *SrvFid, offset uint64, data []byte) (count int, err error)
// AuthWrite is called when the user attempts to write data to an
// authentication fid.
AuthWrite(afid *Fid, offset uint64, data []byte) (count int, err error)
AuthWrite(afid *SrvFid, offset uint64, data []byte) (count int, err error)
}
// Connection operations. These should be implemented if the file server
@ -81,61 +72,41 @@ type ConnOps interface {
ConnClosed(*Conn)
}
// Fid operations. This interface should be implemented if the file server
// needs to be called when a Fid is destroyed.
type FidOps interface {
FidDestroy(*Fid)
// SrvFid operations. This interface should be implemented if the file server
// needs to be called when a SrvFid is destroyed.
type SrvFidOps interface {
FidDestroy(*SrvFid)
}
// Request operations. This interface should be implemented if the file server
// needs to bypass the default request process, or needs to perform certain
// operations before the (any) request is processed, or before (any) response
// sent back to the client.
type ReqProcessOps interface {
type SrvReqProcessOps interface {
// Called when a new request is received from the client. If the
// interface is not implemented, (req *Req) srv.Process() method is
// interface is not implemented, (req *SrvReq) srv.Process() method is
// called. If the interface is implemented, it is the user's
// responsibility to call srv.Process. If srv.Process isn't called,
// Fid, Afid and Newfid fields in Req are not set, and the ReqOps
// SrvFid, Afid and Newfid fields in SrvReq are not set, and the SrvReqOps
// methods are not called.
ReqProcess(*Req)
SrvReqProcess(*SrvReq)
// Called when a request is responded, i.e. when (req *Req)srv.Respond()
// Called when a request is responded, i.e. when (req *SrvReq)srv.Respond()
// is called and before the response is sent. If the interface is not
// implemented, (req *Req) srv.PostProcess() method is called to finalize
// the request. If the interface is implemented and ReqProcess calls
// the srv.Process method, ReqRespond should call the srv.PostProcess
// implemented, (req *SrvReq) srv.PostProcess() method is called to finalize
// the request. If the interface is implemented and SrvReqProcess calls
// the srv.Process method, SrvReqRespond should call the srv.PostProcess
// method.
ReqRespond(*Req)
SrvReqRespond(*SrvReq)
}
// Flush operation. This interface should be implemented if the file server
// can flush pending requests. If the interface is not implemented, requests
// that were passed to the file server implementation won't be flushed.
// The flush method should call the (req *Req) srv.Flush() method if the flush
// The flush method should call the (req *SrvReq) srv.Flush() method if the flush
// was successful so the request can be marked appropriately.
type FlushOp interface {
Flush(*Req)
}
// Request operations. This interface should be implemented by all file servers.
// The operations correspond directly to most of the 9P2000 message types.
type ReqOps interface {
Attach(*Req)
Walk(*Req)
Open(*Req)
Create(*Req)
Read(*Req)
Write(*Req)
Clunk(*Req)
Remove(*Req)
Stat(*Req)
Wstat(*Req)
}
type StatsOps interface {
statsRegister()
statsUnregister()
Flush(*SrvReq)
}
// The Srv type contains the basic fields used to control the 9P2000
@ -145,13 +116,13 @@ type StatsOps interface {
// that implements the file server operations.
type Srv struct {
sync.Mutex
Id string // Used for debugging and stats
Msize uint32 // Maximum size of the 9P2000 messages supported by the server
Dotu bool // If true, the server supports the 9P2000.u extension
Debuglevel int // debug level
Upool p.Users // Interface for finding users and groups known to the file server
Maxpend int // Maximum pending outgoing requests
Log *p.Logger
Id string // Used for debugging and stats
Msize uint32 // Maximum size of the 9P2000 messages supported by the server
Dotu bool // If true, the server supports the 9P2000.u extension
Debuglevel int // debug level
Upool Users // Interface for finding users and groups known to the file server
Maxpend int // Maximum pending outgoing requests
Log *Logger
ops interface{} // operations
conns map[*Conn]*Conn // List of connections
@ -167,11 +138,11 @@ type Conn struct {
Debuglevel int
conn net.Conn
fidpool map[uint32]*Fid
reqs map[uint16]*Req // all outstanding requests
fidpool map[uint32]*SrvFid
reqs map[uint16]*SrvReq // all outstanding requests
reqout chan *Req
rchan chan *p.Fcall
reqout chan *SrvReq
rchan chan *Fcall
done chan bool
// stats
@ -184,41 +155,42 @@ type Conn struct {
nwrites int // number of writes
}
// The Fid type identifies a file on the file server.
// A new Fid is created when the user attaches to the file server (the Attach
// operation), or when Walk-ing to a file. The Fid values are created
// automatically by the srv implementation. The FidDestroy operation is called
// when a Fid is destroyed.
type Fid struct {
// The SrvFid type identifies a file on the file server.
// A new SrvFid is created when the user attaches to the file server (the Attach
// operation), or when Walk-ing to a file. The SrvFid values are created
// automatically by the srv implementation. The SrvFidDestroy operation is called
// when a SrvFid is destroyed.
type SrvFid struct {
sync.Mutex
fid uint32
refcount int
opened bool // True if the Fid is opened
Fconn *Conn // Connection the Fid belongs to
Omode uint8 // Open mode (p.O* flags), if the fid is opened
Type uint8 // Fid type (p.QT* flags)
opened bool // True if the SrvFid is opened
Fconn *Conn // Connection the SrvFid belongs to
Omode uint8 // Open mode (O* flags), if the fid is opened
Type uint8 // SrvFid type (QT* flags)
Diroffset uint64 // If directory, the next valid read position
User p.User // The Fid's user
Aux interface{} // Can be used by the file server implementation for per-Fid data
Dirents []byte // If directory, the serialized dirents
User User // The SrvFid's user
Aux interface{} // Can be used by the file server implementation for per-SrvFid data
}
// The Req type represents a 9P2000 request. Each request has a
// T-message (Tc) and a R-message (Rc). If the ReqProcessOps don't
// override the default behavior, the implementation initializes Fid,
// Afid and Newfid values and automatically keeps track on when the Fids
// The SrvReq type represents a 9P2000 request. Each request has a
// T-message (Tc) and a R-message (Rc). If the SrvReqProcessOps don't
// override the default behavior, the implementation initializes SrvFid,
// Afid and Newfid values and automatically keeps track on when the SrvFids
// should be destroyed.
type Req struct {
type SrvReq struct {
sync.Mutex
Tc *p.Fcall // Incoming 9P2000 message
Rc *p.Fcall // Outgoing 9P2000 response
Fid *Fid // The Fid value for all messages that contain fid[4]
Afid *Fid // The Fid value for the messages that contain afid[4] (Tauth and Tattach)
Newfid *Fid // The Fid value for the messages that contain newfid[4] (Twalk)
Conn *Conn // Connection that the request belongs to
Tc *Fcall // Incoming 9P2000 message
Rc *Fcall // Outgoing 9P2000 response
Fid *SrvFid // The SrvFid value for all messages that contain fid[4]
Afid *SrvFid // The SrvFid value for the messages that contain afid[4] (Tauth and Tattach)
Newfid *SrvFid // The SrvFid value for the messages that contain newfid[4] (Twalk)
Conn *Conn // Connection that the request belongs to
status reqStatus
flushreq *Req
prev, next *Req
flushreq *SrvReq
prev, next *SrvReq
}
// The Start method should be called once the file server implementor
@ -226,23 +198,23 @@ type Req struct {
// values to the fields that are not initialized and creates the goroutines
// required for the server's operation. The method receives an empty
// interface value, ops, that should implement the interfaces the file server is
// interested in. Ops must implement the ReqOps interface.
// interested in. Ops must implement the SrvReqOps interface.
func (srv *Srv) Start(ops interface{}) bool {
if _, ok := (ops).(ReqOps); !ok {
if _, ok := (ops).(SrvReqOps); !ok {
return false
}
srv.ops = ops
if srv.Upool == nil {
srv.Upool = p.OsUsers
srv.Upool = OsUsers
}
if srv.Msize < p.IOHDRSZ {
srv.Msize = p.MSIZE
if srv.Msize < IOHDRSZ {
srv.Msize = MSIZE
}
if srv.Log == nil {
srv.Log = p.NewLogger(1024)
srv.Log = NewLogger(1024)
}
if sop, ok := (interface{}(srv)).(StatsOps); ok {
@ -256,7 +228,7 @@ func (srv *Srv) String() string {
return srv.Id
}
func (req *Req) process() {
func (req *SrvReq) process() {
req.Lock()
flushed := (req.status & reqFlush) != 0
if !flushed {
@ -268,8 +240,8 @@ func (req *Req) process() {
req.Respond()
}
if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok {
rop.ReqProcess(req)
if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok {
rop.SrvReqProcess(req)
} else {
req.Process()
}
@ -283,16 +255,16 @@ func (req *Req) process() {
}
// Performs the default processing of a request. Initializes
// the Fid, Afid and Newfid fields and calls the appropriate
// ReqOps operation for the message. The file server implementer
// should call it only if the file server implements the ReqProcessOps
// within the ReqProcess operation.
func (req *Req) Process() {
// the SrvFid, Afid and Newfid fields and calls the appropriate
// SrvReqOps operation for the message. The file server implementer
// should call it only if the file server implements the SrvReqProcessOps
// within the SrvReqProcess operation.
func (req *SrvReq) Process() {
conn := req.Conn
srv := conn.Srv
tc := req.Tc
if tc.Fid != p.NOFID && tc.Type != p.Tattach {
if tc.Fid != NOFID && tc.Type != Tattach {
srv.Lock()
req.Fid = conn.FidGet(tc.Fid)
srv.Unlock()
@ -304,83 +276,83 @@ func (req *Req) Process() {
switch req.Tc.Type {
default:
req.RespondError(&p.Error{"unknown message type", p.EINVAL})
req.RespondError(&Error{"unknown message type", EINVAL})
case p.Tversion:
case Tversion:
srv.version(req)
case p.Tauth:
case Tauth:
if runtime.GOOS == "windows" {
return
}
srv.auth(req)
case p.Tattach:
case Tattach:
srv.attach(req)
case p.Tflush:
case Tflush:
srv.flush(req)
case p.Twalk:
case Twalk:
srv.walk(req)
case p.Topen:
case Topen:
srv.open(req)
case p.Tcreate:
case Tcreate:
srv.create(req)
case p.Tread:
case Tread:
srv.read(req)
case p.Twrite:
case Twrite:
srv.write(req)
case p.Tclunk:
case Tclunk:
srv.clunk(req)
case p.Tremove:
case Tremove:
srv.remove(req)
case p.Tstat:
case Tstat:
srv.stat(req)
case p.Twstat:
case Twstat:
srv.wstat(req)
}
}
// Performs the post processing required if the (*Req) Process() method
// Performs the post processing required if the (*SrvReq) Process() method
// is called for a request. The file server implementer should call it
// only if the file server implements the ReqProcessOps within the
// ReqRespond operation.
func (req *Req) PostProcess() {
// only if the file server implements the SrvReqProcessOps within the
// SrvReqRespond operation.
func (req *SrvReq) PostProcess() {
srv := req.Conn.Srv
/* call the post-handlers (if needed) */
switch req.Tc.Type {
case p.Tauth:
case Tauth:
srv.authPost(req)
case p.Tattach:
case Tattach:
srv.attachPost(req)
case p.Twalk:
case Twalk:
srv.walkPost(req)
case p.Topen:
case Topen:
srv.openPost(req)
case p.Tcreate:
case Tcreate:
srv.createPost(req)
case p.Tread:
case Tread:
srv.readPost(req)
case p.Tclunk:
case Tclunk:
srv.clunkPost(req)
case p.Tremove:
case Tremove:
srv.removePost(req)
}
@ -404,8 +376,8 @@ func (req *Req) PostProcess() {
// should be initialized and contain valid 9P2000 message. In most cases
// the file server implementer shouldn't call this method directly. Instead
// one of the RespondR* methods should be used.
func (req *Req) Respond() {
var flushreqs *Req
func (req *SrvReq) Respond() {
var flushreqs *SrvReq
conn := req.Conn
req.Lock()
@ -425,7 +397,7 @@ func (req *Req) Respond() {
nextreq.next = nil
// if there are flush requests, move them to the next request
if req.flushreq != nil {
var p *Req = nil
var p *SrvReq = nil
r := nextreq.flushreq
for ; r != nil; p, r = r, r.flushreq {
}
@ -433,7 +405,7 @@ func (req *Req) Respond() {
if p == nil {
nextreq.flushreq = req.flushreq
} else {
p.next = req.flushreq
nextreq = req.flushreq
}
}
@ -444,8 +416,8 @@ func (req *Req) Respond() {
}
conn.Unlock()
if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok {
rop.ReqRespond(req)
if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok {
rop.SrvReqRespond(req)
} else {
req.PostProcess()
}
@ -469,18 +441,18 @@ func (req *Req) Respond() {
// Should be called to cancel a request. Should only be called
// from the Flush operation if the FlushOp is implemented.
func (req *Req) Flush() {
func (req *SrvReq) Flush() {
req.Lock()
req.status |= reqFlush
req.Unlock()
req.Respond()
}
// Lookup a Fid struct based on the 32-bit identifier sent over the wire.
// Lookup a SrvFid struct based on the 32-bit identifier sent over the wire.
// Returns nil if the fid is not found. Increases the reference count of
// the returned fid. The user is responsible to call DecRef once it no
// longer needs it.
func (conn *Conn) FidGet(fidno uint32) *Fid {
func (conn *Conn) FidGet(fidno uint32) *SrvFid {
conn.Lock()
fid, present := conn.fidpool[fidno]
conn.Unlock()
@ -491,10 +463,10 @@ func (conn *Conn) FidGet(fidno uint32) *Fid {
return fid
}
// Creates a new Fid struct for the fidno integer. Returns nil
// if the Fid for that number already exists. The returned fid
// Creates a new SrvFid struct for the fidno integer. Returns nil
// if the SrvFid for that number already exists. The returned fid
// has reference count set to 1.
func (conn *Conn) FidNew(fidno uint32) *Fid {
func (conn *Conn) FidNew(fidno uint32) *SrvFid {
conn.Lock()
_, present := conn.fidpool[fidno]
if present {
@ -502,7 +474,7 @@ func (conn *Conn) FidNew(fidno uint32) *Fid {
return nil
}
fid := new(Fid)
fid := new(SrvFid)
fid.fid = fidno
fid.refcount = 1
fid.Fconn = conn
@ -517,7 +489,7 @@ func (conn *Conn) String() string {
}
// Increase the reference count for the fid.
func (fid *Fid) IncRef() {
func (fid *SrvFid) IncRef() {
fid.Lock()
fid.refcount++
fid.Unlock()
@ -525,7 +497,7 @@ func (fid *Fid) IncRef() {
// Decrease the reference count for the fid. When the
// reference count reaches 0, the fid is no longer valid.
func (fid *Fid) DecRef() {
func (fid *SrvFid) DecRef() {
fid.Lock()
fid.refcount--
n := fid.refcount
@ -540,7 +512,7 @@ func (fid *Fid) DecRef() {
delete(conn.fidpool, fid.fid)
conn.Unlock()
if fop, ok := (conn.Srv.ops).(FidOps); ok {
if fop, ok := (conn.Srv.ops).(SrvFidOps); ok {
fop.FidDestroy(fid)
}
}

View File

@ -1,18 +1,17 @@
// +build httpstats
package srv
package go9p
import (
"fmt"
"io"
"k8s.io/minikube/third_party/go9p/p"
"net/http"
"sync"
)
var mux sync.RWMutex
var stat map[string]http.Handler
var once sync.Once
var httponce sync.Once
func register(s string, h http.Handler) {
mux.Lock()
@ -28,7 +27,7 @@ func register(s string, h http.Handler) {
mux.Unlock()
}
func (srv *Srv) statsRegister() {
once.Do(func() {
httponce.Do(func() {
http.HandleFunc("/go9p/", StatsHandler)
go http.ListenAndServe(":6060", nil)
})
@ -85,7 +84,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
fs := conn.Srv.Log.Filter(conn, DbgLogFcalls)
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
for i, l := range fs {
fc := l.Data.(*p.Fcall)
fc := l.Data.(*Fcall)
if fc.Type == 0 {
continue
}
@ -94,7 +93,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
if fc.Type%2 == 0 {
// try to find the response for the T message
for j := i + 1; j < len(fs); j++ {
rc := fs[j].Data.(*p.Fcall)
rc := fs[j].Data.(*Fcall)
if rc.Tag == fc.Tag {
lbl = fmt.Sprintf("<a href='#fc%d'>&#10164;</a>", j)
break
@ -103,7 +102,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
} else {
// try to find the request for the R message
for j := i - 1; j >= 0; j-- {
tc := fs[j].Data.(*p.Fcall)
tc := fs[j].Data.(*Fcall)
if tc.Tag == fc.Tag {
lbl = fmt.Sprintf("<a href='#fc%d'>&#10166;</a>", j)
break

6
third_party/go9p/stats.go vendored Normal file
View File

@ -0,0 +1,6 @@
package go9p
type StatsOps interface {
statsRegister()
statsUnregister()
}

View File

@ -2,51 +2,49 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ufs
package go9p
import (
"flag"
"io"
"log"
"os"
"os/user"
"path"
"sort"
"strconv"
"syscall"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
)
type Fid struct {
path string
file *os.File
dirs []os.FileInfo
diroffset uint64
st os.FileInfo
type ufsFid struct {
path string
file *os.File
dirs []os.FileInfo
direntends []int
dirents []byte
diroffset uint64
st os.FileInfo
}
type Ufs struct {
srv.Srv
Srv
Root string
}
var addr string
var debug int
var root string
var Enoent = &p.Error{"file not found", p.ENOENT}
func toError(err error) *p.Error {
func toError(err error) *Error {
var ecode uint32
ename := err.Error()
if e, ok := err.(syscall.Errno); ok {
ecode = uint32(e)
} else {
ecode = p.EIO
ecode = EIO
}
return &p.Error{ename, ecode}
return &Error{ename, ecode}
}
func (fid *Fid) stat() *p.Error {
func (fid *ufsFid) stat() *Error {
var err error
fid.st, err = os.Lstat(fid.path)
@ -60,24 +58,24 @@ func (fid *Fid) stat() *p.Error {
func omode2uflags(mode uint8) int {
ret := int(0)
switch mode & 3 {
case p.OREAD:
case OREAD:
ret = os.O_RDONLY
break
case p.ORDWR:
case ORDWR:
ret = os.O_RDWR
break
case p.OWRITE:
case OWRITE:
ret = os.O_WRONLY
break
case p.OEXEC:
case OEXEC:
ret = os.O_RDONLY
break
}
if mode&p.OTRUNC != 0 {
if mode&OTRUNC != 0 {
ret |= os.O_TRUNC
}
@ -87,11 +85,11 @@ func omode2uflags(mode uint8) int {
func dir2QidType(d os.FileInfo) uint8 {
ret := uint8(0)
if d.IsDir() {
ret |= p.QTDIR
ret |= QTDIR
}
if d.Mode()&os.ModeSymlink != 0 {
ret |= p.QTSYMLINK
ret |= QTSYMLINK
}
return ret
@ -100,33 +98,33 @@ func dir2QidType(d os.FileInfo) uint8 {
func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
ret := uint32(d.Mode() & 0777)
if d.IsDir() {
ret |= p.DMDIR
ret |= DMDIR
}
if dotu {
mode := d.Mode()
if mode&os.ModeSymlink != 0 {
ret |= p.DMSYMLINK
ret |= DMSYMLINK
}
if mode&os.ModeSocket != 0 {
ret |= p.DMSOCKET
ret |= DMSOCKET
}
if mode&os.ModeNamedPipe != 0 {
ret |= p.DMNAMEDPIPE
ret |= DMNAMEDPIPE
}
if mode&os.ModeDevice != 0 {
ret |= p.DMDEVICE
ret |= DMDEVICE
}
if mode&os.ModeSetuid != 0 {
ret |= p.DMSETUID
ret |= DMSETUID
}
if mode&os.ModeSetgid != 0 {
ret |= p.DMSETGID
ret |= DMSETGID
}
}
@ -135,48 +133,47 @@ func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
// Dir is an instantiation of the p.Dir structure
// that can act as a receiver for local methods.
type Dir struct {
p.Dir
type ufsDir struct {
Dir
}
func (*Ufs) ConnOpened(conn *srv.Conn) {
func (*Ufs) ConnOpened(conn *Conn) {
if conn.Srv.Debuglevel > 0 {
log.Println("connected")
}
}
func (*Ufs) ConnClosed(conn *srv.Conn) {
func (*Ufs) ConnClosed(conn *Conn) {
if conn.Srv.Debuglevel > 0 {
log.Println("disconnected")
}
}
func (*Ufs) FidDestroy(sfid *srv.Fid) {
var fid *Fid
func (*Ufs) FidDestroy(sfid *SrvFid) {
var fid *ufsFid
if sfid.Aux == nil {
return
}
fid = sfid.Aux.(*Fid)
fid = sfid.Aux.(*ufsFid)
if fid.file != nil {
fid.file.Close()
}
}
func (*Ufs) Attach(req *srv.Req) {
func (ufs *Ufs) Attach(req *SrvReq) {
if req.Afid != nil {
req.RespondError(srv.Enoauth)
req.RespondError(Enoauth)
return
}
tc := req.Tc
fid := new(Fid)
if len(tc.Aname) == 0 {
fid.path = root
} else {
fid.path = tc.Aname
}
fid := new(ufsFid)
// You can think of the ufs.Root as a 'chroot' of a sort.
// clients attach are not allowed to go outside the
// directory represented by ufs.Root
fid.path = path.Join(ufs.Root, tc.Aname)
req.Fid.Aux = fid
err := fid.stat()
@ -189,10 +186,10 @@ func (*Ufs) Attach(req *srv.Req) {
req.RespondRattach(qid)
}
func (*Ufs) Flush(req *srv.Req) {}
func (*Ufs) Flush(req *SrvReq) {}
func (*Ufs) Walk(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc
err := fid.stat()
@ -202,11 +199,11 @@ func (*Ufs) Walk(req *srv.Req) {
}
if req.Newfid.Aux == nil {
req.Newfid.Aux = new(Fid)
req.Newfid.Aux = new(ufsFid)
}
nfid := req.Newfid.Aux.(*Fid)
wqids := make([]p.Qid, len(tc.Wname))
nfid := req.Newfid.Aux.(*ufsFid)
wqids := make([]Qid, len(tc.Wname))
path := fid.path
i := 0
for ; i < len(tc.Wname); i++ {
@ -229,8 +226,8 @@ func (*Ufs) Walk(req *srv.Req) {
req.RespondRwalk(wqids[0:i])
}
func (*Ufs) Open(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Open(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc
err := fid.stat()
if err != nil {
@ -248,8 +245,8 @@ func (*Ufs) Open(req *srv.Req) {
req.RespondRopen(dir2Qid(fid.st), 0)
}
func (*Ufs) Create(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Create(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc
err := fid.stat()
if err != nil {
@ -261,13 +258,13 @@ func (*Ufs) Create(req *srv.Req) {
var e error = nil
var file *os.File = nil
switch {
case tc.Perm&p.DMDIR != 0:
case tc.Perm&DMDIR != 0:
e = os.Mkdir(path, os.FileMode(tc.Perm&0777))
case tc.Perm&p.DMSYMLINK != 0:
case tc.Perm&DMSYMLINK != 0:
e = os.Symlink(tc.Ext, path)
case tc.Perm&p.DMLINK != 0:
case tc.Perm&DMLINK != 0:
n, e := strconv.ParseUint(tc.Ext, 10, 0)
if e != nil {
break
@ -275,25 +272,25 @@ func (*Ufs) Create(req *srv.Req) {
ofid := req.Conn.FidGet(uint32(n))
if ofid == nil {
req.RespondError(srv.Eunknownfid)
req.RespondError(Eunknownfid)
return
}
e = os.Link(ofid.Aux.(*Fid).path, path)
e = os.Link(ofid.Aux.(*ufsFid).path, path)
ofid.DecRef()
case tc.Perm&p.DMNAMEDPIPE != 0:
case tc.Perm&p.DMDEVICE != 0:
req.RespondError(&p.Error{"not implemented", p.EIO})
case tc.Perm&DMNAMEDPIPE != 0:
case tc.Perm&DMDEVICE != 0:
req.RespondError(&Error{"not implemented", EIO})
return
default:
var mode uint32 = tc.Perm & 0777
if req.Conn.Dotu {
if tc.Perm&p.DMSETUID > 0 {
if tc.Perm&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if tc.Perm&p.DMSETGID > 0 {
if tc.Perm&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
@ -320,8 +317,8 @@ func (*Ufs) Create(req *srv.Req) {
req.RespondRcreate(dir2Qid(fid.st), 0)
}
func (*Ufs) Read(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Read(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc
rc := req.Rc
err := fid.stat()
@ -330,67 +327,83 @@ func (*Ufs) Read(req *srv.Req) {
return
}
p.InitRread(rc, tc.Count)
InitRread(rc, tc.Count)
var count int
var e error
if fid.st.IsDir() {
b := rc.Data
if tc.Offset == 0 {
var e error
// If we got here, it was open. Can't really seek
// in most cases, just close and reopen it.
fid.file.Close()
fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0)
if e != nil {
if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil {
req.RespondError(toError(e))
return
}
if fid.dirs, e = fid.file.Readdir(-1); e != nil {
req.RespondError(toError(e))
return
}
fid.dirents = nil
fid.direntends = nil
for i := 0; i < len(fid.dirs); i++ {
path := fid.path + "/" + fid.dirs[i].Name()
st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
continue
}
b := PackDir(st, req.Conn.Dotu)
fid.dirents = append(fid.dirents, b...)
count += len(b)
fid.direntends = append(fid.direntends, count)
}
}
switch {
case tc.Offset > uint64(len(fid.dirents)):
count = 0
case len(fid.dirents[tc.Offset:]) > int(tc.Count):
count = int(tc.Count)
default:
count = len(fid.dirents[tc.Offset:])
}
if !*Akaros {
nextend := sort.SearchInts(fid.direntends, int(tc.Offset)+count)
if nextend < len(fid.direntends) {
if fid.direntends[nextend] > int(tc.Offset)+count {
if nextend > 0 {
count = fid.direntends[nextend-1] - int(tc.Offset)
} else {
count = 0
}
}
}
if count == 0 && int(tc.Offset) < len(fid.dirents) && len(fid.dirents) > 0 {
req.RespondError(&Error{"too small read size for dir entry", EINVAL})
return
}
}
for len(b) > 0 {
if fid.dirs == nil {
fid.dirs, e = fid.file.Readdir(16)
if e != nil && e != io.EOF {
req.RespondError(toError(e))
return
}
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count])
if len(fid.dirs) == 0 {
break
}
}
var i int
for i = 0; i < len(fid.dirs); i++ {
path := fid.path + "/" + fid.dirs[i].Name()
st := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
sz := p.PackDir(st, b, req.Conn.Dotu)
if sz == 0 {
break
}
b = b[sz:]
count += sz
}
if i < len(fid.dirs) {
fid.dirs = fid.dirs[i:]
break
} else {
fid.dirs = nil
}
}
} else {
count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset))
if e != nil && e != io.EOF {
req.RespondError(toError(e))
return
}
}
p.SetRreadCount(rc, uint32(count))
SetRreadCount(rc, uint32(count))
req.Respond()
}
func (*Ufs) Write(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Write(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc
err := fid.stat()
if err != nil {
@ -407,10 +420,10 @@ func (*Ufs) Write(req *srv.Req) {
req.RespondRwrite(uint32(n))
}
func (*Ufs) Clunk(req *srv.Req) { req.RespondRclunk() }
func (*Ufs) Clunk(req *SrvReq) { req.RespondRclunk() }
func (*Ufs) Remove(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Remove(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
@ -426,25 +439,30 @@ func (*Ufs) Remove(req *srv.Req) {
req.RespondRremove()
}
func (*Ufs) Stat(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (*Ufs) Stat(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
st := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
req.RespondError(derr)
return
}
req.RespondRstat(st)
}
func lookup(uid string, group bool) (uint32, *p.Error) {
func lookup(uid string, group bool) (uint32, *Error) {
if uid == "" {
return p.NOUID, nil
return NOUID, nil
}
usr, e := user.Lookup(uid)
if e != nil {
return p.NOUID, toError(e)
return NOUID, toError(e)
}
conv := usr.Uid
if group {
@ -452,23 +470,12 @@ func lookup(uid string, group bool) (uint32, *p.Error) {
}
u, e := strconv.Atoi(conv)
if e != nil {
return p.NOUID, toError(e)
return NOUID, toError(e)
}
return uint32(u), nil
}
func StartServer(addrVal string, debugVal int, rootVal string) {
addr = addrVal
debug = debugVal
root = rootVal
ufs := new(Ufs)
ufs.Dotu = true
ufs.Id = "ufs"
ufs.Debuglevel = debug
ufs.Start(ufs)
err := ufs.StartNetListener("tcp", addr)
if err != nil {
log.Println(err)
}
}
/* enables "Akaros" capabilities, which right now means
* a sane error message format.
*/
var Akaros = flag.Bool("akaros", false, "Akaros extensions")

29
third_party/go9p/ufs/ufs.go vendored Normal file
View File

@ -0,0 +1,29 @@
// 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 ufs
import (
"fmt"
"log"
"k8s.io/minikube/third_party/go9p"
)
func StartServer(addrVal string, debugVal int, rootVal string) {
ufs := new(go9p.Ufs)
ufs.Dotu = true
ufs.Id = "ufs"
ufs.Root = rootVal
ufs.Debuglevel = debugVal
ufs.Start(ufs)
fmt.Print("ufs starting\n")
// determined by build tags
//extraFuncs()
err := ufs.StartNetListener("tcp", addrVal)
if err != nil {
log.Println(err)
}
}

View File

@ -1,20 +1,18 @@
// Copyright 2012 The go9p Authors. All rights reserved.
// 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 ufs
package go9p
import (
"fmt"
"os"
"os/user"
"path"
"strconv"
"strings"
"syscall"
"time"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
)
func atime(stat *syscall.Stat_t) time.Time {
@ -25,16 +23,18 @@ func atime(stat *syscall.Stat_t) time.Time {
func isBlock(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
return true
}
// IsChar reports if the file is a character device
func isChar(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
return true
}
func dir2Qid(d os.FileInfo) *p.Qid {
var qid p.Qid
func dir2Qid(d os.FileInfo) *Qid {
var qid Qid
qid.Path = d.Sys().(*syscall.Stat_t).Ino
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
@ -43,27 +43,34 @@ func dir2Qid(d os.FileInfo) *p.Qid {
return &qid
}
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
sysMode := d.Sys().(*syscall.Stat_t)
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
if r := recover(); r != nil {
fmt.Print("stat failed: ", r)
return nil, &os.PathError{"dir2Dir", path, nil}
}
sysif := d.Sys()
if sysif == nil {
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
}
sysMode := sysif.(*syscall.Stat_t)
dir := new(Dir)
dir := new(ufsDir)
dir.Qid = *dir2Qid(d)
dir.Mode = dir2Npmode(d, dotu)
dir.Atime = uint32(atime(sysMode).Unix())
dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
dir.Mtime = uint32(d.ModTime().Unix())
dir.Length = uint64(d.Size())
dir.Name = path[strings.LastIndex(path, "/")+1:]
if dotu {
dir.dotu(path, d, upool, sysMode)
return &dir.Dir
return &dir.Dir, nil
}
unixUid := int(sysMode.Uid)
unixGid := int(sysMode.Gid)
dir.Uid = strconv.Itoa(unixUid)
dir.Gid = strconv.Itoa(unixGid)
dir.Muid = "none"
// BUG(akumar): LookupId will never find names for
// groups, as it only operates on user ids.
@ -76,10 +83,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
dir.Gid = g.Username
}
return &dir.Dir
/* For Akaros, we use the Muid as the link value. */
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
dir.Muid, err = os.Readlink(path)
if err == nil {
dir.Mode |= DMSYMLINK
}
}
return &dir.Dir, nil
}
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) {
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
@ -95,7 +109,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = p.NOUID
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
@ -109,8 +123,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
}
}
func (*Ufs) Wstat(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (u *Ufs) Wstat(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
@ -121,10 +135,10 @@ func (*Ufs) Wstat(req *srv.Req) {
if dir.Mode != 0xFFFFFFFF {
mode := dir.Mode & 0777
if req.Conn.Dotu {
if dir.Mode&p.DMSETUID > 0 {
if dir.Mode&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if dir.Mode&p.DMSETGID > 0 {
if dir.Mode&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
@ -135,7 +149,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
uid, gid := p.NOUID, p.NOUID
uid, gid := NOUID, NOUID
if req.Conn.Dotu {
uid = dir.Uidnum
gid = dir.Gidnum
@ -159,7 +173,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
if uid != p.NOUID || gid != p.NOUID {
if uid != NOUID || gid != NOUID {
e := os.Chown(fid.path, int(uid), int(gid))
if e != nil {
req.RespondError(toError(e))
@ -168,13 +182,25 @@ func (*Ufs) Wstat(req *srv.Req) {
}
if dir.Name != "" {
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
err := syscall.Rename(fid.path, path)
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
// if first char is / it is relative to root, else relative to
// cwd.
var destpath string
if dir.Name[0] == '/' {
destpath = path.Join(u.Root, dir.Name)
fmt.Printf("/ results in %s\n", destpath)
} else {
fiddir, _ := path.Split(fid.path)
destpath = path.Join(fiddir, dir.Name)
fmt.Printf("rel results in %s\n", destpath)
}
err := syscall.Rename(fid.path, destpath)
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
if err != nil {
req.RespondError(toError(err))
return
}
fid.path = path
fid.path = destpath
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
@ -199,7 +225,7 @@ func (*Ufs) Wstat(req *srv.Req) {
case true:
mt = st.ModTime()
default:
at = atime(st.Sys().(*syscall.Stat_t))
//at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
}
}
e := os.Chtimes(fid.path, at, mt)

View File

@ -1,20 +1,14 @@
// Copyright 2012 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 ufs
package go9p
import (
"fmt"
"os"
"os/user"
"path"
"strconv"
"strings"
"syscall"
"time"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
)
func atime(stat *syscall.Stat_t) time.Time {
@ -25,16 +19,18 @@ func atime(stat *syscall.Stat_t) time.Time {
func isBlock(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
return true
}
// IsChar reports if the file is a character device
func isChar(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
return true
}
func dir2Qid(d os.FileInfo) *p.Qid {
var qid p.Qid
func dir2Qid(d os.FileInfo) *Qid {
var qid Qid
qid.Path = d.Sys().(*syscall.Stat_t).Ino
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
@ -43,27 +39,34 @@ func dir2Qid(d os.FileInfo) *p.Qid {
return &qid
}
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
sysMode := d.Sys().(*syscall.Stat_t)
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
if r := recover(); r != nil {
fmt.Print("stat failed: ", r)
return nil, &os.PathError{"dir2Dir", path, nil}
}
sysif := d.Sys()
if sysif == nil {
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
}
sysMode := sysif.(*syscall.Stat_t)
dir := new(Dir)
dir := new(ufsDir)
dir.Qid = *dir2Qid(d)
dir.Mode = dir2Npmode(d, dotu)
dir.Atime = uint32(atime(sysMode).Unix())
dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
dir.Mtime = uint32(d.ModTime().Unix())
dir.Length = uint64(d.Size())
dir.Name = path[strings.LastIndex(path, "/")+1:]
if dotu {
dir.dotu(path, d, upool, sysMode)
return &dir.Dir
return &dir.Dir, nil
}
unixUid := int(sysMode.Uid)
unixGid := int(sysMode.Gid)
dir.Uid = strconv.Itoa(unixUid)
dir.Gid = strconv.Itoa(unixGid)
dir.Muid = "none"
// BUG(akumar): LookupId will never find names for
// groups, as it only operates on user ids.
@ -76,10 +79,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
dir.Gid = g.Username
}
return &dir.Dir
/* For Akaros, we use the Muid as the link value. */
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
dir.Muid, err = os.Readlink(path)
if err == nil {
dir.Mode |= DMSYMLINK
}
}
return &dir.Dir, nil
}
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) {
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
@ -95,7 +105,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = p.NOUID
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
@ -109,8 +119,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
}
}
func (*Ufs) Wstat(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (u *Ufs) Wstat(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
@ -121,10 +131,10 @@ func (*Ufs) Wstat(req *srv.Req) {
if dir.Mode != 0xFFFFFFFF {
mode := dir.Mode & 0777
if req.Conn.Dotu {
if dir.Mode&p.DMSETUID > 0 {
if dir.Mode&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if dir.Mode&p.DMSETGID > 0 {
if dir.Mode&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
@ -135,7 +145,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
uid, gid := p.NOUID, p.NOUID
uid, gid := NOUID, NOUID
if req.Conn.Dotu {
uid = dir.Uidnum
gid = dir.Gidnum
@ -159,7 +169,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
if uid != p.NOUID || gid != p.NOUID {
if uid != NOUID || gid != NOUID {
e := os.Chown(fid.path, int(uid), int(gid))
if e != nil {
req.RespondError(toError(e))
@ -168,13 +178,25 @@ func (*Ufs) Wstat(req *srv.Req) {
}
if dir.Name != "" {
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
err := syscall.Rename(fid.path, path)
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
// if first char is / it is relative to root, else relative to
// cwd.
var destpath string
if dir.Name[0] == '/' {
destpath = path.Join(u.Root, dir.Name)
fmt.Printf("/ results in %s\n", destpath)
} else {
fiddir, _ := path.Split(fid.path)
destpath = path.Join(fiddir, dir.Name)
fmt.Printf("rel results in %s\n", destpath)
}
err := syscall.Rename(fid.path, destpath)
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
if err != nil {
req.RespondError(toError(err))
return
}
fid.path = path
fid.path = destpath
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
@ -199,7 +221,7 @@ func (*Ufs) Wstat(req *srv.Req) {
case true:
mt = st.ModTime()
default:
at = atime(st.Sys().(*syscall.Stat_t))
//at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
}
}
e := os.Chtimes(fid.path, at, mt)

View File

@ -1,63 +1,39 @@
// Copyright 2009 The Go Authors. All rights reserved.
// 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.
// http://golang.org/src/os/stat_windows.go
package ufs
package go9p
import (
"fmt"
"os"
"path"
"strings"
"syscall"
"time"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
)
// type Win32FileAttributeData struct {
// FileAttributes uint32
// CreationTime Filetime
// LastAccessTime Filetime
// LastWriteTime Filetime
// FileSizeHigh uint32
// FileSizeLow uint32
// }
// A FileInfo describes a file and is returned by Stat and Lstat.
// type FileInfo interface {
// Name() string // base name of the file
// Size() int64 // length in bytes for regular files; system-dependent for others
// Mode() FileMode // file mode bits
// ModTime() time.Time // modification time
// IsDir() bool // abbreviation for Mode().IsDir()
// Sys() interface{} // underlying data source (can return nil)
// }
func atime(fi os.FileInfo) time.Time {
return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
}
// IsBlock reports if the file is a block device
func isBlock(d os.FileInfo) bool {
// return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
// stat := d.Sys().(os.FileInfo)
// stat := d.Sys().(*syscall.Stat_t)
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
return true
}
// IsChar reports if the file is a character device
func isChar(d os.FileInfo) bool {
// stat := d.Sys().(os.FileInfo)
// stat := d.Sys().(*syscall.Stat_t)
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
return true
}
func dir2Qid(d os.FileInfo) *p.Qid {
var qid p.Qid
func dir2Qid(d os.FileInfo) *Qid {
var qid Qid
// d.Sys().(*syscall.Win32FileAttributeData)
qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow)
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
qid.Type = dir2QidType(d)
@ -65,20 +41,28 @@ func dir2Qid(d os.FileInfo) *p.Qid {
return &qid
}
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
// sysMode := d.Sys().(os.FileInfo)
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
if r := recover(); r != nil {
fmt.Print("stat failed: ", r)
return nil, &os.PathError{"dir2Dir", path, nil}
}
sysif := d.Sys()
if sysif == nil {
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
}
sysMode := sysif.(*syscall.Win32FileAttributeData)
dir := new(Dir)
dir := new(ufsDir)
dir.Qid = *dir2Qid(d)
dir.Mode = dir2Npmode(d, dotu)
// dir.Atime = uint32(atime(sysMode).Unix())
// dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
// dir.Mtime = uint32(d.ModTime().Unix())
dir.Length = uint64(d.Size())
dir.Name = path[strings.LastIndex(path, "/")+1:]
if dotu {
// dir.dotu(path, d, upool, sysMode)
return &dir.Dir
dir.dotu(path, d, upool, sysMode)
return &dir.Dir, nil
}
// unixUid := int(sysMode.Uid)
@ -101,10 +85,18 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
// dir.Gid = g.Username
// }
return &dir.Dir
var err error
/* For Akaros, we use the Muid as the link value. */
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
dir.Muid, err = os.Readlink(path)
if err == nil {
dir.Mode |= DMSYMLINK
}
}
return &dir.Dir, nil
}
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) {
// u := upool.Uid2User(int(sysMode.Uid))
// g := upool.Gid2Group(int(sysMode.Gid))
// dir.Uid = u.Name()
@ -120,7 +112,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
// dir.Ext = ""
// dir.Uidnum = uint32(u.Id())
// dir.Gidnum = uint32(g.Id())
// dir.Muidnum = p.NOUID
// dir.Muidnum = NOUID
// if d.Mode()&os.ModeSymlink != 0 {
// var err error
// dir.Ext, err = os.Readlink(path)
@ -137,12 +129,12 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
dir.Muid = "none"
dir.Uidnum = 0
dir.Gidnum = 0
dir.Muidnum = p.NOUID
dir.Muidnum = NOUID
dir.Ext = ""
}
func (*Ufs) Wstat(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (u *Ufs) Wstat(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
@ -153,10 +145,10 @@ func (*Ufs) Wstat(req *srv.Req) {
if dir.Mode != 0xFFFFFFFF {
mode := dir.Mode & 0777
if req.Conn.Dotu {
if dir.Mode&p.DMSETUID > 0 {
if dir.Mode&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if dir.Mode&p.DMSETGID > 0 {
if dir.Mode&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
@ -167,7 +159,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
uid, gid := p.NOUID, p.NOUID
uid, gid := NOUID, NOUID
if req.Conn.Dotu {
uid = dir.Uidnum
gid = dir.Gidnum
@ -191,7 +183,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
if uid != p.NOUID || gid != p.NOUID {
if uid != NOUID || gid != NOUID {
e := os.Chown(fid.path, int(uid), int(gid))
if e != nil {
req.RespondError(toError(e))
@ -200,13 +192,25 @@ func (*Ufs) Wstat(req *srv.Req) {
}
if dir.Name != "" {
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
err := syscall.Rename(fid.path, path)
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
// if first char is / it is relative to root, else relative to
// cwd.
var destpath string
if dir.Name[0] == '/' {
destpath = path.Join(u.Root, dir.Name)
fmt.Printf("/ results in %s\n", destpath)
} else {
fiddir, _ := path.Split(fid.path)
destpath = path.Join(fiddir, dir.Name)
fmt.Printf("rel results in %s\n", destpath)
}
err := syscall.Rename(fid.path, destpath)
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
if err != nil {
req.RespondError(toError(err))
return
}
fid.path = path
fid.path = destpath
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
@ -231,7 +235,7 @@ func (*Ufs) Wstat(req *srv.Req) {
// case true:
// mt = st.ModTime()
// default:
// at = atime(st.Sys().(os.FileInfo))
// //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
// }
// }
// e := os.Chtimes(fid.path, at, mt)

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
import (
"fmt"
@ -77,9 +77,14 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
goto szerror
}
fc.Unamenum = NOUID
if dotu && len(p) > 0 {
fc.Unamenum, p = gint32(p)
if dotu {
if len(p) > 0 {
fc.Unamenum, p = gint32(p)
} else {
fc.Unamenum = NOUID
}
} else {
fc.Unamenum = NOUID
}
case Rauth, Rattach:
@ -101,9 +106,12 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
goto szerror
}
fc.Unamenum = NOUID
if dotu && len(p) > 0 {
fc.Unamenum, p = gint32(p)
if dotu {
if len(p) > 0 {
fc.Unamenum, p = gint32(p)
} else {
fc.Unamenum = NOUID
}
}
case Rerror:
@ -193,15 +201,15 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
case Rstat:
m, p = gint16(p)
p = gstat(p, &fc.Dir, dotu)
if p == nil {
goto szerror
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)
p, _ = gstat(p, &fc.Dir, dotu)
case Rflush, Rclunk, Rremove, Rwstat:
}