From 8e801e3975074601ec4c6f5d51b65986b72360c4 Mon Sep 17 00:00:00 2001 From: Aaron Prindle Date: Thu, 23 Mar 2017 08:26:21 -0700 Subject: [PATCH] Update mount implementation, add mount integration tests, and check that path exists. --- cmd/minikube/cmd/mount.go | 11 +- hack/jenkins/common.sh | 3 +- pkg/minikube/cluster/cluster.go | 1 + pkg/minikube/cluster/cluster_darwin.go | 2 +- pkg/minikube/cluster/commands.go | 11 +- test/integration/functional_test.go | 1 + test/integration/mount_test.go | 112 ++++ .../testdata/busybox-mount-test.yaml | 19 + test/integration/util/util.go | 11 + third_party/go9p/.gitignore | 2 + third_party/go9p/AUTHORS | 13 - third_party/go9p/CONTRIBUTORS | 18 - third_party/go9p/README.md | 11 + .../go9p/{p/clnt/clnt.go => clnt_clnt.go} | 121 ++--- .../go9p/{p/clnt/close.go => clnt_close.go} | 10 +- .../go9p/{p/clnt/mount.go => clnt_mount.go} | 26 +- .../go9p/{p/clnt/open.go => clnt_open.go} | 15 +- .../go9p/{p/clnt/pool.go => clnt_pool.go} | 12 +- .../go9p/{p/clnt/read.go => clnt_read.go} | 27 +- .../go9p/{p/clnt/remove.go => clnt_remove.go} | 8 +- .../go9p/{p/clnt/stat.go => clnt_stat.go} | 14 +- .../clnt/stats_http.go => clnt_stats_http.go} | 5 +- .../go9p/{p/clnt/tag.go => clnt_tag.go} | 50 +- .../go9p/{p/clnt/walk.go => clnt_walk.go} | 13 +- .../go9p/{p/clnt/write.go => clnt_write.go} | 8 +- third_party/go9p/debug.go | 9 + third_party/go9p/{p => }/fmt.go | 2 +- third_party/go9p/{p => }/log.go | 2 +- third_party/go9p/{p => }/osusers.go | 54 +- third_party/go9p/p/clnt/examples/cl/cl.go | 489 ------------------ third_party/go9p/p/clnt/examples/ls/ls.go | 59 --- third_party/go9p/p/clnt/examples/read/read.go | 61 --- third_party/go9p/p/clnt/examples/tag/tag.go | 101 ---- third_party/go9p/p/clnt/examples/tls/tls.go | 74 --- .../go9p/p/clnt/examples/write/write.go | 71 --- third_party/go9p/p/clnt/seek.go | 63 --- .../go9p/p/srv/examples/clonefs/clonefs.go | 147 ------ .../go9p/p/srv/examples/ramfs/ramfs.go | 251 --------- .../go9p/p/srv/examples/timefs/timefs.go | 98 ---- .../go9p/p/srv/examples/tlsramfs/tlsramfs.go | 297 ----------- third_party/go9p/{p => }/p9.go | 61 +-- third_party/go9p/{p => }/packr.go | 14 +- third_party/go9p/{p => }/packt.go | 2 +- .../go9p/{p/srv/conn.go => srv_conn.go} | 42 +- .../go9p/{p/srv/fcall.go => srv_fcall.go} | 141 +++-- .../go9p/{p/srv/file.go => srv_file.go} | 179 +++---- third_party/go9p/srv_pipe.go | 354 +++++++++++++ third_party/go9p/srv_pipe_darwin.go | 41 ++ third_party/go9p/srv_pipe_linux.go | 41 ++ third_party/go9p/srv_pipe_windows.go | 48 ++ .../go9p/{p/srv/respond.go => srv_respond.go} | 80 +-- third_party/go9p/{p/srv/srv.go => srv_srv.go} | 286 +++++----- .../srv/stats_http.go => srv_stats_http.go} | 13 +- third_party/go9p/stats.go | 6 + .../go9p/{p/srv/examples/ufs => }/ufs.go | 265 +++++----- third_party/go9p/ufs/ufs.go | 29 ++ .../{p/srv/examples/ufs => }/ufs_darwin.go | 78 ++- .../{p/srv/examples/ufs => }/ufs_linux.go | 80 +-- .../{p/srv/examples/ufs => }/ufs_windows.go | 108 ++-- third_party/go9p/{p => }/unpack.go | 30 +- 60 files changed, 1596 insertions(+), 2604 deletions(-) create mode 100644 test/integration/mount_test.go create mode 100644 test/integration/testdata/busybox-mount-test.yaml create mode 100644 third_party/go9p/.gitignore delete mode 100644 third_party/go9p/AUTHORS delete mode 100644 third_party/go9p/CONTRIBUTORS create mode 100644 third_party/go9p/README.md rename third_party/go9p/{p/clnt/clnt.go => clnt_clnt.go} (77%) mode change 100755 => 100644 rename third_party/go9p/{p/clnt/close.go => clnt_close.go} (79%) rename third_party/go9p/{p/clnt/mount.go => clnt_mount.go} (65%) rename third_party/go9p/{p/clnt/open.go => clnt_open.go} (82%) rename third_party/go9p/{p/clnt/pool.go => clnt_pool.go} (93%) rename third_party/go9p/{p/clnt/read.go => clnt_read.go} (79%) rename third_party/go9p/{p/clnt/remove.go => clnt_remove.go} (85%) rename third_party/go9p/{p/clnt/stat.go => clnt_stat.go} (71%) rename third_party/go9p/{p/clnt/stats_http.go => clnt_stats_http.go} (94%) rename third_party/go9p/{p/clnt/tag.go => clnt_tag.go} (74%) rename third_party/go9p/{p/clnt/walk.go => clnt_walk.go} (87%) rename third_party/go9p/{p/clnt/write.go => clnt_write.go} (88%) create mode 100644 third_party/go9p/debug.go rename third_party/go9p/{p => }/fmt.go (99%) rename third_party/go9p/{p => }/log.go (99%) rename third_party/go9p/{p => }/osusers.go (57%) delete mode 100644 third_party/go9p/p/clnt/examples/cl/cl.go delete mode 100644 third_party/go9p/p/clnt/examples/ls/ls.go delete mode 100644 third_party/go9p/p/clnt/examples/read/read.go delete mode 100644 third_party/go9p/p/clnt/examples/tag/tag.go delete mode 100644 third_party/go9p/p/clnt/examples/tls/tls.go delete mode 100644 third_party/go9p/p/clnt/examples/write/write.go delete mode 100644 third_party/go9p/p/clnt/seek.go delete mode 100644 third_party/go9p/p/srv/examples/clonefs/clonefs.go delete mode 100644 third_party/go9p/p/srv/examples/ramfs/ramfs.go delete mode 100644 third_party/go9p/p/srv/examples/timefs/timefs.go delete mode 100644 third_party/go9p/p/srv/examples/tlsramfs/tlsramfs.go rename third_party/go9p/{p => }/p9.go (91%) rename third_party/go9p/{p => }/packr.go (93%) rename third_party/go9p/{p => }/packt.go (99%) rename third_party/go9p/{p/srv/conn.go => srv_conn.go} (84%) rename third_party/go9p/{p/srv/fcall.go => srv_fcall.go} (65%) rename third_party/go9p/{p/srv/file.go => srv_file.go} (72%) create mode 100644 third_party/go9p/srv_pipe.go create mode 100644 third_party/go9p/srv_pipe_darwin.go create mode 100644 third_party/go9p/srv_pipe_linux.go create mode 100644 third_party/go9p/srv_pipe_windows.go rename third_party/go9p/{p/srv/respond.go => srv_respond.go} (52%) rename third_party/go9p/{p/srv/srv.go => srv_srv.go} (58%) rename third_party/go9p/{p/srv/stats_http.go => srv_stats_http.go} (94%) create mode 100644 third_party/go9p/stats.go rename third_party/go9p/{p/srv/examples/ufs => }/ufs.go (54%) create mode 100644 third_party/go9p/ufs/ufs.go rename third_party/go9p/{p/srv/examples/ufs => }/ufs_darwin.go (69%) rename third_party/go9p/{p/srv/examples/ufs => }/ufs_linux.go (69%) rename third_party/go9p/{p/srv/examples/ufs => }/ufs_windows.go (68%) rename third_party/go9p/{p => }/unpack.go (90%) diff --git a/cmd/minikube/cmd/mount.go b/cmd/minikube/cmd/mount.go index 305c494c1..9de089b97 100644 --- a/cmd/minikube/cmd/mount.go +++ b/cmd/minikube/cmd/mount.go @@ -26,7 +26,7 @@ import ( "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/machine" - "k8s.io/minikube/third_party/go9p/p/srv/examples/ufs" + "k8s.io/minikube/third_party/go9p/ufs" ) // mountCmd represents the mount command @@ -42,6 +42,15 @@ var mountCmd = &cobra.Command{ fmt.Fprintln(os.Stderr, errText) os.Exit(1) } + if _, err := os.Stat(args[0]); err != nil { + if os.IsNotExist(err) { + errText := fmt.Sprintf("Cannot find directory %s for mount", args[0]) + fmt.Fprintln(os.Stderr, errText) + } else { + errText := fmt.Sprintf("Error accesssing directory %s for mount", args[0]) + fmt.Fprintln(os.Stderr, errText) + } + } var debugVal int if glog.V(1) { debugVal = 1 // ufs.StartServer takes int debug param diff --git a/hack/jenkins/common.sh b/hack/jenkins/common.sh index 54cb1ef4f..a2495df7b 100644 --- a/hack/jenkins/common.sh +++ b/hack/jenkins/common.sh @@ -30,6 +30,7 @@ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH} out/ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH} out/ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox.yaml testdata/ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/pvc.yaml testdata/ +gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox-mount-test.yaml testdata/ # Set the executable bit on the e2e binary and out binary chmod +x out/e2e-${OS_ARCH} @@ -63,4 +64,4 @@ curl "https://api.github.com/repos/kubernetes/minikube/statuses/${COMMIT}?access -d "{\"state\": \"$status\", \"description\": \"Jenkins\", \"target_url\": \"$target_url\", \"context\": \"${JOB_NAME}\"}" set -x -exit $result \ No newline at end of file +exit $result diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index ba45da436..a5e33ad52 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -408,6 +408,7 @@ func Mount9pHost(api libmachine.API) error { if err != nil { return errors.Wrap(err, "Error getting the host IP address to use from within the VM") } + host.RunSSHCommand(GetMount9pCleanupCommand()) _, err = host.RunSSHCommand(GetMount9pCommand(ip)) if err != nil { return err diff --git a/pkg/minikube/cluster/cluster_darwin.go b/pkg/minikube/cluster/cluster_darwin.go index fa1f74522..b55994935 100644 --- a/pkg/minikube/cluster/cluster_darwin.go +++ b/pkg/minikube/cluster/cluster_darwin.go @@ -77,7 +77,7 @@ func getVMHostIP(host *host.Host) (net.IP, error) { case "virtualbox": return net.ParseIP("10.0.2.2"), nil case "xhyve": - return net.ParseIP("10.0.2.2"), nil + return net.ParseIP("192.168.64.1"), nil default: return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver") } diff --git a/pkg/minikube/cluster/commands.go b/pkg/minikube/cluster/commands.go index be59f7243..bc2b1c090 100644 --- a/pkg/minikube/cluster/commands.go +++ b/pkg/minikube/cluster/commands.go @@ -154,7 +154,7 @@ func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) { flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates) } - if kubernetesConfig.APIServerName != "" { + if kubernetesConfig.APIServerName != constants.APIServerName { flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName) } @@ -226,9 +226,16 @@ else fi `, constants.LocalkubePIDPath) +func GetMount9pCleanupCommand() string { + return ` +sudo umount /mount-9p; +sudo rm -rf /mount-9p; +` +} + func GetMount9pCommand(ip net.IP) string { return fmt.Sprintf(` sudo mkdir /mount-9p; -sudo mount -t 9p -o trans=tcp -o port=5640 %s /mount-9p; +sudo mount -t 9p -o trans=tcp -o port=5640 -o uid=1001 -o gid=1001 %s /mount-9p; sudo chmod 775 /mount-9p;`, ip) } diff --git a/test/integration/functional_test.go b/test/integration/functional_test.go index 7e4639ae1..0bd134d1d 100644 --- a/test/integration/functional_test.go +++ b/test/integration/functional_test.go @@ -41,4 +41,5 @@ func TestFunctional(t *testing.T) { t.Run("Dashboard", testDashboard) t.Run("ServicesList", testServicesList) t.Run("Provisioning", testProvisioning) + t.Run("Mounting", testMounting) } diff --git a/test/integration/mount_test.go b/test/integration/mount_test.go new file mode 100644 index 000000000..e72bee384 --- /dev/null +++ b/test/integration/mount_test.go @@ -0,0 +1,112 @@ +// +build integration + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integration + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" + "time" + + "k8s.io/kubernetes/pkg/api" + commonutil "k8s.io/minikube/pkg/util" + "k8s.io/minikube/test/integration/util" +) + +func testMounting(t *testing.T) { + t.Parallel() + minikubeRunner := util.MinikubeRunner{ + Args: *args, + BinaryPath: *binaryPath, + T: t} + + tempDir, err := ioutil.TempDir("", "mounttest") + if err != nil { + t.Fatalf("Unexpected error while creating tempDir: %s", err) + } + defer os.RemoveAll(tempDir) + + mountCmd := fmt.Sprintf("mount %s", tempDir) + cmd := minikubeRunner.RunDaemon(mountCmd) + defer cmd.Process.Kill() + + kubectlRunner := util.NewKubectlRunner(t) + podName := "busybox" + podPath, _ := filepath.Abs("testdata/busybox-mount-test.yaml") + + // Write file in mounted dir from host + expected := "test\n" + files := []string{"fromhost", "fromhostremove"} + for _, file := range files { + path := filepath.Join(tempDir, file) + err = ioutil.WriteFile(path, []byte(expected), 0644) + if err != nil { + t.Fatalf("Unexpected error while writing file %s: %s.", path, err) + } + } + mountTest := func() error { + if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil { + return err + } + defer kubectlRunner.RunCommand([]string{"delete", "-f", podPath}) + + p := &api.Pod{} + for p.Status.Phase != "Running" { + p = kubectlRunner.GetPod(podName, "default") + } + + path := filepath.Join(tempDir, "frompod") + out, err := ioutil.ReadFile(path) + if err != nil { + return &commonutil.RetriableError{Err: err} + } + // test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod + if string(out) != expected { + t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out) + } + + // test that file written from host was read in by the pod via cat /mount-9p/fromhost; + if out, err = kubectlRunner.RunCommand([]string{"logs", podName}); err != nil { + return &commonutil.RetriableError{Err: err} + } + if string(out) != expected { + t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out) + } + + // test that fromhostremove was deleted by the pod from the mount via rm /mount-9p/fromhostremove + path = filepath.Join(tempDir, "fromhostremove") + if _, err := os.Stat(path); err == nil { + t.Fatalf("Expected file %s to be removed", path, expected, out) + } + + // test that frompodremove can be deleted on the host + path = filepath.Join(tempDir, "frompodremove") + if err := os.Remove(path); err != nil { + t.Fatalf("Unexpected error removing file %s: %s", path, err) + } + + return nil + } + if err := commonutil.RetryAfter(40, mountTest, 5*time.Second); err != nil { + t.Fatal("mountTest failed with error:", err) + } + +} diff --git a/test/integration/testdata/busybox-mount-test.yaml b/test/integration/testdata/busybox-mount-test.yaml new file mode 100644 index 000000000..39d563db4 --- /dev/null +++ b/test/integration/testdata/busybox-mount-test.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + name: busybox +spec: + containers: + - image: busybox:glibc + command: [ "/bin/sh", "-c", "--" ] + args: [ "cat /mount-9p/fromhost; echo test > /mount-9p/frompod; rm /mount-9p/fromhostremove; echo test > /mount-9p/frompodremove;" ] + name: busybox + volumeMounts: + - mountPath: /mount-9p + name: test-volume + volumes: + - name: test-volume + hostPath: + # directory location on host + path: /mount-9p + diff --git a/test/integration/util/util.go b/test/integration/util/util.go index ee444d0cf..c9c80cef3 100644 --- a/test/integration/util/util.go +++ b/test/integration/util/util.go @@ -69,6 +69,17 @@ func (m *MinikubeRunner) RunCommand(command string, checkError bool) string { return string(stdout) } +func (m *MinikubeRunner) RunDaemon(command string) *exec.Cmd { + commandArr := strings.Split(command, " ") + path, _ := filepath.Abs(m.BinaryPath) + cmd := exec.Command(path, commandArr...) + err := cmd.Start() + if err != nil { + m.T.Fatalf("Error running command: %s %s", command, err) + } + return cmd +} + func (m *MinikubeRunner) SSH(command string) (string, error) { path, _ := filepath.Abs(m.BinaryPath) cmd := exec.Command(path, "ssh", command) diff --git a/third_party/go9p/.gitignore b/third_party/go9p/.gitignore new file mode 100644 index 000000000..6ffab9ad2 --- /dev/null +++ b/third_party/go9p/.gitignore @@ -0,0 +1,2 @@ +*.orig +*.rej diff --git a/third_party/go9p/AUTHORS b/third_party/go9p/AUTHORS deleted file mode 100644 index 9d63b6432..000000000 --- a/third_party/go9p/AUTHORS +++ /dev/null @@ -1,13 +0,0 @@ -# This is the official list of Go9p authors for copyright purposes. -# This file is distinct from the CONTRIBUTORS files. -# See the latter for an explanation. - -# Names should be added to this file as -# Name or Organization -# The email address is not required for organizations. - -# Please keep the list sorted. - -Andrey Mirtchovski -Latchesar Ionkov -Roger Peppe diff --git a/third_party/go9p/CONTRIBUTORS b/third_party/go9p/CONTRIBUTORS deleted file mode 100644 index 290ca376a..000000000 --- a/third_party/go9p/CONTRIBUTORS +++ /dev/null @@ -1,18 +0,0 @@ -# This is the official list of people who can contribute -# (and typically have contributed) code to the Go9p repository. -# The AUTHORS file lists the copyright holders; this file -# lists people. For example, Google employees are listed here -# but not in AUTHORS, because Google holds the copyright. -# -# The submission process automatically checks to make sure -# that people submitting code are listed in this file (by email address). -# XXX more bumph here? -# Names should be added to this file like so: -# Name - -# Please keep the list sorted. - -Andrey Mirtchovski -Latchesar Ionkov -Akshat Kumar -Roger Peppe diff --git a/third_party/go9p/README.md b/third_party/go9p/README.md new file mode 100644 index 000000000..adebdeb09 --- /dev/null +++ b/third_party/go9p/README.md @@ -0,0 +1,11 @@ +This is go9p done in a way that I can understand. + +To install: + export GOPATH=~rminnich/go + go get -a /k8s.io/minikube/third_party/go9p + go get -a /k8s.io/minikube/third_party/go9p/ufs + go install -a /k8s.io/minikube/third_party/go9p/ufs + +~/go/bin/ufs + + diff --git a/third_party/go9p/p/clnt/clnt.go b/third_party/go9p/clnt_clnt.go old mode 100755 new mode 100644 similarity index 77% rename from third_party/go9p/p/clnt/clnt.go rename to third_party/go9p/clnt_clnt.go index 807a3beaa..5003cc7ed --- a/third_party/go9p/p/clnt/clnt.go +++ b/third_party/go9p/clnt_clnt.go @@ -2,31 +2,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The clnt package provides definitions and functions used to implement +// The clnt package go9provides definitions and functions used to implement // a 9P2000 file client. -package clnt +package go9p import ( "fmt" - "k8s.io/minikube/third_party/go9p/p" "log" "net" "sync" + "sync/atomic" ) -// Debug flags -const ( - DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr - DbgPrintPackets // print the raw packets on stderr - DbgLogFcalls // keep the last N 9P messages (can be accessed over http) - DbgLogPackets // keep the last N 9P messages (can be accessed over http) -) - -type StatsOps interface { - statsRegister() - statsUnregister() -} - // The Clnt type represents a 9P2000 client. The client is connected to // a 9P2000 file server and its methods can be used to access and manipulate // the files exported by the server. @@ -37,7 +24,7 @@ type Clnt struct { Dotu bool // If true, 9P2000.u protocol is spoken Root *Fid // Fid that points to the rood directory Id string // Used when printing debug messages - Log *p.Logger + Log *Logger conn net.Conn tagpool *pool @@ -49,7 +36,7 @@ type Clnt struct { err error reqchan chan *Req - tchan chan *p.Fcall + tchan chan *Fcall next, prev *Clnt } @@ -60,33 +47,26 @@ type Fid struct { sync.Mutex Clnt *Clnt // Client the fid belongs to Iounit uint32 - p.Qid // The Qid description for the file - Mode uint8 // Open mode (one of p.O* values) (if file is open) + Qid // The Qid description for the file + Mode uint8 // Open mode (one of O* values) (if file is open) Fid uint32 // Fid number - p.User // The user the fid belongs to + User // The user the fid belongs to walked bool // true if the fid points to a walked file on the server } // The file is similar to the Fid, but is used in the high-level client -// interface. +// interface. We expose the Fid so that client code can use Remove +// on a fid, the same way a kernel can. type File struct { - fid *Fid + Fid *Fid offset uint64 } -type pool struct { - sync.Mutex - need int - nchan chan uint32 - maxid uint32 - imap []byte -} - type Req struct { sync.Mutex Clnt *Clnt - Tc *p.Fcall - Rc *p.Fcall + Tc *Fcall + Rc *Fcall Err error Done chan *Req tag uint16 @@ -101,18 +81,18 @@ type ClntList struct { var clnts *ClntList var DefaultDebuglevel int -var DefaultLogger *p.Logger +var DefaultLogger *Logger func (clnt *Clnt) Rpcnb(r *Req) error { var tag uint16 - if r.Tc.Type == p.Tversion { - tag = p.NOTAG + if r.Tc.Type == Tversion { + tag = NOTAG } else { tag = r.tag } - p.SetTag(r.Tc, tag) + SetTag(r.Tc, tag) clnt.Lock() if clnt.err != nil { clnt.Unlock() @@ -133,7 +113,7 @@ func (clnt *Clnt) Rpcnb(r *Req) error { return nil } -func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) { +func (clnt *Clnt) Rpc(tc *Fcall) (rc *Fcall, err error) { r := clnt.ReqAlloc() r.Tc = tc r.Done = make(chan *Req) @@ -151,13 +131,15 @@ func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) { func (clnt *Clnt) recv() { var err error + var buf []byte err = nil - buf := make([]byte, clnt.Msize*8) pos := 0 for { - if len(buf) < int(clnt.Msize) { - b := make([]byte, clnt.Msize*8) + // Connect can change the client Msize. + clntmsize := int(atomic.LoadUint32(&clnt.Msize)) + if len(buf) < clntmsize { + b := make([]byte, clntmsize*8) copy(b, buf[0:pos]) buf = b b = nil @@ -165,7 +147,7 @@ func (clnt *Clnt) recv() { n, oerr := clnt.conn.Read(buf[pos:]) if oerr != nil || n == 0 { - err = &p.Error{oerr.Error(), p.EIO} + err = &Error{oerr.Error(), EIO} clnt.Lock() clnt.err = err clnt.Unlock() @@ -174,10 +156,10 @@ func (clnt *Clnt) recv() { pos += n for pos > 4 { - sz, _ := p.Gint32(buf) + sz, _ := Gint32(buf) if pos < int(sz) { if len(buf) < int(sz) { - b := make([]byte, clnt.Msize*8) + b := make([]byte, atomic.LoadUint32(&clnt.Msize)*8) copy(b, buf[0:pos]) buf = b b = nil @@ -186,7 +168,7 @@ func (clnt *Clnt) recv() { break } - fc, err, fcsize := p.Unpack(buf, clnt.Dotu) + fc, err, fcsize := Unpack(buf, clnt.Dotu) clnt.Lock() if err != nil { clnt.err = err @@ -214,7 +196,7 @@ func (clnt *Clnt) recv() { } if r == nil { - clnt.err = &p.Error{"unexpected response", p.EINVAL} + clnt.err = &Error{"unexpected response", EINVAL} clnt.conn.Close() clnt.Unlock() goto closed @@ -235,13 +217,13 @@ func (clnt *Clnt) recv() { clnt.Unlock() if r.Tc.Type != r.Rc.Type-1 { - if r.Rc.Type != p.Rerror { - r.Err = &p.Error{"invalid response", p.EINVAL} + if r.Rc.Type != Rerror { + r.Err = &Error{"invalid response", EINVAL} log.Println(fmt.Sprintf("TTT %v", r.Tc)) log.Println(fmt.Sprintf("RRR %v", r.Rc)) } else { if r.Err == nil { - r.Err = &p.Error{r.Rc.Error, r.Rc.Errornum} + r.Err = &Error{r.Rc.Error, r.Rc.Errornum} } } } @@ -335,12 +317,12 @@ func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt { clnt.Debuglevel = DefaultDebuglevel clnt.Log = DefaultLogger clnt.Id = c.RemoteAddr().String() + ":" - clnt.tagpool = newPool(uint32(p.NOTAG)) - clnt.fidpool = newPool(p.NOFID) + clnt.tagpool = newPool(uint32(NOTAG)) + clnt.fidpool = newPool(NOFID) clnt.reqout = make(chan *Req) clnt.done = make(chan bool) clnt.reqchan = make(chan *Req, 16) - clnt.tchan = make(chan *p.Fcall, 16) + clnt.tchan = make(chan *Fcall, 16) go clnt.recv() go clnt.send() @@ -373,8 +355,9 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) { ver = "9P2000.u" } - tc := p.NewFcall(clnt.Msize) - err := p.PackTversion(tc, clnt.Msize, ver) + clntmsize := atomic.LoadUint32(&clnt.Msize) + tc := NewFcall(clntmsize) + err := PackTversion(tc, clntmsize, ver) if err != nil { return nil, err } @@ -384,8 +367,8 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) { return nil, err } - if rc.Msize < clnt.Msize { - clnt.Msize = rc.Msize + if rc.Msize < atomic.LoadUint32(&clnt.Msize) { + atomic.StoreUint32(&clnt.Msize, rc.Msize) } clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu @@ -401,17 +384,17 @@ func (clnt *Clnt) FidAlloc() *Fid { return fid } -func (clnt *Clnt) NewFcall() *p.Fcall { +func (clnt *Clnt) NewFcall() *Fcall { select { case tc := <-clnt.tchan: return tc default: } - return p.NewFcall(clnt.Msize) + return NewFcall(atomic.LoadUint32(&clnt.Msize)) } -func (clnt *Clnt) FreeFcall(fc *p.Fcall) { - if fc != nil && len(fc.Buf) >= int(clnt.Msize) { +func (clnt *Clnt) FreeFcall(fc *Fcall) { + if fc != nil && len(fc.Buf) >= int(atomic.LoadUint32(&clnt.Msize)) { select { case clnt.tchan <- fc: break @@ -450,15 +433,7 @@ func (clnt *Clnt) ReqFree(req *Req) { } } -func NewFile(f *Fid, offset uint64) *File { - return &File{f, offset} -} - -func (f *File) Fid() *Fid { - return f.fid -} - -func (clnt *Clnt) logFcall(fc *p.Fcall) { +func (clnt *Clnt) logFcall(fc *Fcall) { if clnt.Debuglevel&DbgLogPackets != 0 { pkt := make([]byte, len(fc.Pkt)) copy(pkt, fc.Pkt) @@ -466,13 +441,19 @@ func (clnt *Clnt) logFcall(fc *p.Fcall) { } if clnt.Debuglevel&DbgLogFcalls != 0 { - f := new(p.Fcall) + f := new(Fcall) *f = *fc f.Pkt = nil clnt.Log.Log(f, clnt, DbgLogFcalls) } } +// FidFile returns a File that represents the given Fid, initially at the given +// offset. +func FidFile(fid *Fid, offset uint64) *File { + return &File{fid, offset} +} + func init() { clnts = new(ClntList) if sop, ok := (interface{}(clnts)).(StatsOps); ok { diff --git a/third_party/go9p/p/clnt/close.go b/third_party/go9p/clnt_close.go similarity index 79% rename from third_party/go9p/p/clnt/close.go rename to third_party/go9p/clnt_close.go index ddef36d4f..475640834 100644 --- a/third_party/go9p/p/clnt/close.go +++ b/third_party/go9p/clnt_close.go @@ -2,16 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt - -import "k8s.io/minikube/third_party/go9p/p" +package go9p // Clunks a fid. Returns nil if successful. func (clnt *Clnt) Clunk(fid *Fid) (err error) { err = nil if fid.walked { tc := clnt.NewFcall() - err := p.PackTclunk(tc, fid.Fid) + err := PackTclunk(tc, fid.Fid) if err != nil { return err } @@ -21,12 +19,12 @@ func (clnt *Clnt) Clunk(fid *Fid) (err error) { clnt.fidpool.putId(fid.Fid) fid.walked = false - fid.Fid = p.NOFID + fid.Fid = NOFID return } // Closes a file. Returns nil if successful. func (file *File) Close() error { // Should we cancel all pending requests for the File - return file.fid.Clnt.Clunk(file.fid) + return file.Fid.Clnt.Clunk(file.Fid) } diff --git a/third_party/go9p/p/clnt/mount.go b/third_party/go9p/clnt_mount.go similarity index 65% rename from third_party/go9p/p/clnt/mount.go rename to third_party/go9p/clnt_mount.go index de491a335..1c7a754c6 100644 --- a/third_party/go9p/p/clnt/mount.go +++ b/third_party/go9p/clnt_mount.go @@ -2,19 +2,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt +package go9p import ( - "k8s.io/minikube/third_party/go9p/p" "net" ) // Creates an authentication fid for the specified user. Returns the fid, if // successful, or an Error. -func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) { +func (clnt *Clnt) Auth(user User, aname string) (*Fid, error) { fid := clnt.FidAlloc() tc := clnt.NewFcall() - err := p.PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu) + err := PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu) if err != nil { return nil, err } @@ -24,7 +23,6 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) { return nil, err } - fid.Iounit = clnt.Msize - p.IOHDRSZ fid.User = user fid.walked = true return fid, nil @@ -33,18 +31,18 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) { // Creates a fid for the specified user that points to the root // of the file server's file tree. Returns a Fid pointing to the root, // if successful, or an Error. -func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) { +func (clnt *Clnt) Attach(afid *Fid, user User, aname string) (*Fid, error) { var afno uint32 if afid != nil { afno = afid.Fid } else { - afno = p.NOFID + afno = NOFID } fid := clnt.FidAlloc() tc := clnt.NewFcall() - err := p.PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu) + err := PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu) if err != nil { return nil, err } @@ -61,17 +59,17 @@ func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) { } // Connects to a file server and attaches to it as the specified user. -func Mount(ntype, addr, aname string, user p.User) (*Clnt, error) { +func Mount(ntype, addr, aname string, msize uint32, user User) (*Clnt, error) { c, e := net.Dial(ntype, addr) if e != nil { - return nil, &p.Error{e.Error(), p.EIO} + return nil, &Error{e.Error(), EIO} } - return MountConn(c, aname, user) + return MountConn(c, aname, msize, user) } -func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) { - clnt, err := Connect(c, 8192+p.IOHDRSZ, true) +func MountConn(c net.Conn, aname string, msize uint32, user User) (*Clnt, error) { + clnt, err := Connect(c, msize+IOHDRSZ, true) if err != nil { return nil, err } @@ -89,7 +87,7 @@ func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) { // Closes the connection to the file sever. func (clnt *Clnt) Unmount() { clnt.Lock() - clnt.err = &p.Error{"connection closed", p.EIO} + clnt.err = &Error{"connection closed", EIO} clnt.conn.Close() clnt.Unlock() } diff --git a/third_party/go9p/p/clnt/open.go b/third_party/go9p/clnt_open.go similarity index 82% rename from third_party/go9p/p/clnt/open.go rename to third_party/go9p/clnt_open.go index 6c1889a4e..82ab21d26 100644 --- a/third_party/go9p/p/clnt/open.go +++ b/third_party/go9p/clnt_open.go @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt +package go9p import ( - "k8s.io/minikube/third_party/go9p/p" "strings" ) @@ -13,7 +12,7 @@ import ( // the operation is successful. func (clnt *Clnt) Open(fid *Fid, mode uint8) error { tc := clnt.NewFcall() - err := p.PackTopen(tc, fid.Fid, mode) + err := PackTopen(tc, fid.Fid, mode) if err != nil { return err } @@ -25,8 +24,8 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error { fid.Qid = rc.Qid fid.Iounit = rc.Iounit - if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ { - fid.Iounit = clnt.Msize - p.IOHDRSZ + if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ { + fid.Iounit = clnt.Msize - IOHDRSZ } fid.Mode = mode return nil @@ -36,7 +35,7 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error { // if the operation is successful. func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error { tc := clnt.NewFcall() - err := p.PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu) + err := PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu) if err != nil { return err } @@ -48,8 +47,8 @@ func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext str fid.Qid = rc.Qid fid.Iounit = rc.Iounit - if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ { - fid.Iounit = clnt.Msize - p.IOHDRSZ + if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ { + fid.Iounit = clnt.Msize - IOHDRSZ } fid.Mode = mode return nil diff --git a/third_party/go9p/p/clnt/pool.go b/third_party/go9p/clnt_pool.go similarity index 93% rename from third_party/go9p/p/clnt/pool.go rename to third_party/go9p/clnt_pool.go index c02af8681..38ba4e6f0 100644 --- a/third_party/go9p/p/clnt/pool.go +++ b/third_party/go9p/clnt_pool.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt +package go9p + +import "sync" var m2id = [...]uint8{ 0, 1, 0, 2, 0, 1, 0, 3, @@ -39,6 +41,14 @@ var m2id = [...]uint8{ 0, 1, 0, 2, 0, 1, 0, 0, } +type pool struct { + sync.Mutex + need int + nchan chan uint32 + maxid uint32 + imap []byte +} + func newPool(maxid uint32) *pool { p := new(pool) p.maxid = maxid diff --git a/third_party/go9p/p/clnt/read.go b/third_party/go9p/clnt_read.go similarity index 79% rename from third_party/go9p/p/clnt/read.go rename to third_party/go9p/clnt_read.go index 7c77f08c6..21e8f6165 100644 --- a/third_party/go9p/p/clnt/read.go +++ b/third_party/go9p/clnt_read.go @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt +package go9p import ( "io" - "k8s.io/minikube/third_party/go9p/p" ) // Reads count bytes starting from offset from the file associated with the fid. @@ -18,7 +17,7 @@ func (clnt *Clnt) Read(fid *Fid, offset uint64, count uint32) ([]byte, error) { } tc := clnt.NewFcall() - err := p.PackTread(tc, fid.Fid, offset, count) + err := PackTread(tc, fid.Fid, offset, count) if err != nil { return nil, err } @@ -45,7 +44,7 @@ func (file *File) Read(buf []byte) (int, error) { // Reads up to len(buf) bytes from the file starting from offset. // Returns the number of bytes read, or an Error. func (file *File) ReadAt(buf []byte, offset int64) (int, error) { - b, err := file.fid.Clnt.Read(file.fid, uint64(offset), uint32(len(buf))) + b, err := file.Fid.Clnt.Read(file.Fid, uint64(offset), uint32(len(buf))) if err != nil { return 0, err } @@ -85,10 +84,14 @@ func (file *File) Readn(buf []byte, offset uint64) (int, error) { // Returns an array of maximum num entries (if num is 0, returns // all entries from the directory). If the operation fails, returns // an Error. -func (file *File) Readdir(num int) ([]*p.Dir, error) { - buf := make([]byte, file.fid.Clnt.Msize-p.IOHDRSZ) - dirs := make([]*p.Dir, 32) +func (file *File) Readdir(num int) ([]*Dir, error) { + buf := make([]byte, file.Fid.Clnt.Msize-IOHDRSZ) + dirs := make([]*Dir, 32) pos := 0 + offset := file.offset + defer func() { + file.offset = offset + }() for { n, err := file.Read(buf) if err != nil && err != io.EOF { @@ -100,14 +103,20 @@ func (file *File) Readdir(num int) ([]*p.Dir, error) { } for b := buf[0:n]; len(b) > 0; { - d, perr := p.UnpackDir(b, file.fid.Clnt.Dotu) + d, _, _, perr := UnpackDir(b, file.Fid.Clnt.Dotu) if perr != nil { + // If we have unpacked anything, it is almost certainly + // a too-short buffer. So return what we got. + if pos > 0 { + return dirs[0:pos], nil + } return nil, perr } b = b[d.Size+2:] + offset += uint64(d.Size + 2) if pos >= len(dirs) { - s := make([]*p.Dir, len(dirs)+32) + s := make([]*Dir, len(dirs)+32) copy(s, dirs) dirs = s } diff --git a/third_party/go9p/p/clnt/remove.go b/third_party/go9p/clnt_remove.go similarity index 85% rename from third_party/go9p/p/clnt/remove.go rename to third_party/go9p/clnt_remove.go index 565326f86..9f7663886 100644 --- a/third_party/go9p/p/clnt/remove.go +++ b/third_party/go9p/clnt_remove.go @@ -2,22 +2,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt - -import "k8s.io/minikube/third_party/go9p/p" +package go9p // Removes the file associated with the Fid. Returns nil if the // operation is successful. func (clnt *Clnt) Remove(fid *Fid) error { tc := clnt.NewFcall() - err := p.PackTremove(tc, fid.Fid) + err := PackTremove(tc, fid.Fid) if err != nil { return err } _, err = clnt.Rpc(tc) clnt.fidpool.putId(fid.Fid) - fid.Fid = p.NOFID + fid.Fid = NOFID return err } diff --git a/third_party/go9p/p/clnt/stat.go b/third_party/go9p/clnt_stat.go similarity index 71% rename from third_party/go9p/p/clnt/stat.go rename to third_party/go9p/clnt_stat.go index ddbbe2cfb..77c970b77 100644 --- a/third_party/go9p/p/clnt/stat.go +++ b/third_party/go9p/clnt_stat.go @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt - -import "k8s.io/minikube/third_party/go9p/p" +package go9p // Returns the metadata for the file associated with the Fid, or an Error. -func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) { +func (clnt *Clnt) Stat(fid *Fid) (*Dir, error) { tc := clnt.NewFcall() - err := p.PackTstat(tc, fid.Fid) + err := PackTstat(tc, fid.Fid) if err != nil { return nil, err } @@ -23,7 +21,7 @@ func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) { } // Returns the metadata for a named file, or an Error. -func (clnt *Clnt) FStat(path string) (*p.Dir, error) { +func (clnt *Clnt) FStat(path string) (*Dir, error) { fid, err := clnt.FWalk(path) if err != nil { return nil, err @@ -35,9 +33,9 @@ func (clnt *Clnt) FStat(path string) (*p.Dir, error) { } // Modifies the data of the file associated with the Fid, or an Error. -func (clnt *Clnt) Wstat(fid *Fid, dir *p.Dir) error { +func (clnt *Clnt) Wstat(fid *Fid, dir *Dir) error { tc := clnt.NewFcall() - err := p.PackTwstat(tc, fid.Fid, dir, clnt.Dotu) + err := PackTwstat(tc, fid.Fid, dir, clnt.Dotu) if err != nil { return err } diff --git a/third_party/go9p/p/clnt/stats_http.go b/third_party/go9p/clnt_stats_http.go similarity index 94% rename from third_party/go9p/p/clnt/stats_http.go rename to third_party/go9p/clnt_stats_http.go index bde8ac437..10059b172 100644 --- a/third_party/go9p/p/clnt/stats_http.go +++ b/third_party/go9p/clnt_stats_http.go @@ -1,11 +1,10 @@ // +build httpstats -package clnt +package go9p import ( "fmt" "io" - "k8s.io/minikube/third_party/go9p/p" "net/http" ) @@ -18,7 +17,7 @@ func (clnt *Clnt) ServeHTTP(c http.ResponseWriter, r *http.Request) { fs := clnt.Log.Filter(clnt, DbgLogFcalls) io.WriteString(c, fmt.Sprintf("

