提交 8e801e39 编写于 作者: A Aaron Prindle

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

上级 12e41aea
...@@ -26,7 +26,7 @@ import ( ...@@ -26,7 +26,7 @@ import (
"k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/machine" "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 // mountCmd represents the mount command
...@@ -42,6 +42,15 @@ var mountCmd = &cobra.Command{ ...@@ -42,6 +42,15 @@ var mountCmd = &cobra.Command{
fmt.Fprintln(os.Stderr, errText) fmt.Fprintln(os.Stderr, errText)
os.Exit(1) 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 var debugVal int
if glog.V(1) { if glog.V(1) {
debugVal = 1 // ufs.StartServer takes int debug param debugVal = 1 // ufs.StartServer takes int debug param
......
...@@ -30,6 +30,7 @@ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH} out/ ...@@ -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}/e2e-${OS_ARCH} out/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox.yaml testdata/ 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/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 # Set the executable bit on the e2e binary and out binary
chmod +x out/e2e-${OS_ARCH} chmod +x out/e2e-${OS_ARCH}
...@@ -63,4 +64,4 @@ curl "https://api.github.com/repos/kubernetes/minikube/statuses/${COMMIT}?access ...@@ -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}\"}" -d "{\"state\": \"$status\", \"description\": \"Jenkins\", \"target_url\": \"$target_url\", \"context\": \"${JOB_NAME}\"}"
set -x set -x
exit $result exit $result
\ No newline at end of file
...@@ -408,6 +408,7 @@ func Mount9pHost(api libmachine.API) error { ...@@ -408,6 +408,7 @@ func Mount9pHost(api libmachine.API) error {
if err != nil { if err != nil {
return errors.Wrap(err, "Error getting the host IP address to use from within the VM") return errors.Wrap(err, "Error getting the host IP address to use from within the VM")
} }
host.RunSSHCommand(GetMount9pCleanupCommand())
_, err = host.RunSSHCommand(GetMount9pCommand(ip)) _, err = host.RunSSHCommand(GetMount9pCommand(ip))
if err != nil { if err != nil {
return err return err
......
...@@ -77,7 +77,7 @@ func getVMHostIP(host *host.Host) (net.IP, error) { ...@@ -77,7 +77,7 @@ func getVMHostIP(host *host.Host) (net.IP, error) {
case "virtualbox": case "virtualbox":
return net.ParseIP("10.0.2.2"), nil return net.ParseIP("10.0.2.2"), nil
case "xhyve": case "xhyve":
return net.ParseIP("10.0.2.2"), nil return net.ParseIP("192.168.64.1"), nil
default: default:
return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver") return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver")
} }
......
...@@ -154,7 +154,7 @@ func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) { ...@@ -154,7 +154,7 @@ func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) {
flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates) flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates)
} }
if kubernetesConfig.APIServerName != "" { if kubernetesConfig.APIServerName != constants.APIServerName {
flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName) flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName)
} }
...@@ -226,9 +226,16 @@ else ...@@ -226,9 +226,16 @@ else
fi fi
`, constants.LocalkubePIDPath) `, constants.LocalkubePIDPath)
func GetMount9pCleanupCommand() string {
return `
sudo umount /mount-9p;
sudo rm -rf /mount-9p;
`
}
func GetMount9pCommand(ip net.IP) string { func GetMount9pCommand(ip net.IP) string {
return fmt.Sprintf(` return fmt.Sprintf(`
sudo mkdir /mount-9p; 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) sudo chmod 775 /mount-9p;`, ip)
} }
...@@ -41,4 +41,5 @@ func TestFunctional(t *testing.T) { ...@@ -41,4 +41,5 @@ func TestFunctional(t *testing.T) {
t.Run("Dashboard", testDashboard) t.Run("Dashboard", testDashboard)
t.Run("ServicesList", testServicesList) t.Run("ServicesList", testServicesList)
t.Run("Provisioning", testProvisioning) t.Run("Provisioning", testProvisioning)
t.Run("Mounting", testMounting)
} }
// +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)
}
}
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
...@@ -69,6 +69,17 @@ func (m *MinikubeRunner) RunCommand(command string, checkError bool) string { ...@@ -69,6 +69,17 @@ func (m *MinikubeRunner) RunCommand(command string, checkError bool) string {
return string(stdout) 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) { func (m *MinikubeRunner) SSH(command string) (string, error) {
path, _ := filepath.Abs(m.BinaryPath) path, _ := filepath.Abs(m.BinaryPath)
cmd := exec.Command(path, "ssh", command) cmd := exec.Command(path, "ssh", command)
......
# 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>
# 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>
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
...@@ -2,31 +2,18 @@ ...@@ -2,31 +2,18 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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. // a 9P2000 file client.
package clnt package go9p
import ( import (
"fmt" "fmt"
"k8s.io/minikube/third_party/go9p/p"
"log" "log"
"net" "net"
"sync" "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 // 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 // a 9P2000 file server and its methods can be used to access and manipulate
// the files exported by the server. // the files exported by the server.
...@@ -37,7 +24,7 @@ type Clnt struct { ...@@ -37,7 +24,7 @@ type Clnt struct {
Dotu bool // If true, 9P2000.u protocol is spoken Dotu bool // If true, 9P2000.u protocol is spoken
Root *Fid // Fid that points to the rood directory Root *Fid // Fid that points to the rood directory
Id string // Used when printing debug messages Id string // Used when printing debug messages
Log *p.Logger Log *Logger
conn net.Conn conn net.Conn
tagpool *pool tagpool *pool
...@@ -49,7 +36,7 @@ type Clnt struct { ...@@ -49,7 +36,7 @@ type Clnt struct {
err error err error
reqchan chan *Req reqchan chan *Req
tchan chan *p.Fcall tchan chan *Fcall
next, prev *Clnt next, prev *Clnt
} }
...@@ -60,33 +47,26 @@ type Fid struct { ...@@ -60,33 +47,26 @@ type Fid struct {
sync.Mutex sync.Mutex
Clnt *Clnt // Client the fid belongs to Clnt *Clnt // Client the fid belongs to
Iounit uint32 Iounit uint32
p.Qid // The Qid description for the file Qid // The Qid description for the file
Mode uint8 // Open mode (one of p.O* values) (if file is open) Mode uint8 // Open mode (one of O* values) (if file is open)
Fid uint32 // Fid number 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 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 // 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 { type File struct {
fid *Fid Fid *Fid
offset uint64 offset uint64
} }
type pool struct {
sync.Mutex
need int
nchan chan uint32
maxid uint32
imap []byte
}
type Req struct { type Req struct {
sync.Mutex sync.Mutex
Clnt *Clnt Clnt *Clnt
Tc *p.Fcall Tc *Fcall
Rc *p.Fcall Rc *Fcall
Err error Err error
Done chan *Req Done chan *Req
tag uint16 tag uint16
...@@ -101,18 +81,18 @@ type ClntList struct { ...@@ -101,18 +81,18 @@ type ClntList struct {
var clnts *ClntList var clnts *ClntList
var DefaultDebuglevel int var DefaultDebuglevel int
var DefaultLogger *p.Logger var DefaultLogger *Logger
func (clnt *Clnt) Rpcnb(r *Req) error { func (clnt *Clnt) Rpcnb(r *Req) error {
var tag uint16 var tag uint16
if r.Tc.Type == p.Tversion { if r.Tc.Type == Tversion {
tag = p.NOTAG tag = NOTAG
} else { } else {
tag = r.tag tag = r.tag
} }
p.SetTag(r.Tc, tag) SetTag(r.Tc, tag)
clnt.Lock() clnt.Lock()
if clnt.err != nil { if clnt.err != nil {
clnt.Unlock() clnt.Unlock()
...@@ -133,7 +113,7 @@ func (clnt *Clnt) Rpcnb(r *Req) error { ...@@ -133,7 +113,7 @@ func (clnt *Clnt) Rpcnb(r *Req) error {
return nil 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 := clnt.ReqAlloc()
r.Tc = tc r.Tc = tc
r.Done = make(chan *Req) r.Done = make(chan *Req)
...@@ -151,13 +131,15 @@ func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) { ...@@ -151,13 +131,15 @@ func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
func (clnt *Clnt) recv() { func (clnt *Clnt) recv() {
var err error var err error
var buf []byte
err = nil err = nil
buf := make([]byte, clnt.Msize*8)
pos := 0 pos := 0
for { for {
if len(buf) < int(clnt.Msize) { // Connect can change the client Msize.
b := make([]byte, clnt.Msize*8) clntmsize := int(atomic.LoadUint32(&clnt.Msize))
if len(buf) < clntmsize {
b := make([]byte, clntmsize*8)
copy(b, buf[0:pos]) copy(b, buf[0:pos])
buf = b buf = b
b = nil b = nil
...@@ -165,7 +147,7 @@ func (clnt *Clnt) recv() { ...@@ -165,7 +147,7 @@ func (clnt *Clnt) recv() {
n, oerr := clnt.conn.Read(buf[pos:]) n, oerr := clnt.conn.Read(buf[pos:])
if oerr != nil || n == 0 { if oerr != nil || n == 0 {
err = &p.Error{oerr.Error(), p.EIO} err = &Error{oerr.Error(), EIO}
clnt.Lock() clnt.Lock()
clnt.err = err clnt.err = err
clnt.Unlock() clnt.Unlock()
...@@ -174,10 +156,10 @@ func (clnt *Clnt) recv() { ...@@ -174,10 +156,10 @@ func (clnt *Clnt) recv() {
pos += n pos += n
for pos > 4 { for pos > 4 {
sz, _ := p.Gint32(buf) sz, _ := Gint32(buf)
if pos < int(sz) { if pos < int(sz) {
if len(buf) < 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]) copy(b, buf[0:pos])
buf = b buf = b
b = nil b = nil
...@@ -186,7 +168,7 @@ func (clnt *Clnt) recv() { ...@@ -186,7 +168,7 @@ func (clnt *Clnt) recv() {
break break
} }
fc, err, fcsize := p.Unpack(buf, clnt.Dotu) fc, err, fcsize := Unpack(buf, clnt.Dotu)
clnt.Lock() clnt.Lock()
if err != nil { if err != nil {
clnt.err = err clnt.err = err
...@@ -214,7 +196,7 @@ func (clnt *Clnt) recv() { ...@@ -214,7 +196,7 @@ func (clnt *Clnt) recv() {
} }
if r == nil { if r == nil {
clnt.err = &p.Error{"unexpected response", p.EINVAL} clnt.err = &Error{"unexpected response", EINVAL}
clnt.conn.Close() clnt.conn.Close()
clnt.Unlock() clnt.Unlock()
goto closed goto closed
...@@ -235,13 +217,13 @@ func (clnt *Clnt) recv() { ...@@ -235,13 +217,13 @@ func (clnt *Clnt) recv() {
clnt.Unlock() clnt.Unlock()
if r.Tc.Type != r.Rc.Type-1 { if r.Tc.Type != r.Rc.Type-1 {
if r.Rc.Type != p.Rerror { if r.Rc.Type != Rerror {
r.Err = &p.Error{"invalid response", p.EINVAL} r.Err = &Error{"invalid response", EINVAL}
log.Println(fmt.Sprintf("TTT %v", r.Tc)) log.Println(fmt.Sprintf("TTT %v", r.Tc))
log.Println(fmt.Sprintf("RRR %v", r.Rc)) log.Println(fmt.Sprintf("RRR %v", r.Rc))
} else { } else {
if r.Err == nil { 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 { ...@@ -335,12 +317,12 @@ func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt {
clnt.Debuglevel = DefaultDebuglevel clnt.Debuglevel = DefaultDebuglevel
clnt.Log = DefaultLogger clnt.Log = DefaultLogger
clnt.Id = c.RemoteAddr().String() + ":" clnt.Id = c.RemoteAddr().String() + ":"
clnt.tagpool = newPool(uint32(p.NOTAG)) clnt.tagpool = newPool(uint32(NOTAG))
clnt.fidpool = newPool(p.NOFID) clnt.fidpool = newPool(NOFID)
clnt.reqout = make(chan *Req) clnt.reqout = make(chan *Req)
clnt.done = make(chan bool) clnt.done = make(chan bool)
clnt.reqchan = make(chan *Req, 16) clnt.reqchan = make(chan *Req, 16)
clnt.tchan = make(chan *p.Fcall, 16) clnt.tchan = make(chan *Fcall, 16)
go clnt.recv() go clnt.recv()
go clnt.send() go clnt.send()
...@@ -373,8 +355,9 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) { ...@@ -373,8 +355,9 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
ver = "9P2000.u" ver = "9P2000.u"
} }
tc := p.NewFcall(clnt.Msize) clntmsize := atomic.LoadUint32(&clnt.Msize)
err := p.PackTversion(tc, clnt.Msize, ver) tc := NewFcall(clntmsize)
err := PackTversion(tc, clntmsize, ver)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -384,8 +367,8 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) { ...@@ -384,8 +367,8 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
return nil, err return nil, err
} }
if rc.Msize < clnt.Msize { if rc.Msize < atomic.LoadUint32(&clnt.Msize) {
clnt.Msize = rc.Msize atomic.StoreUint32(&clnt.Msize, rc.Msize)
} }
clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
...@@ -401,17 +384,17 @@ func (clnt *Clnt) FidAlloc() *Fid { ...@@ -401,17 +384,17 @@ func (clnt *Clnt) FidAlloc() *Fid {
return fid return fid
} }
func (clnt *Clnt) NewFcall() *p.Fcall { func (clnt *Clnt) NewFcall() *Fcall {
select { select {
case tc := <-clnt.tchan: case tc := <-clnt.tchan:
return tc return tc
default: default:
} }
return p.NewFcall(clnt.Msize) return NewFcall(atomic.LoadUint32(&clnt.Msize))
} }
func (clnt *Clnt) FreeFcall(fc *p.Fcall) { func (clnt *Clnt) FreeFcall(fc *Fcall) {
if fc != nil && len(fc.Buf) >= int(clnt.Msize) { if fc != nil && len(fc.Buf) >= int(atomic.LoadUint32(&clnt.Msize)) {
select { select {
case clnt.tchan <- fc: case clnt.tchan <- fc:
break break
...@@ -450,15 +433,7 @@ func (clnt *Clnt) ReqFree(req *Req) { ...@@ -450,15 +433,7 @@ func (clnt *Clnt) ReqFree(req *Req) {
} }
} }
func NewFile(f *Fid, offset uint64) *File { func (clnt *Clnt) logFcall(fc *Fcall) {
return &File{f, offset}
}
func (f *File) Fid() *Fid {
return f.fid
}
func (clnt *Clnt) logFcall(fc *p.Fcall) {
if clnt.Debuglevel&DbgLogPackets != 0 { if clnt.Debuglevel&DbgLogPackets != 0 {
pkt := make([]byte, len(fc.Pkt)) pkt := make([]byte, len(fc.Pkt))
copy(pkt, fc.Pkt) copy(pkt, fc.Pkt)
...@@ -466,13 +441,19 @@ func (clnt *Clnt) logFcall(fc *p.Fcall) { ...@@ -466,13 +441,19 @@ func (clnt *Clnt) logFcall(fc *p.Fcall) {
} }
if clnt.Debuglevel&DbgLogFcalls != 0 { if clnt.Debuglevel&DbgLogFcalls != 0 {
f := new(p.Fcall) f := new(Fcall)
*f = *fc *f = *fc
f.Pkt = nil f.Pkt = nil
clnt.Log.Log(f, clnt, DbgLogFcalls) 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() { func init() {
clnts = new(ClntList) clnts = new(ClntList)
if sop, ok := (interface{}(clnts)).(StatsOps); ok { if sop, ok := (interface{}(clnts)).(StatsOps); ok {
......
...@@ -2,16 +2,14 @@ ...@@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import "k8s.io/minikube/third_party/go9p/p"
// Clunks a fid. Returns nil if successful. // Clunks a fid. Returns nil if successful.
func (clnt *Clnt) Clunk(fid *Fid) (err error) { func (clnt *Clnt) Clunk(fid *Fid) (err error) {
err = nil err = nil
if fid.walked { if fid.walked {
tc := clnt.NewFcall() tc := clnt.NewFcall()
err := p.PackTclunk(tc, fid.Fid) err := PackTclunk(tc, fid.Fid)
if err != nil { if err != nil {
return err return err
} }
...@@ -21,12 +19,12 @@ func (clnt *Clnt) Clunk(fid *Fid) (err error) { ...@@ -21,12 +19,12 @@ func (clnt *Clnt) Clunk(fid *Fid) (err error) {
clnt.fidpool.putId(fid.Fid) clnt.fidpool.putId(fid.Fid)
fid.walked = false fid.walked = false
fid.Fid = p.NOFID fid.Fid = NOFID
return return
} }
// Closes a file. Returns nil if successful. // Closes a file. Returns nil if successful.
func (file *File) Close() error { func (file *File) Close() error {
// Should we cancel all pending requests for the File // Should we cancel all pending requests for the File
return file.fid.Clnt.Clunk(file.fid) return file.Fid.Clnt.Clunk(file.Fid)
} }
...@@ -2,19 +2,18 @@ ...@@ -2,19 +2,18 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import ( import (
"k8s.io/minikube/third_party/go9p/p"
"net" "net"
) )
// Creates an authentication fid for the specified user. Returns the fid, if // Creates an authentication fid for the specified user. Returns the fid, if
// successful, or an Error. // 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() fid := clnt.FidAlloc()
tc := clnt.NewFcall() 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 { if err != nil {
return nil, err return nil, err
} }
...@@ -24,7 +23,6 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) { ...@@ -24,7 +23,6 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
return nil, err return nil, err
} }
fid.Iounit = clnt.Msize - p.IOHDRSZ
fid.User = user fid.User = user
fid.walked = true fid.walked = true
return fid, nil return fid, nil
...@@ -33,18 +31,18 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) { ...@@ -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 // 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, // of the file server's file tree. Returns a Fid pointing to the root,
// if successful, or an Error. // 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 var afno uint32
if afid != nil { if afid != nil {
afno = afid.Fid afno = afid.Fid
} else { } else {
afno = p.NOFID afno = NOFID
} }
fid := clnt.FidAlloc() fid := clnt.FidAlloc()
tc := clnt.NewFcall() 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 { if err != nil {
return nil, err return nil, err
} }
...@@ -61,17 +59,17 @@ func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) { ...@@ -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. // 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) c, e := net.Dial(ntype, addr)
if e != nil { 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) { func MountConn(c net.Conn, aname string, msize uint32, user User) (*Clnt, error) {
clnt, err := Connect(c, 8192+p.IOHDRSZ, true) clnt, err := Connect(c, msize+IOHDRSZ, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -89,7 +87,7 @@ func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) { ...@@ -89,7 +87,7 @@ func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
// Closes the connection to the file sever. // Closes the connection to the file sever.
func (clnt *Clnt) Unmount() { func (clnt *Clnt) Unmount() {
clnt.Lock() clnt.Lock()
clnt.err = &p.Error{"connection closed", p.EIO} clnt.err = &Error{"connection closed", EIO}
clnt.conn.Close() clnt.conn.Close()
clnt.Unlock() clnt.Unlock()
} }
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import ( import (
"k8s.io/minikube/third_party/go9p/p"
"strings" "strings"
) )
...@@ -13,7 +12,7 @@ import ( ...@@ -13,7 +12,7 @@ import (
// the operation is successful. // the operation is successful.
func (clnt *Clnt) Open(fid *Fid, mode uint8) error { func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
tc := clnt.NewFcall() tc := clnt.NewFcall()
err := p.PackTopen(tc, fid.Fid, mode) err := PackTopen(tc, fid.Fid, mode)
if err != nil { if err != nil {
return err return err
} }
...@@ -25,8 +24,8 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error { ...@@ -25,8 +24,8 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
fid.Qid = rc.Qid fid.Qid = rc.Qid
fid.Iounit = rc.Iounit fid.Iounit = rc.Iounit
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ { if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
fid.Iounit = clnt.Msize - p.IOHDRSZ fid.Iounit = clnt.Msize - IOHDRSZ
} }
fid.Mode = mode fid.Mode = mode
return nil return nil
...@@ -36,7 +35,7 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error { ...@@ -36,7 +35,7 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
// if the operation is successful. // if the operation is successful.
func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error { func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
tc := clnt.NewFcall() 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 { if err != nil {
return err return err
} }
...@@ -48,8 +47,8 @@ func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext str ...@@ -48,8 +47,8 @@ func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext str
fid.Qid = rc.Qid fid.Qid = rc.Qid
fid.Iounit = rc.Iounit fid.Iounit = rc.Iounit
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ { if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
fid.Iounit = clnt.Msize - p.IOHDRSZ fid.Iounit = clnt.Msize - IOHDRSZ
} }
fid.Mode = mode fid.Mode = mode
return nil return nil
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import "sync"
var m2id = [...]uint8{ var m2id = [...]uint8{
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 3,
...@@ -39,6 +41,14 @@ var m2id = [...]uint8{ ...@@ -39,6 +41,14 @@ var m2id = [...]uint8{
0, 1, 0, 2, 0, 1, 0, 0, 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 { func newPool(maxid uint32) *pool {
p := new(pool) p := new(pool)
p.maxid = maxid p.maxid = maxid
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import ( import (
"io" "io"
"k8s.io/minikube/third_party/go9p/p"
) )
// Reads count bytes starting from offset from the file associated with the fid. // 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) { ...@@ -18,7 +17,7 @@ func (clnt *Clnt) Read(fid *Fid, offset uint64, count uint32) ([]byte, error) {
} }
tc := clnt.NewFcall() tc := clnt.NewFcall()
err := p.PackTread(tc, fid.Fid, offset, count) err := PackTread(tc, fid.Fid, offset, count)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -45,7 +44,7 @@ func (file *File) Read(buf []byte) (int, error) { ...@@ -45,7 +44,7 @@ func (file *File) Read(buf []byte) (int, error) {
// Reads up to len(buf) bytes from the file starting from offset. // Reads up to len(buf) bytes from the file starting from offset.
// Returns the number of bytes read, or an Error. // Returns the number of bytes read, or an Error.
func (file *File) ReadAt(buf []byte, offset int64) (int, 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 { if err != nil {
return 0, err return 0, err
} }
...@@ -85,10 +84,14 @@ func (file *File) Readn(buf []byte, offset uint64) (int, error) { ...@@ -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 // Returns an array of maximum num entries (if num is 0, returns
// all entries from the directory). If the operation fails, returns // all entries from the directory). If the operation fails, returns
// an Error. // an Error.
func (file *File) Readdir(num int) ([]*p.Dir, error) { func (file *File) Readdir(num int) ([]*Dir, error) {
buf := make([]byte, file.fid.Clnt.Msize-p.IOHDRSZ) buf := make([]byte, file.Fid.Clnt.Msize-IOHDRSZ)
dirs := make([]*p.Dir, 32) dirs := make([]*Dir, 32)
pos := 0 pos := 0
offset := file.offset
defer func() {
file.offset = offset
}()
for { for {
n, err := file.Read(buf) n, err := file.Read(buf)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
...@@ -100,14 +103,20 @@ func (file *File) Readdir(num int) ([]*p.Dir, error) { ...@@ -100,14 +103,20 @@ func (file *File) Readdir(num int) ([]*p.Dir, error) {
} }
for b := buf[0:n]; len(b) > 0; { 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 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 return nil, perr
} }
b = b[d.Size+2:] b = b[d.Size+2:]
offset += uint64(d.Size + 2)
if pos >= len(dirs) { if pos >= len(dirs) {
s := make([]*p.Dir, len(dirs)+32) s := make([]*Dir, len(dirs)+32)
copy(s, dirs) copy(s, dirs)
dirs = s dirs = s
} }
......
...@@ -2,22 +2,20 @@ ...@@ -2,22 +2,20 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import "k8s.io/minikube/third_party/go9p/p"
// Removes the file associated with the Fid. Returns nil if the // Removes the file associated with the Fid. Returns nil if the
// operation is successful. // operation is successful.
func (clnt *Clnt) Remove(fid *Fid) error { func (clnt *Clnt) Remove(fid *Fid) error {
tc := clnt.NewFcall() tc := clnt.NewFcall()
err := p.PackTremove(tc, fid.Fid) err := PackTremove(tc, fid.Fid)
if err != nil { if err != nil {
return err return err
} }
_, err = clnt.Rpc(tc) _, err = clnt.Rpc(tc)
clnt.fidpool.putId(fid.Fid) clnt.fidpool.putId(fid.Fid)
fid.Fid = p.NOFID fid.Fid = NOFID
return err return err
} }
......
...@@ -2,14 +2,12 @@ ...@@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import "k8s.io/minikube/third_party/go9p/p"
// Returns the metadata for the file associated with the Fid, or an Error. // 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() tc := clnt.NewFcall()
err := p.PackTstat(tc, fid.Fid) err := PackTstat(tc, fid.Fid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -23,7 +21,7 @@ func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) { ...@@ -23,7 +21,7 @@ func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
} }
// Returns the metadata for a named file, or an 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) fid, err := clnt.FWalk(path)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -35,9 +33,9 @@ func (clnt *Clnt) FStat(path string) (*p.Dir, error) { ...@@ -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. // 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() tc := clnt.NewFcall()
err := p.PackTwstat(tc, fid.Fid, dir, clnt.Dotu) err := PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
if err != nil { if err != nil {
return err return err
} }
......
// +build httpstats // +build httpstats
package clnt package go9p
import ( import (
"fmt" "fmt"
"io" "io"
"k8s.io/minikube/third_party/go9p/p"
"net/http" "net/http"
) )
...@@ -18,7 +17,7 @@ func (clnt *Clnt) ServeHTTP(c http.ResponseWriter, r *http.Request) { ...@@ -18,7 +17,7 @@ func (clnt *Clnt) ServeHTTP(c http.ResponseWriter, r *http.Request) {
fs := clnt.Log.Filter(clnt, DbgLogFcalls) fs := clnt.Log.Filter(clnt, DbgLogFcalls)
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs))) io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
for _, l := range fs { for _, l := range fs {
fc := l.Data.(*p.Fcall) fc := l.Data.(*Fcall)
if fc.Type != 0 { if fc.Type != 0 {
io.WriteString(c, fmt.Sprintf("<br>%s", fc)) io.WriteString(c, fmt.Sprintf("<br>%s", fc))
} }
......
...@@ -2,9 +2,7 @@ ...@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import "k8s.io/minikube/third_party/go9p/p"
type Tag struct { type Tag struct {
clnt *Clnt clnt *Clnt
...@@ -54,22 +52,22 @@ func (tag *Tag) reqproc() { ...@@ -54,22 +52,22 @@ func (tag *Tag) reqproc() {
case r := <-tag.respchan: case r := <-tag.respchan:
rc := r.Rc rc := r.Rc
fid := r.fid fid := r.fid
err := r.Rc.Type == p.Rerror err := r.Rc.Type == Rerror
switch r.Tc.Type { switch r.Tc.Type {
case p.Tauth: case Tauth:
if err { if err {
fid.User = nil fid.User = nil
} }
case p.Tattach: case Tattach:
if !err { if !err {
fid.Qid = rc.Qid fid.Qid = rc.Qid
} else { } else {
fid.User = nil fid.User = nil
} }
case p.Twalk: case Twalk:
if !err { if !err {
fid.walked = true fid.walked = true
if len(rc.Wqid) > 0 { if len(rc.Wqid) > 0 {
...@@ -79,8 +77,8 @@ func (tag *Tag) reqproc() { ...@@ -79,8 +77,8 @@ func (tag *Tag) reqproc() {
fid.User = nil fid.User = nil
} }
case p.Topen: case Topen:
case p.Tcreate: case Tcreate:
if !err { if !err {
fid.Iounit = rc.Iounit fid.Iounit = rc.Iounit
fid.Qid = rc.Qid fid.Qid = rc.Qid
...@@ -88,8 +86,8 @@ func (tag *Tag) reqproc() { ...@@ -88,8 +86,8 @@ func (tag *Tag) reqproc() {
fid.Mode = 0 fid.Mode = 0
} }
case p.Tclunk: case Tclunk:
case p.Tremove: case Tremove:
tag.clnt.fidpool.putId(fid.Fid) tag.clnt.fidpool.putId(fid.Fid)
} }
...@@ -98,10 +96,10 @@ func (tag *Tag) reqproc() { ...@@ -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 := tag.reqAlloc()
req.fid = afid 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 { if err != nil {
return err return err
} }
...@@ -110,18 +108,18 @@ func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error { ...@@ -110,18 +108,18 @@ func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
return tag.clnt.Rpcnb(req) 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 var afno uint32
if afid != nil { if afid != nil {
afno = afid.Fid afno = afid.Fid
} else { } else {
afno = p.NOFID afno = NOFID
} }
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid 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 { if err != nil {
return err return err
} }
...@@ -137,7 +135,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error { ...@@ -137,7 +135,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
newfid.Qid = fid.Qid 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 { if err != nil {
return err return err
} }
...@@ -149,7 +147,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error { ...@@ -149,7 +147,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
func (tag *Tag) Open(fid *Fid, mode uint8) error { func (tag *Tag) Open(fid *Fid, mode uint8) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid req.fid = fid
err := p.PackTopen(req.Tc, fid.Fid, mode) err := PackTopen(req.Tc, fid.Fid, mode)
if err != nil { if err != nil {
return err return err
} }
...@@ -161,7 +159,7 @@ func (tag *Tag) Open(fid *Fid, mode uint8) error { ...@@ -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 { func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid 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 { if err != nil {
return err return err
} }
...@@ -173,7 +171,7 @@ func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext strin ...@@ -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 { func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid req.fid = fid
err := p.PackTread(req.Tc, fid.Fid, offset, count) err := PackTread(req.Tc, fid.Fid, offset, count)
if err != nil { if err != nil {
return err return err
} }
...@@ -184,7 +182,7 @@ func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error { ...@@ -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 { func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid 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 { if err != nil {
return err return err
} }
...@@ -195,7 +193,7 @@ func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error { ...@@ -195,7 +193,7 @@ func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
func (tag *Tag) Clunk(fid *Fid) error { func (tag *Tag) Clunk(fid *Fid) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid req.fid = fid
err := p.PackTclunk(req.Tc, fid.Fid) err := PackTclunk(req.Tc, fid.Fid)
if err != nil { if err != nil {
return err return err
} }
...@@ -206,7 +204,7 @@ func (tag *Tag) Clunk(fid *Fid) error { ...@@ -206,7 +204,7 @@ func (tag *Tag) Clunk(fid *Fid) error {
func (tag *Tag) Remove(fid *Fid) error { func (tag *Tag) Remove(fid *Fid) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid req.fid = fid
err := p.PackTremove(req.Tc, fid.Fid) err := PackTremove(req.Tc, fid.Fid)
if err != nil { if err != nil {
return err return err
} }
...@@ -217,7 +215,7 @@ func (tag *Tag) Remove(fid *Fid) error { ...@@ -217,7 +215,7 @@ func (tag *Tag) Remove(fid *Fid) error {
func (tag *Tag) Stat(fid *Fid) error { func (tag *Tag) Stat(fid *Fid) error {
req := tag.reqAlloc() req := tag.reqAlloc()
req.fid = fid req.fid = fid
err := p.PackTstat(req.Tc, fid.Fid) err := PackTstat(req.Tc, fid.Fid)
if err != nil { if err != nil {
return err return err
} }
...@@ -225,10 +223,10 @@ func (tag *Tag) Stat(fid *Fid) error { ...@@ -225,10 +223,10 @@ func (tag *Tag) Stat(fid *Fid) error {
return tag.clnt.Rpcnb(req) 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 := tag.reqAlloc()
req.fid = fid 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 { if err != nil {
return err return err
} }
......
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import ( import (
"k8s.io/minikube/third_party/go9p/p"
"strings" "strings"
) )
...@@ -13,9 +12,9 @@ import ( ...@@ -13,9 +12,9 @@ import (
// sequence and associates the resulting file with newfid. If no wnames // sequence and associates the resulting file with newfid. If no wnames
// were walked successfully, an Error is returned. Otherwise a slice with a // were walked successfully, an Error is returned. Otherwise a slice with a
// Qid for each walked name is returned. // 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() tc := clnt.NewFcall()
err := p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames) err := PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -66,12 +65,12 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) { ...@@ -66,12 +65,12 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
} }
tc := clnt.NewFcall() 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 { if err != nil {
goto error goto error
} }
var rc *p.Fcall var rc *Fcall
rc, err = clnt.Rpc(tc) rc, err = clnt.Rpc(tc)
if err != nil { if err != nil {
goto error goto error
...@@ -79,7 +78,7 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) { ...@@ -79,7 +78,7 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
newfid.walked = true newfid.walked = true
if len(rc.Wqid) != n { if len(rc.Wqid) != n {
err = &p.Error{"file not found", p.ENOENT} err = &Error{"file not found", ENOENT}
goto error goto error
} }
......
...@@ -2,9 +2,7 @@ ...@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package clnt package go9p
import "k8s.io/minikube/third_party/go9p/p"
// Write up to len(data) bytes starting from offset. Returns the // Write up to len(data) bytes starting from offset. Returns the
// number of bytes written, or an Error. // number of bytes written, or an Error.
...@@ -14,7 +12,7 @@ func (clnt *Clnt) Write(fid *Fid, data []byte, offset uint64) (int, error) { ...@@ -14,7 +12,7 @@ func (clnt *Clnt) Write(fid *Fid, data []byte, offset uint64) (int, error) {
} }
tc := clnt.NewFcall() 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 { if err != nil {
return 0, err return 0, err
} }
...@@ -41,7 +39,7 @@ func (file *File) Write(buf []byte) (int, error) { ...@@ -41,7 +39,7 @@ func (file *File) Write(buf []byte) (int, error) {
// Writes up to len(buf) bytes starting from offset. Returns the number // Writes up to len(buf) bytes starting from offset. Returns the number
// of bytes written, or an Error. // of bytes written, or an Error.
func (file *File) WriteAt(buf []byte, offset int64) (int, 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 // Writes exactly len(buf) bytes starting from offset. Returns the number of
......
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)
)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package p package go9p
import "fmt" import "fmt"
......
package p package go9p
type Log struct { type Log struct {
Data interface{} Data interface{}
......
...@@ -2,38 +2,33 @@ ...@@ -2,38 +2,33 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package p package go9p
import ( import "sync"
"os/user"
"strconv"
"sync"
)
var once sync.Once var once sync.Once
type osUser struct { type osUser struct {
*user.User
uid int uid int
gid int
} }
type osUsers struct { type osUsers struct {
users map[int]*osUser
groups map[int]*osGroup groups map[int]*osGroup
sync.Mutex sync.Mutex
} }
// Simple Users implementation that defers to os/user and fakes // Simple Users implementation that fakes looking up users and groups
// looking up groups by gid only. // by uid only. The names and groups memberships are empty
var OsUsers *osUsers 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) 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 { type osGroup struct {
gid int gid int
...@@ -47,33 +42,28 @@ func (g *osGroup) Members() []User { return nil } ...@@ -47,33 +42,28 @@ func (g *osGroup) Members() []User { return nil }
func initOsusers() { func initOsusers() {
OsUsers = new(osUsers) OsUsers = new(osUsers)
OsUsers.users = make(map[int]*osUser)
OsUsers.groups = make(map[int]*osGroup) 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 { func (up *osUsers) Uid2User(uid int) User {
u, err := user.LookupId(strconv.Itoa(uid)) once.Do(initOsusers)
if err != nil { OsUsers.Lock()
return nil 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 { func (up *osUsers) Uname2User(uname string) User {
u, err := user.Lookup(uname) // unimplemented
if err != nil { return nil
return nil
}
return newUser(u)
} }
func (up *osUsers) Gid2Group(gid int) Group { func (up *osUsers) Gid2Group(gid int) Group {
......
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
}
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
}
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)
}
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)
}
// 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)
}
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)
}
// 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
}
// 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))
}
// 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))
}
// 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))
}
// 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"),
},
}
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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. // the 9P2000 protocol.
package p // TODO.
// All the packet conversion code in this file is crap and needs a rewrite.
package go9p
import ( import (
"fmt" "fmt"
...@@ -44,9 +46,9 @@ const ( ...@@ -44,9 +46,9 @@ const (
) )
const ( const (
MSIZE = 8192 + IOHDRSZ // default message size (8192+IOHdrSz) MSIZE = 1048576 + IOHDRSZ // default message size (1048576+IOHdrSz)
IOHDRSZ = 24 // the non-data size of the Twrite messages IOHDRSZ = 24 // the non-data size of the Twrite messages
PORT = 564 // default port for 9P file servers PORT = 564 // default port for 9P file servers
) )
// Qid types // Qid types
...@@ -301,11 +303,12 @@ func gint64(buf []byte) (uint64, []byte) { ...@@ -301,11 +303,12 @@ func gint64(buf []byte) (uint64, []byte) {
func gstr(buf []byte) (string, []byte) { func gstr(buf []byte) (string, []byte) {
var n uint16 var n uint16
if buf == nil { if buf == nil || len(buf) < 2 {
return "", nil return "", nil
} }
n, buf = gint16(buf) n, buf = gint16(buf)
if int(n) > len(buf) { if int(n) > len(buf) {
return "", nil return "", nil
} }
...@@ -321,7 +324,8 @@ func gqid(buf []byte, qid *Qid) []byte { ...@@ -321,7 +324,8 @@ func gqid(buf []byte, qid *Qid) []byte {
return buf 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.Size, buf = gint16(buf)
d.Type, buf = gint16(buf) d.Type, buf = gint16(buf)
d.Dev, buf = gint32(buf) d.Dev, buf = gint32(buf)
...@@ -332,27 +336,29 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte { ...@@ -332,27 +336,29 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
d.Length, buf = gint64(buf) d.Length, buf = gint64(buf)
d.Name, buf = gstr(buf) d.Name, buf = gstr(buf)
if buf == nil { 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) d.Uid, buf = gstr(buf)
if buf == nil { if buf == nil {
return nil return nil, &Error{"d.Uid failed", EINVAL}
} }
d.Gid, buf = gstr(buf) d.Gid, buf = gstr(buf)
if buf == nil { if buf == nil {
return nil return nil, &Error{"d.Gid failed", EINVAL}
} }
d.Muid, buf = gstr(buf) d.Muid, buf = gstr(buf)
if buf == nil { if buf == nil {
return nil return nil, &Error{"d.Muid failed", EINVAL}
} }
if dotu { if dotu {
d.Ext, buf = gstr(buf) d.Ext, buf = gstr(buf)
if buf == nil { if buf == nil {
return nil return nil, &Error{"d.Ext failed", EINVAL}
} }
d.Uidnum, buf = gint32(buf) d.Uidnum, buf = gint32(buf)
...@@ -364,7 +370,7 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte { ...@@ -364,7 +370,7 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
d.Muidnum = NOUID d.Muidnum = NOUID
} }
return buf return buf, nil
} }
func pint8(val uint8, buf []byte) []byte { func pint8(val uint8, buf []byte) []byte {
...@@ -449,20 +455,17 @@ func pstat(d *Dir, buf []byte, dotu bool) []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 // 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. // 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) sz := statsz(d, dotu)
if sz > len(buf) { buf := make([]byte, sz)
return 0 pstat(d, buf, dotu)
} return buf
buf = pstat(d, buf, dotu)
return sz
} }
// Converts the on-the-wire representation of a stat to Stat value. // Converts the on-the-wire representation of a stat to Stat value.
// Returns an error if the conversion is impossible, otherwise // Returns an error if the conversion is impossible, otherwise
// a pointer to a Stat value. // 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] */ 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] */ 4 + 4 + 8 + /* atime[4] mtime[4] length[8] */
2 + 2 + 2 + 2 /* name[s] uid[s] gid[s] muid[s] */ 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) { ...@@ -472,19 +475,17 @@ func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
} }
if len(buf) < sz { 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) d = new(Dir)
buf = gstat(buf, d, dotu) b, err = gstat(buf, d, dotu)
if buf == nil { if err != nil {
goto szerror return nil, nil, 0, err
} }
return d, nil return d, b, len(buf) - len(b), nil
szerror:
return nil, &Error{"short buffer", EINVAL}
} }
...@@ -522,7 +523,7 @@ func packCommon(fc *Fcall, size int, id uint8) ([]byte, error) { ...@@ -522,7 +523,7 @@ func packCommon(fc *Fcall, size int, id uint8) ([]byte, error) {
func (err *Error) Error() string { func (err *Error) Error() string {
if err != nil { if err != nil {
return fmt.Sprintf("%s: %d", err.Err, err.Errornum) return err.Err
} }
return "" return ""
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package p package go9p
import "fmt"
// Create a Rversion message in the specified Fcall. // Create a Rversion message in the specified Fcall.
func PackRversion(fc *Fcall, msize uint32, version string) error { func PackRversion(fc *Fcall, msize uint32, version string) error {
...@@ -34,9 +36,17 @@ func PackRauth(fc *Fcall, aqid *Qid) error { ...@@ -34,9 +36,17 @@ func PackRauth(fc *Fcall, aqid *Qid) error {
} }
// Create a Rerror message in the specified Fcall. If dotu is true, // 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. // 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 { 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] */ size := 2 + len(error) /* ename[s] */
if dotu { if dotu {
size += 4 /* ecode[4] */ size += 4 /* ecode[4] */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package p package go9p
// Create a Tversion message in the specified Fcall. // Create a Tversion message in the specified Fcall.
func PackTversion(fc *Fcall, msize uint32, version string) error { func PackTversion(fc *Fcall, msize uint32, version string) error {
......
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package srv package go9p
import ( import (
"fmt" "fmt"
"k8s.io/minikube/third_party/go9p/p"
"log" "log"
"net" "net"
) )
...@@ -18,11 +17,11 @@ func (srv *Srv) NewConn(c net.Conn) { ...@@ -18,11 +17,11 @@ func (srv *Srv) NewConn(c net.Conn) {
conn.Dotu = srv.Dotu conn.Dotu = srv.Dotu
conn.Debuglevel = srv.Debuglevel conn.Debuglevel = srv.Debuglevel
conn.conn = c conn.conn = c
conn.fidpool = make(map[uint32]*Fid) conn.fidpool = make(map[uint32]*SrvFid)
conn.reqs = make(map[uint16]*Req) conn.reqs = make(map[uint16]*SrvReq)
conn.reqout = make(chan *Req, srv.Maxpend) conn.reqout = make(chan *SrvReq, srv.Maxpend)
conn.done = make(chan bool) conn.done = make(chan bool)
conn.rchan = make(chan *p.Fcall, 64) conn.rchan = make(chan *Fcall, 64)
srv.Lock() srv.Lock()
if srv.conns == nil { if srv.conns == nil {
...@@ -58,7 +57,7 @@ func (conn *Conn) close() { ...@@ -58,7 +57,7 @@ func (conn *Conn) close() {
} }
/* call FidDestroy for all remaining fids */ /* 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 { for _, fid := range conn.fidpool {
op.FidDestroy(fid) op.FidDestroy(fid)
} }
...@@ -87,7 +86,7 @@ func (conn *Conn) recv() { ...@@ -87,7 +86,7 @@ func (conn *Conn) recv() {
pos += n pos += n
for pos > 4 { for pos > 4 {
sz, _ := p.Gint32(buf) sz, _ := Gint32(buf)
if sz > conn.Msize { if sz > conn.Msize {
log.Println("bad client connection: ", conn.conn.RemoteAddr()) log.Println("bad client connection: ", conn.conn.RemoteAddr())
conn.conn.Close() conn.conn.Close()
...@@ -104,7 +103,7 @@ func (conn *Conn) recv() { ...@@ -104,7 +103,7 @@ func (conn *Conn) recv() {
break break
} }
fc, err, fcsize := p.Unpack(buf, conn.Dotu) fc, err, fcsize := Unpack(buf, conn.Dotu)
if err != nil { if err != nil {
log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf)) log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf))
conn.conn.Close() conn.conn.Close()
...@@ -113,12 +112,12 @@ func (conn *Conn) recv() { ...@@ -113,12 +112,12 @@ func (conn *Conn) recv() {
} }
tag := fc.Tag tag := fc.Tag
req := new(Req) req := new(SrvReq)
select { select {
case req.Rc = <-conn.rchan: case req.Rc = <-conn.rchan:
break break
default: default:
req.Rc = p.NewFcall(conn.Msize) req.Rc = NewFcall(conn.Msize)
} }
req.Conn = conn req.Conn = conn
...@@ -151,7 +150,15 @@ func (conn *Conn) recv() { ...@@ -151,7 +150,15 @@ func (conn *Conn) recv() {
} }
conn.Unlock() conn.Unlock()
if process { 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:] buf = buf[fcsize:]
...@@ -159,7 +166,6 @@ func (conn *Conn) recv() { ...@@ -159,7 +166,6 @@ func (conn *Conn) recv() {
} }
} }
panic("unreached")
} }
func (conn *Conn) send() { func (conn *Conn) send() {
...@@ -169,7 +175,7 @@ func (conn *Conn) send() { ...@@ -169,7 +175,7 @@ func (conn *Conn) send() {
return return
case req := <-conn.reqout: case req := <-conn.reqout:
p.SetTag(req.Rc, req.Tc.Tag) SetTag(req.Rc, req.Tc.Tag)
conn.Lock() conn.Lock()
conn.rsz += uint64(req.Rc.Size) conn.rsz += uint64(req.Rc.Size)
conn.npend-- conn.npend--
...@@ -216,7 +222,7 @@ func (conn *Conn) LocalAddr() net.Addr { ...@@ -216,7 +222,7 @@ func (conn *Conn) LocalAddr() net.Addr {
return conn.conn.LocalAddr() return conn.conn.LocalAddr()
} }
func (conn *Conn) logFcall(fc *p.Fcall) { func (conn *Conn) logFcall(fc *Fcall) {
if conn.Debuglevel&DbgLogPackets != 0 { if conn.Debuglevel&DbgLogPackets != 0 {
pkt := make([]byte, len(fc.Pkt)) pkt := make([]byte, len(fc.Pkt))
copy(pkt, fc.Pkt) copy(pkt, fc.Pkt)
...@@ -224,7 +230,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) { ...@@ -224,7 +230,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
} }
if conn.Debuglevel&DbgLogFcalls != 0 { if conn.Debuglevel&DbgLogFcalls != 0 {
f := new(p.Fcall) f := new(Fcall)
*f = *fc *f = *fc
f.Pkt = nil f.Pkt = nil
conn.Srv.Log.Log(f, conn, DbgLogFcalls) conn.Srv.Log.Log(f, conn, DbgLogFcalls)
...@@ -234,7 +240,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) { ...@@ -234,7 +240,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
func (srv *Srv) StartNetListener(ntype, addr string) error { func (srv *Srv) StartNetListener(ntype, addr string) error {
l, err := net.Listen(ntype, addr) l, err := net.Listen(ntype, addr)
if err != nil { if err != nil {
return &p.Error{err.Error(), p.EIO} return &Error{err.Error(), EIO}
} }
return srv.StartListener(l) return srv.StartListener(l)
...@@ -248,7 +254,7 @@ func (srv *Srv) StartListener(l net.Listener) error { ...@@ -248,7 +254,7 @@ func (srv *Srv) StartListener(l net.Listener) error {
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
return &p.Error{err.Error(), p.EIO} return &Error{err.Error(), EIO}
} }
srv.NewConn(c) srv.NewConn(c)
......
...@@ -2,20 +2,16 @@ ...@@ -2,20 +2,16 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package srv package go9p
import ( import "runtime"
"runtime"
"k8s.io/minikube/third_party/go9p/p" func (srv *Srv) version(req *SrvReq) {
)
func (srv *Srv) version(req *Req) {
tc := req.Tc tc := req.Tc
conn := req.Conn conn := req.Conn
if tc.Msize < p.IOHDRSZ { if tc.Msize < IOHDRSZ {
req.RespondError(&p.Error{"msize too small", p.EINVAL}) req.RespondError(&Error{"msize too small", EINVAL})
return return
} }
...@@ -32,7 +28,7 @@ func (srv *Srv) version(req *Req) { ...@@ -32,7 +28,7 @@ func (srv *Srv) version(req *Req) {
/* make sure that the responses of all current requests will be ignored */ /* make sure that the responses of all current requests will be ignored */
conn.Lock() conn.Lock()
for tag, r := range conn.reqs { for tag, r := range conn.reqs {
if tag == p.NOTAG { if tag == NOTAG {
continue continue
} }
...@@ -47,10 +43,10 @@ func (srv *Srv) version(req *Req) { ...@@ -47,10 +43,10 @@ func (srv *Srv) version(req *Req) {
req.RespondRversion(conn.Msize, ver) req.RespondRversion(conn.Msize, ver)
} }
func (srv *Srv) auth(req *Req) { func (srv *Srv) auth(req *SrvReq) {
tc := req.Tc tc := req.Tc
conn := req.Conn conn := req.Conn
if tc.Afid == p.NOFID { if tc.Afid == NOFID {
req.RespondError(Eunknownfid) req.RespondError(Eunknownfid)
return return
} }
...@@ -61,8 +57,8 @@ func (srv *Srv) auth(req *Req) { ...@@ -61,8 +57,8 @@ func (srv *Srv) auth(req *Req) {
return return
} }
var user p.User = nil var user User = nil
if tc.Unamenum != p.NOUID || conn.Dotu { if tc.Unamenum != NOUID || conn.Dotu {
user = srv.Upool.Uid2User(int(tc.Unamenum)) user = srv.Upool.Uid2User(int(tc.Unamenum))
} else if tc.Uname != "" { } else if tc.Uname != "" {
user = srv.Upool.Uname2User(tc.Uname) user = srv.Upool.Uname2User(tc.Uname)
...@@ -76,13 +72,13 @@ func (srv *Srv) auth(req *Req) { ...@@ -76,13 +72,13 @@ func (srv *Srv) auth(req *Req) {
} }
req.Afid.User = user req.Afid.User = user
req.Afid.Type = p.QTAUTH req.Afid.Type = QTAUTH
if aop, ok := (srv.ops).(AuthOps); ok { if aop, ok := (srv.ops).(AuthOps); ok {
aqid, err := aop.AuthInit(req.Afid, tc.Aname) aqid, err := aop.AuthInit(req.Afid, tc.Aname)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
aqid.Type |= p.QTAUTH // just in case aqid.Type |= QTAUTH // just in case
req.RespondRauth(aqid) req.RespondRauth(aqid)
} }
} else { } else {
...@@ -91,16 +87,16 @@ func (srv *Srv) auth(req *Req) { ...@@ -91,16 +87,16 @@ func (srv *Srv) auth(req *Req) {
} }
func (srv *Srv) authPost(req *Req) { func (srv *Srv) authPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == p.Rauth { if req.Rc != nil && req.Rc.Type == Rauth {
req.Afid.IncRef() req.Afid.IncRef()
} }
} }
func (srv *Srv) attach(req *Req) { func (srv *Srv) attach(req *SrvReq) {
tc := req.Tc tc := req.Tc
conn := req.Conn conn := req.Conn
if tc.Fid == p.NOFID { if tc.Fid == NOFID {
req.RespondError(Eunknownfid) req.RespondError(Eunknownfid)
return return
} }
...@@ -111,15 +107,15 @@ func (srv *Srv) attach(req *Req) { ...@@ -111,15 +107,15 @@ func (srv *Srv) attach(req *Req) {
return return
} }
if tc.Afid != p.NOFID { if tc.Afid != NOFID {
req.Afid = conn.FidGet(tc.Afid) req.Afid = conn.FidGet(tc.Afid)
if req.Afid == nil { if req.Afid == nil {
req.RespondError(Eunknownfid) req.RespondError(Eunknownfid)
} }
} }
var user p.User = nil var user User = nil
if tc.Unamenum != p.NOUID || conn.Dotu { if tc.Unamenum != NOUID || conn.Dotu {
user = srv.Upool.Uid2User(int(tc.Unamenum)) user = srv.Upool.Uid2User(int(tc.Unamenum))
} else if tc.Uname != "" { } else if tc.Uname != "" {
user = srv.Upool.Uname2User(tc.Uname) user = srv.Upool.Uname2User(tc.Uname)
...@@ -141,20 +137,20 @@ func (srv *Srv) attach(req *Req) { ...@@ -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) { func (srv *Srv) attachPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == p.Rattach { if req.Rc != nil && req.Rc.Type == Rattach {
req.Fid.Type = req.Rc.Qid.Type req.Fid.Type = req.Rc.Qid.Type
req.Fid.IncRef() req.Fid.IncRef()
} }
} }
func (srv *Srv) flush(req *Req) { func (srv *Srv) flush(req *SrvReq) {
conn := req.Conn conn := req.Conn
tag := req.Tc.Oldtag tag := req.Tc.Oldtag
p.PackRflush(req.Rc) PackRflush(req.Rc)
conn.Lock() conn.Lock()
r := conn.reqs[tag] r := conn.reqs[tag]
if r != nil { if r != nil {
...@@ -186,13 +182,13 @@ func (srv *Srv) flush(req *Req) { ...@@ -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 conn := req.Conn
tc := req.Tc tc := req.Tc
fid := req.Fid fid := req.Fid
/* we can't walk regular files, only clone them */ /* 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) req.RespondError(Enotdir)
return return
} }
...@@ -217,12 +213,12 @@ func (srv *Srv) walk(req *Req) { ...@@ -217,12 +213,12 @@ func (srv *Srv) walk(req *Req) {
req.Newfid.IncRef() 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 rc := req.Rc
if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil { if rc == nil || rc.Type != Rwalk || req.Newfid == nil {
return return
} }
...@@ -243,7 +239,7 @@ func (srv *Srv) walkPost(req *Req) { ...@@ -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 fid := req.Fid
tc := req.Tc tc := req.Tc
if fid.opened { if fid.opened {
...@@ -251,22 +247,22 @@ func (srv *Srv) open(req *Req) { ...@@ -251,22 +247,22 @@ func (srv *Srv) open(req *Req) {
return return
} }
if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD { if (fid.Type&QTDIR) != 0 && tc.Mode != OREAD {
req.RespondError(Eperm) req.RespondError(Eperm)
return return
} }
fid.Omode = tc.Mode 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 { 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 fid := req.Fid
tc := req.Tc tc := req.Tc
if fid.opened { if fid.opened {
...@@ -274,47 +270,47 @@ func (srv *Srv) create(req *Req) { ...@@ -274,47 +270,47 @@ func (srv *Srv) create(req *Req) {
return return
} }
if (fid.Type & p.QTDIR) == 0 { if (fid.Type & QTDIR) == 0 {
req.RespondError(Enotdir) req.RespondError(Enotdir)
return return
} }
/* can't open directories for other than reading */ /* 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) req.RespondError(Eperm)
return return
} }
/* can't create special files if not 9P2000.u */ /* 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) req.RespondError(Eperm)
return return
} }
fid.Omode = tc.Mode fid.Omode = tc.Mode
(req.Conn.Srv.ops).(ReqOps).Create(req) (req.Conn.Srv.ops).(SrvReqOps).Create(req)
} }
func (srv *Srv) createPost(req *Req) { func (srv *Srv) createPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil { if req.Rc != nil && req.Rc.Type == Rcreate && req.Fid != nil {
req.Fid.Type = req.Rc.Qid.Type req.Fid.Type = req.Rc.Qid.Type
req.Fid.opened = true req.Fid.opened = true
} }
} }
func (srv *Srv) read(req *Req) { func (srv *Srv) read(req *SrvReq) {
tc := req.Tc tc := req.Tc
fid := req.Fid fid := req.Fid
if tc.Count+p.IOHDRSZ > req.Conn.Msize { if tc.Count+IOHDRSZ > req.Conn.Msize {
req.RespondError(Etoolarge) req.RespondError(Etoolarge)
return return
} }
if (fid.Type & p.QTAUTH) != 0 { if (fid.Type & QTAUTH) != 0 {
var n int var n int
rc := req.Rc rc := req.Rc
err := p.InitRread(rc, tc.Count) err := InitRread(rc, tc.Count)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
return return
...@@ -327,7 +323,7 @@ func (srv *Srv) read(req *Req) { ...@@ -327,7 +323,7 @@ func (srv *Srv) read(req *Req) {
return return
} }
p.SetRreadCount(rc, uint32(n)) SetRreadCount(rc, uint32(n))
req.Respond() req.Respond()
} else { } else {
req.RespondError(Enotimpl) req.RespondError(Enotimpl)
...@@ -336,28 +332,27 @@ func (srv *Srv) read(req *Req) { ...@@ -336,28 +332,27 @@ func (srv *Srv) read(req *Req) {
return return
} }
if (fid.Type & p.QTDIR) != 0 { if (fid.Type & QTDIR) != 0 {
if tc.Offset == 0 { if tc.Offset == 0 {
fid.Diroffset = 0 fid.Diroffset = 0
} else if tc.Offset != fid.Diroffset { } else if tc.Offset != fid.Diroffset {
req.RespondError(Ebadoffset) fid.Diroffset = tc.Offset
return
} }
} }
(req.Conn.Srv.ops).(ReqOps).Read(req) (req.Conn.Srv.ops).(SrvReqOps).Read(req)
} }
func (srv *Srv) readPost(req *Req) { func (srv *Srv) readPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 { if req.Rc != nil && req.Rc.Type == Rread && (req.Fid.Type&QTDIR) != 0 {
req.Fid.Diroffset += uint64(req.Rc.Count) req.Fid.Diroffset += uint64(req.Rc.Count)
} }
} }
func (srv *Srv) write(req *Req) { func (srv *Srv) write(req *SrvReq) {
fid := req.Fid fid := req.Fid
tc := req.Tc tc := req.Tc
if (fid.Type & p.QTAUTH) != 0 { if (fid.Type & QTAUTH) != 0 {
tc := req.Tc tc := req.Tc
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok { if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data) n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
...@@ -373,22 +368,22 @@ func (srv *Srv) write(req *Req) { ...@@ -373,22 +368,22 @@ func (srv *Srv) write(req *Req) {
return 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) req.RespondError(Ebaduse)
return return
} }
if tc.Count+p.IOHDRSZ > req.Conn.Msize { if tc.Count+IOHDRSZ > req.Conn.Msize {
req.RespondError(Etoolarge) req.RespondError(Etoolarge)
return 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 fid := req.Fid
if (fid.Type & p.QTAUTH) != 0 { if (fid.Type & QTAUTH) != 0 {
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok { if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
op.AuthDestroy(fid) op.AuthDestroy(fid)
req.RespondRclunk() req.RespondRclunk()
...@@ -399,26 +394,26 @@ func (srv *Srv) clunk(req *Req) { ...@@ -399,26 +394,26 @@ func (srv *Srv) clunk(req *Req) {
return return
} }
(req.Conn.Srv.ops).(ReqOps).Clunk(req) (req.Conn.Srv.ops).(SrvReqOps).Clunk(req)
} }
func (srv *Srv) clunkPost(req *Req) { func (srv *Srv) clunkPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil { if req.Rc != nil && req.Rc.Type == Rclunk && req.Fid != nil {
req.Fid.DecRef() 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 { if req.Rc != nil && req.Fid != nil {
req.Fid.DecRef() 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 fid := req.Fid
d := &req.Tc.Dir d := &req.Tc.Dir
...@@ -428,12 +423,12 @@ func (srv *Srv) wstat(req *Req) { ...@@ -428,12 +423,12 @@ func (srv *Srv) wstat(req *Req) {
return return
} }
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) || if (d.Mode != 0xFFFFFFFF) && (((fid.Type&QTDIR) != 0 && (d.Mode&DMDIR) == 0) ||
((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) { ((d.Type&QTDIR) == 0 && (d.Mode&DMDIR) != 0)) {
req.RespondError(Edirchange) req.RespondError(Edirchange)
return return
} }
*/ */
(req.Conn.Srv.ops).(ReqOps).Wstat(req) (req.Conn.Srv.ops).(SrvReqOps).Wstat(req)
} }
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package srv package go9p
import ( import (
"k8s.io/minikube/third_party/go9p/p"
"log" "log"
"sync" "sync"
"time" "time"
...@@ -13,18 +12,18 @@ import ( ...@@ -13,18 +12,18 @@ import (
// The FStatOp interface provides a single operation (Stat) that will be // The FStatOp interface provides a single operation (Stat) that will be
// called before a file stat is sent back to the client. If implemented, // 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 { type FStatOp interface {
Stat(fid *FFid) error Stat(fid *FFid) error
} }
// The FWstatOp interface provides a single operation (Wstat) that will be // 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. // implemented, the operation will be called when Twstat message is received.
// If not implemented, "permission denied" error will be sent back. If the // If not implemented, "permission denied" error will be sent back. If the
// operation returns an Error, the error is send back to the client. // operation returns an Error, the error is send back to the client.
type FWstatOp interface { type FWstatOp interface {
Wstat(*FFid, *p.Dir) error Wstat(*FFid, *Dir) error
} }
// If the FReadOp interface is implemented, the Read operation will be called // If the FReadOp interface is implemented, the Read operation will be called
...@@ -44,16 +43,16 @@ type FWriteOp interface { ...@@ -44,16 +43,16 @@ type FWriteOp interface {
} }
// If the FCreateOp interface is implemented, the Create operation will be called // 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, // 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 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. // The operation returns the created file, or the error occured while creating it.
type FCreateOp interface { 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 // 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. // If not implemented, "permission denied" error will be send back.
// The operation returns nil if successful, or the error that occured while removing // The operation returns nil if successful, or the error that occured while removing
// the file. // the file.
...@@ -79,39 +78,40 @@ const ( ...@@ -79,39 +78,40 @@ const (
Fremoved FFlags = 1 << iota Fremoved FFlags = 1 << iota
) )
// The File type represents a file (or directory) served by the file server. // The srvFile type represents a file (or directory) served by the file server.
type File struct { type srvFile struct {
sync.Mutex sync.Mutex
p.Dir Dir
flags FFlags flags FFlags
Parent *File // parent Parent *srvFile // parent
next, prev *File // siblings, guarded by parent.Lock next, prev *srvFile // siblings, guarded by parent.Lock
cfirst, clast *File // children (if directory) cfirst, clast *srvFile // children (if directory)
Ops interface{} ops interface{}
} }
type FFid struct { type FFid struct {
F *File F *srvFile
Fid *Fid Fid *SrvFid
dirs []*File // used for readdir dirs []*srvFile // used for readdir
dirents []byte // serialized version of dirs
} }
// The Fsrv can be used to create file servers that serve // The Fsrv can be used to create file servers that serve
// simple trees of synthetic files. // simple trees of synthetic files.
type Fsrv struct { type Fsrv struct {
Srv Srv
Root *File Root *srvFile
} }
var lock sync.Mutex var lock sync.Mutex
var qnext uint64 var qnext uint64
var Eexist = &p.Error{"file already exists", p.EEXIST} var Eexist = &Error{"file already exists", EEXIST}
var Enoent = &p.Error{"file not found", p.ENOENT} var Enoent = &Error{"file not found", ENOENT}
var Enotempty = &p.Error{"directory not empty", p.EPERM} var Enotempty = &Error{"directory not empty", EPERM}
// Creates a file server with root as root directory // Creates a file server with root as root directory
func NewFileSrv(root *File) *Fsrv { func NewsrvFileSrv(root *srvFile) *Fsrv {
srv := new(Fsrv) srv := new(Fsrv)
srv.Root = root srv.Root = root
root.Parent = root // make sure we can .. in root root.Parent = root // make sure we can .. in root
...@@ -121,7 +121,7 @@ func NewFileSrv(root *File) *Fsrv { ...@@ -121,7 +121,7 @@ func NewFileSrv(root *File) *Fsrv {
// Initializes the fields of a file and add it to a directory. // Initializes the fields of a file and add it to a directory.
// Returns nil if successful, or an error. // 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() lock.Lock()
qpath := qnext qpath := qnext
...@@ -141,7 +141,7 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ...@@ -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()) f.Uidnum = uint32(uid.Id())
} else { } else {
f.Uid = "none" f.Uid = "none"
f.Uidnum = p.NOUID f.Uidnum = NOUID
} }
if gid != nil { if gid != nil {
...@@ -149,11 +149,11 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ...@@ -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()) f.Gidnum = uint32(gid.Id())
} else { } else {
f.Gid = "none" f.Gid = "none"
f.Gidnum = p.NOUID f.Gidnum = NOUID
} }
f.Muid = "" f.Muid = ""
f.Muidnum = p.NOUID f.Muidnum = NOUID
f.Ext = "" f.Ext = ""
if dir != nil { if dir != nil {
...@@ -180,12 +180,12 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ...@@ -180,12 +180,12 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Parent = f f.Parent = f
} }
f.Ops = ops f.ops = ops
return nil return nil
} }
// Removes a file from its parent directory. // Removes a file from its parent directory.
func (f *File) Remove() { func (f *srvFile) Remove() {
f.Lock() f.Lock()
if (f.flags & Fremoved) != 0 { if (f.flags & Fremoved) != 0 {
f.Unlock() f.Unlock()
...@@ -214,7 +214,7 @@ func (f *File) Remove() { ...@@ -214,7 +214,7 @@ func (f *File) Remove() {
p.Unlock() p.Unlock()
} }
func (f *File) Rename(name string) error { func (f *srvFile) Rename(name string) error {
p := f.Parent p := f.Parent
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
...@@ -229,8 +229,8 @@ func (f *File) Rename(name string) error { ...@@ -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. // Looks for a file in a directory. Returns nil if the file is not found.
func (p *File) Find(name string) *File { func (p *srvFile) Find(name string) *srvFile {
var f *File var f *srvFile
p.Lock() p.Lock()
for f = p.cfirst; f != nil; f = f.next { for f = p.cfirst; f != nil; f = f.next {
...@@ -244,8 +244,8 @@ func (p *File) Find(name string) *File { ...@@ -244,8 +244,8 @@ func (p *File) Find(name string) *File {
// Checks if the specified user has permission to perform // Checks if the specified user has permission to perform
// certain operation on a file. Perm contains one or more // certain operation on a file. Perm contains one or more
// of p.DMREAD, p.DMWRITE, and p.DMEXEC. // of DMREAD, DMWRITE, and DMEXEC.
func (f *File) CheckPerm(user p.User, perm uint32) bool { func (f *srvFile) CheckPerm(user User, perm uint32) bool {
if user == nil { if user == nil {
return false return false
} }
...@@ -285,7 +285,7 @@ func (f *File) CheckPerm(user p.User, perm uint32) bool { ...@@ -285,7 +285,7 @@ func (f *File) CheckPerm(user p.User, perm uint32) bool {
return false return false
} }
func (s *Fsrv) Attach(req *Req) { func (s *Fsrv) Attach(req *SrvReq) {
fid := new(FFid) fid := new(FFid)
fid.F = s.Root fid.F = s.Root
fid.Fid = req.Fid fid.Fid = req.Fid
...@@ -293,7 +293,7 @@ func (s *Fsrv) Attach(req *Req) { ...@@ -293,7 +293,7 @@ func (s *Fsrv) Attach(req *Req) {
req.RespondRattach(&s.Root.Qid) req.RespondRattach(&s.Root.Qid)
} }
func (*Fsrv) Walk(req *Req) { func (*Fsrv) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
tc := req.Tc tc := req.Tc
...@@ -304,7 +304,7 @@ func (*Fsrv) Walk(req *Req) { ...@@ -304,7 +304,7 @@ func (*Fsrv) Walk(req *Req) {
} }
nfid := req.Newfid.Aux.(*FFid) nfid := req.Newfid.Aux.(*FFid)
wqids := make([]p.Qid, len(tc.Wname)) wqids := make([]Qid, len(tc.Wname))
i := 0 i := 0
f := fid.F f := fid.F
for ; i < len(tc.Wname); i++ { for ; i < len(tc.Wname); i++ {
...@@ -314,8 +314,8 @@ func (*Fsrv) Walk(req *Req) { ...@@ -314,8 +314,8 @@ func (*Fsrv) Walk(req *Req) {
wqids[i] = f.Qid wqids[i] = f.Qid
continue continue
} }
if (wqids[i].Type & p.QTDIR) > 0 { if (wqids[i].Type & QTDIR) > 0 {
if !f.CheckPerm(req.Fid.User, p.DMEXEC) { if !f.CheckPerm(req.Fid.User, DMEXEC) {
break break
} }
} }
...@@ -342,22 +342,22 @@ func mode2Perm(mode uint8) uint32 { ...@@ -342,22 +342,22 @@ func mode2Perm(mode uint8) uint32 {
var perm uint32 = 0 var perm uint32 = 0
switch mode & 3 { switch mode & 3 {
case p.OREAD: case OREAD:
perm = p.DMREAD perm = DMREAD
case p.OWRITE: case OWRITE:
perm = p.DMWRITE perm = DMWRITE
case p.ORDWR: case ORDWR:
perm = p.DMREAD | p.DMWRITE perm = DMREAD | DMWRITE
} }
if (mode & p.OTRUNC) != 0 { if (mode & OTRUNC) != 0 {
perm |= p.DMWRITE perm |= DMWRITE
} }
return perm return perm
} }
func (*Fsrv) Open(req *Req) { func (*Fsrv) Open(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
tc := req.Tc tc := req.Tc
...@@ -366,7 +366,7 @@ func (*Fsrv) Open(req *Req) { ...@@ -366,7 +366,7 @@ func (*Fsrv) Open(req *Req) {
return return
} }
if op, ok := (fid.F.Ops).(FOpenOp); ok { if op, ok := (fid.F.ops).(FOpenOp); ok {
err := op.Open(fid, tc.Mode) err := op.Open(fid, tc.Mode)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -376,17 +376,17 @@ func (*Fsrv) Open(req *Req) { ...@@ -376,17 +376,17 @@ func (*Fsrv) Open(req *Req) {
req.RespondRopen(&fid.F.Qid, 0) req.RespondRopen(&fid.F.Qid, 0)
} }
func (*Fsrv) Create(req *Req) { func (*Fsrv) Create(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
tc := req.Tc tc := req.Tc
dir := fid.F dir := fid.F
if !dir.CheckPerm(req.Fid.User, p.DMWRITE) { if !dir.CheckPerm(req.Fid.User, DMWRITE) {
req.RespondError(Eperm) req.RespondError(Eperm)
return return
} }
if cop, ok := (dir.Ops).(FCreateOp); ok { if cop, ok := (dir.ops).(FCreateOp); ok {
f, err := cop.Create(fid, tc.Name, tc.Perm) f, err := cop.Create(fid, tc.Name, tc.Perm)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -399,55 +399,48 @@ func (*Fsrv) Create(req *Req) { ...@@ -399,55 +399,48 @@ func (*Fsrv) Create(req *Req) {
} }
} }
func (*Fsrv) Read(req *Req) { func (*Fsrv) Read(req *SrvReq) {
var i, n int var n int
var err error var err error
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
f := fid.F f := fid.F
tc := req.Tc tc := req.Tc
rc := req.Rc rc := req.Rc
p.InitRread(rc, tc.Count) InitRread(rc, tc.Count)
if f.Mode&p.DMDIR != 0 { if f.Mode&DMDIR != 0 {
// directory // Get all the directory entries and
// serialize them all into an output buffer.
// This greatly simplifies the directory read.
if tc.Offset == 0 { if tc.Offset == 0 {
var g *File var g *srvFile
fid.dirents = nil
f.Lock() f.Lock()
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next { for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
} }
fid.dirs = make([]*srvFile, n)
fid.dirs = make([]*File, n)
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next { for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
fid.dirs[n] = g fid.dirs[n] = g
fid.dirents = append(fid.dirents,
PackDir(&g.Dir, req.Conn.Dotu)...)
} }
f.Unlock() f.Unlock()
} }
n = 0 switch {
b := rc.Data case tc.Offset > uint64(len(fid.dirents)):
for i = 0; i < len(fid.dirs); i++ { n = 0
g := fid.dirs[i] case len(fid.dirents[tc.Offset:]) > int(tc.Size):
g.Lock() n = int(tc.Size)
if (g.flags & Fremoved) != 0 { default:
g.Unlock() n = len(fid.dirents[tc.Offset:])
continue
}
sz := p.PackDir(&g.Dir, b, req.Conn.Dotu)
g.Unlock()
if sz == 0 {
break
}
b = b[sz:]
n += sz
} }
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+1+n])
fid.dirs = fid.dirs[i:]
} else { } else {
// file // file
if rop, ok := f.Ops.(FReadOp); ok { if rop, ok := f.ops.(FReadOp); ok {
n, err = rop.Read(fid, rc.Data, tc.Offset) n, err = rop.Read(fid, rc.Data, tc.Offset)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -459,16 +452,16 @@ func (*Fsrv) Read(req *Req) { ...@@ -459,16 +452,16 @@ func (*Fsrv) Read(req *Req) {
} }
} }
p.SetRreadCount(rc, uint32(n)) SetRreadCount(rc, uint32(n))
req.Respond() req.Respond()
} }
func (*Fsrv) Write(req *Req) { func (*Fsrv) Write(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
f := fid.F f := fid.F
tc := req.Tc 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) n, err := wop.Write(fid, tc.Data, tc.Offset)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -481,10 +474,10 @@ func (*Fsrv) Write(req *Req) { ...@@ -481,10 +474,10 @@ func (*Fsrv) Write(req *Req) {
} }
func (*Fsrv) Clunk(req *Req) { func (*Fsrv) Clunk(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) 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) err := op.Clunk(fid)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -493,7 +486,7 @@ func (*Fsrv) Clunk(req *Req) { ...@@ -493,7 +486,7 @@ func (*Fsrv) Clunk(req *Req) {
req.RespondRclunk() req.RespondRclunk()
} }
func (*Fsrv) Remove(req *Req) { func (*Fsrv) Remove(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
f := fid.F f := fid.F
f.Lock() f.Lock()
...@@ -504,7 +497,7 @@ func (*Fsrv) Remove(req *Req) { ...@@ -504,7 +497,7 @@ func (*Fsrv) Remove(req *Req) {
} }
f.Unlock() f.Unlock()
if rop, ok := (f.Ops).(FRemoveOp); ok { if rop, ok := (f.ops).(FRemoveOp); ok {
err := rop.Remove(fid) err := rop.Remove(fid)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -518,11 +511,11 @@ func (*Fsrv) Remove(req *Req) { ...@@ -518,11 +511,11 @@ func (*Fsrv) Remove(req *Req) {
} }
} }
func (*Fsrv) Stat(req *Req) { func (*Fsrv) Stat(req *SrvReq) {
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
f := fid.F f := fid.F
if sop, ok := (f.Ops).(FStatOp); ok { if sop, ok := (f.ops).(FStatOp); ok {
err := sop.Stat(fid) err := sop.Stat(fid)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -534,12 +527,12 @@ func (*Fsrv) Stat(req *Req) { ...@@ -534,12 +527,12 @@ func (*Fsrv) Stat(req *Req) {
} }
} }
func (*Fsrv) Wstat(req *Req) { func (*Fsrv) Wstat(req *SrvReq) {
tc := req.Tc tc := req.Tc
fid := req.Fid.Aux.(*FFid) fid := req.Fid.Aux.(*FFid)
f := fid.F f := fid.F
if wop, ok := (f.Ops).(FWstatOp); ok { if wop, ok := (f.ops).(FWstatOp); ok {
err := wop.Wstat(fid, &tc.Dir) err := wop.Wstat(fid, &tc.Dir)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -551,7 +544,7 @@ func (*Fsrv) Wstat(req *Req) { ...@@ -551,7 +544,7 @@ func (*Fsrv) Wstat(req *Req) {
} }
} }
func (*Fsrv) FidDestroy(ffid *Fid) { func (*Fsrv) FidDestroy(ffid *SrvFid) {
if ffid.Aux == nil { if ffid.Aux == nil {
return return
} }
...@@ -562,7 +555,7 @@ func (*Fsrv) FidDestroy(ffid *Fid) { ...@@ -562,7 +555,7 @@ func (*Fsrv) FidDestroy(ffid *Fid) {
return // otherwise errs in bad walks return // otherwise errs in bad walks
} }
if op, ok := (f.Ops).(FDestroyOp); ok { if op, ok := (f.ops).(FDestroyOp); ok {
op.FidDestroy(fid) op.FidDestroy(fid)
} }
} }
// 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)
}
// 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)
}
}
// 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)
}
}
// 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 = ""
}
...@@ -2,28 +2,42 @@ ...@@ -2,28 +2,42 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package srv package go9p
import "fmt" 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 // Respond to the request with Rerror message
func (req *Req) RespondError(err interface{}) { func (req *SrvReq) RespondError(err interface{}) {
switch e := err.(type) { switch e := err.(type) {
case *p.Error: case *Error:
p.PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu) PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
case error: 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: 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() req.Respond()
} }
// Respond to the request with Rversion message // Respond to the request with Rversion message
func (req *Req) RespondRversion(msize uint32, version string) { func (req *SrvReq) RespondRversion(msize uint32, version string) {
err := p.PackRversion(req.Rc, msize, version) err := PackRversion(req.Rc, msize, version)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -32,8 +46,8 @@ func (req *Req) RespondRversion(msize uint32, version string) { ...@@ -32,8 +46,8 @@ func (req *Req) RespondRversion(msize uint32, version string) {
} }
// Respond to the request with Rauth message // Respond to the request with Rauth message
func (req *Req) RespondRauth(aqid *p.Qid) { func (req *SrvReq) RespondRauth(aqid *Qid) {
err := p.PackRauth(req.Rc, aqid) err := PackRauth(req.Rc, aqid)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -42,8 +56,8 @@ func (req *Req) RespondRauth(aqid *p.Qid) { ...@@ -42,8 +56,8 @@ func (req *Req) RespondRauth(aqid *p.Qid) {
} }
// Respond to the request with Rflush message // Respond to the request with Rflush message
func (req *Req) RespondRflush() { func (req *SrvReq) RespondRflush() {
err := p.PackRflush(req.Rc) err := PackRflush(req.Rc)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -52,8 +66,8 @@ func (req *Req) RespondRflush() { ...@@ -52,8 +66,8 @@ func (req *Req) RespondRflush() {
} }
// Respond to the request with Rattach message // Respond to the request with Rattach message
func (req *Req) RespondRattach(aqid *p.Qid) { func (req *SrvReq) RespondRattach(aqid *Qid) {
err := p.PackRattach(req.Rc, aqid) err := PackRattach(req.Rc, aqid)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -62,8 +76,8 @@ func (req *Req) RespondRattach(aqid *p.Qid) { ...@@ -62,8 +76,8 @@ func (req *Req) RespondRattach(aqid *p.Qid) {
} }
// Respond to the request with Rwalk message // Respond to the request with Rwalk message
func (req *Req) RespondRwalk(wqids []p.Qid) { func (req *SrvReq) RespondRwalk(wqids []Qid) {
err := p.PackRwalk(req.Rc, wqids) err := PackRwalk(req.Rc, wqids)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -72,8 +86,8 @@ func (req *Req) RespondRwalk(wqids []p.Qid) { ...@@ -72,8 +86,8 @@ func (req *Req) RespondRwalk(wqids []p.Qid) {
} }
// Respond to the request with Ropen message // Respond to the request with Ropen message
func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) { func (req *SrvReq) RespondRopen(qid *Qid, iounit uint32) {
err := p.PackRopen(req.Rc, qid, iounit) err := PackRopen(req.Rc, qid, iounit)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -82,8 +96,8 @@ func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) { ...@@ -82,8 +96,8 @@ func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
} }
// Respond to the request with Rcreate message // Respond to the request with Rcreate message
func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) { func (req *SrvReq) RespondRcreate(qid *Qid, iounit uint32) {
err := p.PackRcreate(req.Rc, qid, iounit) err := PackRcreate(req.Rc, qid, iounit)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -92,8 +106,8 @@ func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) { ...@@ -92,8 +106,8 @@ func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
} }
// Respond to the request with Rread message // Respond to the request with Rread message
func (req *Req) RespondRread(data []byte) { func (req *SrvReq) RespondRread(data []byte) {
err := p.PackRread(req.Rc, data) err := PackRread(req.Rc, data)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -102,8 +116,8 @@ func (req *Req) RespondRread(data []byte) { ...@@ -102,8 +116,8 @@ func (req *Req) RespondRread(data []byte) {
} }
// Respond to the request with Rwrite message // Respond to the request with Rwrite message
func (req *Req) RespondRwrite(count uint32) { func (req *SrvReq) RespondRwrite(count uint32) {
err := p.PackRwrite(req.Rc, count) err := PackRwrite(req.Rc, count)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -112,8 +126,8 @@ func (req *Req) RespondRwrite(count uint32) { ...@@ -112,8 +126,8 @@ func (req *Req) RespondRwrite(count uint32) {
} }
// Respond to the request with Rclunk message // Respond to the request with Rclunk message
func (req *Req) RespondRclunk() { func (req *SrvReq) RespondRclunk() {
err := p.PackRclunk(req.Rc) err := PackRclunk(req.Rc)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -122,8 +136,8 @@ func (req *Req) RespondRclunk() { ...@@ -122,8 +136,8 @@ func (req *Req) RespondRclunk() {
} }
// Respond to the request with Rremove message // Respond to the request with Rremove message
func (req *Req) RespondRremove() { func (req *SrvReq) RespondRremove() {
err := p.PackRremove(req.Rc) err := PackRremove(req.Rc)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -132,8 +146,8 @@ func (req *Req) RespondRremove() { ...@@ -132,8 +146,8 @@ func (req *Req) RespondRremove() {
} }
// Respond to the request with Rstat message // Respond to the request with Rstat message
func (req *Req) RespondRstat(st *p.Dir) { func (req *SrvReq) RespondRstat(st *Dir) {
err := p.PackRstat(req.Rc, st, req.Conn.Dotu) err := PackRstat(req.Rc, st, req.Conn.Dotu)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
...@@ -142,8 +156,8 @@ func (req *Req) RespondRstat(st *p.Dir) { ...@@ -142,8 +156,8 @@ func (req *Req) RespondRstat(st *p.Dir) {
} }
// Respond to the request with Rwstat message // Respond to the request with Rwstat message
func (req *Req) RespondRwstat() { func (req *SrvReq) RespondRwstat() {
err := p.PackRwstat(req.Rc) err := PackRwstat(req.Rc)
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
} else { } else {
......
// +build httpstats // +build httpstats
package srv package go9p
import ( import (
"fmt" "fmt"
"io" "io"
"k8s.io/minikube/third_party/go9p/p"
"net/http" "net/http"
"sync" "sync"
) )
var mux sync.RWMutex var mux sync.RWMutex
var stat map[string]http.Handler var stat map[string]http.Handler
var once sync.Once var httponce sync.Once
func register(s string, h http.Handler) { func register(s string, h http.Handler) {
mux.Lock() mux.Lock()
...@@ -28,7 +27,7 @@ func register(s string, h http.Handler) { ...@@ -28,7 +27,7 @@ func register(s string, h http.Handler) {
mux.Unlock() mux.Unlock()
} }
func (srv *Srv) statsRegister() { func (srv *Srv) statsRegister() {
once.Do(func() { httponce.Do(func() {
http.HandleFunc("/go9p/", StatsHandler) http.HandleFunc("/go9p/", StatsHandler)
go http.ListenAndServe(":6060", nil) go http.ListenAndServe(":6060", nil)
}) })
...@@ -85,7 +84,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { ...@@ -85,7 +84,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
fs := conn.Srv.Log.Filter(conn, DbgLogFcalls) fs := conn.Srv.Log.Filter(conn, DbgLogFcalls)
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs))) io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
for i, l := range fs { for i, l := range fs {
fc := l.Data.(*p.Fcall) fc := l.Data.(*Fcall)
if fc.Type == 0 { if fc.Type == 0 {
continue continue
} }
...@@ -94,7 +93,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { ...@@ -94,7 +93,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
if fc.Type%2 == 0 { if fc.Type%2 == 0 {
// try to find the response for the T message // try to find the response for the T message
for j := i + 1; j < len(fs); j++ { for j := i + 1; j < len(fs); j++ {
rc := fs[j].Data.(*p.Fcall) rc := fs[j].Data.(*Fcall)
if rc.Tag == fc.Tag { if rc.Tag == fc.Tag {
lbl = fmt.Sprintf("<a href='#fc%d'>&#10164;</a>", j) lbl = fmt.Sprintf("<a href='#fc%d'>&#10164;</a>", j)
break break
...@@ -103,7 +102,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { ...@@ -103,7 +102,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
} else { } else {
// try to find the request for the R message // try to find the request for the R message
for j := i - 1; j >= 0; j-- { for j := i - 1; j >= 0; j-- {
tc := fs[j].Data.(*p.Fcall) tc := fs[j].Data.(*Fcall)
if tc.Tag == fc.Tag { if tc.Tag == fc.Tag {
lbl = fmt.Sprintf("<a href='#fc%d'>&#10166;</a>", j) lbl = fmt.Sprintf("<a href='#fc%d'>&#10166;</a>", j)
break break
......
package go9p
type StatsOps interface {
statsRegister()
statsUnregister()
}
// 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)
}
}
// 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package ufs package go9p
import ( import (
"fmt" "fmt"
"os" "os"
"os/user" "os/user"
"path"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
"time" "time"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
) )
func atime(stat *syscall.Stat_t) time.Time { func atime(stat *syscall.Stat_t) time.Time {
...@@ -25,16 +23,18 @@ 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 { func isBlock(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t) stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
return true
} }
// IsChar reports if the file is a character device // IsChar reports if the file is a character device
func isChar(d os.FileInfo) bool { func isChar(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t) stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
return true
} }
func dir2Qid(d os.FileInfo) *p.Qid { func dir2Qid(d os.FileInfo) *Qid {
var qid p.Qid var qid Qid
qid.Path = d.Sys().(*syscall.Stat_t).Ino qid.Path = d.Sys().(*syscall.Stat_t).Ino
qid.Version = uint32(d.ModTime().UnixNano() / 1000000) qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
...@@ -43,27 +43,34 @@ func dir2Qid(d os.FileInfo) *p.Qid { ...@@ -43,27 +43,34 @@ func dir2Qid(d os.FileInfo) *p.Qid {
return &qid return &qid
} }
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
sysMode := d.Sys().(*syscall.Stat_t) 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.Qid = *dir2Qid(d)
dir.Mode = dir2Npmode(d, dotu) 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.Mtime = uint32(d.ModTime().Unix())
dir.Length = uint64(d.Size()) dir.Length = uint64(d.Size())
dir.Name = path[strings.LastIndex(path, "/")+1:] dir.Name = path[strings.LastIndex(path, "/")+1:]
if dotu { if dotu {
dir.dotu(path, d, upool, sysMode) dir.dotu(path, d, upool, sysMode)
return &dir.Dir return &dir.Dir, nil
} }
unixUid := int(sysMode.Uid) unixUid := int(sysMode.Uid)
unixGid := int(sysMode.Gid) unixGid := int(sysMode.Gid)
dir.Uid = strconv.Itoa(unixUid) dir.Uid = strconv.Itoa(unixUid)
dir.Gid = strconv.Itoa(unixGid) dir.Gid = strconv.Itoa(unixGid)
dir.Muid = "none"
// BUG(akumar): LookupId will never find names for // BUG(akumar): LookupId will never find names for
// groups, as it only operates on user ids. // 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 { ...@@ -76,10 +83,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
dir.Gid = g.Username 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)) u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid)) g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name() dir.Uid = u.Name()
...@@ -95,7 +109,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall ...@@ -95,7 +109,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
dir.Ext = "" dir.Ext = ""
dir.Uidnum = uint32(u.Id()) dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id()) dir.Gidnum = uint32(g.Id())
dir.Muidnum = p.NOUID dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 { if d.Mode()&os.ModeSymlink != 0 {
var err error var err error
dir.Ext, err = os.Readlink(path) dir.Ext, err = os.Readlink(path)
...@@ -109,8 +123,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall ...@@ -109,8 +123,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
} }
} }
func (*Ufs) Wstat(req *srv.Req) { func (u *Ufs) Wstat(req *SrvReq) {
fid := req.Fid.Aux.(*Fid) fid := req.Fid.Aux.(*ufsFid)
err := fid.stat() err := fid.stat()
if err != nil { if err != nil {
req.RespondError(err) req.RespondError(err)
...@@ -121,10 +135,10 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -121,10 +135,10 @@ func (*Ufs) Wstat(req *srv.Req) {
if dir.Mode != 0xFFFFFFFF { if dir.Mode != 0xFFFFFFFF {
mode := dir.Mode & 0777 mode := dir.Mode & 0777
if req.Conn.Dotu { if req.Conn.Dotu {
if dir.Mode&p.DMSETUID > 0 { if dir.Mode&DMSETUID > 0 {
mode |= syscall.S_ISUID mode |= syscall.S_ISUID
} }
if dir.Mode&p.DMSETGID > 0 { if dir.Mode&DMSETGID > 0 {
mode |= syscall.S_ISGID mode |= syscall.S_ISGID
} }
} }
...@@ -135,7 +149,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -135,7 +149,7 @@ func (*Ufs) Wstat(req *srv.Req) {
} }
} }
uid, gid := p.NOUID, p.NOUID uid, gid := NOUID, NOUID
if req.Conn.Dotu { if req.Conn.Dotu {
uid = dir.Uidnum uid = dir.Uidnum
gid = dir.Gidnum gid = dir.Gidnum
...@@ -159,7 +173,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -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)) e := os.Chown(fid.path, int(uid), int(gid))
if e != nil { if e != nil {
req.RespondError(toError(e)) req.RespondError(toError(e))
...@@ -168,13 +182,25 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -168,13 +182,25 @@ func (*Ufs) Wstat(req *srv.Req) {
} }
if dir.Name != "" { if dir.Name != "" {
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
err := syscall.Rename(fid.path, path) // 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 { if err != nil {
req.RespondError(toError(err)) req.RespondError(toError(err))
return return
} }
fid.path = path fid.path = destpath
} }
if dir.Length != 0xFFFFFFFFFFFFFFFF { if dir.Length != 0xFFFFFFFFFFFFFFFF {
...@@ -199,7 +225,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -199,7 +225,7 @@ func (*Ufs) Wstat(req *srv.Req) {
case true: case true:
mt = st.ModTime() mt = st.ModTime()
default: 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) e := os.Chtimes(fid.path, at, mt)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册