提交 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 {
......
...@@ -2,12 +2,11 @@ ...@@ -2,12 +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 srv package provides definitions and functions used to implement // The srv package go9provides definitions and functions used to implement
// a 9P2000 file server. // a 9P2000 file server.
package srv package go9p
import ( import (
"k8s.io/minikube/third_party/go9p/p"
"net" "net"
"runtime" "runtime"
"sync" "sync"
...@@ -22,26 +21,18 @@ const ( ...@@ -22,26 +21,18 @@ const (
reqSaved /* no response was produced after the request is worked on */ reqSaved /* no response was produced after the request is worked on */
) )
// Debug flags var Eunknownfid error = &Error{"unknown fid", EINVAL}
const ( var Enoauth error = &Error{"no authentication required", EINVAL}
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr var Einuse error = &Error{"fid already in use", EINVAL}
DbgPrintPackets // print the raw packets on stderr var Ebaduse error = &Error{"bad use of fid", EINVAL}
DbgLogFcalls // keep the last N 9P messages (can be accessed over http) var Eopen error = &Error{"fid already opened", EINVAL}
DbgLogPackets // keep the last N 9P messages (can be accessed over http) var Enotdir error = &Error{"not a directory", ENOTDIR}
) var Eperm error = &Error{"permission denied", EPERM}
var Etoolarge error = &Error{"i/o count too large", EINVAL}
var Eunknownfid error = &p.Error{"unknown fid", p.EINVAL} var Ebadoffset error = &Error{"bad offset in directory read", EINVAL}
var Enoauth error = &p.Error{"no authentication required", p.EINVAL} var Edirchange error = &Error{"cannot convert between files and directories", EINVAL}
var Einuse error = &p.Error{"fid already in use", p.EINVAL} var Enouser error = &Error{"unknown user", EINVAL}
var Ebaduse error = &p.Error{"bad use of fid", p.EINVAL} var Enotimpl error = &Error{"not implemented", EINVAL}
var Eopen error = &p.Error{"fid already opened", p.EINVAL}
var Enotdir error = &p.Error{"not a directory", p.ENOTDIR}
var Eperm error = &p.Error{"permission denied", p.EPERM}
var Etoolarge error = &p.Error{"i/o count too large", p.EINVAL}
var Ebadoffset error = &p.Error{"bad offset in directory read", p.EINVAL}
var Edirchange error = &p.Error{"cannot convert between files and directories", p.EINVAL}
var Enouser error = &p.Error{"unknown user", p.EINVAL}
var Enotimpl error = &p.Error{"not implemented", p.EINVAL}
// Authentication operations. The file server should implement them if // Authentication operations. The file server should implement them if
// it requires user authentication. The authentication in 9P2000 is // it requires user authentication. The authentication in 9P2000 is
...@@ -50,28 +41,28 @@ var Enotimpl error = &p.Error{"not implemented", p.EINVAL} ...@@ -50,28 +41,28 @@ var Enotimpl error = &p.Error{"not implemented", p.EINVAL}
// fid can be used by the user to get access to the actual files. // fid can be used by the user to get access to the actual files.
type AuthOps interface { type AuthOps interface {
// AuthInit is called when the user starts the authentication // AuthInit is called when the user starts the authentication
// process on Fid afid. The user that is being authenticated // process on SrvFid afid. The user that is being authenticated
// is referred by afid.User. The function should return the Qid // is referred by afid.User. The function should return the Qid
// for the authentication file, or an Error if the user can't be // for the authentication file, or an Error if the user can't be
// authenticated // authenticated
AuthInit(afid *Fid, aname string) (*p.Qid, error) AuthInit(afid *SrvFid, aname string) (*Qid, error)
// AuthDestroy is called when an authentication fid is destroyed. // AuthDestroy is called when an authentication fid is destroyed.
AuthDestroy(afid *Fid) AuthDestroy(afid *SrvFid)
// AuthCheck is called after the authentication process is finished // AuthCheck is called after the authentication process is finished
// when the user tries to attach to the file server. If the function // when the user tries to attach to the file server. If the function
// returns nil, the authentication was successful and the user has // returns nil, the authentication was successful and the user has
// permission to access the files. // permission to access the files.
AuthCheck(fid *Fid, afid *Fid, aname string) error AuthCheck(fid *SrvFid, afid *SrvFid, aname string) error
// AuthRead is called when the user attempts to read data from an // AuthRead is called when the user attempts to read data from an
// authentication fid. // authentication fid.
AuthRead(afid *Fid, offset uint64, data []byte) (count int, err error) AuthRead(afid *SrvFid, offset uint64, data []byte) (count int, err error)
// AuthWrite is called when the user attempts to write data to an // AuthWrite is called when the user attempts to write data to an
// authentication fid. // authentication fid.
AuthWrite(afid *Fid, offset uint64, data []byte) (count int, err error) AuthWrite(afid *SrvFid, offset uint64, data []byte) (count int, err error)
} }
// Connection operations. These should be implemented if the file server // Connection operations. These should be implemented if the file server
...@@ -81,61 +72,41 @@ type ConnOps interface { ...@@ -81,61 +72,41 @@ type ConnOps interface {
ConnClosed(*Conn) ConnClosed(*Conn)
} }
// Fid operations. This interface should be implemented if the file server // SrvFid operations. This interface should be implemented if the file server
// needs to be called when a Fid is destroyed. // needs to be called when a SrvFid is destroyed.
type FidOps interface { type SrvFidOps interface {
FidDestroy(*Fid) FidDestroy(*SrvFid)
} }
// Request operations. This interface should be implemented if the file server // Request operations. This interface should be implemented if the file server
// needs to bypass the default request process, or needs to perform certain // needs to bypass the default request process, or needs to perform certain
// operations before the (any) request is processed, or before (any) response // operations before the (any) request is processed, or before (any) response
// sent back to the client. // sent back to the client.
type ReqProcessOps interface { type SrvReqProcessOps interface {
// Called when a new request is received from the client. If the // Called when a new request is received from the client. If the
// interface is not implemented, (req *Req) srv.Process() method is // interface is not implemented, (req *SrvReq) srv.Process() method is
// called. If the interface is implemented, it is the user's // called. If the interface is implemented, it is the user's
// responsibility to call srv.Process. If srv.Process isn't called, // responsibility to call srv.Process. If srv.Process isn't called,
// Fid, Afid and Newfid fields in Req are not set, and the ReqOps // SrvFid, Afid and Newfid fields in SrvReq are not set, and the SrvReqOps
// methods are not called. // methods are not called.
ReqProcess(*Req) SrvReqProcess(*SrvReq)
// Called when a request is responded, i.e. when (req *Req)srv.Respond() // Called when a request is responded, i.e. when (req *SrvReq)srv.Respond()
// is called and before the response is sent. If the interface is not // is called and before the response is sent. If the interface is not
// implemented, (req *Req) srv.PostProcess() method is called to finalize // implemented, (req *SrvReq) srv.PostProcess() method is called to finalize
// the request. If the interface is implemented and ReqProcess calls // the request. If the interface is implemented and SrvReqProcess calls
// the srv.Process method, ReqRespond should call the srv.PostProcess // the srv.Process method, SrvReqRespond should call the srv.PostProcess
// method. // method.
ReqRespond(*Req) SrvReqRespond(*SrvReq)
} }
// Flush operation. This interface should be implemented if the file server // Flush operation. This interface should be implemented if the file server
// can flush pending requests. If the interface is not implemented, requests // can flush pending requests. If the interface is not implemented, requests
// that were passed to the file server implementation won't be flushed. // that were passed to the file server implementation won't be flushed.
// The flush method should call the (req *Req) srv.Flush() method if the flush // The flush method should call the (req *SrvReq) srv.Flush() method if the flush
// was successful so the request can be marked appropriately. // was successful so the request can be marked appropriately.
type FlushOp interface { type FlushOp interface {
Flush(*Req) Flush(*SrvReq)
}
// Request operations. This interface should be implemented by all file servers.
// The operations correspond directly to most of the 9P2000 message types.
type ReqOps interface {
Attach(*Req)
Walk(*Req)
Open(*Req)
Create(*Req)
Read(*Req)
Write(*Req)
Clunk(*Req)
Remove(*Req)
Stat(*Req)
Wstat(*Req)
}
type StatsOps interface {
statsRegister()
statsUnregister()
} }
// The Srv type contains the basic fields used to control the 9P2000 // The Srv type contains the basic fields used to control the 9P2000
...@@ -145,13 +116,13 @@ type StatsOps interface { ...@@ -145,13 +116,13 @@ type StatsOps interface {
// that implements the file server operations. // that implements the file server operations.
type Srv struct { type Srv struct {
sync.Mutex sync.Mutex
Id string // Used for debugging and stats Id string // Used for debugging and stats
Msize uint32 // Maximum size of the 9P2000 messages supported by the server Msize uint32 // Maximum size of the 9P2000 messages supported by the server
Dotu bool // If true, the server supports the 9P2000.u extension Dotu bool // If true, the server supports the 9P2000.u extension
Debuglevel int // debug level Debuglevel int // debug level
Upool p.Users // Interface for finding users and groups known to the file server Upool Users // Interface for finding users and groups known to the file server
Maxpend int // Maximum pending outgoing requests Maxpend int // Maximum pending outgoing requests
Log *p.Logger Log *Logger
ops interface{} // operations ops interface{} // operations
conns map[*Conn]*Conn // List of connections conns map[*Conn]*Conn // List of connections
...@@ -167,11 +138,11 @@ type Conn struct { ...@@ -167,11 +138,11 @@ type Conn struct {
Debuglevel int Debuglevel int
conn net.Conn conn net.Conn
fidpool map[uint32]*Fid fidpool map[uint32]*SrvFid
reqs map[uint16]*Req // all outstanding requests reqs map[uint16]*SrvReq // all outstanding requests
reqout chan *Req reqout chan *SrvReq
rchan chan *p.Fcall rchan chan *Fcall
done chan bool done chan bool
// stats // stats
...@@ -184,41 +155,42 @@ type Conn struct { ...@@ -184,41 +155,42 @@ type Conn struct {
nwrites int // number of writes nwrites int // number of writes
} }
// The Fid type identifies a file on the file server. // The SrvFid type identifies a file on the file server.
// A new Fid is created when the user attaches to the file server (the Attach // A new SrvFid is created when the user attaches to the file server (the Attach
// operation), or when Walk-ing to a file. The Fid values are created // operation), or when Walk-ing to a file. The SrvFid values are created
// automatically by the srv implementation. The FidDestroy operation is called // automatically by the srv implementation. The SrvFidDestroy operation is called
// when a Fid is destroyed. // when a SrvFid is destroyed.
type Fid struct { type SrvFid struct {
sync.Mutex sync.Mutex
fid uint32 fid uint32
refcount int refcount int
opened bool // True if the Fid is opened opened bool // True if the SrvFid is opened
Fconn *Conn // Connection the Fid belongs to Fconn *Conn // Connection the SrvFid belongs to
Omode uint8 // Open mode (p.O* flags), if the fid is opened Omode uint8 // Open mode (O* flags), if the fid is opened
Type uint8 // Fid type (p.QT* flags) Type uint8 // SrvFid type (QT* flags)
Diroffset uint64 // If directory, the next valid read position Diroffset uint64 // If directory, the next valid read position
User p.User // The Fid's user Dirents []byte // If directory, the serialized dirents
Aux interface{} // Can be used by the file server implementation for per-Fid data User User // The SrvFid's user
Aux interface{} // Can be used by the file server implementation for per-SrvFid data
} }
// The Req type represents a 9P2000 request. Each request has a // The SrvReq type represents a 9P2000 request. Each request has a
// T-message (Tc) and a R-message (Rc). If the ReqProcessOps don't // T-message (Tc) and a R-message (Rc). If the SrvReqProcessOps don't
// override the default behavior, the implementation initializes Fid, // override the default behavior, the implementation initializes SrvFid,
// Afid and Newfid values and automatically keeps track on when the Fids // Afid and Newfid values and automatically keeps track on when the SrvFids
// should be destroyed. // should be destroyed.
type Req struct { type SrvReq struct {
sync.Mutex sync.Mutex
Tc *p.Fcall // Incoming 9P2000 message Tc *Fcall // Incoming 9P2000 message
Rc *p.Fcall // Outgoing 9P2000 response Rc *Fcall // Outgoing 9P2000 response
Fid *Fid // The Fid value for all messages that contain fid[4] Fid *SrvFid // The SrvFid value for all messages that contain fid[4]
Afid *Fid // The Fid value for the messages that contain afid[4] (Tauth and Tattach) Afid *SrvFid // The SrvFid value for the messages that contain afid[4] (Tauth and Tattach)
Newfid *Fid // The Fid value for the messages that contain newfid[4] (Twalk) Newfid *SrvFid // The SrvFid value for the messages that contain newfid[4] (Twalk)
Conn *Conn // Connection that the request belongs to Conn *Conn // Connection that the request belongs to
status reqStatus status reqStatus
flushreq *Req flushreq *SrvReq
prev, next *Req prev, next *SrvReq
} }
// The Start method should be called once the file server implementor // The Start method should be called once the file server implementor
...@@ -226,23 +198,23 @@ type Req struct { ...@@ -226,23 +198,23 @@ type Req struct {
// values to the fields that are not initialized and creates the goroutines // values to the fields that are not initialized and creates the goroutines
// required for the server's operation. The method receives an empty // required for the server's operation. The method receives an empty
// interface value, ops, that should implement the interfaces the file server is // interface value, ops, that should implement the interfaces the file server is
// interested in. Ops must implement the ReqOps interface. // interested in. Ops must implement the SrvReqOps interface.
func (srv *Srv) Start(ops interface{}) bool { func (srv *Srv) Start(ops interface{}) bool {
if _, ok := (ops).(ReqOps); !ok { if _, ok := (ops).(SrvReqOps); !ok {
return false return false
} }
srv.ops = ops srv.ops = ops
if srv.Upool == nil { if srv.Upool == nil {
srv.Upool = p.OsUsers srv.Upool = OsUsers
} }
if srv.Msize < p.IOHDRSZ { if srv.Msize < IOHDRSZ {
srv.Msize = p.MSIZE srv.Msize = MSIZE
} }
if srv.Log == nil { if srv.Log == nil {
srv.Log = p.NewLogger(1024) srv.Log = NewLogger(1024)
} }
if sop, ok := (interface{}(srv)).(StatsOps); ok { if sop, ok := (interface{}(srv)).(StatsOps); ok {
...@@ -256,7 +228,7 @@ func (srv *Srv) String() string { ...@@ -256,7 +228,7 @@ func (srv *Srv) String() string {
return srv.Id return srv.Id
} }
func (req *Req) process() { func (req *SrvReq) process() {
req.Lock() req.Lock()
flushed := (req.status & reqFlush) != 0 flushed := (req.status & reqFlush) != 0
if !flushed { if !flushed {
...@@ -268,8 +240,8 @@ func (req *Req) process() { ...@@ -268,8 +240,8 @@ func (req *Req) process() {
req.Respond() req.Respond()
} }
if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok { if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok {
rop.ReqProcess(req) rop.SrvReqProcess(req)
} else { } else {
req.Process() req.Process()
} }
...@@ -283,16 +255,16 @@ func (req *Req) process() { ...@@ -283,16 +255,16 @@ func (req *Req) process() {
} }
// Performs the default processing of a request. Initializes // Performs the default processing of a request. Initializes
// the Fid, Afid and Newfid fields and calls the appropriate // the SrvFid, Afid and Newfid fields and calls the appropriate
// ReqOps operation for the message. The file server implementer // SrvReqOps operation for the message. The file server implementer
// should call it only if the file server implements the ReqProcessOps // should call it only if the file server implements the SrvReqProcessOps
// within the ReqProcess operation. // within the SrvReqProcess operation.
func (req *Req) Process() { func (req *SrvReq) Process() {
conn := req.Conn conn := req.Conn
srv := conn.Srv srv := conn.Srv
tc := req.Tc tc := req.Tc
if tc.Fid != p.NOFID && tc.Type != p.Tattach { if tc.Fid != NOFID && tc.Type != Tattach {
srv.Lock() srv.Lock()
req.Fid = conn.FidGet(tc.Fid) req.Fid = conn.FidGet(tc.Fid)
srv.Unlock() srv.Unlock()
...@@ -304,83 +276,83 @@ func (req *Req) Process() { ...@@ -304,83 +276,83 @@ func (req *Req) Process() {
switch req.Tc.Type { switch req.Tc.Type {
default: default:
req.RespondError(&p.Error{"unknown message type", p.EINVAL}) req.RespondError(&Error{"unknown message type", EINVAL})
case p.Tversion: case Tversion:
srv.version(req) srv.version(req)
case p.Tauth: case Tauth:
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
return return
} }
srv.auth(req) srv.auth(req)
case p.Tattach: case Tattach:
srv.attach(req) srv.attach(req)
case p.Tflush: case Tflush:
srv.flush(req) srv.flush(req)
case p.Twalk: case Twalk:
srv.walk(req) srv.walk(req)
case p.Topen: case Topen:
srv.open(req) srv.open(req)
case p.Tcreate: case Tcreate:
srv.create(req) srv.create(req)
case p.Tread: case Tread:
srv.read(req) srv.read(req)
case p.Twrite: case Twrite:
srv.write(req) srv.write(req)
case p.Tclunk: case Tclunk:
srv.clunk(req) srv.clunk(req)
case p.Tremove: case Tremove:
srv.remove(req) srv.remove(req)
case p.Tstat: case Tstat:
srv.stat(req) srv.stat(req)
case p.Twstat: case Twstat:
srv.wstat(req) srv.wstat(req)
} }
} }
// Performs the post processing required if the (*Req) Process() method // Performs the post processing required if the (*SrvReq) Process() method
// is called for a request. The file server implementer should call it // is called for a request. The file server implementer should call it
// only if the file server implements the ReqProcessOps within the // only if the file server implements the SrvReqProcessOps within the
// ReqRespond operation. // SrvReqRespond operation.
func (req *Req) PostProcess() { func (req *SrvReq) PostProcess() {
srv := req.Conn.Srv srv := req.Conn.Srv
/* call the post-handlers (if needed) */ /* call the post-handlers (if needed) */
switch req.Tc.Type { switch req.Tc.Type {
case p.Tauth: case Tauth:
srv.authPost(req) srv.authPost(req)
case p.Tattach: case Tattach:
srv.attachPost(req) srv.attachPost(req)
case p.Twalk: case Twalk:
srv.walkPost(req) srv.walkPost(req)
case p.Topen: case Topen:
srv.openPost(req) srv.openPost(req)
case p.Tcreate: case Tcreate:
srv.createPost(req) srv.createPost(req)
case p.Tread: case Tread:
srv.readPost(req) srv.readPost(req)
case p.Tclunk: case Tclunk:
srv.clunkPost(req) srv.clunkPost(req)
case p.Tremove: case Tremove:
srv.removePost(req) srv.removePost(req)
} }
...@@ -404,8 +376,8 @@ func (req *Req) PostProcess() { ...@@ -404,8 +376,8 @@ func (req *Req) PostProcess() {
// should be initialized and contain valid 9P2000 message. In most cases // should be initialized and contain valid 9P2000 message. In most cases
// the file server implementer shouldn't call this method directly. Instead // the file server implementer shouldn't call this method directly. Instead
// one of the RespondR* methods should be used. // one of the RespondR* methods should be used.
func (req *Req) Respond() { func (req *SrvReq) Respond() {
var flushreqs *Req var flushreqs *SrvReq
conn := req.Conn conn := req.Conn
req.Lock() req.Lock()
...@@ -425,7 +397,7 @@ func (req *Req) Respond() { ...@@ -425,7 +397,7 @@ func (req *Req) Respond() {
nextreq.next = nil nextreq.next = nil
// if there are flush requests, move them to the next request // if there are flush requests, move them to the next request
if req.flushreq != nil { if req.flushreq != nil {
var p *Req = nil var p *SrvReq = nil
r := nextreq.flushreq r := nextreq.flushreq
for ; r != nil; p, r = r, r.flushreq { for ; r != nil; p, r = r, r.flushreq {
} }
...@@ -433,7 +405,7 @@ func (req *Req) Respond() { ...@@ -433,7 +405,7 @@ func (req *Req) Respond() {
if p == nil { if p == nil {
nextreq.flushreq = req.flushreq nextreq.flushreq = req.flushreq
} else { } else {
p.next = req.flushreq nextreq = req.flushreq
} }
} }
...@@ -444,8 +416,8 @@ func (req *Req) Respond() { ...@@ -444,8 +416,8 @@ func (req *Req) Respond() {
} }
conn.Unlock() conn.Unlock()
if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok { if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok {
rop.ReqRespond(req) rop.SrvReqRespond(req)
} else { } else {
req.PostProcess() req.PostProcess()
} }
...@@ -469,18 +441,18 @@ func (req *Req) Respond() { ...@@ -469,18 +441,18 @@ func (req *Req) Respond() {
// Should be called to cancel a request. Should only be called // Should be called to cancel a request. Should only be called
// from the Flush operation if the FlushOp is implemented. // from the Flush operation if the FlushOp is implemented.
func (req *Req) Flush() { func (req *SrvReq) Flush() {
req.Lock() req.Lock()
req.status |= reqFlush req.status |= reqFlush
req.Unlock() req.Unlock()
req.Respond() req.Respond()
} }
// Lookup a Fid struct based on the 32-bit identifier sent over the wire. // Lookup a SrvFid struct based on the 32-bit identifier sent over the wire.
// Returns nil if the fid is not found. Increases the reference count of // Returns nil if the fid is not found. Increases the reference count of
// the returned fid. The user is responsible to call DecRef once it no // the returned fid. The user is responsible to call DecRef once it no
// longer needs it. // longer needs it.
func (conn *Conn) FidGet(fidno uint32) *Fid { func (conn *Conn) FidGet(fidno uint32) *SrvFid {
conn.Lock() conn.Lock()
fid, present := conn.fidpool[fidno] fid, present := conn.fidpool[fidno]
conn.Unlock() conn.Unlock()
...@@ -491,10 +463,10 @@ func (conn *Conn) FidGet(fidno uint32) *Fid { ...@@ -491,10 +463,10 @@ func (conn *Conn) FidGet(fidno uint32) *Fid {
return fid return fid
} }
// Creates a new Fid struct for the fidno integer. Returns nil // Creates a new SrvFid struct for the fidno integer. Returns nil
// if the Fid for that number already exists. The returned fid // if the SrvFid for that number already exists. The returned fid
// has reference count set to 1. // has reference count set to 1.
func (conn *Conn) FidNew(fidno uint32) *Fid { func (conn *Conn) FidNew(fidno uint32) *SrvFid {
conn.Lock() conn.Lock()
_, present := conn.fidpool[fidno] _, present := conn.fidpool[fidno]
if present { if present {
...@@ -502,7 +474,7 @@ func (conn *Conn) FidNew(fidno uint32) *Fid { ...@@ -502,7 +474,7 @@ func (conn *Conn) FidNew(fidno uint32) *Fid {
return nil return nil
} }
fid := new(Fid) fid := new(SrvFid)
fid.fid = fidno fid.fid = fidno
fid.refcount = 1 fid.refcount = 1
fid.Fconn = conn fid.Fconn = conn
...@@ -517,7 +489,7 @@ func (conn *Conn) String() string { ...@@ -517,7 +489,7 @@ func (conn *Conn) String() string {
} }
// Increase the reference count for the fid. // Increase the reference count for the fid.
func (fid *Fid) IncRef() { func (fid *SrvFid) IncRef() {
fid.Lock() fid.Lock()
fid.refcount++ fid.refcount++
fid.Unlock() fid.Unlock()
...@@ -525,7 +497,7 @@ func (fid *Fid) IncRef() { ...@@ -525,7 +497,7 @@ func (fid *Fid) IncRef() {
// Decrease the reference count for the fid. When the // Decrease the reference count for the fid. When the
// reference count reaches 0, the fid is no longer valid. // reference count reaches 0, the fid is no longer valid.
func (fid *Fid) DecRef() { func (fid *SrvFid) DecRef() {
fid.Lock() fid.Lock()
fid.refcount-- fid.refcount--
n := fid.refcount n := fid.refcount
...@@ -540,7 +512,7 @@ func (fid *Fid) DecRef() { ...@@ -540,7 +512,7 @@ func (fid *Fid) DecRef() {
delete(conn.fidpool, fid.fid) delete(conn.fidpool, fid.fid)
conn.Unlock() conn.Unlock()
if fop, ok := (conn.Srv.ops).(FidOps); ok { if fop, ok := (conn.Srv.ops).(SrvFidOps); ok {
fop.FidDestroy(fid) fop.FidDestroy(fid)
} }
} }
// +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()
}
...@@ -2,51 +2,49 @@ ...@@ -2,51 +2,49 @@
// 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 (
"flag"
"io" "io"
"log" "log"
"os" "os"
"os/user" "os/user"
"path"
"sort"
"strconv" "strconv"
"syscall" "syscall"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
) )
type Fid struct { type ufsFid struct {
path string path string
file *os.File file *os.File
dirs []os.FileInfo dirs []os.FileInfo
diroffset uint64 direntends []int
st os.FileInfo dirents []byte
diroffset uint64
st os.FileInfo
} }
type Ufs struct { type Ufs struct {
srv.Srv Srv
Root string
} }
var addr string func toError(err error) *Error {
var debug int
var root string
var Enoent = &p.Error{"file not found", p.ENOENT}
func toError(err error) *p.Error {
var ecode uint32 var ecode uint32
ename := err.Error() ename := err.Error()
if e, ok := err.(syscall.Errno); ok { if e, ok := err.(syscall.Errno); ok {
ecode = uint32(e) ecode = uint32(e)
} else { } else {
ecode = p.EIO ecode = EIO
} }
return &p.Error{ename, ecode} return &Error{ename, ecode}
} }
func (fid *Fid) stat() *p.Error { func (fid *ufsFid) stat() *Error {
var err error var err error
fid.st, err = os.Lstat(fid.path) fid.st, err = os.Lstat(fid.path)
...@@ -60,24 +58,24 @@ func (fid *Fid) stat() *p.Error { ...@@ -60,24 +58,24 @@ func (fid *Fid) stat() *p.Error {
func omode2uflags(mode uint8) int { func omode2uflags(mode uint8) int {
ret := int(0) ret := int(0)
switch mode & 3 { switch mode & 3 {
case p.OREAD: case OREAD:
ret = os.O_RDONLY ret = os.O_RDONLY
break break
case p.ORDWR: case ORDWR:
ret = os.O_RDWR ret = os.O_RDWR
break break
case p.OWRITE: case OWRITE:
ret = os.O_WRONLY ret = os.O_WRONLY
break break
case p.OEXEC: case OEXEC:
ret = os.O_RDONLY ret = os.O_RDONLY
break break
} }
if mode&p.OTRUNC != 0 { if mode&OTRUNC != 0 {
ret |= os.O_TRUNC ret |= os.O_TRUNC
} }
...@@ -87,11 +85,11 @@ func omode2uflags(mode uint8) int { ...@@ -87,11 +85,11 @@ func omode2uflags(mode uint8) int {
func dir2QidType(d os.FileInfo) uint8 { func dir2QidType(d os.FileInfo) uint8 {
ret := uint8(0) ret := uint8(0)
if d.IsDir() { if d.IsDir() {
ret |= p.QTDIR ret |= QTDIR
} }
if d.Mode()&os.ModeSymlink != 0 { if d.Mode()&os.ModeSymlink != 0 {
ret |= p.QTSYMLINK ret |= QTSYMLINK
} }
return ret return ret
...@@ -100,33 +98,33 @@ func dir2QidType(d os.FileInfo) uint8 { ...@@ -100,33 +98,33 @@ func dir2QidType(d os.FileInfo) uint8 {
func dir2Npmode(d os.FileInfo, dotu bool) uint32 { func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
ret := uint32(d.Mode() & 0777) ret := uint32(d.Mode() & 0777)
if d.IsDir() { if d.IsDir() {
ret |= p.DMDIR ret |= DMDIR
} }
if dotu { if dotu {
mode := d.Mode() mode := d.Mode()
if mode&os.ModeSymlink != 0 { if mode&os.ModeSymlink != 0 {
ret |= p.DMSYMLINK ret |= DMSYMLINK
} }
if mode&os.ModeSocket != 0 { if mode&os.ModeSocket != 0 {
ret |= p.DMSOCKET ret |= DMSOCKET
} }
if mode&os.ModeNamedPipe != 0 { if mode&os.ModeNamedPipe != 0 {
ret |= p.DMNAMEDPIPE ret |= DMNAMEDPIPE
} }
if mode&os.ModeDevice != 0 { if mode&os.ModeDevice != 0 {
ret |= p.DMDEVICE ret |= DMDEVICE
} }
if mode&os.ModeSetuid != 0 { if mode&os.ModeSetuid != 0 {
ret |= p.DMSETUID ret |= DMSETUID
} }
if mode&os.ModeSetgid != 0 { if mode&os.ModeSetgid != 0 {
ret |= p.DMSETGID ret |= DMSETGID
} }
} }
...@@ -135,48 +133,47 @@ func dir2Npmode(d os.FileInfo, dotu bool) uint32 { ...@@ -135,48 +133,47 @@ func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
// Dir is an instantiation of the p.Dir structure // Dir is an instantiation of the p.Dir structure
// that can act as a receiver for local methods. // that can act as a receiver for local methods.
type Dir struct { type ufsDir struct {
p.Dir Dir
} }
func (*Ufs) ConnOpened(conn *srv.Conn) { func (*Ufs) ConnOpened(conn *Conn) {
if conn.Srv.Debuglevel > 0 { if conn.Srv.Debuglevel > 0 {
log.Println("connected") log.Println("connected")
} }
} }
func (*Ufs) ConnClosed(conn *srv.Conn) { func (*Ufs) ConnClosed(conn *Conn) {
if conn.Srv.Debuglevel > 0 { if conn.Srv.Debuglevel > 0 {
log.Println("disconnected") log.Println("disconnected")
} }
} }
func (*Ufs) FidDestroy(sfid *srv.Fid) { func (*Ufs) FidDestroy(sfid *SrvFid) {
var fid *Fid var fid *ufsFid
if sfid.Aux == nil { if sfid.Aux == nil {
return return
} }
fid = sfid.Aux.(*Fid) fid = sfid.Aux.(*ufsFid)
if fid.file != nil { if fid.file != nil {
fid.file.Close() fid.file.Close()
} }
} }
func (*Ufs) Attach(req *srv.Req) { func (ufs *Ufs) Attach(req *SrvReq) {
if req.Afid != nil { if req.Afid != nil {
req.RespondError(srv.Enoauth) req.RespondError(Enoauth)
return return
} }
tc := req.Tc tc := req.Tc
fid := new(Fid) fid := new(ufsFid)
if len(tc.Aname) == 0 { // You can think of the ufs.Root as a 'chroot' of a sort.
fid.path = root // clients attach are not allowed to go outside the
} else { // directory represented by ufs.Root
fid.path = tc.Aname fid.path = path.Join(ufs.Root, tc.Aname)
}
req.Fid.Aux = fid req.Fid.Aux = fid
err := fid.stat() err := fid.stat()
...@@ -189,10 +186,10 @@ func (*Ufs) Attach(req *srv.Req) { ...@@ -189,10 +186,10 @@ func (*Ufs) Attach(req *srv.Req) {
req.RespondRattach(qid) req.RespondRattach(qid)
} }
func (*Ufs) Flush(req *srv.Req) {} func (*Ufs) Flush(req *SrvReq) {}
func (*Ufs) Walk(req *srv.Req) { func (*Ufs) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*Fid) fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc tc := req.Tc
err := fid.stat() err := fid.stat()
...@@ -202,11 +199,11 @@ func (*Ufs) Walk(req *srv.Req) { ...@@ -202,11 +199,11 @@ func (*Ufs) Walk(req *srv.Req) {
} }
if req.Newfid.Aux == nil { if req.Newfid.Aux == nil {
req.Newfid.Aux = new(Fid) req.Newfid.Aux = new(ufsFid)
} }
nfid := req.Newfid.Aux.(*Fid) nfid := req.Newfid.Aux.(*ufsFid)
wqids := make([]p.Qid, len(tc.Wname)) wqids := make([]Qid, len(tc.Wname))
path := fid.path path := fid.path
i := 0 i := 0
for ; i < len(tc.Wname); i++ { for ; i < len(tc.Wname); i++ {
...@@ -229,8 +226,8 @@ func (*Ufs) Walk(req *srv.Req) { ...@@ -229,8 +226,8 @@ func (*Ufs) Walk(req *srv.Req) {
req.RespondRwalk(wqids[0:i]) req.RespondRwalk(wqids[0:i])
} }
func (*Ufs) Open(req *srv.Req) { func (*Ufs) Open(req *SrvReq) {
fid := req.Fid.Aux.(*Fid) fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc tc := req.Tc
err := fid.stat() err := fid.stat()
if err != nil { if err != nil {
...@@ -248,8 +245,8 @@ func (*Ufs) Open(req *srv.Req) { ...@@ -248,8 +245,8 @@ func (*Ufs) Open(req *srv.Req) {
req.RespondRopen(dir2Qid(fid.st), 0) req.RespondRopen(dir2Qid(fid.st), 0)
} }
func (*Ufs) Create(req *srv.Req) { func (*Ufs) Create(req *SrvReq) {
fid := req.Fid.Aux.(*Fid) fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc tc := req.Tc
err := fid.stat() err := fid.stat()
if err != nil { if err != nil {
...@@ -261,13 +258,13 @@ func (*Ufs) Create(req *srv.Req) { ...@@ -261,13 +258,13 @@ func (*Ufs) Create(req *srv.Req) {
var e error = nil var e error = nil
var file *os.File = nil var file *os.File = nil
switch { switch {
case tc.Perm&p.DMDIR != 0: case tc.Perm&DMDIR != 0:
e = os.Mkdir(path, os.FileMode(tc.Perm&0777)) e = os.Mkdir(path, os.FileMode(tc.Perm&0777))
case tc.Perm&p.DMSYMLINK != 0: case tc.Perm&DMSYMLINK != 0:
e = os.Symlink(tc.Ext, path) e = os.Symlink(tc.Ext, path)
case tc.Perm&p.DMLINK != 0: case tc.Perm&DMLINK != 0:
n, e := strconv.ParseUint(tc.Ext, 10, 0) n, e := strconv.ParseUint(tc.Ext, 10, 0)
if e != nil { if e != nil {
break break
...@@ -275,25 +272,25 @@ func (*Ufs) Create(req *srv.Req) { ...@@ -275,25 +272,25 @@ func (*Ufs) Create(req *srv.Req) {
ofid := req.Conn.FidGet(uint32(n)) ofid := req.Conn.FidGet(uint32(n))
if ofid == nil { if ofid == nil {
req.RespondError(srv.Eunknownfid) req.RespondError(Eunknownfid)
return return
} }
e = os.Link(ofid.Aux.(*Fid).path, path) e = os.Link(ofid.Aux.(*ufsFid).path, path)
ofid.DecRef() ofid.DecRef()
case tc.Perm&p.DMNAMEDPIPE != 0: case tc.Perm&DMNAMEDPIPE != 0:
case tc.Perm&p.DMDEVICE != 0: case tc.Perm&DMDEVICE != 0:
req.RespondError(&p.Error{"not implemented", p.EIO}) req.RespondError(&Error{"not implemented", EIO})
return return
default: default:
var mode uint32 = tc.Perm & 0777 var mode uint32 = tc.Perm & 0777
if req.Conn.Dotu { if req.Conn.Dotu {
if tc.Perm&p.DMSETUID > 0 { if tc.Perm&DMSETUID > 0 {
mode |= syscall.S_ISUID mode |= syscall.S_ISUID
} }
if tc.Perm&p.DMSETGID > 0 { if tc.Perm&DMSETGID > 0 {
mode |= syscall.S_ISGID mode |= syscall.S_ISGID
} }
} }
...@@ -320,8 +317,8 @@ func (*Ufs) Create(req *srv.Req) { ...@@ -320,8 +317,8 @@ func (*Ufs) Create(req *srv.Req) {
req.RespondRcreate(dir2Qid(fid.st), 0) req.RespondRcreate(dir2Qid(fid.st), 0)
} }
func (*Ufs) Read(req *srv.Req) { func (*Ufs) Read(req *SrvReq) {
fid := req.Fid.Aux.(*Fid) fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc tc := req.Tc
rc := req.Rc rc := req.Rc
err := fid.stat() err := fid.stat()
...@@ -330,67 +327,83 @@ func (*Ufs) Read(req *srv.Req) { ...@@ -330,67 +327,83 @@ func (*Ufs) Read(req *srv.Req) {
return return
} }
p.InitRread(rc, tc.Count) InitRread(rc, tc.Count)
var count int var count int
var e error var e error
if fid.st.IsDir() { if fid.st.IsDir() {
b := rc.Data
if tc.Offset == 0 { if tc.Offset == 0 {
var e error
// If we got here, it was open. Can't really seek
// in most cases, just close and reopen it.
fid.file.Close() fid.file.Close()
fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0) if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil {
if e != nil {
req.RespondError(toError(e)) req.RespondError(toError(e))
return return
} }
}
for len(b) > 0 {
if fid.dirs == nil {
fid.dirs, e = fid.file.Readdir(16)
if e != nil && e != io.EOF {
req.RespondError(toError(e))
return
}
if len(fid.dirs) == 0 { if fid.dirs, e = fid.file.Readdir(-1); e != nil {
break req.RespondError(toError(e))
} return
} }
var i int fid.dirents = nil
for i = 0; i < len(fid.dirs); i++ { fid.direntends = nil
for i := 0; i < len(fid.dirs); i++ {
path := fid.path + "/" + fid.dirs[i].Name() path := fid.path + "/" + fid.dirs[i].Name()
st := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool) st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
sz := p.PackDir(st, b, req.Conn.Dotu) if st == nil {
if sz == 0 { continue
break
} }
b := PackDir(st, req.Conn.Dotu)
b = b[sz:] fid.dirents = append(fid.dirents, b...)
count += sz count += len(b)
fid.direntends = append(fid.direntends, count)
} }
}
switch {
case tc.Offset > uint64(len(fid.dirents)):
count = 0
case len(fid.dirents[tc.Offset:]) > int(tc.Count):
count = int(tc.Count)
default:
count = len(fid.dirents[tc.Offset:])
}
if i < len(fid.dirs) { if !*Akaros {
fid.dirs = fid.dirs[i:] nextend := sort.SearchInts(fid.direntends, int(tc.Offset)+count)
break if nextend < len(fid.direntends) {
} else { if fid.direntends[nextend] > int(tc.Offset)+count {
fid.dirs = nil if nextend > 0 {
count = fid.direntends[nextend-1] - int(tc.Offset)
} else {
count = 0
}
}
}
if count == 0 && int(tc.Offset) < len(fid.dirents) && len(fid.dirents) > 0 {
req.RespondError(&Error{"too small read size for dir entry", EINVAL})
return
} }
} }
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count])
} else { } else {
count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset)) count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset))
if e != nil && e != io.EOF { if e != nil && e != io.EOF {
req.RespondError(toError(e)) req.RespondError(toError(e))
return return
} }
} }
p.SetRreadCount(rc, uint32(count)) SetRreadCount(rc, uint32(count))
req.Respond() req.Respond()
} }
func (*Ufs) Write(req *srv.Req) { func (*Ufs) Write(req *SrvReq) {
fid := req.Fid.Aux.(*Fid) fid := req.Fid.Aux.(*ufsFid)
tc := req.Tc tc := req.Tc
err := fid.stat() err := fid.stat()
if err != nil { if err != nil {
...@@ -407,10 +420,10 @@ func (*Ufs) Write(req *srv.Req) { ...@@ -407,10 +420,10 @@ func (*Ufs) Write(req *srv.Req) {
req.RespondRwrite(uint32(n)) req.RespondRwrite(uint32(n))
} }
func (*Ufs) Clunk(req *srv.Req) { req.RespondRclunk() } func (*Ufs) Clunk(req *SrvReq) { req.RespondRclunk() }
func (*Ufs) Remove(req *srv.Req) { func (*Ufs) Remove(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)
...@@ -426,25 +439,30 @@ func (*Ufs) Remove(req *srv.Req) { ...@@ -426,25 +439,30 @@ func (*Ufs) Remove(req *srv.Req) {
req.RespondRremove() req.RespondRremove()
} }
func (*Ufs) Stat(req *srv.Req) { func (*Ufs) Stat(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)
return return
} }
st := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool) st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
req.RespondError(derr)
return
}
req.RespondRstat(st) req.RespondRstat(st)
} }
func lookup(uid string, group bool) (uint32, *p.Error) { func lookup(uid string, group bool) (uint32, *Error) {
if uid == "" { if uid == "" {
return p.NOUID, nil return NOUID, nil
} }
usr, e := user.Lookup(uid) usr, e := user.Lookup(uid)
if e != nil { if e != nil {
return p.NOUID, toError(e) return NOUID, toError(e)
} }
conv := usr.Uid conv := usr.Uid
if group { if group {
...@@ -452,23 +470,12 @@ func lookup(uid string, group bool) (uint32, *p.Error) { ...@@ -452,23 +470,12 @@ func lookup(uid string, group bool) (uint32, *p.Error) {
} }
u, e := strconv.Atoi(conv) u, e := strconv.Atoi(conv)
if e != nil { if e != nil {
return p.NOUID, toError(e) return NOUID, toError(e)
} }
return uint32(u), nil return uint32(u), nil
} }
func StartServer(addrVal string, debugVal int, rootVal string) { /* enables "Akaros" capabilities, which right now means
addr = addrVal * a sane error message format.
debug = debugVal */
root = rootVal var Akaros = flag.Bool("akaros", false, "Akaros extensions")
ufs := new(Ufs)
ufs.Dotu = true
ufs.Id = "ufs"
ufs.Debuglevel = debug
ufs.Start(ufs)
err := ufs.StartNetListener("tcp", addr)
if err != nil {
log.Println(err)
}
}
// 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)
......
// Copyright 2012 The go9p Authors. All rights reserved. package go9p
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ufs
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 +19,18 @@ func atime(stat *syscall.Stat_t) time.Time { ...@@ -25,16 +19,18 @@ func atime(stat *syscall.Stat_t) time.Time {
func isBlock(d os.FileInfo) bool { 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 +39,34 @@ func dir2Qid(d os.FileInfo) *p.Qid { ...@@ -43,27 +39,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 +79,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { ...@@ -76,10 +79,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 +105,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall ...@@ -95,7 +105,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 +119,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall ...@@ -109,8 +119,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 +131,10 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -121,10 +131,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 +145,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -135,7 +145,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 +169,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -159,7 +169,7 @@ func (*Ufs) Wstat(req *srv.Req) {
} }
} }
if uid != p.NOUID || gid != p.NOUID { if uid != NOUID || gid != NOUID {
e := os.Chown(fid.path, int(uid), int(gid)) 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 +178,25 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -168,13 +178,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 +221,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -199,7 +221,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)
......
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // 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.
// http://golang.org/src/os/stat_windows.go package go9p
package ufs
import ( import (
"fmt"
"os" "os"
"path"
"strings" "strings"
"syscall" "syscall"
"time" "time"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
) )
// type Win32FileAttributeData struct {
// FileAttributes uint32
// CreationTime Filetime
// LastAccessTime Filetime
// LastWriteTime Filetime
// FileSizeHigh uint32
// FileSizeLow uint32
// }
// A FileInfo describes a file and is returned by Stat and Lstat.
// type FileInfo interface {
// Name() string // base name of the file
// Size() int64 // length in bytes for regular files; system-dependent for others
// Mode() FileMode // file mode bits
// ModTime() time.Time // modification time
// IsDir() bool // abbreviation for Mode().IsDir()
// Sys() interface{} // underlying data source (can return nil)
// }
func atime(fi os.FileInfo) time.Time { func atime(fi os.FileInfo) time.Time {
return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
} }
// IsBlock reports if the file is a block device // IsBlock reports if the file is a block device
func isBlock(d os.FileInfo) bool { func isBlock(d os.FileInfo) bool {
// return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) // stat := d.Sys().(*syscall.Stat_t)
// stat := d.Sys().(os.FileInfo)
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK // return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
return true 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().(os.FileInfo) // 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 return true
} }
func dir2Qid(d os.FileInfo) *p.Qid { func dir2Qid(d os.FileInfo) *Qid {
var qid p.Qid var qid Qid
// d.Sys().(*syscall.Win32FileAttributeData)
qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow) qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow)
qid.Version = uint32(d.ModTime().UnixNano() / 1000000) qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
qid.Type = dir2QidType(d) qid.Type = dir2QidType(d)
...@@ -65,20 +41,28 @@ func dir2Qid(d os.FileInfo) *p.Qid { ...@@ -65,20 +41,28 @@ 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().(os.FileInfo) if r := recover(); r != nil {
fmt.Print("stat failed: ", r)
return nil, &os.PathError{"dir2Dir", path, nil}
}
sysif := d.Sys()
if sysif == nil {
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
}
sysMode := sysif.(*syscall.Win32FileAttributeData)
dir := new(Dir) dir := new(ufsDir)
dir.Qid = *dir2Qid(d) dir.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)
...@@ -101,10 +85,18 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { ...@@ -101,10 +85,18 @@ 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 var err error
/* For Akaros, we use the Muid as the link value. */
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
dir.Muid, err = os.Readlink(path)
if err == nil {
dir.Mode |= DMSYMLINK
}
}
return &dir.Dir, nil
} }
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) { func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) {
// u := upool.Uid2User(int(sysMode.Uid)) // 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()
...@@ -120,7 +112,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) { ...@@ -120,7 +112,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
// 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)
...@@ -137,12 +129,12 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) { ...@@ -137,12 +129,12 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
dir.Muid = "none" dir.Muid = "none"
dir.Uidnum = 0 dir.Uidnum = 0
dir.Gidnum = 0 dir.Gidnum = 0
dir.Muidnum = p.NOUID dir.Muidnum = NOUID
dir.Ext = "" dir.Ext = ""
} }
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)
...@@ -153,10 +145,10 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -153,10 +145,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
} }
} }
...@@ -167,7 +159,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -167,7 +159,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
...@@ -191,7 +183,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -191,7 +183,7 @@ func (*Ufs) Wstat(req *srv.Req) {
} }
} }
if uid != p.NOUID || gid != p.NOUID { if uid != NOUID || gid != NOUID {
e := os.Chown(fid.path, int(uid), int(gid)) e := os.Chown(fid.path, int(uid), int(gid))
if e != nil { if e != nil {
req.RespondError(toError(e)) req.RespondError(toError(e))
...@@ -200,13 +192,25 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -200,13 +192,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 {
...@@ -231,7 +235,7 @@ func (*Ufs) Wstat(req *srv.Req) { ...@@ -231,7 +235,7 @@ func (*Ufs) Wstat(req *srv.Req) {
// case true: // case true:
// mt = st.ModTime() // mt = st.ModTime()
// default: // default:
// at = atime(st.Sys().(os.FileInfo)) // //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
// } // }
// } // }
// e := os.Chtimes(fid.path, at, mt) // e := os.Chtimes(fid.path, at, mt)
......
...@@ -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 ( import (
"fmt" "fmt"
...@@ -77,9 +77,14 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) { ...@@ -77,9 +77,14 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
goto szerror goto szerror
} }
fc.Unamenum = NOUID if dotu {
if dotu && len(p) > 0 { if len(p) > 0 {
fc.Unamenum, p = gint32(p) fc.Unamenum, p = gint32(p)
} else {
fc.Unamenum = NOUID
}
} else {
fc.Unamenum = NOUID
} }
case Rauth, Rattach: case Rauth, Rattach:
...@@ -101,9 +106,12 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) { ...@@ -101,9 +106,12 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
goto szerror goto szerror
} }
fc.Unamenum = NOUID if dotu {
if dotu && len(p) > 0 { if len(p) > 0 {
fc.Unamenum, p = gint32(p) fc.Unamenum, p = gint32(p)
} else {
fc.Unamenum = NOUID
}
} }
case Rerror: case Rerror:
...@@ -193,15 +201,15 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) { ...@@ -193,15 +201,15 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
case Rstat: case Rstat:
m, p = gint16(p) m, p = gint16(p)
p = gstat(p, &fc.Dir, dotu) p, err = gstat(p, &fc.Dir, dotu)
if p == nil { if err != nil {
goto szerror return nil, err, 0
} }
case Twstat: case Twstat:
fc.Fid, p = gint32(p) fc.Fid, p = gint32(p)
m, p = gint16(p) m, p = gint16(p)
p = gstat(p, &fc.Dir, dotu) p, _ = gstat(p, &fc.Dir, dotu)
case Rflush, Rclunk, Rremove, Rwstat: case Rflush, Rclunk, Rremove, Rwstat:
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册