Last %d 9P messages

", len(fs))) for _, l := range fs { - fc := l.Data.(*p.Fcall) + fc := l.Data.(*Fcall) if fc.Type != 0 { io.WriteString(c, fmt.Sprintf("
%s", fc)) } diff --git a/third_party/go9p/p/clnt/tag.go b/third_party/go9p/clnt_tag.go similarity index 74% rename from third_party/go9p/p/clnt/tag.go rename to third_party/go9p/clnt_tag.go index f8d9a49ab..eb9cd6df1 100644 --- a/third_party/go9p/p/clnt/tag.go +++ b/third_party/go9p/clnt_tag.go @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt - -import "k8s.io/minikube/third_party/go9p/p" +package go9p type Tag struct { clnt *Clnt @@ -54,22 +52,22 @@ func (tag *Tag) reqproc() { case r := <-tag.respchan: rc := r.Rc fid := r.fid - err := r.Rc.Type == p.Rerror + err := r.Rc.Type == Rerror switch r.Tc.Type { - case p.Tauth: + case Tauth: if err { fid.User = nil } - case p.Tattach: + case Tattach: if !err { fid.Qid = rc.Qid } else { fid.User = nil } - case p.Twalk: + case Twalk: if !err { fid.walked = true if len(rc.Wqid) > 0 { @@ -79,8 +77,8 @@ func (tag *Tag) reqproc() { fid.User = nil } - case p.Topen: - case p.Tcreate: + case Topen: + case Tcreate: if !err { fid.Iounit = rc.Iounit fid.Qid = rc.Qid @@ -88,8 +86,8 @@ func (tag *Tag) reqproc() { fid.Mode = 0 } - case p.Tclunk: - case p.Tremove: + case Tclunk: + case Tremove: tag.clnt.fidpool.putId(fid.Fid) } @@ -98,10 +96,10 @@ func (tag *Tag) reqproc() { } } -func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error { +func (tag *Tag) Auth(afid *Fid, user User, aname string) error { req := tag.reqAlloc() req.fid = afid - err := p.PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu) + err := PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu) if err != nil { return err } @@ -110,18 +108,18 @@ func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error { return tag.clnt.Rpcnb(req) } -func (tag *Tag) Attach(fid, afid *Fid, user p.User, aname string) error { +func (tag *Tag) Attach(fid, afid *Fid, user User, aname string) error { var afno uint32 if afid != nil { afno = afid.Fid } else { - afno = p.NOFID + afno = NOFID } req := tag.reqAlloc() req.fid = fid - err := p.PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu) + err := PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu) if err != nil { return err } @@ -137,7 +135,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error { newfid.Qid = fid.Qid } - err := p.PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames) + err := PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames) if err != nil { return err } @@ -149,7 +147,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error { func (tag *Tag) Open(fid *Fid, mode uint8) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTopen(req.Tc, fid.Fid, mode) + err := PackTopen(req.Tc, fid.Fid, mode) if err != nil { return err } @@ -161,7 +159,7 @@ func (tag *Tag) Open(fid *Fid, mode uint8) error { func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu) + err := PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu) if err != nil { return err } @@ -173,7 +171,7 @@ func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext strin func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTread(req.Tc, fid.Fid, offset, count) + err := PackTread(req.Tc, fid.Fid, offset, count) if err != nil { return err } @@ -184,7 +182,7 @@ func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error { func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data) + err := PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data) if err != nil { return err } @@ -195,7 +193,7 @@ func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error { func (tag *Tag) Clunk(fid *Fid) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTclunk(req.Tc, fid.Fid) + err := PackTclunk(req.Tc, fid.Fid) if err != nil { return err } @@ -206,7 +204,7 @@ func (tag *Tag) Clunk(fid *Fid) error { func (tag *Tag) Remove(fid *Fid) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTremove(req.Tc, fid.Fid) + err := PackTremove(req.Tc, fid.Fid) if err != nil { return err } @@ -217,7 +215,7 @@ func (tag *Tag) Remove(fid *Fid) error { func (tag *Tag) Stat(fid *Fid) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTstat(req.Tc, fid.Fid) + err := PackTstat(req.Tc, fid.Fid) if err != nil { return err } @@ -225,10 +223,10 @@ func (tag *Tag) Stat(fid *Fid) error { return tag.clnt.Rpcnb(req) } -func (tag *Tag) Wstat(fid *Fid, dir *p.Dir) error { +func (tag *Tag) Wstat(fid *Fid, dir *Dir) error { req := tag.reqAlloc() req.fid = fid - err := p.PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu) + err := PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu) if err != nil { return err } diff --git a/third_party/go9p/p/clnt/walk.go b/third_party/go9p/clnt_walk.go similarity index 87% rename from third_party/go9p/p/clnt/walk.go rename to third_party/go9p/clnt_walk.go index c094e8175..3401a83ed 100644 --- a/third_party/go9p/p/clnt/walk.go +++ b/third_party/go9p/clnt_walk.go @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt +package go9p import ( - "k8s.io/minikube/third_party/go9p/p" "strings" ) @@ -13,9 +12,9 @@ import ( // sequence and associates the resulting file with newfid. If no wnames // were walked successfully, an Error is returned. Otherwise a slice with a // Qid for each walked name is returned. -func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]p.Qid, error) { +func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]Qid, error) { tc := clnt.NewFcall() - err := p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames) + err := PackTwalk(tc, fid.Fid, newfid.Fid, wnames) if err != nil { return nil, err } @@ -66,12 +65,12 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) { } tc := clnt.NewFcall() - err = p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n]) + err = PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n]) if err != nil { goto error } - var rc *p.Fcall + var rc *Fcall rc, err = clnt.Rpc(tc) if err != nil { goto error @@ -79,7 +78,7 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) { newfid.walked = true if len(rc.Wqid) != n { - err = &p.Error{"file not found", p.ENOENT} + err = &Error{"file not found", ENOENT} goto error } diff --git a/third_party/go9p/p/clnt/write.go b/third_party/go9p/clnt_write.go similarity index 88% rename from third_party/go9p/p/clnt/write.go rename to third_party/go9p/clnt_write.go index 76e140e03..fc280406a 100644 --- a/third_party/go9p/p/clnt/write.go +++ b/third_party/go9p/clnt_write.go @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package clnt - -import "k8s.io/minikube/third_party/go9p/p" +package go9p // Write up to len(data) bytes starting from offset. Returns the // number of bytes written, or an Error. @@ -14,7 +12,7 @@ func (clnt *Clnt) Write(fid *Fid, data []byte, offset uint64) (int, error) { } tc := clnt.NewFcall() - err := p.PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data) + err := PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data) if err != nil { return 0, err } @@ -41,7 +39,7 @@ func (file *File) Write(buf []byte) (int, error) { // Writes up to len(buf) bytes starting from offset. Returns the number // of bytes written, or an Error. func (file *File) WriteAt(buf []byte, offset int64) (int, error) { - return file.fid.Clnt.Write(file.fid, buf, uint64(offset)) + return file.Fid.Clnt.Write(file.Fid, buf, uint64(offset)) } // Writes exactly len(buf) bytes starting from offset. Returns the number of diff --git a/third_party/go9p/debug.go b/third_party/go9p/debug.go new file mode 100644 index 000000000..21d2575fd --- /dev/null +++ b/third_party/go9p/debug.go @@ -0,0 +1,9 @@ +package go9p + +// Debug flags +const ( + DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr + DbgPrintPackets // print the raw packets on stderr + DbgLogFcalls // keep the last N 9P messages (can be accessed over http) + DbgLogPackets // keep the last N 9P messages (can be accessed over http) +) diff --git a/third_party/go9p/p/fmt.go b/third_party/go9p/fmt.go similarity index 99% rename from third_party/go9p/p/fmt.go rename to third_party/go9p/fmt.go index 94e85c601..2dfb3edfa 100644 --- a/third_party/go9p/p/fmt.go +++ b/third_party/go9p/fmt.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +package go9p import "fmt" diff --git a/third_party/go9p/p/log.go b/third_party/go9p/log.go similarity index 99% rename from third_party/go9p/p/log.go rename to third_party/go9p/log.go index 8c6234197..266f02650 100644 --- a/third_party/go9p/p/log.go +++ b/third_party/go9p/log.go @@ -1,4 +1,4 @@ -package p +package go9p type Log struct { Data interface{} diff --git a/third_party/go9p/p/osusers.go b/third_party/go9p/osusers.go similarity index 57% rename from third_party/go9p/p/osusers.go rename to third_party/go9p/osusers.go index 77d421603..fb868a910 100644 --- a/third_party/go9p/p/osusers.go +++ b/third_party/go9p/osusers.go @@ -2,38 +2,33 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +package go9p -import ( - "os/user" - "strconv" - "sync" -) +import "sync" var once sync.Once type osUser struct { - *user.User uid int - gid int } type osUsers struct { + users map[int]*osUser groups map[int]*osGroup sync.Mutex } -// Simple Users implementation that defers to os/user and fakes -// looking up groups by gid only. +// Simple Users implementation that fakes looking up users and groups +// by uid only. The names and groups memberships are empty var OsUsers *osUsers -func (u *osUser) Name() string { return u.Username } +func (u *osUser) Name() string { return "" } func (u *osUser) Id() int { return u.uid } -func (u *osUser) Groups() []Group { return []Group{OsUsers.Gid2Group(u.gid)} } +func (u *osUser) Groups() []Group { return nil } -func (u *osUser) IsMember(g Group) bool { return u.gid == g.Id() } +func (u *osUser) IsMember(g Group) bool { return false } type osGroup struct { gid int @@ -47,33 +42,28 @@ func (g *osGroup) Members() []User { return nil } func initOsusers() { OsUsers = new(osUsers) + OsUsers.users = make(map[int]*osUser) OsUsers.groups = make(map[int]*osGroup) } -func newUser(u *user.User) *osUser { - uid, uerr := strconv.Atoi(u.Uid) - gid, gerr := strconv.Atoi(u.Gid) - if uerr != nil || gerr != nil { - /* non-numeric uid/gid => unsupported system */ - return nil - } - return &osUser{u, uid, gid} -} - func (up *osUsers) Uid2User(uid int) User { - u, err := user.LookupId(strconv.Itoa(uid)) - if err != nil { - return nil + once.Do(initOsusers) + OsUsers.Lock() + defer OsUsers.Unlock() + user, present := OsUsers.users[uid] + if present { + return user } - return newUser(u) + + user = new(osUser) + user.uid = uid + OsUsers.users[uid] = user + return user } func (up *osUsers) Uname2User(uname string) User { - u, err := user.Lookup(uname) - if err != nil { - return nil - } - return newUser(u) + // unimplemented + return nil } func (up *osUsers) Gid2Group(gid int) Group { diff --git a/third_party/go9p/p/clnt/examples/cl/cl.go b/third_party/go9p/p/clnt/examples/cl/cl.go deleted file mode 100644 index 32169c7fd..000000000 --- a/third_party/go9p/p/clnt/examples/cl/cl.go +++ /dev/null @@ -1,489 +0,0 @@ -package main - -// An interactive client for 9P servers. - -import ( - "bufio" - "flag" - "fmt" - "io" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/clnt" - "os" - "path" - "strings" -) - -var addr = flag.String("addr", "127.0.0.1:5640", "network address") -var ouser = flag.String("user", "", "user to connect as") -var cmdfile = flag.String("file", "", "read commands from file") -var prompt = flag.String("prompt", "9p> ", "prompt for interactive client") -var debug = flag.Bool("d", false, "enable debugging (fcalls)") -var debugall = flag.Bool("D", false, "enable debugging (raw packets)") - -var cwd = "/" -var cfid *clnt.Fid - -type Cmd struct { - fun func(c *clnt.Clnt, s []string) - help string -} - -var cmds map[string]*Cmd - -func init() { - cmds = make(map[string]*Cmd) - cmds["write"] = &Cmd{cmdwrite, "write file string [...]\t«write the unmodified string to file, create file if necessary»"} - cmds["echo"] = &Cmd{cmdecho, "echo file string [...]\t«echo string to file (newline appended)»"} - cmds["stat"] = &Cmd{cmdstat, "stat file [...]\t«stat file»"} - cmds["ls"] = &Cmd{cmdls, "ls [-l] file [...]\t«list contents of directory or file»"} - cmds["cd"] = &Cmd{cmdcd, "cd dir\t«change working directory»"} - cmds["cat"] = &Cmd{cmdcat, "cat file [...]\t«print the contents of file»"} - cmds["mkdir"] = &Cmd{cmdmkdir, "mkdir dir [...]\t«create dir on remote server»"} - cmds["get"] = &Cmd{cmdget, "get file [local]\t«get file from remote server»"} - cmds["put"] = &Cmd{cmdput, "put file [remote]\t«put file on the remote server as 'file'»"} - cmds["pwd"] = &Cmd{cmdpwd, "pwd\t«print working directory»"} - cmds["rm"] = &Cmd{cmdrm, "rm file [...]\t«remove file from remote server»"} - cmds["help"] = &Cmd{cmdhelp, "help [cmd]\t«print available commands or help on cmd»"} - cmds["quit"] = &Cmd{cmdquit, "quit\t«exit»"} - cmds["exit"] = &Cmd{cmdquit, "exit\t«quit»"} -} - -// normalize user-supplied path. path starting with '/' is left untouched, otherwise is considered -// local from cwd -func normpath(s string) string { - if len(s) > 0 { - if s[0] == '/' { - return path.Clean(s) - } - return path.Clean(cwd + "/" + s) - } - return "/" -} - -func b(mode uint32, s uint8) string { - var bits = []string{"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"} - return bits[(mode>>s)&7] -} - -// Convert file mode bits to string representation -func modetostr(mode uint32) string { - d := "-" - if mode&p.DMDIR != 0 { - d = "d" - } else if mode&p.DMAPPEND != 0 { - d = "a" - } - return fmt.Sprintf("%s%s%s%s", d, b(mode, 6), b(mode, 3), b(mode, 0)) -} - -// Write the string s to remote file f. Create f if it doesn't exist -func writeone(c *clnt.Clnt, f, s string) { - fname := normpath(f) - file, oserr := c.FCreate(fname, 0666, p.OWRITE) - if oserr != nil { - file, oserr = c.FOpen(fname, p.OWRITE|p.OTRUNC) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error opening %s: %v\n", fname, oserr) - return - } - } - defer file.Close() - - m, oserr := file.Write([]byte(s)) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error writing to %s: %v\n", fname, oserr) - return - } - - if m != len(s) { - fmt.Fprintf(os.Stderr, "short write %s\n", fname) - return - } -} - -// Write s[1:] (with appended spaces) to the file s[0] -func cmdwrite(c *clnt.Clnt, s []string) { - fname := normpath(s[0]) - str := strings.Join(s[1:], " ") - writeone(c, fname, str) -} - -// Echo (append newline) s[1:] to s[0] -func cmdecho(c *clnt.Clnt, s []string) { - fname := normpath(s[0]) - str := strings.Join(s[1:], " ") + "\n" - writeone(c, fname, str) -} - -// Stat the remote file f -func statone(c *clnt.Clnt, f string) { - fname := normpath(f) - - stat, oserr := c.FStat(fname) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error in stat %s: %v\n", fname, oserr) - return - } - fmt.Fprintf(os.Stdout, "%s\n", stat) -} - -func cmdstat(c *clnt.Clnt, s []string) { - for _, f := range s { - statone(c, normpath(f)) - } -} - -func dirtostr(d *p.Dir) string { - return fmt.Sprintf("%s %s %s %-8d\t\t%s", modetostr(d.Mode), d.Uid, d.Gid, d.Length, d.Name) -} - -func lsone(c *clnt.Clnt, s string, long bool) { - st, oserr := c.FStat(normpath(s)) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error stat: %v\n", oserr) - return - } - if st.Mode&p.DMDIR != 0 { - file, oserr := c.FOpen(s, p.OREAD) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error opening dir: %s\n", oserr) - return - } - defer file.Close() - for { - d, oserr := file.Readdir(0) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error reading dir: %v\n", oserr) - } - if d == nil || len(d) == 0 { - break - } - for _, dir := range d { - if long { - fmt.Fprintf(os.Stdout, "%s\n", dirtostr(dir)) - } else { - os.Stdout.WriteString(dir.Name + "\n") - } - } - } - } else { - fmt.Fprintf(os.Stdout, "%s\n", dirtostr(st)) - } -} - -func cmdls(c *clnt.Clnt, s []string) { - long := false - if len(s) > 0 && s[0] == "-l" { - long = true - s = s[1:] - } - if len(s) == 0 { - lsone(c, cwd, long) - } else { - for _, d := range s { - lsone(c, cwd+d, long) - } - } -} - -func walkone(c *clnt.Clnt, s string, fileok bool) { - ncwd := normpath(s) - - fid, err := c.FWalk(ncwd) - defer c.Clunk(fid) - - if err != nil { - fmt.Fprintf(os.Stderr, "walk error: %s\n", err) - return - } - - if fileok != true && (fid.Type&p.QTDIR == 0) { - fmt.Fprintf(os.Stderr, "can't cd to file [%s]\n", ncwd) - return - } - - cwd = ncwd -} - -func cmdcd(c *clnt.Clnt, s []string) { - if s != nil { - walkone(c, strings.Join(s, "/"), false) - } -} - -// Print the contents of f -func cmdcat(c *clnt.Clnt, s []string) { - buf := make([]byte, 8192) -Outer: - for _, f := range s { - fname := normpath(f) - file, oserr := c.FOpen(fname, p.OREAD) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error opening %s: %v\n", f, oserr) - continue Outer - } - defer file.Close() - for { - n, oserr := file.Read(buf) - if oserr != nil && oserr != io.EOF { - fmt.Fprintf(os.Stderr, "error reading %s: %v\n", f, oserr) - } - if n == 0 { - break - } - os.Stdout.Write(buf[0:n]) - } - } -} - -// Create a single directory on remote server -func mkone(c *clnt.Clnt, s string) { - fname := normpath(s) - file, oserr := c.FCreate(fname, 0777|p.DMDIR, p.OWRITE) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error creating directory %s: %v\n", fname, oserr) - return - } - file.Close() -} - -// Create directories on remote server -func cmdmkdir(c *clnt.Clnt, s []string) { - for _, f := range s { - mkone(c, f) - } -} - -// Copy a remote file to local filesystem -func cmdget(c *clnt.Clnt, s []string) { - var from, to string - switch len(s) { - case 1: - from = normpath(s[0]) - _, to = path.Split(s[0]) - case 2: - from, to = normpath(s[0]), s[1] - default: - fmt.Fprintf(os.Stderr, "from arguments; usage: get from to\n") - } - - tofile, err := os.Create(to) - if err != nil { - fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err) - return - } - defer tofile.Close() - - file, ferr := c.FOpen(from, p.OREAD) - if ferr != nil { - fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err) - return - } - defer file.Close() - - buf := make([]byte, 8192) - for { - n, oserr := file.Read(buf) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error reading %s: %s\n", from, oserr) - return - } - if n == 0 { - break - } - - m, err := tofile.Write(buf[0:n]) - if err != nil { - fmt.Fprintf(os.Stderr, "error writing %s: %s\n", to, err) - return - } - - if m != n { - fmt.Fprintf(os.Stderr, "short write %s\n", to) - return - } - } -} - -// Copy a local file to remote server -func cmdput(c *clnt.Clnt, s []string) { - var from, to string - switch len(s) { - case 1: - _, to = path.Split(s[0]) - to = normpath(to) - from = s[0] - case 2: - from, to = s[0], normpath(s[1]) - default: - fmt.Fprintf(os.Stderr, "incorrect arguments; usage: put local [remote]\n") - } - - fromfile, err := os.Open(from) - if err != nil { - fmt.Fprintf(os.Stderr, "error opening %s for reading: %s\n", from, err) - return - } - defer fromfile.Close() - - file, ferr := c.FOpen(to, p.OWRITE|p.OTRUNC) - if ferr != nil { - file, ferr = c.FCreate(to, 0666, p.OWRITE) - if ferr != nil { - fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err) - return - } - } - defer file.Close() - - buf := make([]byte, 8192) - for { - n, oserr := fromfile.Read(buf) - if oserr != nil && oserr != io.EOF { - fmt.Fprintf(os.Stderr, "error reading %s: %s\n", from, oserr) - return - } - - if n == 0 { - break - } - - m, oserr := file.Write(buf[0:n]) - if oserr != nil { - fmt.Fprintf(os.Stderr, "error writing %s: %v\n", to, oserr) - return - } - - if m != n { - fmt.Fprintf(os.Stderr, "short write %s\n", to) - return - } - } -} - -func cmdpwd(c *clnt.Clnt, s []string) { fmt.Fprintf(os.Stdout, cwd+"\n") } - -// Remove f from remote server -func rmone(c *clnt.Clnt, f string) { - fname := normpath(f) - - err := c.FRemove(fname) - if err != nil { - fmt.Fprintf(os.Stderr, "error in stat %s", err) - return - } -} - -// Remove one or more files from the server -func cmdrm(c *clnt.Clnt, s []string) { - for _, f := range s { - rmone(c, normpath(f)) - } -} - -// Print available commands -func cmdhelp(c *clnt.Clnt, s []string) { - cmdstr := "" - if len(s) > 0 { - for _, h := range s { - v, ok := cmds[h] - if ok { - cmdstr = cmdstr + v.help + "\n" - } else { - cmdstr = cmdstr + "unknown command: " + h + "\n" - } - } - } else { - cmdstr = "available commands: " - for k := range cmds { - cmdstr = cmdstr + " " + k - } - cmdstr = cmdstr + "\n" - } - fmt.Fprintf(os.Stdout, "%s", cmdstr) -} - -func cmdquit(c *clnt.Clnt, s []string) { os.Exit(0) } - -func cmd(c *clnt.Clnt, cmd string) { - ncmd := strings.Fields(cmd) - if len(ncmd) <= 0 { - return - } - v, ok := cmds[ncmd[0]] - if ok == false { - fmt.Fprintf(os.Stderr, "unknown command: %s\n", ncmd[0]) - return - } - v.fun(c, ncmd[1:]) - return -} - -func interactive(c *clnt.Clnt) { - reader := bufio.NewReaderSize(os.Stdin, 8192) - for { - fmt.Print(*prompt) - line, err := reader.ReadSlice('\n') - if err != nil { - fmt.Fprintf(os.Stderr, "exiting...\n") - break - } - str := strings.TrimSpace(string(line)) - // TODO: handle larger input lines by doubling buffer - in := strings.Split(str, "\n") - for i := range in { - if len(in[i]) > 0 { - cmd(c, in[i]) - } - } - } -} - -func main() { - var user p.User - var err error - var c *clnt.Clnt - var file *clnt.File - - flag.Parse() - - if *ouser == "" { - user = p.OsUsers.Uid2User(os.Geteuid()) - } else { - user = p.OsUsers.Uname2User(*ouser) - } - - naddr := *addr - if strings.LastIndex(naddr, ":") == -1 { - naddr = naddr + ":5640" - } - c, err = clnt.Mount("tcp", naddr, "", user) - if err != nil { - fmt.Fprintf(os.Stderr, "error mounting %s: %s\n", naddr, err) - os.Exit(1) - } - - if *debug { - c.Debuglevel = 1 - } - if *debugall { - c.Debuglevel = 2 - } - - walkone(c, "/", false) - - if file != nil { - //process(c) - fmt.Sprint(os.Stderr, "file reading unimplemented\n") - } else if flag.NArg() > 0 { - flags := flag.Args() - for _, uc := range flags { - cmd(c, uc) - } - } else { - interactive(c) - } - - return -} diff --git a/third_party/go9p/p/clnt/examples/ls/ls.go b/third_party/go9p/p/clnt/examples/ls/ls.go deleted file mode 100644 index 3a6cd33d8..000000000 --- a/third_party/go9p/p/clnt/examples/ls/ls.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "flag" - "io" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/clnt" - "log" - "os" -) - -var debuglevel = flag.Int("d", 0, "debuglevel") -var addr = flag.String("addr", "127.0.0.1:5640", "network address") - -func main() { - var user p.User - var err error - var c *clnt.Clnt - var file *clnt.File - var d []*p.Dir - - flag.Parse() - user = p.OsUsers.Uid2User(os.Geteuid()) - clnt.DefaultDebuglevel = *debuglevel - c, err = clnt.Mount("tcp", *addr, "", user) - if err != nil { - log.Fatal(err) - } - - lsarg := "/" - if flag.NArg() == 1 { - lsarg = flag.Arg(0) - } else if flag.NArg() > 1 { - log.Fatal("error: only one argument expected") - } - - file, err = c.FOpen(lsarg, p.OREAD) - if err != nil { - log.Fatal(err) - } - - for { - d, err = file.Readdir(0) - if d == nil || len(d) == 0 || err != nil { - break - } - - for i := 0; i < len(d); i++ { - os.Stdout.WriteString(d[i].Name + "\n") - } - } - - file.Close() - if err != nil && err != io.EOF { - log.Fatal(err) - } - - return -} diff --git a/third_party/go9p/p/clnt/examples/read/read.go b/third_party/go9p/p/clnt/examples/read/read.go deleted file mode 100644 index 3c7c9c568..000000000 --- a/third_party/go9p/p/clnt/examples/read/read.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "flag" - "io" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/clnt" - "log" - "os" -) - -var debuglevel = flag.Int("d", 0, "debuglevel") -var addr = flag.String("addr", "127.0.0.1:5640", "network address") - -func main() { - var n int - var user p.User - var err error - var c *clnt.Clnt - var file *clnt.File - var buf []byte - - flag.Parse() - user = p.OsUsers.Uid2User(os.Geteuid()) - clnt.DefaultDebuglevel = *debuglevel - c, err = clnt.Mount("tcp", *addr, "", user) - if err != nil { - goto error - } - - if flag.NArg() != 1 { - log.Println("invalid arguments") - return - } - - file, err = c.FOpen(flag.Arg(0), p.OREAD) - if err != nil { - goto error - } - - buf = make([]byte, 8192) - for { - n, err = file.Read(buf) - if n == 0 { - break - } - - os.Stdout.Write(buf[0:n]) - } - - file.Close() - - if err != nil && err != io.EOF { - goto error - } - - return - -error: - log.Println("Error", err) -} diff --git a/third_party/go9p/p/clnt/examples/tag/tag.go b/third_party/go9p/p/clnt/examples/tag/tag.go deleted file mode 100644 index 21d30953e..000000000 --- a/third_party/go9p/p/clnt/examples/tag/tag.go +++ /dev/null @@ -1,101 +0,0 @@ -package main - -import ( - "flag" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/clnt" - "log" - "os" - "strings" -) - -var debuglevel = flag.Int("d", 0, "debuglevel") -var addr = flag.String("addr", "127.0.0.1:5640", "network address") - -func main() { - var user p.User - var ba [][]byte - var nreqs int - var rchan chan *clnt.Req - var tag *clnt.Tag - var fid *clnt.Fid - var wnames []string - - flag.Parse() - user = p.OsUsers.Uid2User(os.Geteuid()) - clnt.DefaultDebuglevel = *debuglevel - c, err := clnt.Mount("tcp", *addr, "", user) - if err != nil { - goto error - } - - if flag.NArg() != 1 { - log.Println("invalid arguments") - return - } - - ba = make([][]byte, 100) - for i := 0; i < len(ba); i++ { - ba[i] = make([]byte, 8192) - } - - nreqs = 0 - rchan = make(chan *clnt.Req) - tag = c.TagAlloc(rchan) - - // walk the file - wnames = strings.Split(flag.Arg(0), "/") - for wnames[0] == "" { - wnames = wnames[1:] - } - - fid = c.FidAlloc() - for root := c.Root; len(wnames) > 0; root = fid { - n := len(wnames) - if n > 8 { - n = 8 - } - - err = tag.Walk(root, fid, wnames[0:n]) - if err != nil { - goto error - } - - nreqs++ - wnames = wnames[n:] - } - err = tag.Open(fid, p.OREAD) - if err != nil { - goto error - } - - for i := 0; i < len(ba); i++ { - err = tag.Read(fid, uint64(i*8192), 8192) - if err != nil { - goto error - } - nreqs++ - } - - err = tag.Clunk(fid) - - // now start reading... - for nreqs > 0 { - r := <-rchan - if r.Tc.Type == p.Tread { - i := r.Tc.Offset / 8192 - copy(ba[i], r.Rc.Data) - ba[i] = ba[i][0:r.Rc.Count] - } - nreqs-- - } - - for i := 0; i < len(ba); i++ { - os.Stdout.Write(ba[i]) - } - - return - -error: - log.Println("error: ", err) -} diff --git a/third_party/go9p/p/clnt/examples/tls/tls.go b/third_party/go9p/p/clnt/examples/tls/tls.go deleted file mode 100644 index b0955db3d..000000000 --- a/third_party/go9p/p/clnt/examples/tls/tls.go +++ /dev/null @@ -1,74 +0,0 @@ -// Connects to a server over TLS and lists the specified directory -package main - -import ( - "crypto/rand" - "crypto/tls" - "flag" - "fmt" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/clnt" - "log" - "os" -) - -var debuglevel = flag.Int("d", 0, "debuglevel") -var addr = flag.String("addr", "127.0.0.1:5640", "network address") - -func main() { - var user p.User - var file *clnt.File - - flag.Parse() - user = p.OsUsers.Uid2User(os.Geteuid()) - clnt.DefaultDebuglevel = *debuglevel - - c, oerr := tls.Dial("tcp", *addr, &tls.Config{ - Rand: rand.Reader, - InsecureSkipVerify: true, - }) - if oerr != nil { - log.Println("can't dial", oerr) - return - } - - clnt, err := clnt.MountConn(c, "", user) - if err != nil { - goto error - } - - if flag.NArg() != 1 { - log.Println("invalid arguments") - return - } - - file, oerr = clnt.FOpen(flag.Arg(0), p.OREAD) - if oerr != nil { - goto oerror - } - - for { - d, oerr := file.Readdir(0) - if oerr != nil { - goto oerror - } - - if d == nil || len(d) == 0 { - break - } - - for i := 0; i < len(d); i++ { - os.Stdout.WriteString(d[i].Name + "\n") - } - } - - file.Close() - return - -error: - log.Println(fmt.Sprintf("Error: %s", err)) - return - -oerror: - log.Println("Error", oerr) -} diff --git a/third_party/go9p/p/clnt/examples/write/write.go b/third_party/go9p/p/clnt/examples/write/write.go deleted file mode 100644 index d59eda371..000000000 --- a/third_party/go9p/p/clnt/examples/write/write.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "flag" - "io" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/clnt" - "log" - "os" -) - -var debuglevel = flag.Int("d", 0, "debuglevel") -var addr = flag.String("addr", "127.0.0.1:5640", "network address") - -func main() { - var n, m int - var user p.User - var err error - var c *clnt.Clnt - var file *clnt.File - var buf []byte - - flag.Parse() - user = p.OsUsers.Uid2User(os.Geteuid()) - clnt.DefaultDebuglevel = *debuglevel - c, err = clnt.Mount("tcp", *addr, "", user) - if err != nil { - goto error - } - - if flag.NArg() != 1 { - log.Println("invalid arguments") - return - } - - file, err = c.FOpen(flag.Arg(0), p.OWRITE|p.OTRUNC) - if err != nil { - file, err = c.FCreate(flag.Arg(0), 0666, p.OWRITE) - if err != nil { - goto error - } - } - - buf = make([]byte, 8192) - for { - n, err = os.Stdin.Read(buf) - if err != nil && err != io.EOF { - goto error - } - - if n == 0 { - break - } - - m, err = file.Write(buf[0:n]) - if err != nil { - goto error - } - - if m != n { - err = &p.Error{"short write", 0} - goto error - } - } - - file.Close() - return - -error: - log.Println("Error", err) -} diff --git a/third_party/go9p/p/clnt/seek.go b/third_party/go9p/p/clnt/seek.go deleted file mode 100644 index cc9c43580..000000000 --- a/third_party/go9p/p/clnt/seek.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2009 The Go9p Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package clnt - -import ( - "k8s.io/minikube/third_party/go9p/p" -) - -var Eisdir = &p.Error{"file is a directory", p.EIO} -var Enegoff = &p.Error{"negative i/o offset", p.EIO} - -// Seek sets the offset for the next Read or Write to offset, -// interpreted according to whence: 0 means relative to the origin of -// the file, 1 means relative to the current offset, and 2 means -// relative to the end. Seek returns the new offset and an error, if -// any. -// -// Seeking to a negative offset is an error, and results in Enegoff. -// Seeking to 0 in a directory is only valid if whence is 0. Seek returns -// Eisdir otherwise. -func (f *File) Seek(offset int64, whence int) (int64, error) { - var off int64 - - switch whence { - case 0: - // origin - off = offset - if f.fid.Qid.Type&p.QTDIR > 0 && off != 0 { - return 0, Eisdir - } - - case 1: - // current - if f.fid.Qid.Type&p.QTDIR > 0 { - return 0, Eisdir - } - off = offset + int64(f.offset) - - case 2: - // end - if f.fid.Qid.Type&p.QTDIR > 0 { - return 0, Eisdir - } - - dir, err := f.fid.Clnt.Stat(f.fid) - if err != nil { - return 0, &p.Error{"stat error in seek: " + err.Error(), p.EIO} - } - off = int64(dir.Length) + offset - - default: - return 0, &p.Error{"bad whence in seek", p.EIO} - } - - if off < 0 { - return 0, Enegoff - } - f.offset = uint64(off) - - return off, nil -} diff --git a/third_party/go9p/p/srv/examples/clonefs/clonefs.go b/third_party/go9p/p/srv/examples/clonefs/clonefs.go deleted file mode 100644 index 257de5b8d..000000000 --- a/third_party/go9p/p/srv/examples/clonefs/clonefs.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2009 The Go9p Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A synthetic filesystem emulating a persistent cloning interface -// from Plan 9. Reading the /clone file creates new entries in the filesystem -// each containing unique information/data. Clone files remember what it written -// to them. Removing a clone file does what is expected. - -package main - -import ( - "flag" - "fmt" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" - "log" - "os" - "strconv" - "time" -) - -type ClFile struct { - srv.File - created string - id int - data []byte -} - -type Clone struct { - srv.File - clones int -} - -var addr = flag.String("addr", ":5640", "network address") -var debug = flag.Bool("d", false, "print debug messages") - -var root *srv.File - -func (cl *ClFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - var b []byte - if len(cl.data) == 0 { - str := strconv.Itoa(cl.id) + " created on:" + cl.created - b = []byte(str) - } else { - b = cl.data - } - n := len(b) - if offset >= uint64(n) { - return 0, nil - } - - b = b[int(offset):n] - n -= int(offset) - if len(buf) < n { - n = len(buf) - } - - copy(buf[offset:int(offset)+n], b[offset:]) - return n, nil -} - -func (cl *ClFile) Write(fid *srv.FFid, data []byte, offset uint64) (int, error) { - n := uint64(len(cl.data)) - nlen := offset + uint64(len(data)) - if nlen > n { - ndata := make([]byte, nlen) - copy(ndata, cl.data[0:n]) - cl.data = ndata - } - - copy(cl.data[offset:], data[offset:]) - return len(data), nil -} - -func (cl *ClFile) Wstat(fid *srv.FFid, dir *p.Dir) error { - return nil -} - -func (cl *ClFile) Remove(fid *srv.FFid) error { - return nil -} - -func (cl *Clone) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - // we only allow a single read from us, change the offset and we're done - if offset > uint64(0) { - return 0, nil - } - - cl.clones += 1 - ncl := new(ClFile) - ncl.id = cl.clones - ncl.created = time.Now().String() - name := strconv.Itoa(ncl.id) - - err := ncl.Add(root, name, p.OsUsers.Uid2User(os.Geteuid()), nil, 0666, ncl) - if err != nil { - return 0, &p.Error{"can not create file", 0} - } - - b := []byte(name) - if len(buf) < len(b) { - // cleanup - ncl.File.Remove() - return 0, &p.Error{"not enough buffer space for result", 0} - } - - copy(buf, b) - return len(b), nil -} - -func main() { - var err error - var cl *Clone - var s *srv.Fsrv - - flag.Parse() - user := p.OsUsers.Uid2User(os.Geteuid()) - root = new(srv.File) - err = root.Add(nil, "/", user, nil, p.DMDIR|0777, nil) - if err != nil { - goto error - } - - cl = new(Clone) - err = cl.Add(root, "clone", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, cl) - if err != nil { - goto error - } - - s = srv.NewFileSrv(root) - s.Dotu = true - - if *debug { - s.Debuglevel = 1 - } - - s.Start(s) - err = s.StartNetListener("tcp", *addr) - if err != nil { - goto error - } - return - -error: - log.Println(fmt.Sprintf("Error: %s", err)) -} diff --git a/third_party/go9p/p/srv/examples/ramfs/ramfs.go b/third_party/go9p/p/srv/examples/ramfs/ramfs.go deleted file mode 100644 index 1e1908fca..000000000 --- a/third_party/go9p/p/srv/examples/ramfs/ramfs.go +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2009 The Go9p Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" - "log" - "os" -) - -type Ramfs struct { - srv *srv.Fsrv - user p.User - group p.Group - blksz int - blkchan chan []byte - zero []byte // blksz array of zeroes -} - -type RFile struct { - srv.File - data [][]byte -} - -var addr = flag.String("addr", ":5640", "network address") -var debug = flag.Int("d", 0, "debuglevel") -var blksize = flag.Int("b", 8192, "block size") -var logsz = flag.Int("l", 2048, "log size") -var rsrv Ramfs - -func (f *RFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - f.Lock() - defer f.Unlock() - - if offset > f.Length { - return 0, nil - } - - count := uint32(len(buf)) - if offset+uint64(count) > f.Length { - count = uint32(f.Length - offset) - } - - for n, off, b := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz), buf[0:count]; len(b) > 0; n++ { - m := rsrv.blksz - int(off) - if m > len(b) { - m = len(b) - } - - blk := rsrv.zero - if len(f.data[n]) != 0 { - blk = f.data[n] - } - - // log.Stderr("read block", n, "off", off, "len", m, "l", len(blk), "ll", len(b)) - copy(b, blk[off:off+uint64(m)]) - b = b[m:] - off = 0 - } - - return int(count), nil -} - -func (f *RFile) Write(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - f.Lock() - defer f.Unlock() - - // make sure the data array is big enough - sz := offset + uint64(len(buf)) - if f.Length < sz { - f.expand(sz) - } - - count := 0 - for n, off := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz); len(buf) > 0; n++ { - blk := f.data[n] - if len(blk) == 0 { - select { - case blk = <-rsrv.blkchan: - break - default: - blk = make([]byte, rsrv.blksz) - } - - // if off>0 { - copy(blk, rsrv.zero /*[0:off]*/) - // } - - f.data[n] = blk - } - - m := copy(blk[off:], buf) - buf = buf[m:] - count += m - off = 0 - } - - return count, nil -} - -func (f *RFile) Create(fid *srv.FFid, name string, perm uint32) (*srv.File, error) { - ff := new(RFile) - err := ff.Add(&f.File, name, rsrv.user, rsrv.group, perm, ff) - return &ff.File, err -} - -func (f *RFile) Remove(fid *srv.FFid) error { - f.trunc(0) - - return nil -} - -func (f *RFile) Wstat(fid *srv.FFid, dir *p.Dir) error { - var uid, gid uint32 - - f.Lock() - defer f.Unlock() - - up := rsrv.srv.Upool - uid = dir.Uidnum - gid = dir.Gidnum - if uid == p.NOUID && dir.Uid != "" { - user := up.Uname2User(dir.Uid) - if user == nil { - return srv.Enouser - } - - f.Uidnum = uint32(user.Id()) - } - - if gid == p.NOUID && dir.Gid != "" { - group := up.Gname2Group(dir.Gid) - if group == nil { - return srv.Enouser - } - - f.Gidnum = uint32(group.Id()) - } - - if dir.Mode != 0xFFFFFFFF { - f.Mode = (f.Mode &^ 0777) | (dir.Mode & 0777) - } - - if dir.Name != "" { - if err := f.Rename(dir.Name); err != nil { - return err - } - } - - if dir.Length != 0xFFFFFFFFFFFFFFFF { - f.trunc(dir.Length) - } - - return nil -} - -// called with f locked -func (f *RFile) trunc(sz uint64) { - if f.Length == sz { - return - } - - if f.Length > sz { - f.shrink(sz) - } else { - f.expand(sz) - } -} - -// called with f lock held -func (f *RFile) shrink(sz uint64) { - blknum := sz / uint64(rsrv.blksz) - off := sz % uint64(rsrv.blksz) - if off > 0 { - if len(f.data[blknum]) > 0 { - copy(f.data[blknum][off:], rsrv.zero) - } - - blknum++ - } - - for i := blknum; i < uint64(len(f.data)); i++ { - if len(f.data[i]) == 0 { - continue - } - - select { - case rsrv.blkchan <- f.data[i]: - break - default: - } - } - - f.data = f.data[0:blknum] - f.Length = sz -} - -func (f *RFile) expand(sz uint64) { - blknum := sz / uint64(rsrv.blksz) - if sz%uint64(rsrv.blksz) != 0 { - blknum++ - } - - data := make([][]byte, blknum) - if f.data != nil { - copy(data, f.data) - } - - f.data = data - f.Length = sz -} - -func main() { - var err error - var l *p.Logger - - flag.Parse() - rsrv.user = p.OsUsers.Uid2User(os.Geteuid()) - rsrv.group = p.OsUsers.Gid2Group(os.Getegid()) - rsrv.blksz = *blksize - rsrv.blkchan = make(chan []byte, 2048) - rsrv.zero = make([]byte, rsrv.blksz) - - root := new(RFile) - err = root.Add(nil, "/", rsrv.user, nil, p.DMDIR|0777, root) - if err != nil { - goto error - } - - l = p.NewLogger(*logsz) - rsrv.srv = srv.NewFileSrv(&root.File) - rsrv.srv.Dotu = true - rsrv.srv.Debuglevel = *debug - rsrv.srv.Start(rsrv.srv) - rsrv.srv.Id = "ramfs" - rsrv.srv.Log = l - - err = rsrv.srv.StartNetListener("tcp", *addr) - if err != nil { - goto error - } - return - -error: - log.Println(fmt.Sprintf("Error: %s", err)) -} diff --git a/third_party/go9p/p/srv/examples/timefs/timefs.go b/third_party/go9p/p/srv/examples/timefs/timefs.go deleted file mode 100644 index 0b3d694f0..000000000 --- a/third_party/go9p/p/srv/examples/timefs/timefs.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2009 The Go9p Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" - "log" - "os" - "time" -) - -type Time struct { - srv.File -} -type InfTime struct { - srv.File -} - -var addr = flag.String("addr", ":5640", "network address") -var debug = flag.Bool("d", false, "print debug messages") -var debugall = flag.Bool("D", false, "print packets as well as debug messages") - -func (*InfTime) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - // push out time ignoring offset (infinite read) - t := time.Now().String() + "\n" - b := []byte(t) - ml := len(b) - if ml > len(buf) { - ml = len(buf) - } - - copy(buf, b[0:ml]) - return ml, nil -} - -func (*Time) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - b := []byte(time.Now().String()) - have := len(b) - off := int(offset) - - if off >= have { - return 0, nil - } - - return copy(buf, b[off:]), nil -} - -func main() { - var err error - var tm *Time - var ntm *InfTime - var s *srv.Fsrv - - flag.Parse() - user := p.OsUsers.Uid2User(os.Geteuid()) - root := new(srv.File) - err = root.Add(nil, "/", user, nil, p.DMDIR|0555, nil) - if err != nil { - goto error - } - - tm = new(Time) - err = tm.Add(root, "time", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, tm) - if err != nil { - goto error - } - ntm = new(InfTime) - err = ntm.Add(root, "inftime", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, ntm) - if err != nil { - goto error - } - - s = srv.NewFileSrv(root) - s.Dotu = true - - if *debug { - s.Debuglevel = 1 - } - if *debugall { - s.Debuglevel = 2 - } - - s.Start(s) - err = s.StartNetListener("tcp", *addr) - if err != nil { - goto error - } - - return - -error: - log.Println(fmt.Sprintf("Error: %s", err)) -} diff --git a/third_party/go9p/p/srv/examples/tlsramfs/tlsramfs.go b/third_party/go9p/p/srv/examples/tlsramfs/tlsramfs.go deleted file mode 100644 index 325a63206..000000000 --- a/third_party/go9p/p/srv/examples/tlsramfs/tlsramfs.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2009 The Go9p Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Listen on SSL connection, can be used as an example with p/clnt/examples/tls.go -// Sample certificate was copied from the Go source code -package main - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/tls" - "encoding/hex" - "flag" - "fmt" - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" - "log" - "math/big" - "os" -) - -type Ramfs struct { - srv *srv.Fsrv - user p.User - group p.Group - blksz int - blkchan chan []byte - zero []byte // blksz array of zeroes -} - -type RFile struct { - srv.File - data [][]byte -} - -var addr = flag.String("addr", ":5640", "network address") -var debug = flag.Int("d", 0, "debuglevel") -var blksize = flag.Int("b", 8192, "block size") -var logsz = flag.Int("l", 2048, "log size") -var rsrv Ramfs - -func (f *RFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - f.Lock() - defer f.Unlock() - - if offset > f.Length { - return 0, nil - } - - count := uint32(len(buf)) - if offset+uint64(count) > f.Length { - count = uint32(f.Length - offset) - } - - for n, off, b := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz), buf[0:count]; len(b) > 0; n++ { - m := rsrv.blksz - int(off) - if m > len(b) { - m = len(b) - } - - blk := rsrv.zero - if len(f.data[n]) != 0 { - blk = f.data[n] - } - - // log.Stderr("read block", n, "off", off, "len", m, "l", len(blk), "ll", len(b)) - copy(b, blk[off:off+uint64(m)]) - b = b[m:] - off = 0 - } - - return int(count), nil -} - -func (f *RFile) Write(fid *srv.FFid, buf []byte, offset uint64) (int, error) { - f.Lock() - defer f.Unlock() - - // make sure the data array is big enough - sz := offset + uint64(len(buf)) - if f.Length < sz { - f.expand(sz) - } - - count := 0 - for n, off := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz); len(buf) > 0; n++ { - blk := f.data[n] - if len(blk) == 0 { - select { - case blk = <-rsrv.blkchan: - break - default: - blk = make([]byte, rsrv.blksz) - } - - // if off>0 { - copy(blk, rsrv.zero /*[0:off]*/) - // } - - f.data[n] = blk - } - - m := copy(blk[off:], buf) - buf = buf[m:] - count += m - off = 0 - } - - return count, nil -} - -func (f *RFile) Create(fid *srv.FFid, name string, perm uint32) (*srv.File, error) { - ff := new(RFile) - err := ff.Add(&f.File, name, rsrv.user, rsrv.group, perm, ff) - return &ff.File, err -} - -func (f *RFile) Remove(fid *srv.FFid) error { - f.trunc(0) - - return nil -} - -func (f *RFile) Wstat(fid *srv.FFid, dir *p.Dir) error { - var uid, gid uint32 - - f.Lock() - defer f.Unlock() - - up := rsrv.srv.Upool - uid = dir.Uidnum - gid = dir.Gidnum - if uid == p.NOUID && dir.Uid != "" { - user := up.Uname2User(dir.Uid) - if user == nil { - return srv.Enouser - } - - f.Uidnum = uint32(user.Id()) - } - - if gid == p.NOUID && dir.Gid != "" { - group := up.Gname2Group(dir.Gid) - if group == nil { - return srv.Enouser - } - - f.Gidnum = uint32(group.Id()) - } - - if dir.Mode != 0xFFFFFFFF { - f.Mode = (f.Mode &^ 0777) | (dir.Mode & 0777) - } - - if dir.Name != "" { - if err := f.Rename(dir.Name); err != nil { - return err - } - } - - if dir.Length != 0xFFFFFFFFFFFFFFFF { - f.trunc(dir.Length) - } - - return nil -} - -// called with f locked -func (f *RFile) trunc(sz uint64) { - if f.Length == sz { - return - } - - if f.Length > sz { - f.shrink(sz) - } else { - f.expand(sz) - } -} - -// called with f lock held -func (f *RFile) shrink(sz uint64) { - blknum := sz / uint64(rsrv.blksz) - off := sz % uint64(rsrv.blksz) - if off > 0 { - if len(f.data[blknum]) > 0 { - copy(f.data[blknum][off:], rsrv.zero) - } - - blknum++ - } - - for i := blknum; i < uint64(len(f.data)); i++ { - if len(f.data[i]) == 0 { - continue - } - - select { - case rsrv.blkchan <- f.data[i]: - break - default: - } - } - - f.data = f.data[0:blknum] - f.Length = sz -} - -func (f *RFile) expand(sz uint64) { - blknum := sz / uint64(rsrv.blksz) - if sz%uint64(rsrv.blksz) != 0 { - blknum++ - } - - data := make([][]byte, blknum) - if f.data != nil { - copy(data, f.data) - } - - f.data = data - f.Length = sz -} - -func main() { - var err error - - flag.Parse() - rsrv.user = p.OsUsers.Uid2User(os.Geteuid()) - rsrv.group = p.OsUsers.Gid2Group(os.Getegid()) - rsrv.blksz = *blksize - rsrv.blkchan = make(chan []byte, 2048) - rsrv.zero = make([]byte, rsrv.blksz) - - root := new(RFile) - err = root.Add(nil, "/", rsrv.user, nil, p.DMDIR|0777, root) - if err != nil { - log.Println(fmt.Sprintf("Error: %s", err)) - return - } - - l := p.NewLogger(*logsz) - rsrv.srv = srv.NewFileSrv(&root.File) - rsrv.srv.Dotu = true - rsrv.srv.Debuglevel = *debug - rsrv.srv.Start(rsrv.srv) - rsrv.srv.Id = "ramfs" - rsrv.srv.Log = l - - cert := make([]tls.Certificate, 1) - cert[0].Certificate = [][]byte{testCertificate} - cert[0].PrivateKey = testPrivateKey - - ls, oerr := tls.Listen("tcp", *addr, &tls.Config{ - Rand: rand.Reader, - Certificates: cert, - CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA}, - InsecureSkipVerify: true, - }) - if oerr != nil { - log.Println("can't listen:", oerr) - return - } - - err = rsrv.srv.StartListener(ls) - if err != nil { - log.Println(fmt.Sprintf("Error: %s", err)) - return - } - return -} - -// Copied from crypto/tls/handshake_server_test.go from the Go repository -func bigFromString(s string) *big.Int { - ret := new(big.Int) - ret.SetString(s, 10) - return ret -} - -func fromHex(s string) []byte { - b, _ := hex.DecodeString(s) - return b -} - -var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9") - -var testPrivateKey = &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"), - E: 65537, - }, - D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"), - Primes: []*big.Int{ - bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"), - bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"), - }, -} diff --git a/third_party/go9p/p/p9.go b/third_party/go9p/p9.go similarity index 91% rename from third_party/go9p/p/p9.go rename to third_party/go9p/p9.go index 8138c5467..dd6b0a6ac 100644 --- a/third_party/go9p/p/p9.go +++ b/third_party/go9p/p9.go @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The p9 package provides the definitions and functions used to implement +// The p9 package go9provides the definitions and functions used to implement // the 9P2000 protocol. -package p +// TODO. +// All the packet conversion code in this file is crap and needs a rewrite. +package go9p import ( "fmt" @@ -44,9 +46,9 @@ const ( ) const ( - MSIZE = 8192 + IOHDRSZ // default message size (8192+IOHdrSz) - IOHDRSZ = 24 // the non-data size of the Twrite messages - PORT = 564 // default port for 9P file servers + MSIZE = 1048576 + IOHDRSZ // default message size (1048576+IOHdrSz) + IOHDRSZ = 24 // the non-data size of the Twrite messages + PORT = 564 // default port for 9P file servers ) // Qid types @@ -301,11 +303,12 @@ func gint64(buf []byte) (uint64, []byte) { func gstr(buf []byte) (string, []byte) { var n uint16 - if buf == nil { + if buf == nil || len(buf) < 2 { return "", nil } n, buf = gint16(buf) + if int(n) > len(buf) { return "", nil } @@ -321,7 +324,8 @@ func gqid(buf []byte, qid *Qid) []byte { return buf } -func gstat(buf []byte, d *Dir, dotu bool) []byte { +func gstat(buf []byte, d *Dir, dotu bool) ([]byte, error) { + sz := len(buf) d.Size, buf = gint16(buf) d.Type, buf = gint16(buf) d.Dev, buf = gint32(buf) @@ -332,27 +336,29 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte { d.Length, buf = gint64(buf) d.Name, buf = gstr(buf) if buf == nil { - return nil + s := fmt.Sprintf("Buffer too short for basic 9p: need %d, have %d", + 49, sz) + return nil, &Error{s, EINVAL} } d.Uid, buf = gstr(buf) if buf == nil { - return nil + return nil, &Error{"d.Uid failed", EINVAL} } d.Gid, buf = gstr(buf) if buf == nil { - return nil + return nil, &Error{"d.Gid failed", EINVAL} } d.Muid, buf = gstr(buf) if buf == nil { - return nil + return nil, &Error{"d.Muid failed", EINVAL} } if dotu { d.Ext, buf = gstr(buf) if buf == nil { - return nil + return nil, &Error{"d.Ext failed", EINVAL} } d.Uidnum, buf = gint32(buf) @@ -364,7 +370,7 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte { d.Muidnum = NOUID } - return buf + return buf, nil } func pint8(val uint8, buf []byte) []byte { @@ -449,20 +455,17 @@ func pstat(d *Dir, buf []byte, dotu bool) []byte { // Converts a Dir value to its on-the-wire representation and writes it to // the buf. Returns the number of bytes written, 0 if there is not enough space. -func PackDir(d *Dir, buf []byte, dotu bool) int { +func PackDir(d *Dir, dotu bool) []byte { sz := statsz(d, dotu) - if sz > len(buf) { - return 0 - } - - buf = pstat(d, buf, dotu) - return sz + buf := make([]byte, sz) + pstat(d, buf, dotu) + return buf } // Converts the on-the-wire representation of a stat to Stat value. // Returns an error if the conversion is impossible, otherwise // a pointer to a Stat value. -func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) { +func UnpackDir(buf []byte, dotu bool) (d *Dir, b []byte, amt int, err error) { sz := 2 + 2 + 4 + 13 + 4 + /* size[2] type[2] dev[4] qid[13] mode[4] */ 4 + 4 + 8 + /* atime[4] mtime[4] length[8] */ 2 + 2 + 2 + 2 /* name[s] uid[s] gid[s] muid[s] */ @@ -472,19 +475,17 @@ func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) { } if len(buf) < sz { - goto szerror + s := fmt.Sprintf("short buffer: Need %d and have %v", sz, len(buf)) + return nil, nil, 0, &Error{s, EINVAL} } d = new(Dir) - buf = gstat(buf, d, dotu) - if buf == nil { - goto szerror + b, err = gstat(buf, d, dotu) + if err != nil { + return nil, nil, 0, err } - return d, nil - -szerror: - return nil, &Error{"short buffer", EINVAL} + return d, b, len(buf) - len(b), nil } @@ -522,7 +523,7 @@ func packCommon(fc *Fcall, size int, id uint8) ([]byte, error) { func (err *Error) Error() string { if err != nil { - return fmt.Sprintf("%s: %d", err.Err, err.Errornum) + return err.Err } return "" diff --git a/third_party/go9p/p/packr.go b/third_party/go9p/packr.go similarity index 93% rename from third_party/go9p/p/packr.go rename to third_party/go9p/packr.go index 8d30cef17..1bf1f97f8 100644 --- a/third_party/go9p/p/packr.go +++ b/third_party/go9p/packr.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +package go9p + +import "fmt" // Create a Rversion message in the specified Fcall. func PackRversion(fc *Fcall, msize uint32, version string) error { @@ -34,9 +36,17 @@ func PackRauth(fc *Fcall, aqid *Qid) error { } // Create a Rerror message in the specified Fcall. If dotu is true, -// the function will create a 9P2000.u message. If false, nerror is +// the function will create a 9P2000.u message. If false, errornum is // ignored. +// The Akaros global is hurl-inducing but this whole blob of code +// needs a redo. dotu is even worse, since it bakes in ONE PARTICULAR +// EXTENSION ... + func PackRerror(fc *Fcall, error string, errornum uint32, dotu bool) error { + if *Akaros { + error = fmt.Sprintf("%04X %v", errornum, error) + } + size := 2 + len(error) /* ename[s] */ if dotu { size += 4 /* ecode[4] */ diff --git a/third_party/go9p/p/packt.go b/third_party/go9p/packt.go similarity index 99% rename from third_party/go9p/p/packt.go rename to third_party/go9p/packt.go index d77705d5d..4096f1b4b 100644 --- a/third_party/go9p/p/packt.go +++ b/third_party/go9p/packt.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +package go9p // Create a Tversion message in the specified Fcall. func PackTversion(fc *Fcall, msize uint32, version string) error { diff --git a/third_party/go9p/p/srv/conn.go b/third_party/go9p/srv_conn.go similarity index 84% rename from third_party/go9p/p/srv/conn.go rename to third_party/go9p/srv_conn.go index 15c7ae5c8..4f9e1bdc7 100644 --- a/third_party/go9p/p/srv/conn.go +++ b/third_party/go9p/srv_conn.go @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package srv +package go9p import ( "fmt" - "k8s.io/minikube/third_party/go9p/p" "log" "net" ) @@ -18,11 +17,11 @@ func (srv *Srv) NewConn(c net.Conn) { conn.Dotu = srv.Dotu conn.Debuglevel = srv.Debuglevel conn.conn = c - conn.fidpool = make(map[uint32]*Fid) - conn.reqs = make(map[uint16]*Req) - conn.reqout = make(chan *Req, srv.Maxpend) + conn.fidpool = make(map[uint32]*SrvFid) + conn.reqs = make(map[uint16]*SrvReq) + conn.reqout = make(chan *SrvReq, srv.Maxpend) conn.done = make(chan bool) - conn.rchan = make(chan *p.Fcall, 64) + conn.rchan = make(chan *Fcall, 64) srv.Lock() if srv.conns == nil { @@ -58,7 +57,7 @@ func (conn *Conn) close() { } /* call FidDestroy for all remaining fids */ - if op, ok := (conn.Srv.ops).(FidOps); ok { + if op, ok := (conn.Srv.ops).(SrvFidOps); ok { for _, fid := range conn.fidpool { op.FidDestroy(fid) } @@ -87,7 +86,7 @@ func (conn *Conn) recv() { pos += n for pos > 4 { - sz, _ := p.Gint32(buf) + sz, _ := Gint32(buf) if sz > conn.Msize { log.Println("bad client connection: ", conn.conn.RemoteAddr()) conn.conn.Close() @@ -104,7 +103,7 @@ func (conn *Conn) recv() { break } - fc, err, fcsize := p.Unpack(buf, conn.Dotu) + fc, err, fcsize := Unpack(buf, conn.Dotu) if err != nil { log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf)) conn.conn.Close() @@ -113,12 +112,12 @@ func (conn *Conn) recv() { } tag := fc.Tag - req := new(Req) + req := new(SrvReq) select { case req.Rc = <-conn.rchan: break default: - req.Rc = p.NewFcall(conn.Msize) + req.Rc = NewFcall(conn.Msize) } req.Conn = conn @@ -151,7 +150,15 @@ func (conn *Conn) recv() { } conn.Unlock() if process { - go req.process() + // Tversion may change some attributes of the + // connection, so we block on it. Otherwise, + // we may loop back to reading and that is a race. + // This fix brought to you by the race detector. + if req.Tc.Type == Tversion { + req.process() + } else { + go req.process() + } } buf = buf[fcsize:] @@ -159,7 +166,6 @@ func (conn *Conn) recv() { } } - panic("unreached") } func (conn *Conn) send() { @@ -169,7 +175,7 @@ func (conn *Conn) send() { return case req := <-conn.reqout: - p.SetTag(req.Rc, req.Tc.Tag) + SetTag(req.Rc, req.Tc.Tag) conn.Lock() conn.rsz += uint64(req.Rc.Size) conn.npend-- @@ -216,7 +222,7 @@ func (conn *Conn) LocalAddr() net.Addr { return conn.conn.LocalAddr() } -func (conn *Conn) logFcall(fc *p.Fcall) { +func (conn *Conn) logFcall(fc *Fcall) { if conn.Debuglevel&DbgLogPackets != 0 { pkt := make([]byte, len(fc.Pkt)) copy(pkt, fc.Pkt) @@ -224,7 +230,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) { } if conn.Debuglevel&DbgLogFcalls != 0 { - f := new(p.Fcall) + f := new(Fcall) *f = *fc f.Pkt = nil conn.Srv.Log.Log(f, conn, DbgLogFcalls) @@ -234,7 +240,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) { func (srv *Srv) StartNetListener(ntype, addr string) error { l, err := net.Listen(ntype, addr) if err != nil { - return &p.Error{err.Error(), p.EIO} + return &Error{err.Error(), EIO} } return srv.StartListener(l) @@ -248,7 +254,7 @@ func (srv *Srv) StartListener(l net.Listener) error { for { c, err := l.Accept() if err != nil { - return &p.Error{err.Error(), p.EIO} + return &Error{err.Error(), EIO} } srv.NewConn(c) diff --git a/third_party/go9p/p/srv/fcall.go b/third_party/go9p/srv_fcall.go similarity index 65% rename from third_party/go9p/p/srv/fcall.go rename to third_party/go9p/srv_fcall.go index 386fbf8a4..c25d9dc14 100644 --- a/third_party/go9p/p/srv/fcall.go +++ b/third_party/go9p/srv_fcall.go @@ -2,20 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package srv +package go9p -import ( - "runtime" +import "runtime" - "k8s.io/minikube/third_party/go9p/p" -) - -func (srv *Srv) version(req *Req) { +func (srv *Srv) version(req *SrvReq) { tc := req.Tc conn := req.Conn - if tc.Msize < p.IOHDRSZ { - req.RespondError(&p.Error{"msize too small", p.EINVAL}) + if tc.Msize < IOHDRSZ { + req.RespondError(&Error{"msize too small", EINVAL}) return } @@ -32,7 +28,7 @@ func (srv *Srv) version(req *Req) { /* make sure that the responses of all current requests will be ignored */ conn.Lock() for tag, r := range conn.reqs { - if tag == p.NOTAG { + if tag == NOTAG { continue } @@ -47,10 +43,10 @@ func (srv *Srv) version(req *Req) { req.RespondRversion(conn.Msize, ver) } -func (srv *Srv) auth(req *Req) { +func (srv *Srv) auth(req *SrvReq) { tc := req.Tc conn := req.Conn - if tc.Afid == p.NOFID { + if tc.Afid == NOFID { req.RespondError(Eunknownfid) return } @@ -61,8 +57,8 @@ func (srv *Srv) auth(req *Req) { return } - var user p.User = nil - if tc.Unamenum != p.NOUID || conn.Dotu { + var user User = nil + if tc.Unamenum != NOUID || conn.Dotu { user = srv.Upool.Uid2User(int(tc.Unamenum)) } else if tc.Uname != "" { user = srv.Upool.Uname2User(tc.Uname) @@ -76,13 +72,13 @@ func (srv *Srv) auth(req *Req) { } req.Afid.User = user - req.Afid.Type = p.QTAUTH + req.Afid.Type = QTAUTH if aop, ok := (srv.ops).(AuthOps); ok { aqid, err := aop.AuthInit(req.Afid, tc.Aname) if err != nil { req.RespondError(err) } else { - aqid.Type |= p.QTAUTH // just in case + aqid.Type |= QTAUTH // just in case req.RespondRauth(aqid) } } else { @@ -91,16 +87,16 @@ func (srv *Srv) auth(req *Req) { } -func (srv *Srv) authPost(req *Req) { - if req.Rc != nil && req.Rc.Type == p.Rauth { +func (srv *Srv) authPost(req *SrvReq) { + if req.Rc != nil && req.Rc.Type == Rauth { req.Afid.IncRef() } } -func (srv *Srv) attach(req *Req) { +func (srv *Srv) attach(req *SrvReq) { tc := req.Tc conn := req.Conn - if tc.Fid == p.NOFID { + if tc.Fid == NOFID { req.RespondError(Eunknownfid) return } @@ -111,15 +107,15 @@ func (srv *Srv) attach(req *Req) { return } - if tc.Afid != p.NOFID { + if tc.Afid != NOFID { req.Afid = conn.FidGet(tc.Afid) if req.Afid == nil { req.RespondError(Eunknownfid) } } - var user p.User = nil - if tc.Unamenum != p.NOUID || conn.Dotu { + var user User = nil + if tc.Unamenum != NOUID || conn.Dotu { user = srv.Upool.Uid2User(int(tc.Unamenum)) } else if tc.Uname != "" { user = srv.Upool.Uname2User(tc.Uname) @@ -141,20 +137,20 @@ func (srv *Srv) attach(req *Req) { } } - (srv.ops).(ReqOps).Attach(req) + (srv.ops).(SrvReqOps).Attach(req) } -func (srv *Srv) attachPost(req *Req) { - if req.Rc != nil && req.Rc.Type == p.Rattach { +func (srv *Srv) attachPost(req *SrvReq) { + if req.Rc != nil && req.Rc.Type == Rattach { req.Fid.Type = req.Rc.Qid.Type req.Fid.IncRef() } } -func (srv *Srv) flush(req *Req) { +func (srv *Srv) flush(req *SrvReq) { conn := req.Conn tag := req.Tc.Oldtag - p.PackRflush(req.Rc) + PackRflush(req.Rc) conn.Lock() r := conn.reqs[tag] if r != nil { @@ -186,13 +182,13 @@ func (srv *Srv) flush(req *Req) { } } -func (srv *Srv) walk(req *Req) { +func (srv *Srv) walk(req *SrvReq) { conn := req.Conn tc := req.Tc fid := req.Fid /* we can't walk regular files, only clone them */ - if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 { + if len(tc.Wname) > 0 && (fid.Type&QTDIR) == 0 { req.RespondError(Enotdir) return } @@ -217,12 +213,12 @@ func (srv *Srv) walk(req *Req) { req.Newfid.IncRef() } - (req.Conn.Srv.ops).(ReqOps).Walk(req) + (req.Conn.Srv.ops).(SrvReqOps).Walk(req) } -func (srv *Srv) walkPost(req *Req) { +func (srv *Srv) walkPost(req *SrvReq) { rc := req.Rc - if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil { + if rc == nil || rc.Type != Rwalk || req.Newfid == nil { return } @@ -243,7 +239,7 @@ func (srv *Srv) walkPost(req *Req) { } } -func (srv *Srv) open(req *Req) { +func (srv *Srv) open(req *SrvReq) { fid := req.Fid tc := req.Tc if fid.opened { @@ -251,22 +247,22 @@ func (srv *Srv) open(req *Req) { return } - if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD { + if (fid.Type&QTDIR) != 0 && tc.Mode != OREAD { req.RespondError(Eperm) return } fid.Omode = tc.Mode - (req.Conn.Srv.ops).(ReqOps).Open(req) + (req.Conn.Srv.ops).(SrvReqOps).Open(req) } -func (srv *Srv) openPost(req *Req) { +func (srv *Srv) openPost(req *SrvReq) { if req.Fid != nil { - req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen + req.Fid.opened = req.Rc != nil && req.Rc.Type == Ropen } } -func (srv *Srv) create(req *Req) { +func (srv *Srv) create(req *SrvReq) { fid := req.Fid tc := req.Tc if fid.opened { @@ -274,47 +270,47 @@ func (srv *Srv) create(req *Req) { return } - if (fid.Type & p.QTDIR) == 0 { + if (fid.Type & QTDIR) == 0 { req.RespondError(Enotdir) return } /* can't open directories for other than reading */ - if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD { + if (tc.Perm&DMDIR) != 0 && tc.Mode != OREAD { req.RespondError(Eperm) return } /* can't create special files if not 9P2000.u */ - if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu { + if (tc.Perm&(DMNAMEDPIPE|DMSYMLINK|DMLINK|DMDEVICE|DMSOCKET)) != 0 && !req.Conn.Dotu { req.RespondError(Eperm) return } fid.Omode = tc.Mode - (req.Conn.Srv.ops).(ReqOps).Create(req) + (req.Conn.Srv.ops).(SrvReqOps).Create(req) } -func (srv *Srv) createPost(req *Req) { - if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil { +func (srv *Srv) createPost(req *SrvReq) { + if req.Rc != nil && req.Rc.Type == Rcreate && req.Fid != nil { req.Fid.Type = req.Rc.Qid.Type req.Fid.opened = true } } -func (srv *Srv) read(req *Req) { +func (srv *Srv) read(req *SrvReq) { tc := req.Tc fid := req.Fid - if tc.Count+p.IOHDRSZ > req.Conn.Msize { + if tc.Count+IOHDRSZ > req.Conn.Msize { req.RespondError(Etoolarge) return } - if (fid.Type & p.QTAUTH) != 0 { + if (fid.Type & QTAUTH) != 0 { var n int rc := req.Rc - err := p.InitRread(rc, tc.Count) + err := InitRread(rc, tc.Count) if err != nil { req.RespondError(err) return @@ -327,7 +323,7 @@ func (srv *Srv) read(req *Req) { return } - p.SetRreadCount(rc, uint32(n)) + SetRreadCount(rc, uint32(n)) req.Respond() } else { req.RespondError(Enotimpl) @@ -336,28 +332,27 @@ func (srv *Srv) read(req *Req) { return } - if (fid.Type & p.QTDIR) != 0 { + if (fid.Type & QTDIR) != 0 { if tc.Offset == 0 { fid.Diroffset = 0 } else if tc.Offset != fid.Diroffset { - req.RespondError(Ebadoffset) - return + fid.Diroffset = tc.Offset } } - (req.Conn.Srv.ops).(ReqOps).Read(req) + (req.Conn.Srv.ops).(SrvReqOps).Read(req) } -func (srv *Srv) readPost(req *Req) { - if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 { +func (srv *Srv) readPost(req *SrvReq) { + if req.Rc != nil && req.Rc.Type == Rread && (req.Fid.Type&QTDIR) != 0 { req.Fid.Diroffset += uint64(req.Rc.Count) } } -func (srv *Srv) write(req *Req) { +func (srv *Srv) write(req *SrvReq) { fid := req.Fid tc := req.Tc - if (fid.Type & p.QTAUTH) != 0 { + if (fid.Type & QTAUTH) != 0 { tc := req.Tc if op, ok := (req.Conn.Srv.ops).(AuthOps); ok { n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data) @@ -373,22 +368,22 @@ func (srv *Srv) write(req *Req) { return } - if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD { + if !fid.opened || (fid.Type&QTDIR) != 0 || (fid.Omode&3) == OREAD { req.RespondError(Ebaduse) return } - if tc.Count+p.IOHDRSZ > req.Conn.Msize { + if tc.Count+IOHDRSZ > req.Conn.Msize { req.RespondError(Etoolarge) return } - (req.Conn.Srv.ops).(ReqOps).Write(req) + (req.Conn.Srv.ops).(SrvReqOps).Write(req) } -func (srv *Srv) clunk(req *Req) { +func (srv *Srv) clunk(req *SrvReq) { fid := req.Fid - if (fid.Type & p.QTAUTH) != 0 { + if (fid.Type & QTAUTH) != 0 { if op, ok := (req.Conn.Srv.ops).(AuthOps); ok { op.AuthDestroy(fid) req.RespondRclunk() @@ -399,26 +394,26 @@ func (srv *Srv) clunk(req *Req) { return } - (req.Conn.Srv.ops).(ReqOps).Clunk(req) + (req.Conn.Srv.ops).(SrvReqOps).Clunk(req) } -func (srv *Srv) clunkPost(req *Req) { - if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil { +func (srv *Srv) clunkPost(req *SrvReq) { + if req.Rc != nil && req.Rc.Type == Rclunk && req.Fid != nil { req.Fid.DecRef() } } -func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) } +func (srv *Srv) remove(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Remove(req) } -func (srv *Srv) removePost(req *Req) { +func (srv *Srv) removePost(req *SrvReq) { if req.Rc != nil && req.Fid != nil { req.Fid.DecRef() } } -func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) } +func (srv *Srv) stat(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Stat(req) } -func (srv *Srv) wstat(req *Req) { +func (srv *Srv) wstat(req *SrvReq) { /* fid := req.Fid d := &req.Tc.Dir @@ -428,12 +423,12 @@ func (srv *Srv) wstat(req *Req) { return } - if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) || - ((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) { + if (d.Mode != 0xFFFFFFFF) && (((fid.Type&QTDIR) != 0 && (d.Mode&DMDIR) == 0) || + ((d.Type&QTDIR) == 0 && (d.Mode&DMDIR) != 0)) { req.RespondError(Edirchange) return } */ - (req.Conn.Srv.ops).(ReqOps).Wstat(req) + (req.Conn.Srv.ops).(SrvReqOps).Wstat(req) } diff --git a/third_party/go9p/p/srv/file.go b/third_party/go9p/srv_file.go similarity index 72% rename from third_party/go9p/p/srv/file.go rename to third_party/go9p/srv_file.go index efdf35c12..1489662c0 100644 --- a/third_party/go9p/p/srv/file.go +++ b/third_party/go9p/srv_file.go @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package srv +package go9p import ( - "k8s.io/minikube/third_party/go9p/p" "log" "sync" "time" @@ -13,18 +12,18 @@ import ( // The FStatOp interface provides a single operation (Stat) that will be // called before a file stat is sent back to the client. If implemented, -// the operation should update the data in the File struct. +// the operation should update the data in the srvFile struct. type FStatOp interface { Stat(fid *FFid) error } // The FWstatOp interface provides a single operation (Wstat) that will be -// called when the client requests the File metadata to be modified. If +// called when the client requests the srvFile metadata to be modified. If // implemented, the operation will be called when Twstat message is received. // If not implemented, "permission denied" error will be sent back. If the // operation returns an Error, the error is send back to the client. type FWstatOp interface { - Wstat(*FFid, *p.Dir) error + Wstat(*FFid, *Dir) error } // If the FReadOp interface is implemented, the Read operation will be called @@ -44,16 +43,16 @@ type FWriteOp interface { } // If the FCreateOp interface is implemented, the Create operation will be called -// when the client attempts to create a file in the File implementing the interface. +// when the client attempts to create a file in the srvFile implementing the interface. // If not implemented, "permission denied" error will be send back. If successful, // the operation should call (*File)Add() to add the created file to the directory. // The operation returns the created file, or the error occured while creating it. type FCreateOp interface { - Create(fid *FFid, name string, perm uint32) (*File, error) + Create(fid *FFid, name string, perm uint32) (*srvFile, error) } // If the FRemoveOp interface is implemented, the Remove operation will be called -// when the client attempts to create a file in the File implementing the interface. +// when the client attempts to create a file in the srvFile implementing the interface. // If not implemented, "permission denied" error will be send back. // The operation returns nil if successful, or the error that occured while removing // the file. @@ -79,39 +78,40 @@ const ( Fremoved FFlags = 1 << iota ) -// The File type represents a file (or directory) served by the file server. -type File struct { +// The srvFile type represents a file (or directory) served by the file server. +type srvFile struct { sync.Mutex - p.Dir + Dir flags FFlags - Parent *File // parent - next, prev *File // siblings, guarded by parent.Lock - cfirst, clast *File // children (if directory) - Ops interface{} + Parent *srvFile // parent + next, prev *srvFile // siblings, guarded by parent.Lock + cfirst, clast *srvFile // children (if directory) + ops interface{} } type FFid struct { - F *File - Fid *Fid - dirs []*File // used for readdir + F *srvFile + Fid *SrvFid + dirs []*srvFile // used for readdir + dirents []byte // serialized version of dirs } // The Fsrv can be used to create file servers that serve // simple trees of synthetic files. type Fsrv struct { Srv - Root *File + Root *srvFile } var lock sync.Mutex var qnext uint64 -var Eexist = &p.Error{"file already exists", p.EEXIST} -var Enoent = &p.Error{"file not found", p.ENOENT} -var Enotempty = &p.Error{"directory not empty", p.EPERM} +var Eexist = &Error{"file already exists", EEXIST} +var Enoent = &Error{"file not found", ENOENT} +var Enotempty = &Error{"directory not empty", EPERM} // Creates a file server with root as root directory -func NewFileSrv(root *File) *Fsrv { +func NewsrvFileSrv(root *srvFile) *Fsrv { srv := new(Fsrv) srv.Root = root root.Parent = root // make sure we can .. in root @@ -121,7 +121,7 @@ func NewFileSrv(root *File) *Fsrv { // Initializes the fields of a file and add it to a directory. // Returns nil if successful, or an error. -func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ops interface{}) error { +func (f *srvFile) Add(dir *srvFile, name string, uid User, gid Group, mode uint32, ops interface{}) error { lock.Lock() qpath := qnext @@ -141,7 +141,7 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, f.Uidnum = uint32(uid.Id()) } else { f.Uid = "none" - f.Uidnum = p.NOUID + f.Uidnum = NOUID } if gid != nil { @@ -149,11 +149,11 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, f.Gidnum = uint32(gid.Id()) } else { f.Gid = "none" - f.Gidnum = p.NOUID + f.Gidnum = NOUID } f.Muid = "" - f.Muidnum = p.NOUID + f.Muidnum = NOUID f.Ext = "" if dir != nil { @@ -180,12 +180,12 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, f.Parent = f } - f.Ops = ops + f.ops = ops return nil } // Removes a file from its parent directory. -func (f *File) Remove() { +func (f *srvFile) Remove() { f.Lock() if (f.flags & Fremoved) != 0 { f.Unlock() @@ -214,7 +214,7 @@ func (f *File) Remove() { p.Unlock() } -func (f *File) Rename(name string) error { +func (f *srvFile) Rename(name string) error { p := f.Parent p.Lock() defer p.Unlock() @@ -229,8 +229,8 @@ func (f *File) Rename(name string) error { } // Looks for a file in a directory. Returns nil if the file is not found. -func (p *File) Find(name string) *File { - var f *File +func (p *srvFile) Find(name string) *srvFile { + var f *srvFile p.Lock() for f = p.cfirst; f != nil; f = f.next { @@ -244,8 +244,8 @@ func (p *File) Find(name string) *File { // Checks if the specified user has permission to perform // certain operation on a file. Perm contains one or more -// of p.DMREAD, p.DMWRITE, and p.DMEXEC. -func (f *File) CheckPerm(user p.User, perm uint32) bool { +// of DMREAD, DMWRITE, and DMEXEC. +func (f *srvFile) CheckPerm(user User, perm uint32) bool { if user == nil { return false } @@ -285,7 +285,7 @@ func (f *File) CheckPerm(user p.User, perm uint32) bool { return false } -func (s *Fsrv) Attach(req *Req) { +func (s *Fsrv) Attach(req *SrvReq) { fid := new(FFid) fid.F = s.Root fid.Fid = req.Fid @@ -293,7 +293,7 @@ func (s *Fsrv) Attach(req *Req) { req.RespondRattach(&s.Root.Qid) } -func (*Fsrv) Walk(req *Req) { +func (*Fsrv) Walk(req *SrvReq) { fid := req.Fid.Aux.(*FFid) tc := req.Tc @@ -304,7 +304,7 @@ func (*Fsrv) Walk(req *Req) { } nfid := req.Newfid.Aux.(*FFid) - wqids := make([]p.Qid, len(tc.Wname)) + wqids := make([]Qid, len(tc.Wname)) i := 0 f := fid.F for ; i < len(tc.Wname); i++ { @@ -314,8 +314,8 @@ func (*Fsrv) Walk(req *Req) { wqids[i] = f.Qid continue } - if (wqids[i].Type & p.QTDIR) > 0 { - if !f.CheckPerm(req.Fid.User, p.DMEXEC) { + if (wqids[i].Type & QTDIR) > 0 { + if !f.CheckPerm(req.Fid.User, DMEXEC) { break } } @@ -342,22 +342,22 @@ func mode2Perm(mode uint8) uint32 { var perm uint32 = 0 switch mode & 3 { - case p.OREAD: - perm = p.DMREAD - case p.OWRITE: - perm = p.DMWRITE - case p.ORDWR: - perm = p.DMREAD | p.DMWRITE + case OREAD: + perm = DMREAD + case OWRITE: + perm = DMWRITE + case ORDWR: + perm = DMREAD | DMWRITE } - if (mode & p.OTRUNC) != 0 { - perm |= p.DMWRITE + if (mode & OTRUNC) != 0 { + perm |= DMWRITE } return perm } -func (*Fsrv) Open(req *Req) { +func (*Fsrv) Open(req *SrvReq) { fid := req.Fid.Aux.(*FFid) tc := req.Tc @@ -366,7 +366,7 @@ func (*Fsrv) Open(req *Req) { return } - if op, ok := (fid.F.Ops).(FOpenOp); ok { + if op, ok := (fid.F.ops).(FOpenOp); ok { err := op.Open(fid, tc.Mode) if err != nil { req.RespondError(err) @@ -376,17 +376,17 @@ func (*Fsrv) Open(req *Req) { req.RespondRopen(&fid.F.Qid, 0) } -func (*Fsrv) Create(req *Req) { +func (*Fsrv) Create(req *SrvReq) { fid := req.Fid.Aux.(*FFid) tc := req.Tc dir := fid.F - if !dir.CheckPerm(req.Fid.User, p.DMWRITE) { + if !dir.CheckPerm(req.Fid.User, DMWRITE) { req.RespondError(Eperm) return } - if cop, ok := (dir.Ops).(FCreateOp); ok { + if cop, ok := (dir.ops).(FCreateOp); ok { f, err := cop.Create(fid, tc.Name, tc.Perm) if err != nil { req.RespondError(err) @@ -399,55 +399,48 @@ func (*Fsrv) Create(req *Req) { } } -func (*Fsrv) Read(req *Req) { - var i, n int +func (*Fsrv) Read(req *SrvReq) { + var n int var err error fid := req.Fid.Aux.(*FFid) f := fid.F tc := req.Tc rc := req.Rc - p.InitRread(rc, tc.Count) + InitRread(rc, tc.Count) - if f.Mode&p.DMDIR != 0 { - // directory + if f.Mode&DMDIR != 0 { + // Get all the directory entries and + // serialize them all into an output buffer. + // This greatly simplifies the directory read. if tc.Offset == 0 { - var g *File + var g *srvFile + fid.dirents = nil f.Lock() for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next { } - - fid.dirs = make([]*File, n) + fid.dirs = make([]*srvFile, n) for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next { fid.dirs[n] = g + fid.dirents = append(fid.dirents, + PackDir(&g.Dir, req.Conn.Dotu)...) } f.Unlock() } - n = 0 - b := rc.Data - for i = 0; i < len(fid.dirs); i++ { - g := fid.dirs[i] - g.Lock() - if (g.flags & Fremoved) != 0 { - g.Unlock() - continue - } - - sz := p.PackDir(&g.Dir, b, req.Conn.Dotu) - g.Unlock() - if sz == 0 { - break - } - - b = b[sz:] - n += sz + switch { + case tc.Offset > uint64(len(fid.dirents)): + n = 0 + case len(fid.dirents[tc.Offset:]) > int(tc.Size): + n = int(tc.Size) + default: + n = len(fid.dirents[tc.Offset:]) } + copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+1+n]) - fid.dirs = fid.dirs[i:] } else { // file - if rop, ok := f.Ops.(FReadOp); ok { + if rop, ok := f.ops.(FReadOp); ok { n, err = rop.Read(fid, rc.Data, tc.Offset) if err != nil { req.RespondError(err) @@ -459,16 +452,16 @@ func (*Fsrv) Read(req *Req) { } } - p.SetRreadCount(rc, uint32(n)) + SetRreadCount(rc, uint32(n)) req.Respond() } -func (*Fsrv) Write(req *Req) { +func (*Fsrv) Write(req *SrvReq) { fid := req.Fid.Aux.(*FFid) f := fid.F tc := req.Tc - if wop, ok := (f.Ops).(FWriteOp); ok { + if wop, ok := (f.ops).(FWriteOp); ok { n, err := wop.Write(fid, tc.Data, tc.Offset) if err != nil { req.RespondError(err) @@ -481,10 +474,10 @@ func (*Fsrv) Write(req *Req) { } -func (*Fsrv) Clunk(req *Req) { +func (*Fsrv) Clunk(req *SrvReq) { fid := req.Fid.Aux.(*FFid) - if op, ok := (fid.F.Ops).(FClunkOp); ok { + if op, ok := (fid.F.ops).(FClunkOp); ok { err := op.Clunk(fid) if err != nil { req.RespondError(err) @@ -493,7 +486,7 @@ func (*Fsrv) Clunk(req *Req) { req.RespondRclunk() } -func (*Fsrv) Remove(req *Req) { +func (*Fsrv) Remove(req *SrvReq) { fid := req.Fid.Aux.(*FFid) f := fid.F f.Lock() @@ -504,7 +497,7 @@ func (*Fsrv) Remove(req *Req) { } f.Unlock() - if rop, ok := (f.Ops).(FRemoveOp); ok { + if rop, ok := (f.ops).(FRemoveOp); ok { err := rop.Remove(fid) if err != nil { req.RespondError(err) @@ -518,11 +511,11 @@ func (*Fsrv) Remove(req *Req) { } } -func (*Fsrv) Stat(req *Req) { +func (*Fsrv) Stat(req *SrvReq) { fid := req.Fid.Aux.(*FFid) f := fid.F - if sop, ok := (f.Ops).(FStatOp); ok { + if sop, ok := (f.ops).(FStatOp); ok { err := sop.Stat(fid) if err != nil { req.RespondError(err) @@ -534,12 +527,12 @@ func (*Fsrv) Stat(req *Req) { } } -func (*Fsrv) Wstat(req *Req) { +func (*Fsrv) Wstat(req *SrvReq) { tc := req.Tc fid := req.Fid.Aux.(*FFid) f := fid.F - if wop, ok := (f.Ops).(FWstatOp); ok { + if wop, ok := (f.ops).(FWstatOp); ok { err := wop.Wstat(fid, &tc.Dir) if err != nil { req.RespondError(err) @@ -551,7 +544,7 @@ func (*Fsrv) Wstat(req *Req) { } } -func (*Fsrv) FidDestroy(ffid *Fid) { +func (*Fsrv) FidDestroy(ffid *SrvFid) { if ffid.Aux == nil { return } @@ -562,7 +555,7 @@ func (*Fsrv) FidDestroy(ffid *Fid) { return // otherwise errs in bad walks } - if op, ok := (f.Ops).(FDestroyOp); ok { + if op, ok := (f.ops).(FDestroyOp); ok { op.FidDestroy(fid) } } diff --git a/third_party/go9p/srv_pipe.go b/third_party/go9p/srv_pipe.go new file mode 100644 index 000000000..21033acf0 --- /dev/null +++ b/third_party/go9p/srv_pipe.go @@ -0,0 +1,354 @@ +// Copyright 2009 The go9p Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go9p + +import ( + "log" + "os" + "strconv" + "syscall" +) + +type pipeFid struct { + path string + file *os.File + dirs []os.FileInfo + dirents []byte + diroffset uint64 + st os.FileInfo + data []uint8 + eof bool +} + +type Pipefs struct { + Srv + Root string +} + +func (fid *pipeFid) stat() *Error { + var err error + + fid.st, err = os.Lstat(fid.path) + if err != nil { + return toError(err) + } + + return nil +} + +// Dir is an instantiation of the p.Dir structure +// that can act as a receiver for local methods. +type pipeDir struct { + Dir +} + +func (*Pipefs) ConnOpened(conn *Conn) { + if conn.Srv.Debuglevel > 0 { + log.Println("connected") + } +} + +func (*Pipefs) ConnClosed(conn *Conn) { + if conn.Srv.Debuglevel > 0 { + log.Println("disconnected") + } +} + +func (*Pipefs) FidDestroy(sfid *SrvFid) { + var fid *pipeFid + + if sfid.Aux == nil { + return + } + + fid = sfid.Aux.(*pipeFid) + if fid.file != nil { + fid.file.Close() + } +} + +func (pipe *Pipefs) Attach(req *SrvReq) { + if req.Afid != nil { + req.RespondError(Enoauth) + return + } + + tc := req.Tc + fid := new(pipeFid) + if len(tc.Aname) == 0 { + fid.path = pipe.Root + } else { + fid.path = tc.Aname + } + + req.Fid.Aux = fid + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + qid := dir2Qid(fid.st) + req.RespondRattach(qid) +} + +func (*Pipefs) Flush(req *SrvReq) {} + +func (*Pipefs) Walk(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + tc := req.Tc + + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + if req.Newfid.Aux == nil { + req.Newfid.Aux = new(pipeFid) + } + + nfid := req.Newfid.Aux.(*pipeFid) + wqids := make([]Qid, len(tc.Wname)) + path := fid.path + i := 0 + for ; i < len(tc.Wname); i++ { + p := path + "/" + tc.Wname[i] + st, err := os.Lstat(p) + if err != nil { + if i == 0 { + req.RespondError(Enoent) + return + } + + break + } + + wqids[i] = *dir2Qid(st) + path = p + } + + nfid.path = path + req.RespondRwalk(wqids[0:i]) +} + +func (*Pipefs) Open(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + tc := req.Tc + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + var e error + fid.file, e = os.OpenFile(fid.path, omode2uflags(tc.Mode), 0) + if e != nil { + req.RespondError(toError(e)) + return + } + + req.RespondRopen(dir2Qid(fid.st), 0) +} + +func (*Pipefs) Create(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + tc := req.Tc + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + path := fid.path + "/" + tc.Name + var e error = nil + var file *os.File = nil + switch { + case tc.Perm&DMDIR != 0: + e = os.Mkdir(path, os.FileMode(tc.Perm&0777)) + + case tc.Perm&DMSYMLINK != 0: + e = os.Symlink(tc.Ext, path) + + case tc.Perm&DMLINK != 0: + n, e := strconv.ParseUint(tc.Ext, 10, 0) + if e != nil { + break + } + + ofid := req.Conn.FidGet(uint32(n)) + if ofid == nil { + req.RespondError(Eunknownfid) + return + } + + e = os.Link(ofid.Aux.(*pipeFid).path, path) + ofid.DecRef() + + case tc.Perm&DMNAMEDPIPE != 0: + case tc.Perm&DMDEVICE != 0: + req.RespondError(&Error{"not implemented", EIO}) + return + + default: + var mode uint32 = tc.Perm & 0777 + if req.Conn.Dotu { + if tc.Perm&DMSETUID > 0 { + mode |= syscall.S_ISUID + } + if tc.Perm&DMSETGID > 0 { + mode |= syscall.S_ISGID + } + } + file, e = os.OpenFile(path, omode2uflags(tc.Mode)|os.O_CREATE, os.FileMode(mode)) + } + + if file == nil && e == nil { + file, e = os.OpenFile(path, omode2uflags(tc.Mode), 0) + } + + if e != nil { + req.RespondError(toError(e)) + return + } + + fid.path = path + fid.file = file + err = fid.stat() + if err != nil { + req.RespondError(err) + return + } + + req.RespondRcreate(dir2Qid(fid.st), 0) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func (*Pipefs) Read(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + tc := req.Tc + rc := req.Rc + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + InitRread(rc, tc.Count) + var count int + var e error + if fid.st.IsDir() { + if tc.Offset == 0 { + var e error + // If we got here, it was open. Can't really seek + // in most cases, just close and reopen it. + fid.file.Close() + if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil { + req.RespondError(toError(e)) + return + } + + if fid.dirs, e = fid.file.Readdir(-1); e != nil { + req.RespondError(toError(e)) + return + } + fid.dirents = nil + + for i := 0; i < len(fid.dirs); i++ { + path := fid.path + "/" + fid.dirs[i].Name() + st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool) + if st == nil { + continue + } + b := PackDir(st, req.Conn.Dotu) + fid.dirents = append(fid.dirents, b...) + count += len(b) + } + } + switch { + case tc.Offset > uint64(len(fid.dirents)): + count = 0 + case len(fid.dirents[tc.Offset:]) > int(tc.Count): + count = int(tc.Count) + default: + count = len(fid.dirents[tc.Offset:]) + } + + copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count]) + + } else { + if fid.eof { + req.RespondError(toError(e)) + return + } + length := min(len(rc.Data), len(fid.data)) + count = length + copy(rc.Data, fid.data[:length]) + fid.data = fid.data[length:] + } + + SetRreadCount(rc, uint32(count)) + req.Respond() +} + +func (*Pipefs) Write(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + tc := req.Tc + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + fid.data = append(fid.data, tc.Data...) + + req.RespondRwrite(uint32(len(tc.Data))) +} + +func (*Pipefs) Clunk(req *SrvReq) { req.RespondRclunk() } + +func (*Pipefs) Remove(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + e := os.Remove(fid.path) + if e != nil { + req.RespondError(toError(e)) + return + } + + req.RespondRremove() +} + +func (*Pipefs) Stat(req *SrvReq) { + fid := req.Fid.Aux.(*pipeFid) + err := fid.stat() + if err != nil { + req.RespondError(err) + return + } + + st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool) + if st == nil { + req.RespondError(derr) + return + } + + req.RespondRstat(st) +} + +func (*Pipefs) Wstat(req *SrvReq) { + req.RespondError(Eperm) +} diff --git a/third_party/go9p/srv_pipe_darwin.go b/third_party/go9p/srv_pipe_darwin.go new file mode 100644 index 000000000..453c52fec --- /dev/null +++ b/third_party/go9p/srv_pipe_darwin.go @@ -0,0 +1,41 @@ +// Copyright 2009 The go9p Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go9p + +import ( + "fmt" + "os" + "syscall" +) + +func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) { + u := upool.Uid2User(int(sysMode.Uid)) + g := upool.Gid2Group(int(sysMode.Gid)) + dir.Uid = u.Name() + if dir.Uid == "" { + dir.Uid = "none" + } + + dir.Gid = g.Name() + if dir.Gid == "" { + dir.Gid = "none" + } + dir.Muid = "none" + dir.Ext = "" + dir.Uidnum = uint32(u.Id()) + dir.Gidnum = uint32(g.Id()) + dir.Muidnum = NOUID + if d.Mode()&os.ModeSymlink != 0 { + var err error + dir.Ext, err = os.Readlink(path) + if err != nil { + dir.Ext = "" + } + } else if isBlock(d) { + dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF) + } else if isChar(d) { + dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF) + } +} diff --git a/third_party/go9p/srv_pipe_linux.go b/third_party/go9p/srv_pipe_linux.go new file mode 100644 index 000000000..453c52fec --- /dev/null +++ b/third_party/go9p/srv_pipe_linux.go @@ -0,0 +1,41 @@ +// Copyright 2009 The go9p Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go9p + +import ( + "fmt" + "os" + "syscall" +) + +func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) { + u := upool.Uid2User(int(sysMode.Uid)) + g := upool.Gid2Group(int(sysMode.Gid)) + dir.Uid = u.Name() + if dir.Uid == "" { + dir.Uid = "none" + } + + dir.Gid = g.Name() + if dir.Gid == "" { + dir.Gid = "none" + } + dir.Muid = "none" + dir.Ext = "" + dir.Uidnum = uint32(u.Id()) + dir.Gidnum = uint32(g.Id()) + dir.Muidnum = NOUID + if d.Mode()&os.ModeSymlink != 0 { + var err error + dir.Ext, err = os.Readlink(path) + if err != nil { + dir.Ext = "" + } + } else if isBlock(d) { + dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF) + } else if isChar(d) { + dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF) + } +} diff --git a/third_party/go9p/srv_pipe_windows.go b/third_party/go9p/srv_pipe_windows.go new file mode 100644 index 000000000..156dbd4a4 --- /dev/null +++ b/third_party/go9p/srv_pipe_windows.go @@ -0,0 +1,48 @@ +// Copyright 2009 The go9p Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package go9p + +import ( + "os" + "syscall" +) + +func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) { + // u := upool.Uid2User(int(sysMode.Uid)) + // g := upool.Gid2Group(int(sysMode.Gid)) + // dir.Uid = u.Name() + // if dir.Uid == "" { + // dir.Uid = "none" + // } + + // dir.Gid = g.Name() + // if dir.Gid == "" { + // dir.Gid = "none" + // } + // dir.Muid = "none" + // dir.Ext = "" + // dir.Uidnum = uint32(u.Id()) + // dir.Gidnum = uint32(g.Id()) + // dir.Muidnum = NOUID + // if d.Mode()&os.ModeSymlink != 0 { + // var err error + // dir.Ext, err = os.Readlink(path) + // if err != nil { + // dir.Ext = "" + // } + // } else if isBlock(d) { + // dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF) + // } else if isChar(d) { + // dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF) + // } + + dir.Uid = "none" + dir.Gid = "none" + dir.Muid = "none" + dir.Uidnum = 0 + dir.Gidnum = 0 + dir.Muidnum = NOUID + dir.Ext = "" +} diff --git a/third_party/go9p/p/srv/respond.go b/third_party/go9p/srv_respond.go similarity index 52% rename from third_party/go9p/p/srv/respond.go rename to third_party/go9p/srv_respond.go index 762626e1a..e7990e9d4 100644 --- a/third_party/go9p/p/srv/respond.go +++ b/third_party/go9p/srv_respond.go @@ -2,28 +2,42 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package srv +package go9p import "fmt" -import "k8s.io/minikube/third_party/go9p/p" + +// SrvRequest operations. This interface should be implemented by all file servers. +// The operations correspond directly to most of the 9P2000 message types. +type SrvReqOps interface { + Attach(*SrvReq) + Walk(*SrvReq) + Open(*SrvReq) + Create(*SrvReq) + Read(*SrvReq) + Write(*SrvReq) + Clunk(*SrvReq) + Remove(*SrvReq) + Stat(*SrvReq) + Wstat(*SrvReq) +} // Respond to the request with Rerror message -func (req *Req) RespondError(err interface{}) { +func (req *SrvReq) RespondError(err interface{}) { switch e := err.(type) { - case *p.Error: - p.PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu) + case *Error: + PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu) case error: - p.PackRerror(req.Rc, e.Error(), uint32(p.EIO), req.Conn.Dotu) + PackRerror(req.Rc, e.Error(), uint32(EIO), req.Conn.Dotu) default: - p.PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(p.EIO), req.Conn.Dotu) + PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(EIO), req.Conn.Dotu) } req.Respond() } // Respond to the request with Rversion message -func (req *Req) RespondRversion(msize uint32, version string) { - err := p.PackRversion(req.Rc, msize, version) +func (req *SrvReq) RespondRversion(msize uint32, version string) { + err := PackRversion(req.Rc, msize, version) if err != nil { req.RespondError(err) } else { @@ -32,8 +46,8 @@ func (req *Req) RespondRversion(msize uint32, version string) { } // Respond to the request with Rauth message -func (req *Req) RespondRauth(aqid *p.Qid) { - err := p.PackRauth(req.Rc, aqid) +func (req *SrvReq) RespondRauth(aqid *Qid) { + err := PackRauth(req.Rc, aqid) if err != nil { req.RespondError(err) } else { @@ -42,8 +56,8 @@ func (req *Req) RespondRauth(aqid *p.Qid) { } // Respond to the request with Rflush message -func (req *Req) RespondRflush() { - err := p.PackRflush(req.Rc) +func (req *SrvReq) RespondRflush() { + err := PackRflush(req.Rc) if err != nil { req.RespondError(err) } else { @@ -52,8 +66,8 @@ func (req *Req) RespondRflush() { } // Respond to the request with Rattach message -func (req *Req) RespondRattach(aqid *p.Qid) { - err := p.PackRattach(req.Rc, aqid) +func (req *SrvReq) RespondRattach(aqid *Qid) { + err := PackRattach(req.Rc, aqid) if err != nil { req.RespondError(err) } else { @@ -62,8 +76,8 @@ func (req *Req) RespondRattach(aqid *p.Qid) { } // Respond to the request with Rwalk message -func (req *Req) RespondRwalk(wqids []p.Qid) { - err := p.PackRwalk(req.Rc, wqids) +func (req *SrvReq) RespondRwalk(wqids []Qid) { + err := PackRwalk(req.Rc, wqids) if err != nil { req.RespondError(err) } else { @@ -72,8 +86,8 @@ func (req *Req) RespondRwalk(wqids []p.Qid) { } // Respond to the request with Ropen message -func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) { - err := p.PackRopen(req.Rc, qid, iounit) +func (req *SrvReq) RespondRopen(qid *Qid, iounit uint32) { + err := PackRopen(req.Rc, qid, iounit) if err != nil { req.RespondError(err) } else { @@ -82,8 +96,8 @@ func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) { } // Respond to the request with Rcreate message -func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) { - err := p.PackRcreate(req.Rc, qid, iounit) +func (req *SrvReq) RespondRcreate(qid *Qid, iounit uint32) { + err := PackRcreate(req.Rc, qid, iounit) if err != nil { req.RespondError(err) } else { @@ -92,8 +106,8 @@ func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) { } // Respond to the request with Rread message -func (req *Req) RespondRread(data []byte) { - err := p.PackRread(req.Rc, data) +func (req *SrvReq) RespondRread(data []byte) { + err := PackRread(req.Rc, data) if err != nil { req.RespondError(err) } else { @@ -102,8 +116,8 @@ func (req *Req) RespondRread(data []byte) { } // Respond to the request with Rwrite message -func (req *Req) RespondRwrite(count uint32) { - err := p.PackRwrite(req.Rc, count) +func (req *SrvReq) RespondRwrite(count uint32) { + err := PackRwrite(req.Rc, count) if err != nil { req.RespondError(err) } else { @@ -112,8 +126,8 @@ func (req *Req) RespondRwrite(count uint32) { } // Respond to the request with Rclunk message -func (req *Req) RespondRclunk() { - err := p.PackRclunk(req.Rc) +func (req *SrvReq) RespondRclunk() { + err := PackRclunk(req.Rc) if err != nil { req.RespondError(err) } else { @@ -122,8 +136,8 @@ func (req *Req) RespondRclunk() { } // Respond to the request with Rremove message -func (req *Req) RespondRremove() { - err := p.PackRremove(req.Rc) +func (req *SrvReq) RespondRremove() { + err := PackRremove(req.Rc) if err != nil { req.RespondError(err) } else { @@ -132,8 +146,8 @@ func (req *Req) RespondRremove() { } // Respond to the request with Rstat message -func (req *Req) RespondRstat(st *p.Dir) { - err := p.PackRstat(req.Rc, st, req.Conn.Dotu) +func (req *SrvReq) RespondRstat(st *Dir) { + err := PackRstat(req.Rc, st, req.Conn.Dotu) if err != nil { req.RespondError(err) } else { @@ -142,8 +156,8 @@ func (req *Req) RespondRstat(st *p.Dir) { } // Respond to the request with Rwstat message -func (req *Req) RespondRwstat() { - err := p.PackRwstat(req.Rc) +func (req *SrvReq) RespondRwstat() { + err := PackRwstat(req.Rc) if err != nil { req.RespondError(err) } else { diff --git a/third_party/go9p/p/srv/srv.go b/third_party/go9p/srv_srv.go similarity index 58% rename from third_party/go9p/p/srv/srv.go rename to third_party/go9p/srv_srv.go index 95c4f635d..f1dc590e8 100644 --- a/third_party/go9p/p/srv/srv.go +++ b/third_party/go9p/srv_srv.go @@ -2,12 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// The srv package provides definitions and functions used to implement +// The srv package go9provides definitions and functions used to implement // a 9P2000 file server. -package srv +package go9p import ( - "k8s.io/minikube/third_party/go9p/p" "net" "runtime" "sync" @@ -22,26 +21,18 @@ const ( reqSaved /* no response was produced after the request is worked on */ ) -// Debug flags -const ( - DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr - DbgPrintPackets // print the raw packets on stderr - DbgLogFcalls // keep the last N 9P messages (can be accessed over http) - DbgLogPackets // keep the last N 9P messages (can be accessed over http) -) - -var Eunknownfid error = &p.Error{"unknown fid", p.EINVAL} -var Enoauth error = &p.Error{"no authentication required", p.EINVAL} -var Einuse error = &p.Error{"fid already in use", p.EINVAL} -var Ebaduse error = &p.Error{"bad use of fid", p.EINVAL} -var Eopen error = &p.Error{"fid already opened", p.EINVAL} -var Enotdir error = &p.Error{"not a directory", p.ENOTDIR} -var Eperm error = &p.Error{"permission denied", p.EPERM} -var Etoolarge error = &p.Error{"i/o count too large", p.EINVAL} -var Ebadoffset error = &p.Error{"bad offset in directory read", p.EINVAL} -var Edirchange error = &p.Error{"cannot convert between files and directories", p.EINVAL} -var Enouser error = &p.Error{"unknown user", p.EINVAL} -var Enotimpl error = &p.Error{"not implemented", p.EINVAL} +var Eunknownfid error = &Error{"unknown fid", EINVAL} +var Enoauth error = &Error{"no authentication required", EINVAL} +var Einuse error = &Error{"fid already in use", EINVAL} +var Ebaduse error = &Error{"bad use of fid", EINVAL} +var Eopen error = &Error{"fid already opened", EINVAL} +var Enotdir error = &Error{"not a directory", ENOTDIR} +var Eperm error = &Error{"permission denied", EPERM} +var Etoolarge error = &Error{"i/o count too large", EINVAL} +var Ebadoffset error = &Error{"bad offset in directory read", EINVAL} +var Edirchange error = &Error{"cannot convert between files and directories", EINVAL} +var Enouser error = &Error{"unknown user", EINVAL} +var Enotimpl error = &Error{"not implemented", EINVAL} // Authentication operations. The file server should implement them if // it requires user authentication. The authentication in 9P2000 is @@ -50,28 +41,28 @@ var Enotimpl error = &p.Error{"not implemented", p.EINVAL} // fid can be used by the user to get access to the actual files. type AuthOps interface { // AuthInit is called when the user starts the authentication - // process on Fid afid. The user that is being authenticated + // process on SrvFid afid. The user that is being authenticated // is referred by afid.User. The function should return the Qid // for the authentication file, or an Error if the user can't be // authenticated - AuthInit(afid *Fid, aname string) (*p.Qid, error) + AuthInit(afid *SrvFid, aname string) (*Qid, error) // AuthDestroy is called when an authentication fid is destroyed. - AuthDestroy(afid *Fid) + AuthDestroy(afid *SrvFid) // AuthCheck is called after the authentication process is finished // when the user tries to attach to the file server. If the function // returns nil, the authentication was successful and the user has // permission to access the files. - AuthCheck(fid *Fid, afid *Fid, aname string) error + AuthCheck(fid *SrvFid, afid *SrvFid, aname string) error // AuthRead is called when the user attempts to read data from an // authentication fid. - AuthRead(afid *Fid, offset uint64, data []byte) (count int, err error) + AuthRead(afid *SrvFid, offset uint64, data []byte) (count int, err error) // AuthWrite is called when the user attempts to write data to an // authentication fid. - AuthWrite(afid *Fid, offset uint64, data []byte) (count int, err error) + AuthWrite(afid *SrvFid, offset uint64, data []byte) (count int, err error) } // Connection operations. These should be implemented if the file server @@ -81,61 +72,41 @@ type ConnOps interface { ConnClosed(*Conn) } -// Fid operations. This interface should be implemented if the file server -// needs to be called when a Fid is destroyed. -type FidOps interface { - FidDestroy(*Fid) +// SrvFid operations. This interface should be implemented if the file server +// needs to be called when a SrvFid is destroyed. +type SrvFidOps interface { + FidDestroy(*SrvFid) } // Request operations. This interface should be implemented if the file server // needs to bypass the default request process, or needs to perform certain // operations before the (any) request is processed, or before (any) response // sent back to the client. -type ReqProcessOps interface { +type SrvReqProcessOps interface { // Called when a new request is received from the client. If the - // interface is not implemented, (req *Req) srv.Process() method is + // interface is not implemented, (req *SrvReq) srv.Process() method is // called. If the interface is implemented, it is the user's // responsibility to call srv.Process. If srv.Process isn't called, - // Fid, Afid and Newfid fields in Req are not set, and the ReqOps + // SrvFid, Afid and Newfid fields in SrvReq are not set, and the SrvReqOps // methods are not called. - ReqProcess(*Req) + SrvReqProcess(*SrvReq) - // Called when a request is responded, i.e. when (req *Req)srv.Respond() + // Called when a request is responded, i.e. when (req *SrvReq)srv.Respond() // is called and before the response is sent. If the interface is not - // implemented, (req *Req) srv.PostProcess() method is called to finalize - // the request. If the interface is implemented and ReqProcess calls - // the srv.Process method, ReqRespond should call the srv.PostProcess + // implemented, (req *SrvReq) srv.PostProcess() method is called to finalize + // the request. If the interface is implemented and SrvReqProcess calls + // the srv.Process method, SrvReqRespond should call the srv.PostProcess // method. - ReqRespond(*Req) + SrvReqRespond(*SrvReq) } // Flush operation. This interface should be implemented if the file server // can flush pending requests. If the interface is not implemented, requests // that were passed to the file server implementation won't be flushed. -// The flush method should call the (req *Req) srv.Flush() method if the flush +// The flush method should call the (req *SrvReq) srv.Flush() method if the flush // was successful so the request can be marked appropriately. type FlushOp interface { - Flush(*Req) -} - -// Request operations. This interface should be implemented by all file servers. -// The operations correspond directly to most of the 9P2000 message types. -type ReqOps interface { - Attach(*Req) - Walk(*Req) - Open(*Req) - Create(*Req) - Read(*Req) - Write(*Req) - Clunk(*Req) - Remove(*Req) - Stat(*Req) - Wstat(*Req) -} - -type StatsOps interface { - statsRegister() - statsUnregister() + Flush(*SrvReq) } // The Srv type contains the basic fields used to control the 9P2000 @@ -145,13 +116,13 @@ type StatsOps interface { // that implements the file server operations. type Srv struct { sync.Mutex - Id string // Used for debugging and stats - Msize uint32 // Maximum size of the 9P2000 messages supported by the server - Dotu bool // If true, the server supports the 9P2000.u extension - Debuglevel int // debug level - Upool p.Users // Interface for finding users and groups known to the file server - Maxpend int // Maximum pending outgoing requests - Log *p.Logger + Id string // Used for debugging and stats + Msize uint32 // Maximum size of the 9P2000 messages supported by the server + Dotu bool // If true, the server supports the 9P2000.u extension + Debuglevel int // debug level + Upool Users // Interface for finding users and groups known to the file server + Maxpend int // Maximum pending outgoing requests + Log *Logger ops interface{} // operations conns map[*Conn]*Conn // List of connections @@ -167,11 +138,11 @@ type Conn struct { Debuglevel int conn net.Conn - fidpool map[uint32]*Fid - reqs map[uint16]*Req // all outstanding requests + fidpool map[uint32]*SrvFid + reqs map[uint16]*SrvReq // all outstanding requests - reqout chan *Req - rchan chan *p.Fcall + reqout chan *SrvReq + rchan chan *Fcall done chan bool // stats @@ -184,41 +155,42 @@ type Conn struct { nwrites int // number of writes } -// The Fid type identifies a file on the file server. -// A new Fid is created when the user attaches to the file server (the Attach -// operation), or when Walk-ing to a file. The Fid values are created -// automatically by the srv implementation. The FidDestroy operation is called -// when a Fid is destroyed. -type Fid struct { +// The SrvFid type identifies a file on the file server. +// A new SrvFid is created when the user attaches to the file server (the Attach +// operation), or when Walk-ing to a file. The SrvFid values are created +// automatically by the srv implementation. The SrvFidDestroy operation is called +// when a SrvFid is destroyed. +type SrvFid struct { sync.Mutex fid uint32 refcount int - opened bool // True if the Fid is opened - Fconn *Conn // Connection the Fid belongs to - Omode uint8 // Open mode (p.O* flags), if the fid is opened - Type uint8 // Fid type (p.QT* flags) + opened bool // True if the SrvFid is opened + Fconn *Conn // Connection the SrvFid belongs to + Omode uint8 // Open mode (O* flags), if the fid is opened + Type uint8 // SrvFid type (QT* flags) Diroffset uint64 // If directory, the next valid read position - User p.User // The Fid's user - Aux interface{} // Can be used by the file server implementation for per-Fid data + Dirents []byte // If directory, the serialized dirents + User User // The SrvFid's user + Aux interface{} // Can be used by the file server implementation for per-SrvFid data } -// The Req type represents a 9P2000 request. Each request has a -// T-message (Tc) and a R-message (Rc). If the ReqProcessOps don't -// override the default behavior, the implementation initializes Fid, -// Afid and Newfid values and automatically keeps track on when the Fids +// The SrvReq type represents a 9P2000 request. Each request has a +// T-message (Tc) and a R-message (Rc). If the SrvReqProcessOps don't +// override the default behavior, the implementation initializes SrvFid, +// Afid and Newfid values and automatically keeps track on when the SrvFids // should be destroyed. -type Req struct { +type SrvReq struct { sync.Mutex - Tc *p.Fcall // Incoming 9P2000 message - Rc *p.Fcall // Outgoing 9P2000 response - Fid *Fid // The Fid value for all messages that contain fid[4] - Afid *Fid // The Fid value for the messages that contain afid[4] (Tauth and Tattach) - Newfid *Fid // The Fid value for the messages that contain newfid[4] (Twalk) - Conn *Conn // Connection that the request belongs to + Tc *Fcall // Incoming 9P2000 message + Rc *Fcall // Outgoing 9P2000 response + Fid *SrvFid // The SrvFid value for all messages that contain fid[4] + Afid *SrvFid // The SrvFid value for the messages that contain afid[4] (Tauth and Tattach) + Newfid *SrvFid // The SrvFid value for the messages that contain newfid[4] (Twalk) + Conn *Conn // Connection that the request belongs to status reqStatus - flushreq *Req - prev, next *Req + flushreq *SrvReq + prev, next *SrvReq } // The Start method should be called once the file server implementor @@ -226,23 +198,23 @@ type Req struct { // values to the fields that are not initialized and creates the goroutines // required for the server's operation. The method receives an empty // interface value, ops, that should implement the interfaces the file server is -// interested in. Ops must implement the ReqOps interface. +// interested in. Ops must implement the SrvReqOps interface. func (srv *Srv) Start(ops interface{}) bool { - if _, ok := (ops).(ReqOps); !ok { + if _, ok := (ops).(SrvReqOps); !ok { return false } srv.ops = ops if srv.Upool == nil { - srv.Upool = p.OsUsers + srv.Upool = OsUsers } - if srv.Msize < p.IOHDRSZ { - srv.Msize = p.MSIZE + if srv.Msize < IOHDRSZ { + srv.Msize = MSIZE } if srv.Log == nil { - srv.Log = p.NewLogger(1024) + srv.Log = NewLogger(1024) } if sop, ok := (interface{}(srv)).(StatsOps); ok { @@ -256,7 +228,7 @@ func (srv *Srv) String() string { return srv.Id } -func (req *Req) process() { +func (req *SrvReq) process() { req.Lock() flushed := (req.status & reqFlush) != 0 if !flushed { @@ -268,8 +240,8 @@ func (req *Req) process() { req.Respond() } - if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok { - rop.ReqProcess(req) + if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok { + rop.SrvReqProcess(req) } else { req.Process() } @@ -283,16 +255,16 @@ func (req *Req) process() { } // Performs the default processing of a request. Initializes -// the Fid, Afid and Newfid fields and calls the appropriate -// ReqOps operation for the message. The file server implementer -// should call it only if the file server implements the ReqProcessOps -// within the ReqProcess operation. -func (req *Req) Process() { +// the SrvFid, Afid and Newfid fields and calls the appropriate +// SrvReqOps operation for the message. The file server implementer +// should call it only if the file server implements the SrvReqProcessOps +// within the SrvReqProcess operation. +func (req *SrvReq) Process() { conn := req.Conn srv := conn.Srv tc := req.Tc - if tc.Fid != p.NOFID && tc.Type != p.Tattach { + if tc.Fid != NOFID && tc.Type != Tattach { srv.Lock() req.Fid = conn.FidGet(tc.Fid) srv.Unlock() @@ -304,83 +276,83 @@ func (req *Req) Process() { switch req.Tc.Type { default: - req.RespondError(&p.Error{"unknown message type", p.EINVAL}) + req.RespondError(&Error{"unknown message type", EINVAL}) - case p.Tversion: + case Tversion: srv.version(req) - case p.Tauth: + case Tauth: if runtime.GOOS == "windows" { return } srv.auth(req) - case p.Tattach: + case Tattach: srv.attach(req) - case p.Tflush: + case Tflush: srv.flush(req) - case p.Twalk: + case Twalk: srv.walk(req) - case p.Topen: + case Topen: srv.open(req) - case p.Tcreate: + case Tcreate: srv.create(req) - case p.Tread: + case Tread: srv.read(req) - case p.Twrite: + case Twrite: srv.write(req) - case p.Tclunk: + case Tclunk: srv.clunk(req) - case p.Tremove: + case Tremove: srv.remove(req) - case p.Tstat: + case Tstat: srv.stat(req) - case p.Twstat: + case Twstat: srv.wstat(req) } } -// Performs the post processing required if the (*Req) Process() method +// Performs the post processing required if the (*SrvReq) Process() method // is called for a request. The file server implementer should call it -// only if the file server implements the ReqProcessOps within the -// ReqRespond operation. -func (req *Req) PostProcess() { +// only if the file server implements the SrvReqProcessOps within the +// SrvReqRespond operation. +func (req *SrvReq) PostProcess() { srv := req.Conn.Srv /* call the post-handlers (if needed) */ switch req.Tc.Type { - case p.Tauth: + case Tauth: srv.authPost(req) - case p.Tattach: + case Tattach: srv.attachPost(req) - case p.Twalk: + case Twalk: srv.walkPost(req) - case p.Topen: + case Topen: srv.openPost(req) - case p.Tcreate: + case Tcreate: srv.createPost(req) - case p.Tread: + case Tread: srv.readPost(req) - case p.Tclunk: + case Tclunk: srv.clunkPost(req) - case p.Tremove: + case Tremove: srv.removePost(req) } @@ -404,8 +376,8 @@ func (req *Req) PostProcess() { // should be initialized and contain valid 9P2000 message. In most cases // the file server implementer shouldn't call this method directly. Instead // one of the RespondR* methods should be used. -func (req *Req) Respond() { - var flushreqs *Req +func (req *SrvReq) Respond() { + var flushreqs *SrvReq conn := req.Conn req.Lock() @@ -425,7 +397,7 @@ func (req *Req) Respond() { nextreq.next = nil // if there are flush requests, move them to the next request if req.flushreq != nil { - var p *Req = nil + var p *SrvReq = nil r := nextreq.flushreq for ; r != nil; p, r = r, r.flushreq { } @@ -433,7 +405,7 @@ func (req *Req) Respond() { if p == nil { nextreq.flushreq = req.flushreq } else { - p.next = req.flushreq + nextreq = req.flushreq } } @@ -444,8 +416,8 @@ func (req *Req) Respond() { } conn.Unlock() - if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok { - rop.ReqRespond(req) + if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok { + rop.SrvReqRespond(req) } else { req.PostProcess() } @@ -469,18 +441,18 @@ func (req *Req) Respond() { // Should be called to cancel a request. Should only be called // from the Flush operation if the FlushOp is implemented. -func (req *Req) Flush() { +func (req *SrvReq) Flush() { req.Lock() req.status |= reqFlush req.Unlock() req.Respond() } -// Lookup a Fid struct based on the 32-bit identifier sent over the wire. +// Lookup a SrvFid struct based on the 32-bit identifier sent over the wire. // Returns nil if the fid is not found. Increases the reference count of // the returned fid. The user is responsible to call DecRef once it no // longer needs it. -func (conn *Conn) FidGet(fidno uint32) *Fid { +func (conn *Conn) FidGet(fidno uint32) *SrvFid { conn.Lock() fid, present := conn.fidpool[fidno] conn.Unlock() @@ -491,10 +463,10 @@ func (conn *Conn) FidGet(fidno uint32) *Fid { return fid } -// Creates a new Fid struct for the fidno integer. Returns nil -// if the Fid for that number already exists. The returned fid +// Creates a new SrvFid struct for the fidno integer. Returns nil +// if the SrvFid for that number already exists. The returned fid // has reference count set to 1. -func (conn *Conn) FidNew(fidno uint32) *Fid { +func (conn *Conn) FidNew(fidno uint32) *SrvFid { conn.Lock() _, present := conn.fidpool[fidno] if present { @@ -502,7 +474,7 @@ func (conn *Conn) FidNew(fidno uint32) *Fid { return nil } - fid := new(Fid) + fid := new(SrvFid) fid.fid = fidno fid.refcount = 1 fid.Fconn = conn @@ -517,7 +489,7 @@ func (conn *Conn) String() string { } // Increase the reference count for the fid. -func (fid *Fid) IncRef() { +func (fid *SrvFid) IncRef() { fid.Lock() fid.refcount++ fid.Unlock() @@ -525,7 +497,7 @@ func (fid *Fid) IncRef() { // Decrease the reference count for the fid. When the // reference count reaches 0, the fid is no longer valid. -func (fid *Fid) DecRef() { +func (fid *SrvFid) DecRef() { fid.Lock() fid.refcount-- n := fid.refcount @@ -540,7 +512,7 @@ func (fid *Fid) DecRef() { delete(conn.fidpool, fid.fid) conn.Unlock() - if fop, ok := (conn.Srv.ops).(FidOps); ok { + if fop, ok := (conn.Srv.ops).(SrvFidOps); ok { fop.FidDestroy(fid) } } diff --git a/third_party/go9p/p/srv/stats_http.go b/third_party/go9p/srv_stats_http.go similarity index 94% rename from third_party/go9p/p/srv/stats_http.go rename to third_party/go9p/srv_stats_http.go index 0f9230f3c..5eca6e269 100644 --- a/third_party/go9p/p/srv/stats_http.go +++ b/third_party/go9p/srv_stats_http.go @@ -1,18 +1,17 @@ // +build httpstats -package srv +package go9p import ( "fmt" "io" - "k8s.io/minikube/third_party/go9p/p" "net/http" "sync" ) var mux sync.RWMutex var stat map[string]http.Handler -var once sync.Once +var httponce sync.Once func register(s string, h http.Handler) { mux.Lock() @@ -28,7 +27,7 @@ func register(s string, h http.Handler) { mux.Unlock() } func (srv *Srv) statsRegister() { - once.Do(func() { + httponce.Do(func() { http.HandleFunc("/go9p/", StatsHandler) go http.ListenAndServe(":6060", nil) }) @@ -85,7 +84,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { fs := conn.Srv.Log.Filter(conn, DbgLogFcalls) io.WriteString(c, fmt.Sprintf("

Last %d 9P messages

", len(fs))) for i, l := range fs { - fc := l.Data.(*p.Fcall) + fc := l.Data.(*Fcall) if fc.Type == 0 { continue } @@ -94,7 +93,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { if fc.Type%2 == 0 { // try to find the response for the T message for j := i + 1; j < len(fs); j++ { - rc := fs[j].Data.(*p.Fcall) + rc := fs[j].Data.(*Fcall) if rc.Tag == fc.Tag { lbl = fmt.Sprintf("", j) break @@ -103,7 +102,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) { } else { // try to find the request for the R message for j := i - 1; j >= 0; j-- { - tc := fs[j].Data.(*p.Fcall) + tc := fs[j].Data.(*Fcall) if tc.Tag == fc.Tag { lbl = fmt.Sprintf("", j) break diff --git a/third_party/go9p/stats.go b/third_party/go9p/stats.go new file mode 100644 index 000000000..e2323b6c4 --- /dev/null +++ b/third_party/go9p/stats.go @@ -0,0 +1,6 @@ +package go9p + +type StatsOps interface { + statsRegister() + statsUnregister() +} diff --git a/third_party/go9p/p/srv/examples/ufs/ufs.go b/third_party/go9p/ufs.go similarity index 54% rename from third_party/go9p/p/srv/examples/ufs/ufs.go rename to third_party/go9p/ufs.go index c29955243..8fdcc9638 100644 --- a/third_party/go9p/p/srv/examples/ufs/ufs.go +++ b/third_party/go9p/ufs.go @@ -2,51 +2,49 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package ufs +package go9p import ( + "flag" "io" "log" "os" "os/user" + "path" + "sort" "strconv" "syscall" - - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" ) -type Fid struct { - path string - file *os.File - dirs []os.FileInfo - diroffset uint64 - st os.FileInfo +type ufsFid struct { + path string + file *os.File + dirs []os.FileInfo + direntends []int + dirents []byte + diroffset uint64 + st os.FileInfo } type Ufs struct { - srv.Srv + Srv + Root string } -var addr string -var debug int -var root string -var Enoent = &p.Error{"file not found", p.ENOENT} - -func toError(err error) *p.Error { +func toError(err error) *Error { var ecode uint32 ename := err.Error() if e, ok := err.(syscall.Errno); ok { ecode = uint32(e) } else { - ecode = p.EIO + ecode = EIO } - return &p.Error{ename, ecode} + return &Error{ename, ecode} } -func (fid *Fid) stat() *p.Error { +func (fid *ufsFid) stat() *Error { var err error fid.st, err = os.Lstat(fid.path) @@ -60,24 +58,24 @@ func (fid *Fid) stat() *p.Error { func omode2uflags(mode uint8) int { ret := int(0) switch mode & 3 { - case p.OREAD: + case OREAD: ret = os.O_RDONLY break - case p.ORDWR: + case ORDWR: ret = os.O_RDWR break - case p.OWRITE: + case OWRITE: ret = os.O_WRONLY break - case p.OEXEC: + case OEXEC: ret = os.O_RDONLY break } - if mode&p.OTRUNC != 0 { + if mode&OTRUNC != 0 { ret |= os.O_TRUNC } @@ -87,11 +85,11 @@ func omode2uflags(mode uint8) int { func dir2QidType(d os.FileInfo) uint8 { ret := uint8(0) if d.IsDir() { - ret |= p.QTDIR + ret |= QTDIR } if d.Mode()&os.ModeSymlink != 0 { - ret |= p.QTSYMLINK + ret |= QTSYMLINK } return ret @@ -100,33 +98,33 @@ func dir2QidType(d os.FileInfo) uint8 { func dir2Npmode(d os.FileInfo, dotu bool) uint32 { ret := uint32(d.Mode() & 0777) if d.IsDir() { - ret |= p.DMDIR + ret |= DMDIR } if dotu { mode := d.Mode() if mode&os.ModeSymlink != 0 { - ret |= p.DMSYMLINK + ret |= DMSYMLINK } if mode&os.ModeSocket != 0 { - ret |= p.DMSOCKET + ret |= DMSOCKET } if mode&os.ModeNamedPipe != 0 { - ret |= p.DMNAMEDPIPE + ret |= DMNAMEDPIPE } if mode&os.ModeDevice != 0 { - ret |= p.DMDEVICE + ret |= DMDEVICE } if mode&os.ModeSetuid != 0 { - ret |= p.DMSETUID + ret |= DMSETUID } if mode&os.ModeSetgid != 0 { - ret |= p.DMSETGID + ret |= DMSETGID } } @@ -135,48 +133,47 @@ func dir2Npmode(d os.FileInfo, dotu bool) uint32 { // Dir is an instantiation of the p.Dir structure // that can act as a receiver for local methods. -type Dir struct { - p.Dir +type ufsDir struct { + Dir } -func (*Ufs) ConnOpened(conn *srv.Conn) { +func (*Ufs) ConnOpened(conn *Conn) { if conn.Srv.Debuglevel > 0 { log.Println("connected") } } -func (*Ufs) ConnClosed(conn *srv.Conn) { +func (*Ufs) ConnClosed(conn *Conn) { if conn.Srv.Debuglevel > 0 { log.Println("disconnected") } } -func (*Ufs) FidDestroy(sfid *srv.Fid) { - var fid *Fid +func (*Ufs) FidDestroy(sfid *SrvFid) { + var fid *ufsFid if sfid.Aux == nil { return } - fid = sfid.Aux.(*Fid) + fid = sfid.Aux.(*ufsFid) if fid.file != nil { fid.file.Close() } } -func (*Ufs) Attach(req *srv.Req) { +func (ufs *Ufs) Attach(req *SrvReq) { if req.Afid != nil { - req.RespondError(srv.Enoauth) + req.RespondError(Enoauth) return } tc := req.Tc - fid := new(Fid) - if len(tc.Aname) == 0 { - fid.path = root - } else { - fid.path = tc.Aname - } + fid := new(ufsFid) + // You can think of the ufs.Root as a 'chroot' of a sort. + // clients attach are not allowed to go outside the + // directory represented by ufs.Root + fid.path = path.Join(ufs.Root, tc.Aname) req.Fid.Aux = fid err := fid.stat() @@ -189,10 +186,10 @@ func (*Ufs) Attach(req *srv.Req) { req.RespondRattach(qid) } -func (*Ufs) Flush(req *srv.Req) {} +func (*Ufs) Flush(req *SrvReq) {} -func (*Ufs) Walk(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Walk(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) tc := req.Tc err := fid.stat() @@ -202,11 +199,11 @@ func (*Ufs) Walk(req *srv.Req) { } if req.Newfid.Aux == nil { - req.Newfid.Aux = new(Fid) + req.Newfid.Aux = new(ufsFid) } - nfid := req.Newfid.Aux.(*Fid) - wqids := make([]p.Qid, len(tc.Wname)) + nfid := req.Newfid.Aux.(*ufsFid) + wqids := make([]Qid, len(tc.Wname)) path := fid.path i := 0 for ; i < len(tc.Wname); i++ { @@ -229,8 +226,8 @@ func (*Ufs) Walk(req *srv.Req) { req.RespondRwalk(wqids[0:i]) } -func (*Ufs) Open(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Open(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) tc := req.Tc err := fid.stat() if err != nil { @@ -248,8 +245,8 @@ func (*Ufs) Open(req *srv.Req) { req.RespondRopen(dir2Qid(fid.st), 0) } -func (*Ufs) Create(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Create(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) tc := req.Tc err := fid.stat() if err != nil { @@ -261,13 +258,13 @@ func (*Ufs) Create(req *srv.Req) { var e error = nil var file *os.File = nil switch { - case tc.Perm&p.DMDIR != 0: + case tc.Perm&DMDIR != 0: e = os.Mkdir(path, os.FileMode(tc.Perm&0777)) - case tc.Perm&p.DMSYMLINK != 0: + case tc.Perm&DMSYMLINK != 0: e = os.Symlink(tc.Ext, path) - case tc.Perm&p.DMLINK != 0: + case tc.Perm&DMLINK != 0: n, e := strconv.ParseUint(tc.Ext, 10, 0) if e != nil { break @@ -275,25 +272,25 @@ func (*Ufs) Create(req *srv.Req) { ofid := req.Conn.FidGet(uint32(n)) if ofid == nil { - req.RespondError(srv.Eunknownfid) + req.RespondError(Eunknownfid) return } - e = os.Link(ofid.Aux.(*Fid).path, path) + e = os.Link(ofid.Aux.(*ufsFid).path, path) ofid.DecRef() - case tc.Perm&p.DMNAMEDPIPE != 0: - case tc.Perm&p.DMDEVICE != 0: - req.RespondError(&p.Error{"not implemented", p.EIO}) + case tc.Perm&DMNAMEDPIPE != 0: + case tc.Perm&DMDEVICE != 0: + req.RespondError(&Error{"not implemented", EIO}) return default: var mode uint32 = tc.Perm & 0777 if req.Conn.Dotu { - if tc.Perm&p.DMSETUID > 0 { + if tc.Perm&DMSETUID > 0 { mode |= syscall.S_ISUID } - if tc.Perm&p.DMSETGID > 0 { + if tc.Perm&DMSETGID > 0 { mode |= syscall.S_ISGID } } @@ -320,8 +317,8 @@ func (*Ufs) Create(req *srv.Req) { req.RespondRcreate(dir2Qid(fid.st), 0) } -func (*Ufs) Read(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Read(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) tc := req.Tc rc := req.Rc err := fid.stat() @@ -330,67 +327,83 @@ func (*Ufs) Read(req *srv.Req) { return } - p.InitRread(rc, tc.Count) + InitRread(rc, tc.Count) var count int var e error if fid.st.IsDir() { - b := rc.Data if tc.Offset == 0 { + var e error + // If we got here, it was open. Can't really seek + // in most cases, just close and reopen it. fid.file.Close() - fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0) - if e != nil { + if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil { req.RespondError(toError(e)) return } - } - - 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 { - break - } + if fid.dirs, e = fid.file.Readdir(-1); e != nil { + req.RespondError(toError(e)) + return } - var i int - for i = 0; i < len(fid.dirs); i++ { + fid.dirents = nil + fid.direntends = nil + for i := 0; i < len(fid.dirs); i++ { path := fid.path + "/" + fid.dirs[i].Name() - st := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool) - sz := p.PackDir(st, b, req.Conn.Dotu) - if sz == 0 { - break + st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool) + if st == nil { + continue } - - b = b[sz:] - count += sz + b := PackDir(st, req.Conn.Dotu) + fid.dirents = append(fid.dirents, b...) + count += len(b) + fid.direntends = append(fid.direntends, count) } + } + + switch { + case tc.Offset > uint64(len(fid.dirents)): + count = 0 + case len(fid.dirents[tc.Offset:]) > int(tc.Count): + count = int(tc.Count) + default: + count = len(fid.dirents[tc.Offset:]) + } - if i < len(fid.dirs) { - fid.dirs = fid.dirs[i:] - break - } else { - fid.dirs = nil + if !*Akaros { + nextend := sort.SearchInts(fid.direntends, int(tc.Offset)+count) + if nextend < len(fid.direntends) { + if fid.direntends[nextend] > int(tc.Offset)+count { + if nextend > 0 { + count = fid.direntends[nextend-1] - int(tc.Offset) + } else { + count = 0 + } + } + } + if count == 0 && int(tc.Offset) < len(fid.dirents) && len(fid.dirents) > 0 { + req.RespondError(&Error{"too small read size for dir entry", EINVAL}) + return } } + + copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count]) + } else { count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset)) if e != nil && e != io.EOF { req.RespondError(toError(e)) return } + } - p.SetRreadCount(rc, uint32(count)) + SetRreadCount(rc, uint32(count)) req.Respond() } -func (*Ufs) Write(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Write(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) tc := req.Tc err := fid.stat() if err != nil { @@ -407,10 +420,10 @@ func (*Ufs) Write(req *srv.Req) { req.RespondRwrite(uint32(n)) } -func (*Ufs) Clunk(req *srv.Req) { req.RespondRclunk() } +func (*Ufs) Clunk(req *SrvReq) { req.RespondRclunk() } -func (*Ufs) Remove(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Remove(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) err := fid.stat() if err != nil { req.RespondError(err) @@ -426,25 +439,30 @@ func (*Ufs) Remove(req *srv.Req) { req.RespondRremove() } -func (*Ufs) Stat(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (*Ufs) Stat(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) err := fid.stat() if err != nil { req.RespondError(err) return } - st := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool) + st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool) + if st == nil { + req.RespondError(derr) + return + } + req.RespondRstat(st) } -func lookup(uid string, group bool) (uint32, *p.Error) { +func lookup(uid string, group bool) (uint32, *Error) { if uid == "" { - return p.NOUID, nil + return NOUID, nil } usr, e := user.Lookup(uid) if e != nil { - return p.NOUID, toError(e) + return NOUID, toError(e) } conv := usr.Uid if group { @@ -452,23 +470,12 @@ func lookup(uid string, group bool) (uint32, *p.Error) { } u, e := strconv.Atoi(conv) if e != nil { - return p.NOUID, toError(e) + return NOUID, toError(e) } return uint32(u), nil } -func StartServer(addrVal string, debugVal int, rootVal string) { - addr = addrVal - debug = debugVal - root = rootVal - ufs := new(Ufs) - ufs.Dotu = true - ufs.Id = "ufs" - ufs.Debuglevel = debug - ufs.Start(ufs) - - err := ufs.StartNetListener("tcp", addr) - if err != nil { - log.Println(err) - } -} +/* enables "Akaros" capabilities, which right now means + * a sane error message format. + */ +var Akaros = flag.Bool("akaros", false, "Akaros extensions") diff --git a/third_party/go9p/ufs/ufs.go b/third_party/go9p/ufs/ufs.go new file mode 100644 index 000000000..34ca8a528 --- /dev/null +++ b/third_party/go9p/ufs/ufs.go @@ -0,0 +1,29 @@ +// Copyright 2009 The go9p Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ufs + +import ( + "fmt" + "log" + + "k8s.io/minikube/third_party/go9p" +) + +func StartServer(addrVal string, debugVal int, rootVal string) { + ufs := new(go9p.Ufs) + ufs.Dotu = true + ufs.Id = "ufs" + ufs.Root = rootVal + ufs.Debuglevel = debugVal + ufs.Start(ufs) + + fmt.Print("ufs starting\n") + // determined by build tags + //extraFuncs() + err := ufs.StartNetListener("tcp", addrVal) + if err != nil { + log.Println(err) + } +} diff --git a/third_party/go9p/p/srv/examples/ufs/ufs_darwin.go b/third_party/go9p/ufs_darwin.go similarity index 69% rename from third_party/go9p/p/srv/examples/ufs/ufs_darwin.go rename to third_party/go9p/ufs_darwin.go index bd2d03ef8..b7b592e18 100644 --- a/third_party/go9p/p/srv/examples/ufs/ufs_darwin.go +++ b/third_party/go9p/ufs_darwin.go @@ -1,20 +1,18 @@ -// Copyright 2012 The go9p Authors. All rights reserved. +// Copyright 2009 The go9p Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package ufs +package go9p import ( "fmt" "os" "os/user" + "path" "strconv" "strings" "syscall" "time" - - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" ) func atime(stat *syscall.Stat_t) time.Time { @@ -25,16 +23,18 @@ func atime(stat *syscall.Stat_t) time.Time { func isBlock(d os.FileInfo) bool { stat := d.Sys().(*syscall.Stat_t) return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK + return true } // IsChar reports if the file is a character device func isChar(d os.FileInfo) bool { stat := d.Sys().(*syscall.Stat_t) return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR + return true } -func dir2Qid(d os.FileInfo) *p.Qid { - var qid p.Qid +func dir2Qid(d os.FileInfo) *Qid { + var qid Qid qid.Path = d.Sys().(*syscall.Stat_t).Ino qid.Version = uint32(d.ModTime().UnixNano() / 1000000) @@ -43,27 +43,34 @@ func dir2Qid(d os.FileInfo) *p.Qid { return &qid } -func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { - sysMode := d.Sys().(*syscall.Stat_t) +func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) { + if r := recover(); r != nil { + fmt.Print("stat failed: ", r) + return nil, &os.PathError{"dir2Dir", path, nil} + } + sysif := d.Sys() + if sysif == nil { + return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil} + } + sysMode := sysif.(*syscall.Stat_t) - dir := new(Dir) + dir := new(ufsDir) dir.Qid = *dir2Qid(d) dir.Mode = dir2Npmode(d, dotu) - dir.Atime = uint32(atime(sysMode).Unix()) + dir.Atime = uint32(0 /*atime(sysMode).Unix()*/) dir.Mtime = uint32(d.ModTime().Unix()) dir.Length = uint64(d.Size()) dir.Name = path[strings.LastIndex(path, "/")+1:] if dotu { dir.dotu(path, d, upool, sysMode) - return &dir.Dir + return &dir.Dir, nil } unixUid := int(sysMode.Uid) unixGid := int(sysMode.Gid) dir.Uid = strconv.Itoa(unixUid) dir.Gid = strconv.Itoa(unixGid) - dir.Muid = "none" // BUG(akumar): LookupId will never find names for // groups, as it only operates on user ids. @@ -76,10 +83,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { dir.Gid = g.Username } - return &dir.Dir + /* For Akaros, we use the Muid as the link value. */ + if *Akaros && (d.Mode()&os.ModeSymlink != 0) { + dir.Muid, err = os.Readlink(path) + if err == nil { + dir.Mode |= DMSYMLINK + } + } + return &dir.Dir, nil } -func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) { +func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) { u := upool.Uid2User(int(sysMode.Uid)) g := upool.Gid2Group(int(sysMode.Gid)) dir.Uid = u.Name() @@ -95,7 +109,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall dir.Ext = "" dir.Uidnum = uint32(u.Id()) dir.Gidnum = uint32(g.Id()) - dir.Muidnum = p.NOUID + dir.Muidnum = NOUID if d.Mode()&os.ModeSymlink != 0 { var err error dir.Ext, err = os.Readlink(path) @@ -109,8 +123,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall } } -func (*Ufs) Wstat(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (u *Ufs) Wstat(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) err := fid.stat() if err != nil { req.RespondError(err) @@ -121,10 +135,10 @@ func (*Ufs) Wstat(req *srv.Req) { if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 if req.Conn.Dotu { - if dir.Mode&p.DMSETUID > 0 { + if dir.Mode&DMSETUID > 0 { mode |= syscall.S_ISUID } - if dir.Mode&p.DMSETGID > 0 { + if dir.Mode&DMSETGID > 0 { mode |= syscall.S_ISGID } } @@ -135,7 +149,7 @@ func (*Ufs) Wstat(req *srv.Req) { } } - uid, gid := p.NOUID, p.NOUID + uid, gid := NOUID, NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum @@ -159,7 +173,7 @@ func (*Ufs) Wstat(req *srv.Req) { } } - if uid != p.NOUID || gid != p.NOUID { + if uid != NOUID || gid != NOUID { e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) @@ -168,13 +182,25 @@ func (*Ufs) Wstat(req *srv.Req) { } if dir.Name != "" { - path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name - err := syscall.Rename(fid.path, path) + fmt.Printf("Rename %s to %s\n", fid.path, dir.Name) + // if first char is / it is relative to root, else relative to + // cwd. + var destpath string + if dir.Name[0] == '/' { + destpath = path.Join(u.Root, dir.Name) + fmt.Printf("/ results in %s\n", destpath) + } else { + fiddir, _ := path.Split(fid.path) + destpath = path.Join(fiddir, dir.Name) + fmt.Printf("rel results in %s\n", destpath) + } + err := syscall.Rename(fid.path, destpath) + fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err) if err != nil { req.RespondError(toError(err)) return } - fid.path = path + fid.path = destpath } if dir.Length != 0xFFFFFFFFFFFFFFFF { @@ -199,7 +225,7 @@ func (*Ufs) Wstat(req *srv.Req) { case true: mt = st.ModTime() default: - at = atime(st.Sys().(*syscall.Stat_t)) + //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) diff --git a/third_party/go9p/p/srv/examples/ufs/ufs_linux.go b/third_party/go9p/ufs_linux.go similarity index 69% rename from third_party/go9p/p/srv/examples/ufs/ufs_linux.go rename to third_party/go9p/ufs_linux.go index 6743b34bb..03210c377 100644 --- a/third_party/go9p/p/srv/examples/ufs/ufs_linux.go +++ b/third_party/go9p/ufs_linux.go @@ -1,20 +1,14 @@ -// Copyright 2012 The go9p Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ufs +package go9p import ( "fmt" "os" "os/user" + "path" "strconv" "strings" "syscall" "time" - - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" ) func atime(stat *syscall.Stat_t) time.Time { @@ -25,16 +19,18 @@ func atime(stat *syscall.Stat_t) time.Time { func isBlock(d os.FileInfo) bool { stat := d.Sys().(*syscall.Stat_t) return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK + return true } // IsChar reports if the file is a character device func isChar(d os.FileInfo) bool { stat := d.Sys().(*syscall.Stat_t) return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR + return true } -func dir2Qid(d os.FileInfo) *p.Qid { - var qid p.Qid +func dir2Qid(d os.FileInfo) *Qid { + var qid Qid qid.Path = d.Sys().(*syscall.Stat_t).Ino qid.Version = uint32(d.ModTime().UnixNano() / 1000000) @@ -43,27 +39,34 @@ func dir2Qid(d os.FileInfo) *p.Qid { return &qid } -func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { - sysMode := d.Sys().(*syscall.Stat_t) +func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) { + if r := recover(); r != nil { + fmt.Print("stat failed: ", r) + return nil, &os.PathError{"dir2Dir", path, nil} + } + sysif := d.Sys() + if sysif == nil { + return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil} + } + sysMode := sysif.(*syscall.Stat_t) - dir := new(Dir) + dir := new(ufsDir) dir.Qid = *dir2Qid(d) dir.Mode = dir2Npmode(d, dotu) - dir.Atime = uint32(atime(sysMode).Unix()) + dir.Atime = uint32(0 /*atime(sysMode).Unix()*/) dir.Mtime = uint32(d.ModTime().Unix()) dir.Length = uint64(d.Size()) dir.Name = path[strings.LastIndex(path, "/")+1:] if dotu { dir.dotu(path, d, upool, sysMode) - return &dir.Dir + return &dir.Dir, nil } unixUid := int(sysMode.Uid) unixGid := int(sysMode.Gid) dir.Uid = strconv.Itoa(unixUid) dir.Gid = strconv.Itoa(unixGid) - dir.Muid = "none" // BUG(akumar): LookupId will never find names for // groups, as it only operates on user ids. @@ -76,10 +79,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { dir.Gid = g.Username } - return &dir.Dir + /* For Akaros, we use the Muid as the link value. */ + if *Akaros && (d.Mode()&os.ModeSymlink != 0) { + dir.Muid, err = os.Readlink(path) + if err == nil { + dir.Mode |= DMSYMLINK + } + } + return &dir.Dir, nil } -func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) { +func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) { u := upool.Uid2User(int(sysMode.Uid)) g := upool.Gid2Group(int(sysMode.Gid)) dir.Uid = u.Name() @@ -95,7 +105,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall dir.Ext = "" dir.Uidnum = uint32(u.Id()) dir.Gidnum = uint32(g.Id()) - dir.Muidnum = p.NOUID + dir.Muidnum = NOUID if d.Mode()&os.ModeSymlink != 0 { var err error dir.Ext, err = os.Readlink(path) @@ -109,8 +119,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall } } -func (*Ufs) Wstat(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (u *Ufs) Wstat(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) err := fid.stat() if err != nil { req.RespondError(err) @@ -121,10 +131,10 @@ func (*Ufs) Wstat(req *srv.Req) { if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 if req.Conn.Dotu { - if dir.Mode&p.DMSETUID > 0 { + if dir.Mode&DMSETUID > 0 { mode |= syscall.S_ISUID } - if dir.Mode&p.DMSETGID > 0 { + if dir.Mode&DMSETGID > 0 { mode |= syscall.S_ISGID } } @@ -135,7 +145,7 @@ func (*Ufs) Wstat(req *srv.Req) { } } - uid, gid := p.NOUID, p.NOUID + uid, gid := NOUID, NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum @@ -159,7 +169,7 @@ func (*Ufs) Wstat(req *srv.Req) { } } - if uid != p.NOUID || gid != p.NOUID { + if uid != NOUID || gid != NOUID { e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) @@ -168,13 +178,25 @@ func (*Ufs) Wstat(req *srv.Req) { } if dir.Name != "" { - path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name - err := syscall.Rename(fid.path, path) + fmt.Printf("Rename %s to %s\n", fid.path, dir.Name) + // if first char is / it is relative to root, else relative to + // cwd. + var destpath string + if dir.Name[0] == '/' { + destpath = path.Join(u.Root, dir.Name) + fmt.Printf("/ results in %s\n", destpath) + } else { + fiddir, _ := path.Split(fid.path) + destpath = path.Join(fiddir, dir.Name) + fmt.Printf("rel results in %s\n", destpath) + } + err := syscall.Rename(fid.path, destpath) + fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err) if err != nil { req.RespondError(toError(err)) return } - fid.path = path + fid.path = destpath } if dir.Length != 0xFFFFFFFFFFFFFFFF { @@ -199,7 +221,7 @@ func (*Ufs) Wstat(req *srv.Req) { case true: mt = st.ModTime() default: - at = atime(st.Sys().(*syscall.Stat_t)) + //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) diff --git a/third_party/go9p/p/srv/examples/ufs/ufs_windows.go b/third_party/go9p/ufs_windows.go similarity index 68% rename from third_party/go9p/p/srv/examples/ufs/ufs_windows.go rename to third_party/go9p/ufs_windows.go index 428af76a1..b4f761c4f 100644 --- a/third_party/go9p/p/srv/examples/ufs/ufs_windows.go +++ b/third_party/go9p/ufs_windows.go @@ -1,63 +1,39 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2009 The go9p Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// http://golang.org/src/os/stat_windows.go - -package ufs +package go9p import ( + "fmt" "os" + "path" "strings" "syscall" "time" - - "k8s.io/minikube/third_party/go9p/p" - "k8s.io/minikube/third_party/go9p/p/srv" ) -// type Win32FileAttributeData struct { -// FileAttributes uint32 -// CreationTime Filetime -// LastAccessTime Filetime -// LastWriteTime Filetime -// FileSizeHigh uint32 -// FileSizeLow uint32 -// } - -// A FileInfo describes a file and is returned by Stat and Lstat. -// type FileInfo interface { -// Name() string // base name of the file -// Size() int64 // length in bytes for regular files; system-dependent for others -// Mode() FileMode // file mode bits -// ModTime() time.Time // modification time -// IsDir() bool // abbreviation for Mode().IsDir() -// Sys() interface{} // underlying data source (can return nil) -// } - func atime(fi os.FileInfo) time.Time { return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) } // IsBlock reports if the file is a block device func isBlock(d os.FileInfo) bool { - // return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) - // stat := d.Sys().(os.FileInfo) + // stat := d.Sys().(*syscall.Stat_t) // return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK return true } // IsChar reports if the file is a character device func isChar(d os.FileInfo) bool { - // stat := d.Sys().(os.FileInfo) + // stat := d.Sys().(*syscall.Stat_t) // return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR return true } -func dir2Qid(d os.FileInfo) *p.Qid { - var qid p.Qid +func dir2Qid(d os.FileInfo) *Qid { + var qid Qid - // d.Sys().(*syscall.Win32FileAttributeData) qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow) qid.Version = uint32(d.ModTime().UnixNano() / 1000000) qid.Type = dir2QidType(d) @@ -65,20 +41,28 @@ func dir2Qid(d os.FileInfo) *p.Qid { return &qid } -func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { - // sysMode := d.Sys().(os.FileInfo) +func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) { + if r := recover(); r != nil { + fmt.Print("stat failed: ", r) + return nil, &os.PathError{"dir2Dir", path, nil} + } + sysif := d.Sys() + if sysif == nil { + return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil} + } + sysMode := sysif.(*syscall.Win32FileAttributeData) - dir := new(Dir) + dir := new(ufsDir) dir.Qid = *dir2Qid(d) dir.Mode = dir2Npmode(d, dotu) - // dir.Atime = uint32(atime(sysMode).Unix()) + // dir.Atime = uint32(0 /*atime(sysMode).Unix()*/) // dir.Mtime = uint32(d.ModTime().Unix()) dir.Length = uint64(d.Size()) dir.Name = path[strings.LastIndex(path, "/")+1:] if dotu { - // dir.dotu(path, d, upool, sysMode) - return &dir.Dir + dir.dotu(path, d, upool, sysMode) + return &dir.Dir, nil } // unixUid := int(sysMode.Uid) @@ -101,10 +85,18 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir { // dir.Gid = g.Username // } - return &dir.Dir + var err error + /* For Akaros, we use the Muid as the link value. */ + if *Akaros && (d.Mode()&os.ModeSymlink != 0) { + dir.Muid, err = os.Readlink(path) + if err == nil { + dir.Mode |= DMSYMLINK + } + } + return &dir.Dir, nil } -func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) { +func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) { // u := upool.Uid2User(int(sysMode.Uid)) // g := upool.Gid2Group(int(sysMode.Gid)) // dir.Uid = u.Name() @@ -120,7 +112,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) { // dir.Ext = "" // dir.Uidnum = uint32(u.Id()) // dir.Gidnum = uint32(g.Id()) - // dir.Muidnum = p.NOUID + // dir.Muidnum = NOUID // if d.Mode()&os.ModeSymlink != 0 { // var err error // dir.Ext, err = os.Readlink(path) @@ -137,12 +129,12 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) { dir.Muid = "none" dir.Uidnum = 0 dir.Gidnum = 0 - dir.Muidnum = p.NOUID + dir.Muidnum = NOUID dir.Ext = "" } -func (*Ufs) Wstat(req *srv.Req) { - fid := req.Fid.Aux.(*Fid) +func (u *Ufs) Wstat(req *SrvReq) { + fid := req.Fid.Aux.(*ufsFid) err := fid.stat() if err != nil { req.RespondError(err) @@ -153,10 +145,10 @@ func (*Ufs) Wstat(req *srv.Req) { if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 if req.Conn.Dotu { - if dir.Mode&p.DMSETUID > 0 { + if dir.Mode&DMSETUID > 0 { mode |= syscall.S_ISUID } - if dir.Mode&p.DMSETGID > 0 { + if dir.Mode&DMSETGID > 0 { mode |= syscall.S_ISGID } } @@ -167,7 +159,7 @@ func (*Ufs) Wstat(req *srv.Req) { } } - uid, gid := p.NOUID, p.NOUID + uid, gid := NOUID, NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum @@ -191,7 +183,7 @@ func (*Ufs) Wstat(req *srv.Req) { } } - if uid != p.NOUID || gid != p.NOUID { + if uid != NOUID || gid != NOUID { e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) @@ -200,13 +192,25 @@ func (*Ufs) Wstat(req *srv.Req) { } if dir.Name != "" { - path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name - err := syscall.Rename(fid.path, path) + fmt.Printf("Rename %s to %s\n", fid.path, dir.Name) + // if first char is / it is relative to root, else relative to + // cwd. + var destpath string + if dir.Name[0] == '/' { + destpath = path.Join(u.Root, dir.Name) + fmt.Printf("/ results in %s\n", destpath) + } else { + fiddir, _ := path.Split(fid.path) + destpath = path.Join(fiddir, dir.Name) + fmt.Printf("rel results in %s\n", destpath) + } + err := syscall.Rename(fid.path, destpath) + fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err) if err != nil { req.RespondError(toError(err)) return } - fid.path = path + fid.path = destpath } if dir.Length != 0xFFFFFFFFFFFFFFFF { @@ -231,7 +235,7 @@ func (*Ufs) Wstat(req *srv.Req) { // case true: // mt = st.ModTime() // default: - // at = atime(st.Sys().(os.FileInfo)) + // //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t)) // } // } // e := os.Chtimes(fid.path, at, mt) diff --git a/third_party/go9p/p/unpack.go b/third_party/go9p/unpack.go similarity index 90% rename from third_party/go9p/p/unpack.go rename to third_party/go9p/unpack.go index a093bc785..8c19e0bc2 100644 --- a/third_party/go9p/p/unpack.go +++ b/third_party/go9p/unpack.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package p +package go9p import ( "fmt" @@ -77,9 +77,14 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) { goto szerror } - fc.Unamenum = NOUID - if dotu && len(p) > 0 { - fc.Unamenum, p = gint32(p) + if dotu { + if len(p) > 0 { + fc.Unamenum, p = gint32(p) + } else { + fc.Unamenum = NOUID + } + } else { + fc.Unamenum = NOUID } case Rauth, Rattach: @@ -101,9 +106,12 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) { goto szerror } - fc.Unamenum = NOUID - if dotu && len(p) > 0 { - fc.Unamenum, p = gint32(p) + if dotu { + if len(p) > 0 { + fc.Unamenum, p = gint32(p) + } else { + fc.Unamenum = NOUID + } } case Rerror: @@ -193,15 +201,15 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) { case Rstat: m, p = gint16(p) - p = gstat(p, &fc.Dir, dotu) - if p == nil { - goto szerror + p, err = gstat(p, &fc.Dir, dotu) + if err != nil { + return nil, err, 0 } case Twstat: fc.Fid, p = gint32(p) m, p = gint16(p) - p = gstat(p, &fc.Dir, dotu) + p, _ = gstat(p, &fc.Dir, dotu) case Rflush, Rclunk, Rremove, Rwstat: } -- GitLab