Update mount implementation, add mount integration tests, and check that path exists.
parent
12e41aeaba
commit
8e801e3975
|
@ -26,7 +26,7 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/cluster"
|
"k8s.io/minikube/pkg/minikube/cluster"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
"k8s.io/minikube/pkg/minikube/machine"
|
"k8s.io/minikube/pkg/minikube/machine"
|
||||||
"k8s.io/minikube/third_party/go9p/p/srv/examples/ufs"
|
"k8s.io/minikube/third_party/go9p/ufs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// mountCmd represents the mount command
|
// mountCmd represents the mount command
|
||||||
|
@ -42,6 +42,15 @@ var mountCmd = &cobra.Command{
|
||||||
fmt.Fprintln(os.Stderr, errText)
|
fmt.Fprintln(os.Stderr, errText)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
if _, err := os.Stat(args[0]); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
errText := fmt.Sprintf("Cannot find directory %s for mount", args[0])
|
||||||
|
fmt.Fprintln(os.Stderr, errText)
|
||||||
|
} else {
|
||||||
|
errText := fmt.Sprintf("Error accesssing directory %s for mount", args[0])
|
||||||
|
fmt.Fprintln(os.Stderr, errText)
|
||||||
|
}
|
||||||
|
}
|
||||||
var debugVal int
|
var debugVal int
|
||||||
if glog.V(1) {
|
if glog.V(1) {
|
||||||
debugVal = 1 // ufs.StartServer takes int debug param
|
debugVal = 1 // ufs.StartServer takes int debug param
|
||||||
|
|
|
@ -30,6 +30,7 @@ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH} out/
|
||||||
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH} out/
|
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH} out/
|
||||||
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox.yaml testdata/
|
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox.yaml testdata/
|
||||||
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/pvc.yaml testdata/
|
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/pvc.yaml testdata/
|
||||||
|
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox-mount-test.yaml testdata/
|
||||||
|
|
||||||
# Set the executable bit on the e2e binary and out binary
|
# Set the executable bit on the e2e binary and out binary
|
||||||
chmod +x out/e2e-${OS_ARCH}
|
chmod +x out/e2e-${OS_ARCH}
|
||||||
|
@ -63,4 +64,4 @@ curl "https://api.github.com/repos/kubernetes/minikube/statuses/${COMMIT}?access
|
||||||
-d "{\"state\": \"$status\", \"description\": \"Jenkins\", \"target_url\": \"$target_url\", \"context\": \"${JOB_NAME}\"}"
|
-d "{\"state\": \"$status\", \"description\": \"Jenkins\", \"target_url\": \"$target_url\", \"context\": \"${JOB_NAME}\"}"
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
exit $result
|
exit $result
|
||||||
|
|
|
@ -408,6 +408,7 @@ func Mount9pHost(api libmachine.API) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Error getting the host IP address to use from within the VM")
|
return errors.Wrap(err, "Error getting the host IP address to use from within the VM")
|
||||||
}
|
}
|
||||||
|
host.RunSSHCommand(GetMount9pCleanupCommand())
|
||||||
_, err = host.RunSSHCommand(GetMount9pCommand(ip))
|
_, err = host.RunSSHCommand(GetMount9pCommand(ip))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -77,7 +77,7 @@ func getVMHostIP(host *host.Host) (net.IP, error) {
|
||||||
case "virtualbox":
|
case "virtualbox":
|
||||||
return net.ParseIP("10.0.2.2"), nil
|
return net.ParseIP("10.0.2.2"), nil
|
||||||
case "xhyve":
|
case "xhyve":
|
||||||
return net.ParseIP("10.0.2.2"), nil
|
return net.ParseIP("192.168.64.1"), nil
|
||||||
default:
|
default:
|
||||||
return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver")
|
return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver")
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) {
|
||||||
flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates)
|
flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates)
|
||||||
}
|
}
|
||||||
|
|
||||||
if kubernetesConfig.APIServerName != "" {
|
if kubernetesConfig.APIServerName != constants.APIServerName {
|
||||||
flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName)
|
flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,9 +226,16 @@ else
|
||||||
fi
|
fi
|
||||||
`, constants.LocalkubePIDPath)
|
`, constants.LocalkubePIDPath)
|
||||||
|
|
||||||
|
func GetMount9pCleanupCommand() string {
|
||||||
|
return `
|
||||||
|
sudo umount /mount-9p;
|
||||||
|
sudo rm -rf /mount-9p;
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
func GetMount9pCommand(ip net.IP) string {
|
func GetMount9pCommand(ip net.IP) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
sudo mkdir /mount-9p;
|
sudo mkdir /mount-9p;
|
||||||
sudo mount -t 9p -o trans=tcp -o port=5640 %s /mount-9p;
|
sudo mount -t 9p -o trans=tcp -o port=5640 -o uid=1001 -o gid=1001 %s /mount-9p;
|
||||||
sudo chmod 775 /mount-9p;`, ip)
|
sudo chmod 775 /mount-9p;`, ip)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,4 +41,5 @@ func TestFunctional(t *testing.T) {
|
||||||
t.Run("Dashboard", testDashboard)
|
t.Run("Dashboard", testDashboard)
|
||||||
t.Run("ServicesList", testServicesList)
|
t.Run("ServicesList", testServicesList)
|
||||||
t.Run("Provisioning", testProvisioning)
|
t.Run("Provisioning", testProvisioning)
|
||||||
|
t.Run("Mounting", testMounting)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -69,6 +69,17 @@ func (m *MinikubeRunner) RunCommand(command string, checkError bool) string {
|
||||||
return string(stdout)
|
return string(stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MinikubeRunner) RunDaemon(command string) *exec.Cmd {
|
||||||
|
commandArr := strings.Split(command, " ")
|
||||||
|
path, _ := filepath.Abs(m.BinaryPath)
|
||||||
|
cmd := exec.Command(path, commandArr...)
|
||||||
|
err := cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
m.T.Fatalf("Error running command: %s %s", command, err)
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MinikubeRunner) SSH(command string) (string, error) {
|
func (m *MinikubeRunner) SSH(command string) (string, error) {
|
||||||
path, _ := filepath.Abs(m.BinaryPath)
|
path, _ := filepath.Abs(m.BinaryPath)
|
||||||
cmd := exec.Command(path, "ssh", command)
|
cmd := exec.Command(path, "ssh", command)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
*.orig
|
||||||
|
*.rej
|
|
@ -1,13 +0,0 @@
|
||||||
# This is the official list of Go9p authors for copyright purposes.
|
|
||||||
# This file is distinct from the CONTRIBUTORS files.
|
|
||||||
# See the latter for an explanation.
|
|
||||||
|
|
||||||
# Names should be added to this file as
|
|
||||||
# Name or Organization <email address>
|
|
||||||
# The email address is not required for organizations.
|
|
||||||
|
|
||||||
# Please keep the list sorted.
|
|
||||||
|
|
||||||
Andrey Mirtchovski <mirtchovski@gmail.com>
|
|
||||||
Latchesar Ionkov <lionkov@gmail.com>
|
|
||||||
Roger Peppe <rogpeppe@gmail.com>
|
|
|
@ -1,18 +0,0 @@
|
||||||
# This is the official list of people who can contribute
|
|
||||||
# (and typically have contributed) code to the Go9p repository.
|
|
||||||
# The AUTHORS file lists the copyright holders; this file
|
|
||||||
# lists people. For example, Google employees are listed here
|
|
||||||
# but not in AUTHORS, because Google holds the copyright.
|
|
||||||
#
|
|
||||||
# The submission process automatically checks to make sure
|
|
||||||
# that people submitting code are listed in this file (by email address).
|
|
||||||
# XXX more bumph here?
|
|
||||||
# Names should be added to this file like so:
|
|
||||||
# Name <email address>
|
|
||||||
|
|
||||||
# Please keep the list sorted.
|
|
||||||
|
|
||||||
Andrey Mirtchovski <mirtchovski@gmail.com>
|
|
||||||
Latchesar Ionkov <lionkov@gmail.com>
|
|
||||||
Akshat Kumar <seed@mail.nanosouffle.net>
|
|
||||||
Roger Peppe <rogpeppe@gmail.com>
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
This is go9p done in a way that I can understand.
|
||||||
|
|
||||||
|
To install:
|
||||||
|
export GOPATH=~rminnich/go
|
||||||
|
go get -a /k8s.io/minikube/third_party/go9p
|
||||||
|
go get -a /k8s.io/minikube/third_party/go9p/ufs
|
||||||
|
go install -a /k8s.io/minikube/third_party/go9p/ufs
|
||||||
|
|
||||||
|
~/go/bin/ufs
|
||||||
|
|
||||||
|
|
121
third_party/go9p/p/clnt/clnt.go → third_party/go9p/clnt_clnt.go
vendored
Executable file → Normal file
121
third_party/go9p/p/clnt/clnt.go → third_party/go9p/clnt_clnt.go
vendored
Executable file → Normal file
|
@ -2,31 +2,18 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// The clnt package provides definitions and functions used to implement
|
// The clnt package go9provides definitions and functions used to implement
|
||||||
// a 9P2000 file client.
|
// a 9P2000 file client.
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Debug flags
|
|
||||||
const (
|
|
||||||
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr
|
|
||||||
DbgPrintPackets // print the raw packets on stderr
|
|
||||||
DbgLogFcalls // keep the last N 9P messages (can be accessed over http)
|
|
||||||
DbgLogPackets // keep the last N 9P messages (can be accessed over http)
|
|
||||||
)
|
|
||||||
|
|
||||||
type StatsOps interface {
|
|
||||||
statsRegister()
|
|
||||||
statsUnregister()
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Clnt type represents a 9P2000 client. The client is connected to
|
// The Clnt type represents a 9P2000 client. The client is connected to
|
||||||
// a 9P2000 file server and its methods can be used to access and manipulate
|
// a 9P2000 file server and its methods can be used to access and manipulate
|
||||||
// the files exported by the server.
|
// the files exported by the server.
|
||||||
|
@ -37,7 +24,7 @@ type Clnt struct {
|
||||||
Dotu bool // If true, 9P2000.u protocol is spoken
|
Dotu bool // If true, 9P2000.u protocol is spoken
|
||||||
Root *Fid // Fid that points to the rood directory
|
Root *Fid // Fid that points to the rood directory
|
||||||
Id string // Used when printing debug messages
|
Id string // Used when printing debug messages
|
||||||
Log *p.Logger
|
Log *Logger
|
||||||
|
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
tagpool *pool
|
tagpool *pool
|
||||||
|
@ -49,7 +36,7 @@ type Clnt struct {
|
||||||
err error
|
err error
|
||||||
|
|
||||||
reqchan chan *Req
|
reqchan chan *Req
|
||||||
tchan chan *p.Fcall
|
tchan chan *Fcall
|
||||||
|
|
||||||
next, prev *Clnt
|
next, prev *Clnt
|
||||||
}
|
}
|
||||||
|
@ -60,33 +47,26 @@ type Fid struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
Clnt *Clnt // Client the fid belongs to
|
Clnt *Clnt // Client the fid belongs to
|
||||||
Iounit uint32
|
Iounit uint32
|
||||||
p.Qid // The Qid description for the file
|
Qid // The Qid description for the file
|
||||||
Mode uint8 // Open mode (one of p.O* values) (if file is open)
|
Mode uint8 // Open mode (one of O* values) (if file is open)
|
||||||
Fid uint32 // Fid number
|
Fid uint32 // Fid number
|
||||||
p.User // The user the fid belongs to
|
User // The user the fid belongs to
|
||||||
walked bool // true if the fid points to a walked file on the server
|
walked bool // true if the fid points to a walked file on the server
|
||||||
}
|
}
|
||||||
|
|
||||||
// The file is similar to the Fid, but is used in the high-level client
|
// The file is similar to the Fid, but is used in the high-level client
|
||||||
// interface.
|
// interface. We expose the Fid so that client code can use Remove
|
||||||
|
// on a fid, the same way a kernel can.
|
||||||
type File struct {
|
type File struct {
|
||||||
fid *Fid
|
Fid *Fid
|
||||||
offset uint64
|
offset uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type pool struct {
|
|
||||||
sync.Mutex
|
|
||||||
need int
|
|
||||||
nchan chan uint32
|
|
||||||
maxid uint32
|
|
||||||
imap []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type Req struct {
|
type Req struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
Clnt *Clnt
|
Clnt *Clnt
|
||||||
Tc *p.Fcall
|
Tc *Fcall
|
||||||
Rc *p.Fcall
|
Rc *Fcall
|
||||||
Err error
|
Err error
|
||||||
Done chan *Req
|
Done chan *Req
|
||||||
tag uint16
|
tag uint16
|
||||||
|
@ -101,18 +81,18 @@ type ClntList struct {
|
||||||
|
|
||||||
var clnts *ClntList
|
var clnts *ClntList
|
||||||
var DefaultDebuglevel int
|
var DefaultDebuglevel int
|
||||||
var DefaultLogger *p.Logger
|
var DefaultLogger *Logger
|
||||||
|
|
||||||
func (clnt *Clnt) Rpcnb(r *Req) error {
|
func (clnt *Clnt) Rpcnb(r *Req) error {
|
||||||
var tag uint16
|
var tag uint16
|
||||||
|
|
||||||
if r.Tc.Type == p.Tversion {
|
if r.Tc.Type == Tversion {
|
||||||
tag = p.NOTAG
|
tag = NOTAG
|
||||||
} else {
|
} else {
|
||||||
tag = r.tag
|
tag = r.tag
|
||||||
}
|
}
|
||||||
|
|
||||||
p.SetTag(r.Tc, tag)
|
SetTag(r.Tc, tag)
|
||||||
clnt.Lock()
|
clnt.Lock()
|
||||||
if clnt.err != nil {
|
if clnt.err != nil {
|
||||||
clnt.Unlock()
|
clnt.Unlock()
|
||||||
|
@ -133,7 +113,7 @@ func (clnt *Clnt) Rpcnb(r *Req) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
|
func (clnt *Clnt) Rpc(tc *Fcall) (rc *Fcall, err error) {
|
||||||
r := clnt.ReqAlloc()
|
r := clnt.ReqAlloc()
|
||||||
r.Tc = tc
|
r.Tc = tc
|
||||||
r.Done = make(chan *Req)
|
r.Done = make(chan *Req)
|
||||||
|
@ -151,13 +131,15 @@ func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
|
||||||
|
|
||||||
func (clnt *Clnt) recv() {
|
func (clnt *Clnt) recv() {
|
||||||
var err error
|
var err error
|
||||||
|
var buf []byte
|
||||||
|
|
||||||
err = nil
|
err = nil
|
||||||
buf := make([]byte, clnt.Msize*8)
|
|
||||||
pos := 0
|
pos := 0
|
||||||
for {
|
for {
|
||||||
if len(buf) < int(clnt.Msize) {
|
// Connect can change the client Msize.
|
||||||
b := make([]byte, clnt.Msize*8)
|
clntmsize := int(atomic.LoadUint32(&clnt.Msize))
|
||||||
|
if len(buf) < clntmsize {
|
||||||
|
b := make([]byte, clntmsize*8)
|
||||||
copy(b, buf[0:pos])
|
copy(b, buf[0:pos])
|
||||||
buf = b
|
buf = b
|
||||||
b = nil
|
b = nil
|
||||||
|
@ -165,7 +147,7 @@ func (clnt *Clnt) recv() {
|
||||||
|
|
||||||
n, oerr := clnt.conn.Read(buf[pos:])
|
n, oerr := clnt.conn.Read(buf[pos:])
|
||||||
if oerr != nil || n == 0 {
|
if oerr != nil || n == 0 {
|
||||||
err = &p.Error{oerr.Error(), p.EIO}
|
err = &Error{oerr.Error(), EIO}
|
||||||
clnt.Lock()
|
clnt.Lock()
|
||||||
clnt.err = err
|
clnt.err = err
|
||||||
clnt.Unlock()
|
clnt.Unlock()
|
||||||
|
@ -174,10 +156,10 @@ func (clnt *Clnt) recv() {
|
||||||
|
|
||||||
pos += n
|
pos += n
|
||||||
for pos > 4 {
|
for pos > 4 {
|
||||||
sz, _ := p.Gint32(buf)
|
sz, _ := Gint32(buf)
|
||||||
if pos < int(sz) {
|
if pos < int(sz) {
|
||||||
if len(buf) < int(sz) {
|
if len(buf) < int(sz) {
|
||||||
b := make([]byte, clnt.Msize*8)
|
b := make([]byte, atomic.LoadUint32(&clnt.Msize)*8)
|
||||||
copy(b, buf[0:pos])
|
copy(b, buf[0:pos])
|
||||||
buf = b
|
buf = b
|
||||||
b = nil
|
b = nil
|
||||||
|
@ -186,7 +168,7 @@ func (clnt *Clnt) recv() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fc, err, fcsize := p.Unpack(buf, clnt.Dotu)
|
fc, err, fcsize := Unpack(buf, clnt.Dotu)
|
||||||
clnt.Lock()
|
clnt.Lock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
clnt.err = err
|
clnt.err = err
|
||||||
|
@ -214,7 +196,7 @@ func (clnt *Clnt) recv() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if r == nil {
|
if r == nil {
|
||||||
clnt.err = &p.Error{"unexpected response", p.EINVAL}
|
clnt.err = &Error{"unexpected response", EINVAL}
|
||||||
clnt.conn.Close()
|
clnt.conn.Close()
|
||||||
clnt.Unlock()
|
clnt.Unlock()
|
||||||
goto closed
|
goto closed
|
||||||
|
@ -235,13 +217,13 @@ func (clnt *Clnt) recv() {
|
||||||
clnt.Unlock()
|
clnt.Unlock()
|
||||||
|
|
||||||
if r.Tc.Type != r.Rc.Type-1 {
|
if r.Tc.Type != r.Rc.Type-1 {
|
||||||
if r.Rc.Type != p.Rerror {
|
if r.Rc.Type != Rerror {
|
||||||
r.Err = &p.Error{"invalid response", p.EINVAL}
|
r.Err = &Error{"invalid response", EINVAL}
|
||||||
log.Println(fmt.Sprintf("TTT %v", r.Tc))
|
log.Println(fmt.Sprintf("TTT %v", r.Tc))
|
||||||
log.Println(fmt.Sprintf("RRR %v", r.Rc))
|
log.Println(fmt.Sprintf("RRR %v", r.Rc))
|
||||||
} else {
|
} else {
|
||||||
if r.Err == nil {
|
if r.Err == nil {
|
||||||
r.Err = &p.Error{r.Rc.Error, r.Rc.Errornum}
|
r.Err = &Error{r.Rc.Error, r.Rc.Errornum}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,12 +317,12 @@ func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt {
|
||||||
clnt.Debuglevel = DefaultDebuglevel
|
clnt.Debuglevel = DefaultDebuglevel
|
||||||
clnt.Log = DefaultLogger
|
clnt.Log = DefaultLogger
|
||||||
clnt.Id = c.RemoteAddr().String() + ":"
|
clnt.Id = c.RemoteAddr().String() + ":"
|
||||||
clnt.tagpool = newPool(uint32(p.NOTAG))
|
clnt.tagpool = newPool(uint32(NOTAG))
|
||||||
clnt.fidpool = newPool(p.NOFID)
|
clnt.fidpool = newPool(NOFID)
|
||||||
clnt.reqout = make(chan *Req)
|
clnt.reqout = make(chan *Req)
|
||||||
clnt.done = make(chan bool)
|
clnt.done = make(chan bool)
|
||||||
clnt.reqchan = make(chan *Req, 16)
|
clnt.reqchan = make(chan *Req, 16)
|
||||||
clnt.tchan = make(chan *p.Fcall, 16)
|
clnt.tchan = make(chan *Fcall, 16)
|
||||||
|
|
||||||
go clnt.recv()
|
go clnt.recv()
|
||||||
go clnt.send()
|
go clnt.send()
|
||||||
|
@ -373,8 +355,9 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
|
||||||
ver = "9P2000.u"
|
ver = "9P2000.u"
|
||||||
}
|
}
|
||||||
|
|
||||||
tc := p.NewFcall(clnt.Msize)
|
clntmsize := atomic.LoadUint32(&clnt.Msize)
|
||||||
err := p.PackTversion(tc, clnt.Msize, ver)
|
tc := NewFcall(clntmsize)
|
||||||
|
err := PackTversion(tc, clntmsize, ver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -384,8 +367,8 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if rc.Msize < clnt.Msize {
|
if rc.Msize < atomic.LoadUint32(&clnt.Msize) {
|
||||||
clnt.Msize = rc.Msize
|
atomic.StoreUint32(&clnt.Msize, rc.Msize)
|
||||||
}
|
}
|
||||||
|
|
||||||
clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
|
clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
|
||||||
|
@ -401,17 +384,17 @@ func (clnt *Clnt) FidAlloc() *Fid {
|
||||||
return fid
|
return fid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clnt *Clnt) NewFcall() *p.Fcall {
|
func (clnt *Clnt) NewFcall() *Fcall {
|
||||||
select {
|
select {
|
||||||
case tc := <-clnt.tchan:
|
case tc := <-clnt.tchan:
|
||||||
return tc
|
return tc
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return p.NewFcall(clnt.Msize)
|
return NewFcall(atomic.LoadUint32(&clnt.Msize))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clnt *Clnt) FreeFcall(fc *p.Fcall) {
|
func (clnt *Clnt) FreeFcall(fc *Fcall) {
|
||||||
if fc != nil && len(fc.Buf) >= int(clnt.Msize) {
|
if fc != nil && len(fc.Buf) >= int(atomic.LoadUint32(&clnt.Msize)) {
|
||||||
select {
|
select {
|
||||||
case clnt.tchan <- fc:
|
case clnt.tchan <- fc:
|
||||||
break
|
break
|
||||||
|
@ -450,15 +433,7 @@ func (clnt *Clnt) ReqFree(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFile(f *Fid, offset uint64) *File {
|
func (clnt *Clnt) logFcall(fc *Fcall) {
|
||||||
return &File{f, offset}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *File) Fid() *Fid {
|
|
||||||
return f.fid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (clnt *Clnt) logFcall(fc *p.Fcall) {
|
|
||||||
if clnt.Debuglevel&DbgLogPackets != 0 {
|
if clnt.Debuglevel&DbgLogPackets != 0 {
|
||||||
pkt := make([]byte, len(fc.Pkt))
|
pkt := make([]byte, len(fc.Pkt))
|
||||||
copy(pkt, fc.Pkt)
|
copy(pkt, fc.Pkt)
|
||||||
|
@ -466,13 +441,19 @@ func (clnt *Clnt) logFcall(fc *p.Fcall) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if clnt.Debuglevel&DbgLogFcalls != 0 {
|
if clnt.Debuglevel&DbgLogFcalls != 0 {
|
||||||
f := new(p.Fcall)
|
f := new(Fcall)
|
||||||
*f = *fc
|
*f = *fc
|
||||||
f.Pkt = nil
|
f.Pkt = nil
|
||||||
clnt.Log.Log(f, clnt, DbgLogFcalls)
|
clnt.Log.Log(f, clnt, DbgLogFcalls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FidFile returns a File that represents the given Fid, initially at the given
|
||||||
|
// offset.
|
||||||
|
func FidFile(fid *Fid, offset uint64) *File {
|
||||||
|
return &File{fid, offset}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
clnts = new(ClntList)
|
clnts = new(ClntList)
|
||||||
if sop, ok := (interface{}(clnts)).(StatsOps); ok {
|
if sop, ok := (interface{}(clnts)).(StatsOps); ok {
|
|
@ -2,16 +2,14 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import "k8s.io/minikube/third_party/go9p/p"
|
|
||||||
|
|
||||||
// Clunks a fid. Returns nil if successful.
|
// Clunks a fid. Returns nil if successful.
|
||||||
func (clnt *Clnt) Clunk(fid *Fid) (err error) {
|
func (clnt *Clnt) Clunk(fid *Fid) (err error) {
|
||||||
err = nil
|
err = nil
|
||||||
if fid.walked {
|
if fid.walked {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTclunk(tc, fid.Fid)
|
err := PackTclunk(tc, fid.Fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -21,12 +19,12 @@ func (clnt *Clnt) Clunk(fid *Fid) (err error) {
|
||||||
|
|
||||||
clnt.fidpool.putId(fid.Fid)
|
clnt.fidpool.putId(fid.Fid)
|
||||||
fid.walked = false
|
fid.walked = false
|
||||||
fid.Fid = p.NOFID
|
fid.Fid = NOFID
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closes a file. Returns nil if successful.
|
// Closes a file. Returns nil if successful.
|
||||||
func (file *File) Close() error {
|
func (file *File) Close() error {
|
||||||
// Should we cancel all pending requests for the File
|
// Should we cancel all pending requests for the File
|
||||||
return file.fid.Clnt.Clunk(file.fid)
|
return file.Fid.Clnt.Clunk(file.Fid)
|
||||||
}
|
}
|
|
@ -2,19 +2,18 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Creates an authentication fid for the specified user. Returns the fid, if
|
// Creates an authentication fid for the specified user. Returns the fid, if
|
||||||
// successful, or an Error.
|
// successful, or an Error.
|
||||||
func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
|
func (clnt *Clnt) Auth(user User, aname string) (*Fid, error) {
|
||||||
fid := clnt.FidAlloc()
|
fid := clnt.FidAlloc()
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
|
err := PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -24,7 +23,6 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fid.Iounit = clnt.Msize - p.IOHDRSZ
|
|
||||||
fid.User = user
|
fid.User = user
|
||||||
fid.walked = true
|
fid.walked = true
|
||||||
return fid, nil
|
return fid, nil
|
||||||
|
@ -33,18 +31,18 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
|
||||||
// Creates a fid for the specified user that points to the root
|
// Creates a fid for the specified user that points to the root
|
||||||
// of the file server's file tree. Returns a Fid pointing to the root,
|
// of the file server's file tree. Returns a Fid pointing to the root,
|
||||||
// if successful, or an Error.
|
// if successful, or an Error.
|
||||||
func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) {
|
func (clnt *Clnt) Attach(afid *Fid, user User, aname string) (*Fid, error) {
|
||||||
var afno uint32
|
var afno uint32
|
||||||
|
|
||||||
if afid != nil {
|
if afid != nil {
|
||||||
afno = afid.Fid
|
afno = afid.Fid
|
||||||
} else {
|
} else {
|
||||||
afno = p.NOFID
|
afno = NOFID
|
||||||
}
|
}
|
||||||
|
|
||||||
fid := clnt.FidAlloc()
|
fid := clnt.FidAlloc()
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
|
err := PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -61,17 +59,17 @@ func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connects to a file server and attaches to it as the specified user.
|
// Connects to a file server and attaches to it as the specified user.
|
||||||
func Mount(ntype, addr, aname string, user p.User) (*Clnt, error) {
|
func Mount(ntype, addr, aname string, msize uint32, user User) (*Clnt, error) {
|
||||||
c, e := net.Dial(ntype, addr)
|
c, e := net.Dial(ntype, addr)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, &p.Error{e.Error(), p.EIO}
|
return nil, &Error{e.Error(), EIO}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MountConn(c, aname, user)
|
return MountConn(c, aname, msize, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
|
func MountConn(c net.Conn, aname string, msize uint32, user User) (*Clnt, error) {
|
||||||
clnt, err := Connect(c, 8192+p.IOHDRSZ, true)
|
clnt, err := Connect(c, msize+IOHDRSZ, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -89,7 +87,7 @@ func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
|
||||||
// Closes the connection to the file sever.
|
// Closes the connection to the file sever.
|
||||||
func (clnt *Clnt) Unmount() {
|
func (clnt *Clnt) Unmount() {
|
||||||
clnt.Lock()
|
clnt.Lock()
|
||||||
clnt.err = &p.Error{"connection closed", p.EIO}
|
clnt.err = &Error{"connection closed", EIO}
|
||||||
clnt.conn.Close()
|
clnt.conn.Close()
|
||||||
clnt.Unlock()
|
clnt.Unlock()
|
||||||
}
|
}
|
|
@ -2,10 +2,9 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ import (
|
||||||
// the operation is successful.
|
// the operation is successful.
|
||||||
func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
|
func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTopen(tc, fid.Fid, mode)
|
err := PackTopen(tc, fid.Fid, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -25,8 +24,8 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
|
||||||
|
|
||||||
fid.Qid = rc.Qid
|
fid.Qid = rc.Qid
|
||||||
fid.Iounit = rc.Iounit
|
fid.Iounit = rc.Iounit
|
||||||
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ {
|
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
|
||||||
fid.Iounit = clnt.Msize - p.IOHDRSZ
|
fid.Iounit = clnt.Msize - IOHDRSZ
|
||||||
}
|
}
|
||||||
fid.Mode = mode
|
fid.Mode = mode
|
||||||
return nil
|
return nil
|
||||||
|
@ -36,7 +35,7 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
|
||||||
// if the operation is successful.
|
// if the operation is successful.
|
||||||
func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
|
func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu)
|
err := PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,8 +47,8 @@ func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext str
|
||||||
|
|
||||||
fid.Qid = rc.Qid
|
fid.Qid = rc.Qid
|
||||||
fid.Iounit = rc.Iounit
|
fid.Iounit = rc.Iounit
|
||||||
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ {
|
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
|
||||||
fid.Iounit = clnt.Msize - p.IOHDRSZ
|
fid.Iounit = clnt.Msize - IOHDRSZ
|
||||||
}
|
}
|
||||||
fid.Mode = mode
|
fid.Mode = mode
|
||||||
return nil
|
return nil
|
|
@ -2,7 +2,9 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
var m2id = [...]uint8{
|
var m2id = [...]uint8{
|
||||||
0, 1, 0, 2, 0, 1, 0, 3,
|
0, 1, 0, 2, 0, 1, 0, 3,
|
||||||
|
@ -39,6 +41,14 @@ var m2id = [...]uint8{
|
||||||
0, 1, 0, 2, 0, 1, 0, 0,
|
0, 1, 0, 2, 0, 1, 0, 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pool struct {
|
||||||
|
sync.Mutex
|
||||||
|
need int
|
||||||
|
nchan chan uint32
|
||||||
|
maxid uint32
|
||||||
|
imap []byte
|
||||||
|
}
|
||||||
|
|
||||||
func newPool(maxid uint32) *pool {
|
func newPool(maxid uint32) *pool {
|
||||||
p := new(pool)
|
p := new(pool)
|
||||||
p.maxid = maxid
|
p.maxid = maxid
|
|
@ -2,11 +2,10 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reads count bytes starting from offset from the file associated with the fid.
|
// Reads count bytes starting from offset from the file associated with the fid.
|
||||||
|
@ -18,7 +17,7 @@ func (clnt *Clnt) Read(fid *Fid, offset uint64, count uint32) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTread(tc, fid.Fid, offset, count)
|
err := PackTread(tc, fid.Fid, offset, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -45,7 +44,7 @@ func (file *File) Read(buf []byte) (int, error) {
|
||||||
// Reads up to len(buf) bytes from the file starting from offset.
|
// Reads up to len(buf) bytes from the file starting from offset.
|
||||||
// Returns the number of bytes read, or an Error.
|
// Returns the number of bytes read, or an Error.
|
||||||
func (file *File) ReadAt(buf []byte, offset int64) (int, error) {
|
func (file *File) ReadAt(buf []byte, offset int64) (int, error) {
|
||||||
b, err := file.fid.Clnt.Read(file.fid, uint64(offset), uint32(len(buf)))
|
b, err := file.Fid.Clnt.Read(file.Fid, uint64(offset), uint32(len(buf)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -85,10 +84,14 @@ func (file *File) Readn(buf []byte, offset uint64) (int, error) {
|
||||||
// Returns an array of maximum num entries (if num is 0, returns
|
// Returns an array of maximum num entries (if num is 0, returns
|
||||||
// all entries from the directory). If the operation fails, returns
|
// all entries from the directory). If the operation fails, returns
|
||||||
// an Error.
|
// an Error.
|
||||||
func (file *File) Readdir(num int) ([]*p.Dir, error) {
|
func (file *File) Readdir(num int) ([]*Dir, error) {
|
||||||
buf := make([]byte, file.fid.Clnt.Msize-p.IOHDRSZ)
|
buf := make([]byte, file.Fid.Clnt.Msize-IOHDRSZ)
|
||||||
dirs := make([]*p.Dir, 32)
|
dirs := make([]*Dir, 32)
|
||||||
pos := 0
|
pos := 0
|
||||||
|
offset := file.offset
|
||||||
|
defer func() {
|
||||||
|
file.offset = offset
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
n, err := file.Read(buf)
|
n, err := file.Read(buf)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
|
@ -100,14 +103,20 @@ func (file *File) Readdir(num int) ([]*p.Dir, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for b := buf[0:n]; len(b) > 0; {
|
for b := buf[0:n]; len(b) > 0; {
|
||||||
d, perr := p.UnpackDir(b, file.fid.Clnt.Dotu)
|
d, _, _, perr := UnpackDir(b, file.Fid.Clnt.Dotu)
|
||||||
if perr != nil {
|
if perr != nil {
|
||||||
|
// If we have unpacked anything, it is almost certainly
|
||||||
|
// a too-short buffer. So return what we got.
|
||||||
|
if pos > 0 {
|
||||||
|
return dirs[0:pos], nil
|
||||||
|
}
|
||||||
return nil, perr
|
return nil, perr
|
||||||
}
|
}
|
||||||
|
|
||||||
b = b[d.Size+2:]
|
b = b[d.Size+2:]
|
||||||
|
offset += uint64(d.Size + 2)
|
||||||
if pos >= len(dirs) {
|
if pos >= len(dirs) {
|
||||||
s := make([]*p.Dir, len(dirs)+32)
|
s := make([]*Dir, len(dirs)+32)
|
||||||
copy(s, dirs)
|
copy(s, dirs)
|
||||||
dirs = s
|
dirs = s
|
||||||
}
|
}
|
|
@ -2,22 +2,20 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import "k8s.io/minikube/third_party/go9p/p"
|
|
||||||
|
|
||||||
// Removes the file associated with the Fid. Returns nil if the
|
// Removes the file associated with the Fid. Returns nil if the
|
||||||
// operation is successful.
|
// operation is successful.
|
||||||
func (clnt *Clnt) Remove(fid *Fid) error {
|
func (clnt *Clnt) Remove(fid *Fid) error {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTremove(tc, fid.Fid)
|
err := PackTremove(tc, fid.Fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = clnt.Rpc(tc)
|
_, err = clnt.Rpc(tc)
|
||||||
clnt.fidpool.putId(fid.Fid)
|
clnt.fidpool.putId(fid.Fid)
|
||||||
fid.Fid = p.NOFID
|
fid.Fid = NOFID
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -2,14 +2,12 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import "k8s.io/minikube/third_party/go9p/p"
|
|
||||||
|
|
||||||
// Returns the metadata for the file associated with the Fid, or an Error.
|
// Returns the metadata for the file associated with the Fid, or an Error.
|
||||||
func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
|
func (clnt *Clnt) Stat(fid *Fid) (*Dir, error) {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTstat(tc, fid.Fid)
|
err := PackTstat(tc, fid.Fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -23,7 +21,7 @@ func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the metadata for a named file, or an Error.
|
// Returns the metadata for a named file, or an Error.
|
||||||
func (clnt *Clnt) FStat(path string) (*p.Dir, error) {
|
func (clnt *Clnt) FStat(path string) (*Dir, error) {
|
||||||
fid, err := clnt.FWalk(path)
|
fid, err := clnt.FWalk(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -35,9 +33,9 @@ func (clnt *Clnt) FStat(path string) (*p.Dir, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modifies the data of the file associated with the Fid, or an Error.
|
// Modifies the data of the file associated with the Fid, or an Error.
|
||||||
func (clnt *Clnt) Wstat(fid *Fid, dir *p.Dir) error {
|
func (clnt *Clnt) Wstat(fid *Fid, dir *Dir) error {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
|
err := PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
// +build httpstats
|
// +build httpstats
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ func (clnt *Clnt) ServeHTTP(c http.ResponseWriter, r *http.Request) {
|
||||||
fs := clnt.Log.Filter(clnt, DbgLogFcalls)
|
fs := clnt.Log.Filter(clnt, DbgLogFcalls)
|
||||||
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
|
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
|
||||||
for _, l := range fs {
|
for _, l := range fs {
|
||||||
fc := l.Data.(*p.Fcall)
|
fc := l.Data.(*Fcall)
|
||||||
if fc.Type != 0 {
|
if fc.Type != 0 {
|
||||||
io.WriteString(c, fmt.Sprintf("<br>%s", fc))
|
io.WriteString(c, fmt.Sprintf("<br>%s", fc))
|
||||||
}
|
}
|
|
@ -2,9 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import "k8s.io/minikube/third_party/go9p/p"
|
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
clnt *Clnt
|
clnt *Clnt
|
||||||
|
@ -54,22 +52,22 @@ func (tag *Tag) reqproc() {
|
||||||
case r := <-tag.respchan:
|
case r := <-tag.respchan:
|
||||||
rc := r.Rc
|
rc := r.Rc
|
||||||
fid := r.fid
|
fid := r.fid
|
||||||
err := r.Rc.Type == p.Rerror
|
err := r.Rc.Type == Rerror
|
||||||
|
|
||||||
switch r.Tc.Type {
|
switch r.Tc.Type {
|
||||||
case p.Tauth:
|
case Tauth:
|
||||||
if err {
|
if err {
|
||||||
fid.User = nil
|
fid.User = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case p.Tattach:
|
case Tattach:
|
||||||
if !err {
|
if !err {
|
||||||
fid.Qid = rc.Qid
|
fid.Qid = rc.Qid
|
||||||
} else {
|
} else {
|
||||||
fid.User = nil
|
fid.User = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case p.Twalk:
|
case Twalk:
|
||||||
if !err {
|
if !err {
|
||||||
fid.walked = true
|
fid.walked = true
|
||||||
if len(rc.Wqid) > 0 {
|
if len(rc.Wqid) > 0 {
|
||||||
|
@ -79,8 +77,8 @@ func (tag *Tag) reqproc() {
|
||||||
fid.User = nil
|
fid.User = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case p.Topen:
|
case Topen:
|
||||||
case p.Tcreate:
|
case Tcreate:
|
||||||
if !err {
|
if !err {
|
||||||
fid.Iounit = rc.Iounit
|
fid.Iounit = rc.Iounit
|
||||||
fid.Qid = rc.Qid
|
fid.Qid = rc.Qid
|
||||||
|
@ -88,8 +86,8 @@ func (tag *Tag) reqproc() {
|
||||||
fid.Mode = 0
|
fid.Mode = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
case p.Tclunk:
|
case Tclunk:
|
||||||
case p.Tremove:
|
case Tremove:
|
||||||
tag.clnt.fidpool.putId(fid.Fid)
|
tag.clnt.fidpool.putId(fid.Fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,10 +96,10 @@ func (tag *Tag) reqproc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
|
func (tag *Tag) Auth(afid *Fid, user User, aname string) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = afid
|
req.fid = afid
|
||||||
err := p.PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
|
err := PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -110,18 +108,18 @@ func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
|
||||||
return tag.clnt.Rpcnb(req)
|
return tag.clnt.Rpcnb(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tag *Tag) Attach(fid, afid *Fid, user p.User, aname string) error {
|
func (tag *Tag) Attach(fid, afid *Fid, user User, aname string) error {
|
||||||
var afno uint32
|
var afno uint32
|
||||||
|
|
||||||
if afid != nil {
|
if afid != nil {
|
||||||
afno = afid.Fid
|
afno = afid.Fid
|
||||||
} else {
|
} else {
|
||||||
afno = p.NOFID
|
afno = NOFID
|
||||||
}
|
}
|
||||||
|
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
|
err := PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -137,7 +135,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
|
||||||
newfid.Qid = fid.Qid
|
newfid.Qid = fid.Qid
|
||||||
}
|
}
|
||||||
|
|
||||||
err := p.PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames)
|
err := PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -149,7 +147,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
|
||||||
func (tag *Tag) Open(fid *Fid, mode uint8) error {
|
func (tag *Tag) Open(fid *Fid, mode uint8) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTopen(req.Tc, fid.Fid, mode)
|
err := PackTopen(req.Tc, fid.Fid, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -161,7 +159,7 @@ func (tag *Tag) Open(fid *Fid, mode uint8) error {
|
||||||
func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
|
func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu)
|
err := PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -173,7 +171,7 @@ func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext strin
|
||||||
func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
|
func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTread(req.Tc, fid.Fid, offset, count)
|
err := PackTread(req.Tc, fid.Fid, offset, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -184,7 +182,7 @@ func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
|
||||||
func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
|
func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data)
|
err := PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -195,7 +193,7 @@ func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
|
||||||
func (tag *Tag) Clunk(fid *Fid) error {
|
func (tag *Tag) Clunk(fid *Fid) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTclunk(req.Tc, fid.Fid)
|
err := PackTclunk(req.Tc, fid.Fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -206,7 +204,7 @@ func (tag *Tag) Clunk(fid *Fid) error {
|
||||||
func (tag *Tag) Remove(fid *Fid) error {
|
func (tag *Tag) Remove(fid *Fid) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTremove(req.Tc, fid.Fid)
|
err := PackTremove(req.Tc, fid.Fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -217,7 +215,7 @@ func (tag *Tag) Remove(fid *Fid) error {
|
||||||
func (tag *Tag) Stat(fid *Fid) error {
|
func (tag *Tag) Stat(fid *Fid) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTstat(req.Tc, fid.Fid)
|
err := PackTstat(req.Tc, fid.Fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -225,10 +223,10 @@ func (tag *Tag) Stat(fid *Fid) error {
|
||||||
return tag.clnt.Rpcnb(req)
|
return tag.clnt.Rpcnb(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tag *Tag) Wstat(fid *Fid, dir *p.Dir) error {
|
func (tag *Tag) Wstat(fid *Fid, dir *Dir) error {
|
||||||
req := tag.reqAlloc()
|
req := tag.reqAlloc()
|
||||||
req.fid = fid
|
req.fid = fid
|
||||||
err := p.PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu)
|
err := PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -2,10 +2,9 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,9 +12,9 @@ import (
|
||||||
// sequence and associates the resulting file with newfid. If no wnames
|
// sequence and associates the resulting file with newfid. If no wnames
|
||||||
// were walked successfully, an Error is returned. Otherwise a slice with a
|
// were walked successfully, an Error is returned. Otherwise a slice with a
|
||||||
// Qid for each walked name is returned.
|
// Qid for each walked name is returned.
|
||||||
func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]p.Qid, error) {
|
func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]Qid, error) {
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
|
err := PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -66,12 +65,12 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err = p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n])
|
err = PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto error
|
goto error
|
||||||
}
|
}
|
||||||
|
|
||||||
var rc *p.Fcall
|
var rc *Fcall
|
||||||
rc, err = clnt.Rpc(tc)
|
rc, err = clnt.Rpc(tc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto error
|
goto error
|
||||||
|
@ -79,7 +78,7 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
|
||||||
|
|
||||||
newfid.walked = true
|
newfid.walked = true
|
||||||
if len(rc.Wqid) != n {
|
if len(rc.Wqid) != n {
|
||||||
err = &p.Error{"file not found", p.ENOENT}
|
err = &Error{"file not found", ENOENT}
|
||||||
goto error
|
goto error
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package clnt
|
package go9p
|
||||||
|
|
||||||
import "k8s.io/minikube/third_party/go9p/p"
|
|
||||||
|
|
||||||
// Write up to len(data) bytes starting from offset. Returns the
|
// Write up to len(data) bytes starting from offset. Returns the
|
||||||
// number of bytes written, or an Error.
|
// number of bytes written, or an Error.
|
||||||
|
@ -14,7 +12,7 @@ func (clnt *Clnt) Write(fid *Fid, data []byte, offset uint64) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tc := clnt.NewFcall()
|
tc := clnt.NewFcall()
|
||||||
err := p.PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data)
|
err := PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -41,7 +39,7 @@ func (file *File) Write(buf []byte) (int, error) {
|
||||||
// Writes up to len(buf) bytes starting from offset. Returns the number
|
// Writes up to len(buf) bytes starting from offset. Returns the number
|
||||||
// of bytes written, or an Error.
|
// of bytes written, or an Error.
|
||||||
func (file *File) WriteAt(buf []byte, offset int64) (int, error) {
|
func (file *File) WriteAt(buf []byte, offset int64) (int, error) {
|
||||||
return file.fid.Clnt.Write(file.fid, buf, uint64(offset))
|
return file.Fid.Clnt.Write(file.Fid, buf, uint64(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes exactly len(buf) bytes starting from offset. Returns the number of
|
// Writes exactly len(buf) bytes starting from offset. Returns the number of
|
|
@ -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)
|
||||||
|
)
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package p
|
package go9p
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package p
|
package go9p
|
||||||
|
|
||||||
type Log struct {
|
type Log struct {
|
||||||
Data interface{}
|
Data interface{}
|
|
@ -2,38 +2,33 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package p
|
package go9p
|
||||||
|
|
||||||
import (
|
import "sync"
|
||||||
"os/user"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
|
|
||||||
type osUser struct {
|
type osUser struct {
|
||||||
*user.User
|
|
||||||
uid int
|
uid int
|
||||||
gid int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type osUsers struct {
|
type osUsers struct {
|
||||||
|
users map[int]*osUser
|
||||||
groups map[int]*osGroup
|
groups map[int]*osGroup
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple Users implementation that defers to os/user and fakes
|
// Simple Users implementation that fakes looking up users and groups
|
||||||
// looking up groups by gid only.
|
// by uid only. The names and groups memberships are empty
|
||||||
var OsUsers *osUsers
|
var OsUsers *osUsers
|
||||||
|
|
||||||
func (u *osUser) Name() string { return u.Username }
|
func (u *osUser) Name() string { return "" }
|
||||||
|
|
||||||
func (u *osUser) Id() int { return u.uid }
|
func (u *osUser) Id() int { return u.uid }
|
||||||
|
|
||||||
func (u *osUser) Groups() []Group { return []Group{OsUsers.Gid2Group(u.gid)} }
|
func (u *osUser) Groups() []Group { return nil }
|
||||||
|
|
||||||
func (u *osUser) IsMember(g Group) bool { return u.gid == g.Id() }
|
func (u *osUser) IsMember(g Group) bool { return false }
|
||||||
|
|
||||||
type osGroup struct {
|
type osGroup struct {
|
||||||
gid int
|
gid int
|
||||||
|
@ -47,33 +42,28 @@ func (g *osGroup) Members() []User { return nil }
|
||||||
|
|
||||||
func initOsusers() {
|
func initOsusers() {
|
||||||
OsUsers = new(osUsers)
|
OsUsers = new(osUsers)
|
||||||
|
OsUsers.users = make(map[int]*osUser)
|
||||||
OsUsers.groups = make(map[int]*osGroup)
|
OsUsers.groups = make(map[int]*osGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUser(u *user.User) *osUser {
|
|
||||||
uid, uerr := strconv.Atoi(u.Uid)
|
|
||||||
gid, gerr := strconv.Atoi(u.Gid)
|
|
||||||
if uerr != nil || gerr != nil {
|
|
||||||
/* non-numeric uid/gid => unsupported system */
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &osUser{u, uid, gid}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (up *osUsers) Uid2User(uid int) User {
|
func (up *osUsers) Uid2User(uid int) User {
|
||||||
u, err := user.LookupId(strconv.Itoa(uid))
|
once.Do(initOsusers)
|
||||||
if err != nil {
|
OsUsers.Lock()
|
||||||
return nil
|
defer OsUsers.Unlock()
|
||||||
|
user, present := OsUsers.users[uid]
|
||||||
|
if present {
|
||||||
|
return user
|
||||||
}
|
}
|
||||||
return newUser(u)
|
|
||||||
|
user = new(osUser)
|
||||||
|
user.uid = uid
|
||||||
|
OsUsers.users[uid] = user
|
||||||
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func (up *osUsers) Uname2User(uname string) User {
|
func (up *osUsers) Uname2User(uname string) User {
|
||||||
u, err := user.Lookup(uname)
|
// unimplemented
|
||||||
if err != nil {
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return newUser(u)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (up *osUsers) Gid2Group(gid int) Group {
|
func (up *osUsers) Gid2Group(gid int) Group {
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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))
|
|
||||||
}
|
|
|
@ -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))
|
|
||||||
}
|
|
|
@ -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))
|
|
||||||
}
|
|
|
@ -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"),
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -2,9 +2,11 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// The p9 package provides the definitions and functions used to implement
|
// The p9 package go9provides the definitions and functions used to implement
|
||||||
// the 9P2000 protocol.
|
// the 9P2000 protocol.
|
||||||
package p
|
// TODO.
|
||||||
|
// All the packet conversion code in this file is crap and needs a rewrite.
|
||||||
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -44,9 +46,9 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MSIZE = 8192 + IOHDRSZ // default message size (8192+IOHdrSz)
|
MSIZE = 1048576 + IOHDRSZ // default message size (1048576+IOHdrSz)
|
||||||
IOHDRSZ = 24 // the non-data size of the Twrite messages
|
IOHDRSZ = 24 // the non-data size of the Twrite messages
|
||||||
PORT = 564 // default port for 9P file servers
|
PORT = 564 // default port for 9P file servers
|
||||||
)
|
)
|
||||||
|
|
||||||
// Qid types
|
// Qid types
|
||||||
|
@ -301,11 +303,12 @@ func gint64(buf []byte) (uint64, []byte) {
|
||||||
func gstr(buf []byte) (string, []byte) {
|
func gstr(buf []byte) (string, []byte) {
|
||||||
var n uint16
|
var n uint16
|
||||||
|
|
||||||
if buf == nil {
|
if buf == nil || len(buf) < 2 {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
n, buf = gint16(buf)
|
n, buf = gint16(buf)
|
||||||
|
|
||||||
if int(n) > len(buf) {
|
if int(n) > len(buf) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -321,7 +324,8 @@ func gqid(buf []byte, qid *Qid) []byte {
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func gstat(buf []byte, d *Dir, dotu bool) []byte {
|
func gstat(buf []byte, d *Dir, dotu bool) ([]byte, error) {
|
||||||
|
sz := len(buf)
|
||||||
d.Size, buf = gint16(buf)
|
d.Size, buf = gint16(buf)
|
||||||
d.Type, buf = gint16(buf)
|
d.Type, buf = gint16(buf)
|
||||||
d.Dev, buf = gint32(buf)
|
d.Dev, buf = gint32(buf)
|
||||||
|
@ -332,27 +336,29 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
|
||||||
d.Length, buf = gint64(buf)
|
d.Length, buf = gint64(buf)
|
||||||
d.Name, buf = gstr(buf)
|
d.Name, buf = gstr(buf)
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return nil
|
s := fmt.Sprintf("Buffer too short for basic 9p: need %d, have %d",
|
||||||
|
49, sz)
|
||||||
|
return nil, &Error{s, EINVAL}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Uid, buf = gstr(buf)
|
d.Uid, buf = gstr(buf)
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return nil
|
return nil, &Error{"d.Uid failed", EINVAL}
|
||||||
}
|
}
|
||||||
d.Gid, buf = gstr(buf)
|
d.Gid, buf = gstr(buf)
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return nil
|
return nil, &Error{"d.Gid failed", EINVAL}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Muid, buf = gstr(buf)
|
d.Muid, buf = gstr(buf)
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return nil
|
return nil, &Error{"d.Muid failed", EINVAL}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dotu {
|
if dotu {
|
||||||
d.Ext, buf = gstr(buf)
|
d.Ext, buf = gstr(buf)
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return nil
|
return nil, &Error{"d.Ext failed", EINVAL}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Uidnum, buf = gint32(buf)
|
d.Uidnum, buf = gint32(buf)
|
||||||
|
@ -364,7 +370,7 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
|
||||||
d.Muidnum = NOUID
|
d.Muidnum = NOUID
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pint8(val uint8, buf []byte) []byte {
|
func pint8(val uint8, buf []byte) []byte {
|
||||||
|
@ -449,20 +455,17 @@ func pstat(d *Dir, buf []byte, dotu bool) []byte {
|
||||||
|
|
||||||
// Converts a Dir value to its on-the-wire representation and writes it to
|
// Converts a Dir value to its on-the-wire representation and writes it to
|
||||||
// the buf. Returns the number of bytes written, 0 if there is not enough space.
|
// the buf. Returns the number of bytes written, 0 if there is not enough space.
|
||||||
func PackDir(d *Dir, buf []byte, dotu bool) int {
|
func PackDir(d *Dir, dotu bool) []byte {
|
||||||
sz := statsz(d, dotu)
|
sz := statsz(d, dotu)
|
||||||
if sz > len(buf) {
|
buf := make([]byte, sz)
|
||||||
return 0
|
pstat(d, buf, dotu)
|
||||||
}
|
return buf
|
||||||
|
|
||||||
buf = pstat(d, buf, dotu)
|
|
||||||
return sz
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the on-the-wire representation of a stat to Stat value.
|
// Converts the on-the-wire representation of a stat to Stat value.
|
||||||
// Returns an error if the conversion is impossible, otherwise
|
// Returns an error if the conversion is impossible, otherwise
|
||||||
// a pointer to a Stat value.
|
// a pointer to a Stat value.
|
||||||
func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
|
func UnpackDir(buf []byte, dotu bool) (d *Dir, b []byte, amt int, err error) {
|
||||||
sz := 2 + 2 + 4 + 13 + 4 + /* size[2] type[2] dev[4] qid[13] mode[4] */
|
sz := 2 + 2 + 4 + 13 + 4 + /* size[2] type[2] dev[4] qid[13] mode[4] */
|
||||||
4 + 4 + 8 + /* atime[4] mtime[4] length[8] */
|
4 + 4 + 8 + /* atime[4] mtime[4] length[8] */
|
||||||
2 + 2 + 2 + 2 /* name[s] uid[s] gid[s] muid[s] */
|
2 + 2 + 2 + 2 /* name[s] uid[s] gid[s] muid[s] */
|
||||||
|
@ -472,19 +475,17 @@ func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(buf) < sz {
|
if len(buf) < sz {
|
||||||
goto szerror
|
s := fmt.Sprintf("short buffer: Need %d and have %v", sz, len(buf))
|
||||||
|
return nil, nil, 0, &Error{s, EINVAL}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = new(Dir)
|
d = new(Dir)
|
||||||
buf = gstat(buf, d, dotu)
|
b, err = gstat(buf, d, dotu)
|
||||||
if buf == nil {
|
if err != nil {
|
||||||
goto szerror
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return d, nil
|
return d, b, len(buf) - len(b), nil
|
||||||
|
|
||||||
szerror:
|
|
||||||
return nil, &Error{"short buffer", EINVAL}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +523,7 @@ func packCommon(fc *Fcall, size int, id uint8) ([]byte, error) {
|
||||||
|
|
||||||
func (err *Error) Error() string {
|
func (err *Error) Error() string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Sprintf("%s: %d", err.Err, err.Errornum)
|
return err.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
|
@ -2,7 +2,9 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package p
|
package go9p
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// Create a Rversion message in the specified Fcall.
|
// Create a Rversion message in the specified Fcall.
|
||||||
func PackRversion(fc *Fcall, msize uint32, version string) error {
|
func PackRversion(fc *Fcall, msize uint32, version string) error {
|
||||||
|
@ -34,9 +36,17 @@ func PackRauth(fc *Fcall, aqid *Qid) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a Rerror message in the specified Fcall. If dotu is true,
|
// Create a Rerror message in the specified Fcall. If dotu is true,
|
||||||
// the function will create a 9P2000.u message. If false, nerror is
|
// the function will create a 9P2000.u message. If false, errornum is
|
||||||
// ignored.
|
// ignored.
|
||||||
|
// The Akaros global is hurl-inducing but this whole blob of code
|
||||||
|
// needs a redo. dotu is even worse, since it bakes in ONE PARTICULAR
|
||||||
|
// EXTENSION ...
|
||||||
|
|
||||||
func PackRerror(fc *Fcall, error string, errornum uint32, dotu bool) error {
|
func PackRerror(fc *Fcall, error string, errornum uint32, dotu bool) error {
|
||||||
|
if *Akaros {
|
||||||
|
error = fmt.Sprintf("%04X %v", errornum, error)
|
||||||
|
}
|
||||||
|
|
||||||
size := 2 + len(error) /* ename[s] */
|
size := 2 + len(error) /* ename[s] */
|
||||||
if dotu {
|
if dotu {
|
||||||
size += 4 /* ecode[4] */
|
size += 4 /* ecode[4] */
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package p
|
package go9p
|
||||||
|
|
||||||
// Create a Tversion message in the specified Fcall.
|
// Create a Tversion message in the specified Fcall.
|
||||||
func PackTversion(fc *Fcall, msize uint32, version string) error {
|
func PackTversion(fc *Fcall, msize uint32, version string) error {
|
|
@ -2,11 +2,10 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package srv
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
@ -18,11 +17,11 @@ func (srv *Srv) NewConn(c net.Conn) {
|
||||||
conn.Dotu = srv.Dotu
|
conn.Dotu = srv.Dotu
|
||||||
conn.Debuglevel = srv.Debuglevel
|
conn.Debuglevel = srv.Debuglevel
|
||||||
conn.conn = c
|
conn.conn = c
|
||||||
conn.fidpool = make(map[uint32]*Fid)
|
conn.fidpool = make(map[uint32]*SrvFid)
|
||||||
conn.reqs = make(map[uint16]*Req)
|
conn.reqs = make(map[uint16]*SrvReq)
|
||||||
conn.reqout = make(chan *Req, srv.Maxpend)
|
conn.reqout = make(chan *SrvReq, srv.Maxpend)
|
||||||
conn.done = make(chan bool)
|
conn.done = make(chan bool)
|
||||||
conn.rchan = make(chan *p.Fcall, 64)
|
conn.rchan = make(chan *Fcall, 64)
|
||||||
|
|
||||||
srv.Lock()
|
srv.Lock()
|
||||||
if srv.conns == nil {
|
if srv.conns == nil {
|
||||||
|
@ -58,7 +57,7 @@ func (conn *Conn) close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call FidDestroy for all remaining fids */
|
/* call FidDestroy for all remaining fids */
|
||||||
if op, ok := (conn.Srv.ops).(FidOps); ok {
|
if op, ok := (conn.Srv.ops).(SrvFidOps); ok {
|
||||||
for _, fid := range conn.fidpool {
|
for _, fid := range conn.fidpool {
|
||||||
op.FidDestroy(fid)
|
op.FidDestroy(fid)
|
||||||
}
|
}
|
||||||
|
@ -87,7 +86,7 @@ func (conn *Conn) recv() {
|
||||||
|
|
||||||
pos += n
|
pos += n
|
||||||
for pos > 4 {
|
for pos > 4 {
|
||||||
sz, _ := p.Gint32(buf)
|
sz, _ := Gint32(buf)
|
||||||
if sz > conn.Msize {
|
if sz > conn.Msize {
|
||||||
log.Println("bad client connection: ", conn.conn.RemoteAddr())
|
log.Println("bad client connection: ", conn.conn.RemoteAddr())
|
||||||
conn.conn.Close()
|
conn.conn.Close()
|
||||||
|
@ -104,7 +103,7 @@ func (conn *Conn) recv() {
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
fc, err, fcsize := p.Unpack(buf, conn.Dotu)
|
fc, err, fcsize := Unpack(buf, conn.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf))
|
log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf))
|
||||||
conn.conn.Close()
|
conn.conn.Close()
|
||||||
|
@ -113,12 +112,12 @@ func (conn *Conn) recv() {
|
||||||
}
|
}
|
||||||
|
|
||||||
tag := fc.Tag
|
tag := fc.Tag
|
||||||
req := new(Req)
|
req := new(SrvReq)
|
||||||
select {
|
select {
|
||||||
case req.Rc = <-conn.rchan:
|
case req.Rc = <-conn.rchan:
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
req.Rc = p.NewFcall(conn.Msize)
|
req.Rc = NewFcall(conn.Msize)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Conn = conn
|
req.Conn = conn
|
||||||
|
@ -151,7 +150,15 @@ func (conn *Conn) recv() {
|
||||||
}
|
}
|
||||||
conn.Unlock()
|
conn.Unlock()
|
||||||
if process {
|
if process {
|
||||||
go req.process()
|
// Tversion may change some attributes of the
|
||||||
|
// connection, so we block on it. Otherwise,
|
||||||
|
// we may loop back to reading and that is a race.
|
||||||
|
// This fix brought to you by the race detector.
|
||||||
|
if req.Tc.Type == Tversion {
|
||||||
|
req.process()
|
||||||
|
} else {
|
||||||
|
go req.process()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = buf[fcsize:]
|
buf = buf[fcsize:]
|
||||||
|
@ -159,7 +166,6 @@ func (conn *Conn) recv() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("unreached")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) send() {
|
func (conn *Conn) send() {
|
||||||
|
@ -169,7 +175,7 @@ func (conn *Conn) send() {
|
||||||
return
|
return
|
||||||
|
|
||||||
case req := <-conn.reqout:
|
case req := <-conn.reqout:
|
||||||
p.SetTag(req.Rc, req.Tc.Tag)
|
SetTag(req.Rc, req.Tc.Tag)
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
conn.rsz += uint64(req.Rc.Size)
|
conn.rsz += uint64(req.Rc.Size)
|
||||||
conn.npend--
|
conn.npend--
|
||||||
|
@ -216,7 +222,7 @@ func (conn *Conn) LocalAddr() net.Addr {
|
||||||
return conn.conn.LocalAddr()
|
return conn.conn.LocalAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) logFcall(fc *p.Fcall) {
|
func (conn *Conn) logFcall(fc *Fcall) {
|
||||||
if conn.Debuglevel&DbgLogPackets != 0 {
|
if conn.Debuglevel&DbgLogPackets != 0 {
|
||||||
pkt := make([]byte, len(fc.Pkt))
|
pkt := make([]byte, len(fc.Pkt))
|
||||||
copy(pkt, fc.Pkt)
|
copy(pkt, fc.Pkt)
|
||||||
|
@ -224,7 +230,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if conn.Debuglevel&DbgLogFcalls != 0 {
|
if conn.Debuglevel&DbgLogFcalls != 0 {
|
||||||
f := new(p.Fcall)
|
f := new(Fcall)
|
||||||
*f = *fc
|
*f = *fc
|
||||||
f.Pkt = nil
|
f.Pkt = nil
|
||||||
conn.Srv.Log.Log(f, conn, DbgLogFcalls)
|
conn.Srv.Log.Log(f, conn, DbgLogFcalls)
|
||||||
|
@ -234,7 +240,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
|
||||||
func (srv *Srv) StartNetListener(ntype, addr string) error {
|
func (srv *Srv) StartNetListener(ntype, addr string) error {
|
||||||
l, err := net.Listen(ntype, addr)
|
l, err := net.Listen(ntype, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &p.Error{err.Error(), p.EIO}
|
return &Error{err.Error(), EIO}
|
||||||
}
|
}
|
||||||
|
|
||||||
return srv.StartListener(l)
|
return srv.StartListener(l)
|
||||||
|
@ -248,7 +254,7 @@ func (srv *Srv) StartListener(l net.Listener) error {
|
||||||
for {
|
for {
|
||||||
c, err := l.Accept()
|
c, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &p.Error{err.Error(), p.EIO}
|
return &Error{err.Error(), EIO}
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.NewConn(c)
|
srv.NewConn(c)
|
|
@ -2,20 +2,16 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package srv
|
package go9p
|
||||||
|
|
||||||
import (
|
import "runtime"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
func (srv *Srv) version(req *SrvReq) {
|
||||||
)
|
|
||||||
|
|
||||||
func (srv *Srv) version(req *Req) {
|
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
|
|
||||||
if tc.Msize < p.IOHDRSZ {
|
if tc.Msize < IOHDRSZ {
|
||||||
req.RespondError(&p.Error{"msize too small", p.EINVAL})
|
req.RespondError(&Error{"msize too small", EINVAL})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +28,7 @@ func (srv *Srv) version(req *Req) {
|
||||||
/* make sure that the responses of all current requests will be ignored */
|
/* make sure that the responses of all current requests will be ignored */
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
for tag, r := range conn.reqs {
|
for tag, r := range conn.reqs {
|
||||||
if tag == p.NOTAG {
|
if tag == NOTAG {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +43,10 @@ func (srv *Srv) version(req *Req) {
|
||||||
req.RespondRversion(conn.Msize, ver)
|
req.RespondRversion(conn.Msize, ver)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) auth(req *Req) {
|
func (srv *Srv) auth(req *SrvReq) {
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
if tc.Afid == p.NOFID {
|
if tc.Afid == NOFID {
|
||||||
req.RespondError(Eunknownfid)
|
req.RespondError(Eunknownfid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -61,8 +57,8 @@ func (srv *Srv) auth(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var user p.User = nil
|
var user User = nil
|
||||||
if tc.Unamenum != p.NOUID || conn.Dotu {
|
if tc.Unamenum != NOUID || conn.Dotu {
|
||||||
user = srv.Upool.Uid2User(int(tc.Unamenum))
|
user = srv.Upool.Uid2User(int(tc.Unamenum))
|
||||||
} else if tc.Uname != "" {
|
} else if tc.Uname != "" {
|
||||||
user = srv.Upool.Uname2User(tc.Uname)
|
user = srv.Upool.Uname2User(tc.Uname)
|
||||||
|
@ -76,13 +72,13 @@ func (srv *Srv) auth(req *Req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Afid.User = user
|
req.Afid.User = user
|
||||||
req.Afid.Type = p.QTAUTH
|
req.Afid.Type = QTAUTH
|
||||||
if aop, ok := (srv.ops).(AuthOps); ok {
|
if aop, ok := (srv.ops).(AuthOps); ok {
|
||||||
aqid, err := aop.AuthInit(req.Afid, tc.Aname)
|
aqid, err := aop.AuthInit(req.Afid, tc.Aname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
aqid.Type |= p.QTAUTH // just in case
|
aqid.Type |= QTAUTH // just in case
|
||||||
req.RespondRauth(aqid)
|
req.RespondRauth(aqid)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,16 +87,16 @@ func (srv *Srv) auth(req *Req) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) authPost(req *Req) {
|
func (srv *Srv) authPost(req *SrvReq) {
|
||||||
if req.Rc != nil && req.Rc.Type == p.Rauth {
|
if req.Rc != nil && req.Rc.Type == Rauth {
|
||||||
req.Afid.IncRef()
|
req.Afid.IncRef()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) attach(req *Req) {
|
func (srv *Srv) attach(req *SrvReq) {
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
if tc.Fid == p.NOFID {
|
if tc.Fid == NOFID {
|
||||||
req.RespondError(Eunknownfid)
|
req.RespondError(Eunknownfid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -111,15 +107,15 @@ func (srv *Srv) attach(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.Afid != p.NOFID {
|
if tc.Afid != NOFID {
|
||||||
req.Afid = conn.FidGet(tc.Afid)
|
req.Afid = conn.FidGet(tc.Afid)
|
||||||
if req.Afid == nil {
|
if req.Afid == nil {
|
||||||
req.RespondError(Eunknownfid)
|
req.RespondError(Eunknownfid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var user p.User = nil
|
var user User = nil
|
||||||
if tc.Unamenum != p.NOUID || conn.Dotu {
|
if tc.Unamenum != NOUID || conn.Dotu {
|
||||||
user = srv.Upool.Uid2User(int(tc.Unamenum))
|
user = srv.Upool.Uid2User(int(tc.Unamenum))
|
||||||
} else if tc.Uname != "" {
|
} else if tc.Uname != "" {
|
||||||
user = srv.Upool.Uname2User(tc.Uname)
|
user = srv.Upool.Uname2User(tc.Uname)
|
||||||
|
@ -141,20 +137,20 @@ func (srv *Srv) attach(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(srv.ops).(ReqOps).Attach(req)
|
(srv.ops).(SrvReqOps).Attach(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) attachPost(req *Req) {
|
func (srv *Srv) attachPost(req *SrvReq) {
|
||||||
if req.Rc != nil && req.Rc.Type == p.Rattach {
|
if req.Rc != nil && req.Rc.Type == Rattach {
|
||||||
req.Fid.Type = req.Rc.Qid.Type
|
req.Fid.Type = req.Rc.Qid.Type
|
||||||
req.Fid.IncRef()
|
req.Fid.IncRef()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) flush(req *Req) {
|
func (srv *Srv) flush(req *SrvReq) {
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
tag := req.Tc.Oldtag
|
tag := req.Tc.Oldtag
|
||||||
p.PackRflush(req.Rc)
|
PackRflush(req.Rc)
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
r := conn.reqs[tag]
|
r := conn.reqs[tag]
|
||||||
if r != nil {
|
if r != nil {
|
||||||
|
@ -186,13 +182,13 @@ func (srv *Srv) flush(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) walk(req *Req) {
|
func (srv *Srv) walk(req *SrvReq) {
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
|
|
||||||
/* we can't walk regular files, only clone them */
|
/* we can't walk regular files, only clone them */
|
||||||
if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
|
if len(tc.Wname) > 0 && (fid.Type&QTDIR) == 0 {
|
||||||
req.RespondError(Enotdir)
|
req.RespondError(Enotdir)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -217,12 +213,12 @@ func (srv *Srv) walk(req *Req) {
|
||||||
req.Newfid.IncRef()
|
req.Newfid.IncRef()
|
||||||
}
|
}
|
||||||
|
|
||||||
(req.Conn.Srv.ops).(ReqOps).Walk(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Walk(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) walkPost(req *Req) {
|
func (srv *Srv) walkPost(req *SrvReq) {
|
||||||
rc := req.Rc
|
rc := req.Rc
|
||||||
if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
|
if rc == nil || rc.Type != Rwalk || req.Newfid == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +239,7 @@ func (srv *Srv) walkPost(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) open(req *Req) {
|
func (srv *Srv) open(req *SrvReq) {
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
if fid.opened {
|
if fid.opened {
|
||||||
|
@ -251,22 +247,22 @@ func (srv *Srv) open(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
|
if (fid.Type&QTDIR) != 0 && tc.Mode != OREAD {
|
||||||
req.RespondError(Eperm)
|
req.RespondError(Eperm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fid.Omode = tc.Mode
|
fid.Omode = tc.Mode
|
||||||
(req.Conn.Srv.ops).(ReqOps).Open(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Open(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) openPost(req *Req) {
|
func (srv *Srv) openPost(req *SrvReq) {
|
||||||
if req.Fid != nil {
|
if req.Fid != nil {
|
||||||
req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
|
req.Fid.opened = req.Rc != nil && req.Rc.Type == Ropen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) create(req *Req) {
|
func (srv *Srv) create(req *SrvReq) {
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
if fid.opened {
|
if fid.opened {
|
||||||
|
@ -274,47 +270,47 @@ func (srv *Srv) create(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fid.Type & p.QTDIR) == 0 {
|
if (fid.Type & QTDIR) == 0 {
|
||||||
req.RespondError(Enotdir)
|
req.RespondError(Enotdir)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/* can't open directories for other than reading */
|
/* can't open directories for other than reading */
|
||||||
if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
|
if (tc.Perm&DMDIR) != 0 && tc.Mode != OREAD {
|
||||||
req.RespondError(Eperm)
|
req.RespondError(Eperm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/* can't create special files if not 9P2000.u */
|
/* can't create special files if not 9P2000.u */
|
||||||
if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
|
if (tc.Perm&(DMNAMEDPIPE|DMSYMLINK|DMLINK|DMDEVICE|DMSOCKET)) != 0 && !req.Conn.Dotu {
|
||||||
req.RespondError(Eperm)
|
req.RespondError(Eperm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fid.Omode = tc.Mode
|
fid.Omode = tc.Mode
|
||||||
(req.Conn.Srv.ops).(ReqOps).Create(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Create(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) createPost(req *Req) {
|
func (srv *Srv) createPost(req *SrvReq) {
|
||||||
if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
|
if req.Rc != nil && req.Rc.Type == Rcreate && req.Fid != nil {
|
||||||
req.Fid.Type = req.Rc.Qid.Type
|
req.Fid.Type = req.Rc.Qid.Type
|
||||||
req.Fid.opened = true
|
req.Fid.opened = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) read(req *Req) {
|
func (srv *Srv) read(req *SrvReq) {
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
if tc.Count+p.IOHDRSZ > req.Conn.Msize {
|
if tc.Count+IOHDRSZ > req.Conn.Msize {
|
||||||
req.RespondError(Etoolarge)
|
req.RespondError(Etoolarge)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fid.Type & p.QTAUTH) != 0 {
|
if (fid.Type & QTAUTH) != 0 {
|
||||||
var n int
|
var n int
|
||||||
|
|
||||||
rc := req.Rc
|
rc := req.Rc
|
||||||
err := p.InitRread(rc, tc.Count)
|
err := InitRread(rc, tc.Count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
return
|
return
|
||||||
|
@ -327,7 +323,7 @@ func (srv *Srv) read(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.SetRreadCount(rc, uint32(n))
|
SetRreadCount(rc, uint32(n))
|
||||||
req.Respond()
|
req.Respond()
|
||||||
} else {
|
} else {
|
||||||
req.RespondError(Enotimpl)
|
req.RespondError(Enotimpl)
|
||||||
|
@ -336,28 +332,27 @@ func (srv *Srv) read(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fid.Type & p.QTDIR) != 0 {
|
if (fid.Type & QTDIR) != 0 {
|
||||||
if tc.Offset == 0 {
|
if tc.Offset == 0 {
|
||||||
fid.Diroffset = 0
|
fid.Diroffset = 0
|
||||||
} else if tc.Offset != fid.Diroffset {
|
} else if tc.Offset != fid.Diroffset {
|
||||||
req.RespondError(Ebadoffset)
|
fid.Diroffset = tc.Offset
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(req.Conn.Srv.ops).(ReqOps).Read(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Read(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) readPost(req *Req) {
|
func (srv *Srv) readPost(req *SrvReq) {
|
||||||
if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
|
if req.Rc != nil && req.Rc.Type == Rread && (req.Fid.Type&QTDIR) != 0 {
|
||||||
req.Fid.Diroffset += uint64(req.Rc.Count)
|
req.Fid.Diroffset += uint64(req.Rc.Count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) write(req *Req) {
|
func (srv *Srv) write(req *SrvReq) {
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
if (fid.Type & p.QTAUTH) != 0 {
|
if (fid.Type & QTAUTH) != 0 {
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
||||||
n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
|
n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
|
||||||
|
@ -373,22 +368,22 @@ func (srv *Srv) write(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
|
if !fid.opened || (fid.Type&QTDIR) != 0 || (fid.Omode&3) == OREAD {
|
||||||
req.RespondError(Ebaduse)
|
req.RespondError(Ebaduse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.Count+p.IOHDRSZ > req.Conn.Msize {
|
if tc.Count+IOHDRSZ > req.Conn.Msize {
|
||||||
req.RespondError(Etoolarge)
|
req.RespondError(Etoolarge)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
(req.Conn.Srv.ops).(ReqOps).Write(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Write(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) clunk(req *Req) {
|
func (srv *Srv) clunk(req *SrvReq) {
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
if (fid.Type & p.QTAUTH) != 0 {
|
if (fid.Type & QTAUTH) != 0 {
|
||||||
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
|
||||||
op.AuthDestroy(fid)
|
op.AuthDestroy(fid)
|
||||||
req.RespondRclunk()
|
req.RespondRclunk()
|
||||||
|
@ -399,26 +394,26 @@ func (srv *Srv) clunk(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
(req.Conn.Srv.ops).(ReqOps).Clunk(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Clunk(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) clunkPost(req *Req) {
|
func (srv *Srv) clunkPost(req *SrvReq) {
|
||||||
if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
|
if req.Rc != nil && req.Rc.Type == Rclunk && req.Fid != nil {
|
||||||
req.Fid.DecRef()
|
req.Fid.DecRef()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }
|
func (srv *Srv) remove(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Remove(req) }
|
||||||
|
|
||||||
func (srv *Srv) removePost(req *Req) {
|
func (srv *Srv) removePost(req *SrvReq) {
|
||||||
if req.Rc != nil && req.Fid != nil {
|
if req.Rc != nil && req.Fid != nil {
|
||||||
req.Fid.DecRef()
|
req.Fid.DecRef()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }
|
func (srv *Srv) stat(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Stat(req) }
|
||||||
|
|
||||||
func (srv *Srv) wstat(req *Req) {
|
func (srv *Srv) wstat(req *SrvReq) {
|
||||||
/*
|
/*
|
||||||
fid := req.Fid
|
fid := req.Fid
|
||||||
d := &req.Tc.Dir
|
d := &req.Tc.Dir
|
||||||
|
@ -428,12 +423,12 @@ func (srv *Srv) wstat(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
|
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&QTDIR) != 0 && (d.Mode&DMDIR) == 0) ||
|
||||||
((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
|
((d.Type&QTDIR) == 0 && (d.Mode&DMDIR) != 0)) {
|
||||||
req.RespondError(Edirchange)
|
req.RespondError(Edirchange)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(req.Conn.Srv.ops).(ReqOps).Wstat(req)
|
(req.Conn.Srv.ops).(SrvReqOps).Wstat(req)
|
||||||
}
|
}
|
|
@ -2,10 +2,9 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package srv
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -13,18 +12,18 @@ import (
|
||||||
|
|
||||||
// The FStatOp interface provides a single operation (Stat) that will be
|
// The FStatOp interface provides a single operation (Stat) that will be
|
||||||
// called before a file stat is sent back to the client. If implemented,
|
// called before a file stat is sent back to the client. If implemented,
|
||||||
// the operation should update the data in the File struct.
|
// the operation should update the data in the srvFile struct.
|
||||||
type FStatOp interface {
|
type FStatOp interface {
|
||||||
Stat(fid *FFid) error
|
Stat(fid *FFid) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// The FWstatOp interface provides a single operation (Wstat) that will be
|
// The FWstatOp interface provides a single operation (Wstat) that will be
|
||||||
// called when the client requests the File metadata to be modified. If
|
// called when the client requests the srvFile metadata to be modified. If
|
||||||
// implemented, the operation will be called when Twstat message is received.
|
// implemented, the operation will be called when Twstat message is received.
|
||||||
// If not implemented, "permission denied" error will be sent back. If the
|
// If not implemented, "permission denied" error will be sent back. If the
|
||||||
// operation returns an Error, the error is send back to the client.
|
// operation returns an Error, the error is send back to the client.
|
||||||
type FWstatOp interface {
|
type FWstatOp interface {
|
||||||
Wstat(*FFid, *p.Dir) error
|
Wstat(*FFid, *Dir) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the FReadOp interface is implemented, the Read operation will be called
|
// If the FReadOp interface is implemented, the Read operation will be called
|
||||||
|
@ -44,16 +43,16 @@ type FWriteOp interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the FCreateOp interface is implemented, the Create operation will be called
|
// If the FCreateOp interface is implemented, the Create operation will be called
|
||||||
// when the client attempts to create a file in the File implementing the interface.
|
// when the client attempts to create a file in the srvFile implementing the interface.
|
||||||
// If not implemented, "permission denied" error will be send back. If successful,
|
// If not implemented, "permission denied" error will be send back. If successful,
|
||||||
// the operation should call (*File)Add() to add the created file to the directory.
|
// the operation should call (*File)Add() to add the created file to the directory.
|
||||||
// The operation returns the created file, or the error occured while creating it.
|
// The operation returns the created file, or the error occured while creating it.
|
||||||
type FCreateOp interface {
|
type FCreateOp interface {
|
||||||
Create(fid *FFid, name string, perm uint32) (*File, error)
|
Create(fid *FFid, name string, perm uint32) (*srvFile, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the FRemoveOp interface is implemented, the Remove operation will be called
|
// If the FRemoveOp interface is implemented, the Remove operation will be called
|
||||||
// when the client attempts to create a file in the File implementing the interface.
|
// when the client attempts to create a file in the srvFile implementing the interface.
|
||||||
// If not implemented, "permission denied" error will be send back.
|
// If not implemented, "permission denied" error will be send back.
|
||||||
// The operation returns nil if successful, or the error that occured while removing
|
// The operation returns nil if successful, or the error that occured while removing
|
||||||
// the file.
|
// the file.
|
||||||
|
@ -79,39 +78,40 @@ const (
|
||||||
Fremoved FFlags = 1 << iota
|
Fremoved FFlags = 1 << iota
|
||||||
)
|
)
|
||||||
|
|
||||||
// The File type represents a file (or directory) served by the file server.
|
// The srvFile type represents a file (or directory) served by the file server.
|
||||||
type File struct {
|
type srvFile struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
p.Dir
|
Dir
|
||||||
flags FFlags
|
flags FFlags
|
||||||
|
|
||||||
Parent *File // parent
|
Parent *srvFile // parent
|
||||||
next, prev *File // siblings, guarded by parent.Lock
|
next, prev *srvFile // siblings, guarded by parent.Lock
|
||||||
cfirst, clast *File // children (if directory)
|
cfirst, clast *srvFile // children (if directory)
|
||||||
Ops interface{}
|
ops interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FFid struct {
|
type FFid struct {
|
||||||
F *File
|
F *srvFile
|
||||||
Fid *Fid
|
Fid *SrvFid
|
||||||
dirs []*File // used for readdir
|
dirs []*srvFile // used for readdir
|
||||||
|
dirents []byte // serialized version of dirs
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Fsrv can be used to create file servers that serve
|
// The Fsrv can be used to create file servers that serve
|
||||||
// simple trees of synthetic files.
|
// simple trees of synthetic files.
|
||||||
type Fsrv struct {
|
type Fsrv struct {
|
||||||
Srv
|
Srv
|
||||||
Root *File
|
Root *srvFile
|
||||||
}
|
}
|
||||||
|
|
||||||
var lock sync.Mutex
|
var lock sync.Mutex
|
||||||
var qnext uint64
|
var qnext uint64
|
||||||
var Eexist = &p.Error{"file already exists", p.EEXIST}
|
var Eexist = &Error{"file already exists", EEXIST}
|
||||||
var Enoent = &p.Error{"file not found", p.ENOENT}
|
var Enoent = &Error{"file not found", ENOENT}
|
||||||
var Enotempty = &p.Error{"directory not empty", p.EPERM}
|
var Enotempty = &Error{"directory not empty", EPERM}
|
||||||
|
|
||||||
// Creates a file server with root as root directory
|
// Creates a file server with root as root directory
|
||||||
func NewFileSrv(root *File) *Fsrv {
|
func NewsrvFileSrv(root *srvFile) *Fsrv {
|
||||||
srv := new(Fsrv)
|
srv := new(Fsrv)
|
||||||
srv.Root = root
|
srv.Root = root
|
||||||
root.Parent = root // make sure we can .. in root
|
root.Parent = root // make sure we can .. in root
|
||||||
|
@ -121,7 +121,7 @@ func NewFileSrv(root *File) *Fsrv {
|
||||||
|
|
||||||
// Initializes the fields of a file and add it to a directory.
|
// Initializes the fields of a file and add it to a directory.
|
||||||
// Returns nil if successful, or an error.
|
// Returns nil if successful, or an error.
|
||||||
func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ops interface{}) error {
|
func (f *srvFile) Add(dir *srvFile, name string, uid User, gid Group, mode uint32, ops interface{}) error {
|
||||||
|
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
qpath := qnext
|
qpath := qnext
|
||||||
|
@ -141,7 +141,7 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
|
||||||
f.Uidnum = uint32(uid.Id())
|
f.Uidnum = uint32(uid.Id())
|
||||||
} else {
|
} else {
|
||||||
f.Uid = "none"
|
f.Uid = "none"
|
||||||
f.Uidnum = p.NOUID
|
f.Uidnum = NOUID
|
||||||
}
|
}
|
||||||
|
|
||||||
if gid != nil {
|
if gid != nil {
|
||||||
|
@ -149,11 +149,11 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
|
||||||
f.Gidnum = uint32(gid.Id())
|
f.Gidnum = uint32(gid.Id())
|
||||||
} else {
|
} else {
|
||||||
f.Gid = "none"
|
f.Gid = "none"
|
||||||
f.Gidnum = p.NOUID
|
f.Gidnum = NOUID
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Muid = ""
|
f.Muid = ""
|
||||||
f.Muidnum = p.NOUID
|
f.Muidnum = NOUID
|
||||||
f.Ext = ""
|
f.Ext = ""
|
||||||
|
|
||||||
if dir != nil {
|
if dir != nil {
|
||||||
|
@ -180,12 +180,12 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
|
||||||
f.Parent = f
|
f.Parent = f
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Ops = ops
|
f.ops = ops
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a file from its parent directory.
|
// Removes a file from its parent directory.
|
||||||
func (f *File) Remove() {
|
func (f *srvFile) Remove() {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
if (f.flags & Fremoved) != 0 {
|
if (f.flags & Fremoved) != 0 {
|
||||||
f.Unlock()
|
f.Unlock()
|
||||||
|
@ -214,7 +214,7 @@ func (f *File) Remove() {
|
||||||
p.Unlock()
|
p.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) Rename(name string) error {
|
func (f *srvFile) Rename(name string) error {
|
||||||
p := f.Parent
|
p := f.Parent
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
|
@ -229,8 +229,8 @@ func (f *File) Rename(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks for a file in a directory. Returns nil if the file is not found.
|
// Looks for a file in a directory. Returns nil if the file is not found.
|
||||||
func (p *File) Find(name string) *File {
|
func (p *srvFile) Find(name string) *srvFile {
|
||||||
var f *File
|
var f *srvFile
|
||||||
|
|
||||||
p.Lock()
|
p.Lock()
|
||||||
for f = p.cfirst; f != nil; f = f.next {
|
for f = p.cfirst; f != nil; f = f.next {
|
||||||
|
@ -244,8 +244,8 @@ func (p *File) Find(name string) *File {
|
||||||
|
|
||||||
// Checks if the specified user has permission to perform
|
// Checks if the specified user has permission to perform
|
||||||
// certain operation on a file. Perm contains one or more
|
// certain operation on a file. Perm contains one or more
|
||||||
// of p.DMREAD, p.DMWRITE, and p.DMEXEC.
|
// of DMREAD, DMWRITE, and DMEXEC.
|
||||||
func (f *File) CheckPerm(user p.User, perm uint32) bool {
|
func (f *srvFile) CheckPerm(user User, perm uint32) bool {
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ func (f *File) CheckPerm(user p.User, perm uint32) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Fsrv) Attach(req *Req) {
|
func (s *Fsrv) Attach(req *SrvReq) {
|
||||||
fid := new(FFid)
|
fid := new(FFid)
|
||||||
fid.F = s.Root
|
fid.F = s.Root
|
||||||
fid.Fid = req.Fid
|
fid.Fid = req.Fid
|
||||||
|
@ -293,7 +293,7 @@ func (s *Fsrv) Attach(req *Req) {
|
||||||
req.RespondRattach(&s.Root.Qid)
|
req.RespondRattach(&s.Root.Qid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Walk(req *Req) {
|
func (*Fsrv) Walk(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ func (*Fsrv) Walk(req *Req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nfid := req.Newfid.Aux.(*FFid)
|
nfid := req.Newfid.Aux.(*FFid)
|
||||||
wqids := make([]p.Qid, len(tc.Wname))
|
wqids := make([]Qid, len(tc.Wname))
|
||||||
i := 0
|
i := 0
|
||||||
f := fid.F
|
f := fid.F
|
||||||
for ; i < len(tc.Wname); i++ {
|
for ; i < len(tc.Wname); i++ {
|
||||||
|
@ -314,8 +314,8 @@ func (*Fsrv) Walk(req *Req) {
|
||||||
wqids[i] = f.Qid
|
wqids[i] = f.Qid
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (wqids[i].Type & p.QTDIR) > 0 {
|
if (wqids[i].Type & QTDIR) > 0 {
|
||||||
if !f.CheckPerm(req.Fid.User, p.DMEXEC) {
|
if !f.CheckPerm(req.Fid.User, DMEXEC) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,22 +342,22 @@ func mode2Perm(mode uint8) uint32 {
|
||||||
var perm uint32 = 0
|
var perm uint32 = 0
|
||||||
|
|
||||||
switch mode & 3 {
|
switch mode & 3 {
|
||||||
case p.OREAD:
|
case OREAD:
|
||||||
perm = p.DMREAD
|
perm = DMREAD
|
||||||
case p.OWRITE:
|
case OWRITE:
|
||||||
perm = p.DMWRITE
|
perm = DMWRITE
|
||||||
case p.ORDWR:
|
case ORDWR:
|
||||||
perm = p.DMREAD | p.DMWRITE
|
perm = DMREAD | DMWRITE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode & p.OTRUNC) != 0 {
|
if (mode & OTRUNC) != 0 {
|
||||||
perm |= p.DMWRITE
|
perm |= DMWRITE
|
||||||
}
|
}
|
||||||
|
|
||||||
return perm
|
return perm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Open(req *Req) {
|
func (*Fsrv) Open(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ func (*Fsrv) Open(req *Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if op, ok := (fid.F.Ops).(FOpenOp); ok {
|
if op, ok := (fid.F.ops).(FOpenOp); ok {
|
||||||
err := op.Open(fid, tc.Mode)
|
err := op.Open(fid, tc.Mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -376,17 +376,17 @@ func (*Fsrv) Open(req *Req) {
|
||||||
req.RespondRopen(&fid.F.Qid, 0)
|
req.RespondRopen(&fid.F.Qid, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Create(req *Req) {
|
func (*Fsrv) Create(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
|
|
||||||
dir := fid.F
|
dir := fid.F
|
||||||
if !dir.CheckPerm(req.Fid.User, p.DMWRITE) {
|
if !dir.CheckPerm(req.Fid.User, DMWRITE) {
|
||||||
req.RespondError(Eperm)
|
req.RespondError(Eperm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if cop, ok := (dir.Ops).(FCreateOp); ok {
|
if cop, ok := (dir.ops).(FCreateOp); ok {
|
||||||
f, err := cop.Create(fid, tc.Name, tc.Perm)
|
f, err := cop.Create(fid, tc.Name, tc.Perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -399,55 +399,48 @@ func (*Fsrv) Create(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Read(req *Req) {
|
func (*Fsrv) Read(req *SrvReq) {
|
||||||
var i, n int
|
var n int
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
f := fid.F
|
f := fid.F
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
rc := req.Rc
|
rc := req.Rc
|
||||||
p.InitRread(rc, tc.Count)
|
InitRread(rc, tc.Count)
|
||||||
|
|
||||||
if f.Mode&p.DMDIR != 0 {
|
if f.Mode&DMDIR != 0 {
|
||||||
// directory
|
// Get all the directory entries and
|
||||||
|
// serialize them all into an output buffer.
|
||||||
|
// This greatly simplifies the directory read.
|
||||||
if tc.Offset == 0 {
|
if tc.Offset == 0 {
|
||||||
var g *File
|
var g *srvFile
|
||||||
|
fid.dirents = nil
|
||||||
f.Lock()
|
f.Lock()
|
||||||
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
|
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
|
||||||
}
|
}
|
||||||
|
fid.dirs = make([]*srvFile, n)
|
||||||
fid.dirs = make([]*File, n)
|
|
||||||
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
|
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
|
||||||
fid.dirs[n] = g
|
fid.dirs[n] = g
|
||||||
|
fid.dirents = append(fid.dirents,
|
||||||
|
PackDir(&g.Dir, req.Conn.Dotu)...)
|
||||||
}
|
}
|
||||||
f.Unlock()
|
f.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
n = 0
|
switch {
|
||||||
b := rc.Data
|
case tc.Offset > uint64(len(fid.dirents)):
|
||||||
for i = 0; i < len(fid.dirs); i++ {
|
n = 0
|
||||||
g := fid.dirs[i]
|
case len(fid.dirents[tc.Offset:]) > int(tc.Size):
|
||||||
g.Lock()
|
n = int(tc.Size)
|
||||||
if (g.flags & Fremoved) != 0 {
|
default:
|
||||||
g.Unlock()
|
n = len(fid.dirents[tc.Offset:])
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sz := p.PackDir(&g.Dir, b, req.Conn.Dotu)
|
|
||||||
g.Unlock()
|
|
||||||
if sz == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
b = b[sz:]
|
|
||||||
n += sz
|
|
||||||
}
|
}
|
||||||
|
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+1+n])
|
||||||
|
|
||||||
fid.dirs = fid.dirs[i:]
|
|
||||||
} else {
|
} else {
|
||||||
// file
|
// file
|
||||||
if rop, ok := f.Ops.(FReadOp); ok {
|
if rop, ok := f.ops.(FReadOp); ok {
|
||||||
n, err = rop.Read(fid, rc.Data, tc.Offset)
|
n, err = rop.Read(fid, rc.Data, tc.Offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -459,16 +452,16 @@ func (*Fsrv) Read(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.SetRreadCount(rc, uint32(n))
|
SetRreadCount(rc, uint32(n))
|
||||||
req.Respond()
|
req.Respond()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Write(req *Req) {
|
func (*Fsrv) Write(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
f := fid.F
|
f := fid.F
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
|
|
||||||
if wop, ok := (f.Ops).(FWriteOp); ok {
|
if wop, ok := (f.ops).(FWriteOp); ok {
|
||||||
n, err := wop.Write(fid, tc.Data, tc.Offset)
|
n, err := wop.Write(fid, tc.Data, tc.Offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -481,10 +474,10 @@ func (*Fsrv) Write(req *Req) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Clunk(req *Req) {
|
func (*Fsrv) Clunk(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
|
|
||||||
if op, ok := (fid.F.Ops).(FClunkOp); ok {
|
if op, ok := (fid.F.ops).(FClunkOp); ok {
|
||||||
err := op.Clunk(fid)
|
err := op.Clunk(fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -493,7 +486,7 @@ func (*Fsrv) Clunk(req *Req) {
|
||||||
req.RespondRclunk()
|
req.RespondRclunk()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Remove(req *Req) {
|
func (*Fsrv) Remove(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
f := fid.F
|
f := fid.F
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -504,7 +497,7 @@ func (*Fsrv) Remove(req *Req) {
|
||||||
}
|
}
|
||||||
f.Unlock()
|
f.Unlock()
|
||||||
|
|
||||||
if rop, ok := (f.Ops).(FRemoveOp); ok {
|
if rop, ok := (f.ops).(FRemoveOp); ok {
|
||||||
err := rop.Remove(fid)
|
err := rop.Remove(fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -518,11 +511,11 @@ func (*Fsrv) Remove(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Stat(req *Req) {
|
func (*Fsrv) Stat(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
f := fid.F
|
f := fid.F
|
||||||
|
|
||||||
if sop, ok := (f.Ops).(FStatOp); ok {
|
if sop, ok := (f.ops).(FStatOp); ok {
|
||||||
err := sop.Stat(fid)
|
err := sop.Stat(fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -534,12 +527,12 @@ func (*Fsrv) Stat(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) Wstat(req *Req) {
|
func (*Fsrv) Wstat(req *SrvReq) {
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
fid := req.Fid.Aux.(*FFid)
|
fid := req.Fid.Aux.(*FFid)
|
||||||
f := fid.F
|
f := fid.F
|
||||||
|
|
||||||
if wop, ok := (f.Ops).(FWstatOp); ok {
|
if wop, ok := (f.ops).(FWstatOp); ok {
|
||||||
err := wop.Wstat(fid, &tc.Dir)
|
err := wop.Wstat(fid, &tc.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -551,7 +544,7 @@ func (*Fsrv) Wstat(req *Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Fsrv) FidDestroy(ffid *Fid) {
|
func (*Fsrv) FidDestroy(ffid *SrvFid) {
|
||||||
if ffid.Aux == nil {
|
if ffid.Aux == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -562,7 +555,7 @@ func (*Fsrv) FidDestroy(ffid *Fid) {
|
||||||
return // otherwise errs in bad walks
|
return // otherwise errs in bad walks
|
||||||
}
|
}
|
||||||
|
|
||||||
if op, ok := (f.Ops).(FDestroyOp); ok {
|
if op, ok := (f.ops).(FDestroyOp); ok {
|
||||||
op.FidDestroy(fid)
|
op.FidDestroy(fid)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 = ""
|
||||||
|
}
|
|
@ -2,28 +2,42 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package srv
|
package go9p
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "k8s.io/minikube/third_party/go9p/p"
|
|
||||||
|
// SrvRequest operations. This interface should be implemented by all file servers.
|
||||||
|
// The operations correspond directly to most of the 9P2000 message types.
|
||||||
|
type SrvReqOps interface {
|
||||||
|
Attach(*SrvReq)
|
||||||
|
Walk(*SrvReq)
|
||||||
|
Open(*SrvReq)
|
||||||
|
Create(*SrvReq)
|
||||||
|
Read(*SrvReq)
|
||||||
|
Write(*SrvReq)
|
||||||
|
Clunk(*SrvReq)
|
||||||
|
Remove(*SrvReq)
|
||||||
|
Stat(*SrvReq)
|
||||||
|
Wstat(*SrvReq)
|
||||||
|
}
|
||||||
|
|
||||||
// Respond to the request with Rerror message
|
// Respond to the request with Rerror message
|
||||||
func (req *Req) RespondError(err interface{}) {
|
func (req *SrvReq) RespondError(err interface{}) {
|
||||||
switch e := err.(type) {
|
switch e := err.(type) {
|
||||||
case *p.Error:
|
case *Error:
|
||||||
p.PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
|
PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
|
||||||
case error:
|
case error:
|
||||||
p.PackRerror(req.Rc, e.Error(), uint32(p.EIO), req.Conn.Dotu)
|
PackRerror(req.Rc, e.Error(), uint32(EIO), req.Conn.Dotu)
|
||||||
default:
|
default:
|
||||||
p.PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(p.EIO), req.Conn.Dotu)
|
PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(EIO), req.Conn.Dotu)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Respond()
|
req.Respond()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rversion message
|
// Respond to the request with Rversion message
|
||||||
func (req *Req) RespondRversion(msize uint32, version string) {
|
func (req *SrvReq) RespondRversion(msize uint32, version string) {
|
||||||
err := p.PackRversion(req.Rc, msize, version)
|
err := PackRversion(req.Rc, msize, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,8 +46,8 @@ func (req *Req) RespondRversion(msize uint32, version string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rauth message
|
// Respond to the request with Rauth message
|
||||||
func (req *Req) RespondRauth(aqid *p.Qid) {
|
func (req *SrvReq) RespondRauth(aqid *Qid) {
|
||||||
err := p.PackRauth(req.Rc, aqid)
|
err := PackRauth(req.Rc, aqid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -42,8 +56,8 @@ func (req *Req) RespondRauth(aqid *p.Qid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rflush message
|
// Respond to the request with Rflush message
|
||||||
func (req *Req) RespondRflush() {
|
func (req *SrvReq) RespondRflush() {
|
||||||
err := p.PackRflush(req.Rc)
|
err := PackRflush(req.Rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -52,8 +66,8 @@ func (req *Req) RespondRflush() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rattach message
|
// Respond to the request with Rattach message
|
||||||
func (req *Req) RespondRattach(aqid *p.Qid) {
|
func (req *SrvReq) RespondRattach(aqid *Qid) {
|
||||||
err := p.PackRattach(req.Rc, aqid)
|
err := PackRattach(req.Rc, aqid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,8 +76,8 @@ func (req *Req) RespondRattach(aqid *p.Qid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rwalk message
|
// Respond to the request with Rwalk message
|
||||||
func (req *Req) RespondRwalk(wqids []p.Qid) {
|
func (req *SrvReq) RespondRwalk(wqids []Qid) {
|
||||||
err := p.PackRwalk(req.Rc, wqids)
|
err := PackRwalk(req.Rc, wqids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,8 +86,8 @@ func (req *Req) RespondRwalk(wqids []p.Qid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Ropen message
|
// Respond to the request with Ropen message
|
||||||
func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
|
func (req *SrvReq) RespondRopen(qid *Qid, iounit uint32) {
|
||||||
err := p.PackRopen(req.Rc, qid, iounit)
|
err := PackRopen(req.Rc, qid, iounit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -82,8 +96,8 @@ func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rcreate message
|
// Respond to the request with Rcreate message
|
||||||
func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
|
func (req *SrvReq) RespondRcreate(qid *Qid, iounit uint32) {
|
||||||
err := p.PackRcreate(req.Rc, qid, iounit)
|
err := PackRcreate(req.Rc, qid, iounit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -92,8 +106,8 @@ func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rread message
|
// Respond to the request with Rread message
|
||||||
func (req *Req) RespondRread(data []byte) {
|
func (req *SrvReq) RespondRread(data []byte) {
|
||||||
err := p.PackRread(req.Rc, data)
|
err := PackRread(req.Rc, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,8 +116,8 @@ func (req *Req) RespondRread(data []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rwrite message
|
// Respond to the request with Rwrite message
|
||||||
func (req *Req) RespondRwrite(count uint32) {
|
func (req *SrvReq) RespondRwrite(count uint32) {
|
||||||
err := p.PackRwrite(req.Rc, count)
|
err := PackRwrite(req.Rc, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -112,8 +126,8 @@ func (req *Req) RespondRwrite(count uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rclunk message
|
// Respond to the request with Rclunk message
|
||||||
func (req *Req) RespondRclunk() {
|
func (req *SrvReq) RespondRclunk() {
|
||||||
err := p.PackRclunk(req.Rc)
|
err := PackRclunk(req.Rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,8 +136,8 @@ func (req *Req) RespondRclunk() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rremove message
|
// Respond to the request with Rremove message
|
||||||
func (req *Req) RespondRremove() {
|
func (req *SrvReq) RespondRremove() {
|
||||||
err := p.PackRremove(req.Rc)
|
err := PackRremove(req.Rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -132,8 +146,8 @@ func (req *Req) RespondRremove() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rstat message
|
// Respond to the request with Rstat message
|
||||||
func (req *Req) RespondRstat(st *p.Dir) {
|
func (req *SrvReq) RespondRstat(st *Dir) {
|
||||||
err := p.PackRstat(req.Rc, st, req.Conn.Dotu)
|
err := PackRstat(req.Rc, st, req.Conn.Dotu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,8 +156,8 @@ func (req *Req) RespondRstat(st *p.Dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respond to the request with Rwstat message
|
// Respond to the request with Rwstat message
|
||||||
func (req *Req) RespondRwstat() {
|
func (req *SrvReq) RespondRwstat() {
|
||||||
err := p.PackRwstat(req.Rc)
|
err := PackRwstat(req.Rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
} else {
|
} else {
|
|
@ -2,12 +2,11 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// The srv package provides definitions and functions used to implement
|
// The srv package go9provides definitions and functions used to implement
|
||||||
// a 9P2000 file server.
|
// a 9P2000 file server.
|
||||||
package srv
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -22,26 +21,18 @@ const (
|
||||||
reqSaved /* no response was produced after the request is worked on */
|
reqSaved /* no response was produced after the request is worked on */
|
||||||
)
|
)
|
||||||
|
|
||||||
// Debug flags
|
var Eunknownfid error = &Error{"unknown fid", EINVAL}
|
||||||
const (
|
var Enoauth error = &Error{"no authentication required", EINVAL}
|
||||||
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr
|
var Einuse error = &Error{"fid already in use", EINVAL}
|
||||||
DbgPrintPackets // print the raw packets on stderr
|
var Ebaduse error = &Error{"bad use of fid", EINVAL}
|
||||||
DbgLogFcalls // keep the last N 9P messages (can be accessed over http)
|
var Eopen error = &Error{"fid already opened", EINVAL}
|
||||||
DbgLogPackets // keep the last N 9P messages (can be accessed over http)
|
var Enotdir error = &Error{"not a directory", ENOTDIR}
|
||||||
)
|
var Eperm error = &Error{"permission denied", EPERM}
|
||||||
|
var Etoolarge error = &Error{"i/o count too large", EINVAL}
|
||||||
var Eunknownfid error = &p.Error{"unknown fid", p.EINVAL}
|
var Ebadoffset error = &Error{"bad offset in directory read", EINVAL}
|
||||||
var Enoauth error = &p.Error{"no authentication required", p.EINVAL}
|
var Edirchange error = &Error{"cannot convert between files and directories", EINVAL}
|
||||||
var Einuse error = &p.Error{"fid already in use", p.EINVAL}
|
var Enouser error = &Error{"unknown user", EINVAL}
|
||||||
var Ebaduse error = &p.Error{"bad use of fid", p.EINVAL}
|
var Enotimpl error = &Error{"not implemented", EINVAL}
|
||||||
var Eopen error = &p.Error{"fid already opened", p.EINVAL}
|
|
||||||
var Enotdir error = &p.Error{"not a directory", p.ENOTDIR}
|
|
||||||
var Eperm error = &p.Error{"permission denied", p.EPERM}
|
|
||||||
var Etoolarge error = &p.Error{"i/o count too large", p.EINVAL}
|
|
||||||
var Ebadoffset error = &p.Error{"bad offset in directory read", p.EINVAL}
|
|
||||||
var Edirchange error = &p.Error{"cannot convert between files and directories", p.EINVAL}
|
|
||||||
var Enouser error = &p.Error{"unknown user", p.EINVAL}
|
|
||||||
var Enotimpl error = &p.Error{"not implemented", p.EINVAL}
|
|
||||||
|
|
||||||
// Authentication operations. The file server should implement them if
|
// Authentication operations. The file server should implement them if
|
||||||
// it requires user authentication. The authentication in 9P2000 is
|
// it requires user authentication. The authentication in 9P2000 is
|
||||||
|
@ -50,28 +41,28 @@ var Enotimpl error = &p.Error{"not implemented", p.EINVAL}
|
||||||
// fid can be used by the user to get access to the actual files.
|
// fid can be used by the user to get access to the actual files.
|
||||||
type AuthOps interface {
|
type AuthOps interface {
|
||||||
// AuthInit is called when the user starts the authentication
|
// AuthInit is called when the user starts the authentication
|
||||||
// process on Fid afid. The user that is being authenticated
|
// process on SrvFid afid. The user that is being authenticated
|
||||||
// is referred by afid.User. The function should return the Qid
|
// is referred by afid.User. The function should return the Qid
|
||||||
// for the authentication file, or an Error if the user can't be
|
// for the authentication file, or an Error if the user can't be
|
||||||
// authenticated
|
// authenticated
|
||||||
AuthInit(afid *Fid, aname string) (*p.Qid, error)
|
AuthInit(afid *SrvFid, aname string) (*Qid, error)
|
||||||
|
|
||||||
// AuthDestroy is called when an authentication fid is destroyed.
|
// AuthDestroy is called when an authentication fid is destroyed.
|
||||||
AuthDestroy(afid *Fid)
|
AuthDestroy(afid *SrvFid)
|
||||||
|
|
||||||
// AuthCheck is called after the authentication process is finished
|
// AuthCheck is called after the authentication process is finished
|
||||||
// when the user tries to attach to the file server. If the function
|
// when the user tries to attach to the file server. If the function
|
||||||
// returns nil, the authentication was successful and the user has
|
// returns nil, the authentication was successful and the user has
|
||||||
// permission to access the files.
|
// permission to access the files.
|
||||||
AuthCheck(fid *Fid, afid *Fid, aname string) error
|
AuthCheck(fid *SrvFid, afid *SrvFid, aname string) error
|
||||||
|
|
||||||
// AuthRead is called when the user attempts to read data from an
|
// AuthRead is called when the user attempts to read data from an
|
||||||
// authentication fid.
|
// authentication fid.
|
||||||
AuthRead(afid *Fid, offset uint64, data []byte) (count int, err error)
|
AuthRead(afid *SrvFid, offset uint64, data []byte) (count int, err error)
|
||||||
|
|
||||||
// AuthWrite is called when the user attempts to write data to an
|
// AuthWrite is called when the user attempts to write data to an
|
||||||
// authentication fid.
|
// authentication fid.
|
||||||
AuthWrite(afid *Fid, offset uint64, data []byte) (count int, err error)
|
AuthWrite(afid *SrvFid, offset uint64, data []byte) (count int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connection operations. These should be implemented if the file server
|
// Connection operations. These should be implemented if the file server
|
||||||
|
@ -81,61 +72,41 @@ type ConnOps interface {
|
||||||
ConnClosed(*Conn)
|
ConnClosed(*Conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fid operations. This interface should be implemented if the file server
|
// SrvFid operations. This interface should be implemented if the file server
|
||||||
// needs to be called when a Fid is destroyed.
|
// needs to be called when a SrvFid is destroyed.
|
||||||
type FidOps interface {
|
type SrvFidOps interface {
|
||||||
FidDestroy(*Fid)
|
FidDestroy(*SrvFid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request operations. This interface should be implemented if the file server
|
// Request operations. This interface should be implemented if the file server
|
||||||
// needs to bypass the default request process, or needs to perform certain
|
// needs to bypass the default request process, or needs to perform certain
|
||||||
// operations before the (any) request is processed, or before (any) response
|
// operations before the (any) request is processed, or before (any) response
|
||||||
// sent back to the client.
|
// sent back to the client.
|
||||||
type ReqProcessOps interface {
|
type SrvReqProcessOps interface {
|
||||||
// Called when a new request is received from the client. If the
|
// Called when a new request is received from the client. If the
|
||||||
// interface is not implemented, (req *Req) srv.Process() method is
|
// interface is not implemented, (req *SrvReq) srv.Process() method is
|
||||||
// called. If the interface is implemented, it is the user's
|
// called. If the interface is implemented, it is the user's
|
||||||
// responsibility to call srv.Process. If srv.Process isn't called,
|
// responsibility to call srv.Process. If srv.Process isn't called,
|
||||||
// Fid, Afid and Newfid fields in Req are not set, and the ReqOps
|
// SrvFid, Afid and Newfid fields in SrvReq are not set, and the SrvReqOps
|
||||||
// methods are not called.
|
// methods are not called.
|
||||||
ReqProcess(*Req)
|
SrvReqProcess(*SrvReq)
|
||||||
|
|
||||||
// Called when a request is responded, i.e. when (req *Req)srv.Respond()
|
// Called when a request is responded, i.e. when (req *SrvReq)srv.Respond()
|
||||||
// is called and before the response is sent. If the interface is not
|
// is called and before the response is sent. If the interface is not
|
||||||
// implemented, (req *Req) srv.PostProcess() method is called to finalize
|
// implemented, (req *SrvReq) srv.PostProcess() method is called to finalize
|
||||||
// the request. If the interface is implemented and ReqProcess calls
|
// the request. If the interface is implemented and SrvReqProcess calls
|
||||||
// the srv.Process method, ReqRespond should call the srv.PostProcess
|
// the srv.Process method, SrvReqRespond should call the srv.PostProcess
|
||||||
// method.
|
// method.
|
||||||
ReqRespond(*Req)
|
SrvReqRespond(*SrvReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush operation. This interface should be implemented if the file server
|
// Flush operation. This interface should be implemented if the file server
|
||||||
// can flush pending requests. If the interface is not implemented, requests
|
// can flush pending requests. If the interface is not implemented, requests
|
||||||
// that were passed to the file server implementation won't be flushed.
|
// that were passed to the file server implementation won't be flushed.
|
||||||
// The flush method should call the (req *Req) srv.Flush() method if the flush
|
// The flush method should call the (req *SrvReq) srv.Flush() method if the flush
|
||||||
// was successful so the request can be marked appropriately.
|
// was successful so the request can be marked appropriately.
|
||||||
type FlushOp interface {
|
type FlushOp interface {
|
||||||
Flush(*Req)
|
Flush(*SrvReq)
|
||||||
}
|
|
||||||
|
|
||||||
// Request operations. This interface should be implemented by all file servers.
|
|
||||||
// The operations correspond directly to most of the 9P2000 message types.
|
|
||||||
type ReqOps interface {
|
|
||||||
Attach(*Req)
|
|
||||||
Walk(*Req)
|
|
||||||
Open(*Req)
|
|
||||||
Create(*Req)
|
|
||||||
Read(*Req)
|
|
||||||
Write(*Req)
|
|
||||||
Clunk(*Req)
|
|
||||||
Remove(*Req)
|
|
||||||
Stat(*Req)
|
|
||||||
Wstat(*Req)
|
|
||||||
}
|
|
||||||
|
|
||||||
type StatsOps interface {
|
|
||||||
statsRegister()
|
|
||||||
statsUnregister()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Srv type contains the basic fields used to control the 9P2000
|
// The Srv type contains the basic fields used to control the 9P2000
|
||||||
|
@ -145,13 +116,13 @@ type StatsOps interface {
|
||||||
// that implements the file server operations.
|
// that implements the file server operations.
|
||||||
type Srv struct {
|
type Srv struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
Id string // Used for debugging and stats
|
Id string // Used for debugging and stats
|
||||||
Msize uint32 // Maximum size of the 9P2000 messages supported by the server
|
Msize uint32 // Maximum size of the 9P2000 messages supported by the server
|
||||||
Dotu bool // If true, the server supports the 9P2000.u extension
|
Dotu bool // If true, the server supports the 9P2000.u extension
|
||||||
Debuglevel int // debug level
|
Debuglevel int // debug level
|
||||||
Upool p.Users // Interface for finding users and groups known to the file server
|
Upool Users // Interface for finding users and groups known to the file server
|
||||||
Maxpend int // Maximum pending outgoing requests
|
Maxpend int // Maximum pending outgoing requests
|
||||||
Log *p.Logger
|
Log *Logger
|
||||||
|
|
||||||
ops interface{} // operations
|
ops interface{} // operations
|
||||||
conns map[*Conn]*Conn // List of connections
|
conns map[*Conn]*Conn // List of connections
|
||||||
|
@ -167,11 +138,11 @@ type Conn struct {
|
||||||
Debuglevel int
|
Debuglevel int
|
||||||
|
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
fidpool map[uint32]*Fid
|
fidpool map[uint32]*SrvFid
|
||||||
reqs map[uint16]*Req // all outstanding requests
|
reqs map[uint16]*SrvReq // all outstanding requests
|
||||||
|
|
||||||
reqout chan *Req
|
reqout chan *SrvReq
|
||||||
rchan chan *p.Fcall
|
rchan chan *Fcall
|
||||||
done chan bool
|
done chan bool
|
||||||
|
|
||||||
// stats
|
// stats
|
||||||
|
@ -184,41 +155,42 @@ type Conn struct {
|
||||||
nwrites int // number of writes
|
nwrites int // number of writes
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Fid type identifies a file on the file server.
|
// The SrvFid type identifies a file on the file server.
|
||||||
// A new Fid is created when the user attaches to the file server (the Attach
|
// A new SrvFid is created when the user attaches to the file server (the Attach
|
||||||
// operation), or when Walk-ing to a file. The Fid values are created
|
// operation), or when Walk-ing to a file. The SrvFid values are created
|
||||||
// automatically by the srv implementation. The FidDestroy operation is called
|
// automatically by the srv implementation. The SrvFidDestroy operation is called
|
||||||
// when a Fid is destroyed.
|
// when a SrvFid is destroyed.
|
||||||
type Fid struct {
|
type SrvFid struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
fid uint32
|
fid uint32
|
||||||
refcount int
|
refcount int
|
||||||
opened bool // True if the Fid is opened
|
opened bool // True if the SrvFid is opened
|
||||||
Fconn *Conn // Connection the Fid belongs to
|
Fconn *Conn // Connection the SrvFid belongs to
|
||||||
Omode uint8 // Open mode (p.O* flags), if the fid is opened
|
Omode uint8 // Open mode (O* flags), if the fid is opened
|
||||||
Type uint8 // Fid type (p.QT* flags)
|
Type uint8 // SrvFid type (QT* flags)
|
||||||
Diroffset uint64 // If directory, the next valid read position
|
Diroffset uint64 // If directory, the next valid read position
|
||||||
User p.User // The Fid's user
|
Dirents []byte // If directory, the serialized dirents
|
||||||
Aux interface{} // Can be used by the file server implementation for per-Fid data
|
User User // The SrvFid's user
|
||||||
|
Aux interface{} // Can be used by the file server implementation for per-SrvFid data
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Req type represents a 9P2000 request. Each request has a
|
// The SrvReq type represents a 9P2000 request. Each request has a
|
||||||
// T-message (Tc) and a R-message (Rc). If the ReqProcessOps don't
|
// T-message (Tc) and a R-message (Rc). If the SrvReqProcessOps don't
|
||||||
// override the default behavior, the implementation initializes Fid,
|
// override the default behavior, the implementation initializes SrvFid,
|
||||||
// Afid and Newfid values and automatically keeps track on when the Fids
|
// Afid and Newfid values and automatically keeps track on when the SrvFids
|
||||||
// should be destroyed.
|
// should be destroyed.
|
||||||
type Req struct {
|
type SrvReq struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
Tc *p.Fcall // Incoming 9P2000 message
|
Tc *Fcall // Incoming 9P2000 message
|
||||||
Rc *p.Fcall // Outgoing 9P2000 response
|
Rc *Fcall // Outgoing 9P2000 response
|
||||||
Fid *Fid // The Fid value for all messages that contain fid[4]
|
Fid *SrvFid // The SrvFid value for all messages that contain fid[4]
|
||||||
Afid *Fid // The Fid value for the messages that contain afid[4] (Tauth and Tattach)
|
Afid *SrvFid // The SrvFid value for the messages that contain afid[4] (Tauth and Tattach)
|
||||||
Newfid *Fid // The Fid value for the messages that contain newfid[4] (Twalk)
|
Newfid *SrvFid // The SrvFid value for the messages that contain newfid[4] (Twalk)
|
||||||
Conn *Conn // Connection that the request belongs to
|
Conn *Conn // Connection that the request belongs to
|
||||||
|
|
||||||
status reqStatus
|
status reqStatus
|
||||||
flushreq *Req
|
flushreq *SrvReq
|
||||||
prev, next *Req
|
prev, next *SrvReq
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Start method should be called once the file server implementor
|
// The Start method should be called once the file server implementor
|
||||||
|
@ -226,23 +198,23 @@ type Req struct {
|
||||||
// values to the fields that are not initialized and creates the goroutines
|
// values to the fields that are not initialized and creates the goroutines
|
||||||
// required for the server's operation. The method receives an empty
|
// required for the server's operation. The method receives an empty
|
||||||
// interface value, ops, that should implement the interfaces the file server is
|
// interface value, ops, that should implement the interfaces the file server is
|
||||||
// interested in. Ops must implement the ReqOps interface.
|
// interested in. Ops must implement the SrvReqOps interface.
|
||||||
func (srv *Srv) Start(ops interface{}) bool {
|
func (srv *Srv) Start(ops interface{}) bool {
|
||||||
if _, ok := (ops).(ReqOps); !ok {
|
if _, ok := (ops).(SrvReqOps); !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.ops = ops
|
srv.ops = ops
|
||||||
if srv.Upool == nil {
|
if srv.Upool == nil {
|
||||||
srv.Upool = p.OsUsers
|
srv.Upool = OsUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
if srv.Msize < p.IOHDRSZ {
|
if srv.Msize < IOHDRSZ {
|
||||||
srv.Msize = p.MSIZE
|
srv.Msize = MSIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
if srv.Log == nil {
|
if srv.Log == nil {
|
||||||
srv.Log = p.NewLogger(1024)
|
srv.Log = NewLogger(1024)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sop, ok := (interface{}(srv)).(StatsOps); ok {
|
if sop, ok := (interface{}(srv)).(StatsOps); ok {
|
||||||
|
@ -256,7 +228,7 @@ func (srv *Srv) String() string {
|
||||||
return srv.Id
|
return srv.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *Req) process() {
|
func (req *SrvReq) process() {
|
||||||
req.Lock()
|
req.Lock()
|
||||||
flushed := (req.status & reqFlush) != 0
|
flushed := (req.status & reqFlush) != 0
|
||||||
if !flushed {
|
if !flushed {
|
||||||
|
@ -268,8 +240,8 @@ func (req *Req) process() {
|
||||||
req.Respond()
|
req.Respond()
|
||||||
}
|
}
|
||||||
|
|
||||||
if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok {
|
if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok {
|
||||||
rop.ReqProcess(req)
|
rop.SrvReqProcess(req)
|
||||||
} else {
|
} else {
|
||||||
req.Process()
|
req.Process()
|
||||||
}
|
}
|
||||||
|
@ -283,16 +255,16 @@ func (req *Req) process() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs the default processing of a request. Initializes
|
// Performs the default processing of a request. Initializes
|
||||||
// the Fid, Afid and Newfid fields and calls the appropriate
|
// the SrvFid, Afid and Newfid fields and calls the appropriate
|
||||||
// ReqOps operation for the message. The file server implementer
|
// SrvReqOps operation for the message. The file server implementer
|
||||||
// should call it only if the file server implements the ReqProcessOps
|
// should call it only if the file server implements the SrvReqProcessOps
|
||||||
// within the ReqProcess operation.
|
// within the SrvReqProcess operation.
|
||||||
func (req *Req) Process() {
|
func (req *SrvReq) Process() {
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
srv := conn.Srv
|
srv := conn.Srv
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
|
|
||||||
if tc.Fid != p.NOFID && tc.Type != p.Tattach {
|
if tc.Fid != NOFID && tc.Type != Tattach {
|
||||||
srv.Lock()
|
srv.Lock()
|
||||||
req.Fid = conn.FidGet(tc.Fid)
|
req.Fid = conn.FidGet(tc.Fid)
|
||||||
srv.Unlock()
|
srv.Unlock()
|
||||||
|
@ -304,83 +276,83 @@ func (req *Req) Process() {
|
||||||
|
|
||||||
switch req.Tc.Type {
|
switch req.Tc.Type {
|
||||||
default:
|
default:
|
||||||
req.RespondError(&p.Error{"unknown message type", p.EINVAL})
|
req.RespondError(&Error{"unknown message type", EINVAL})
|
||||||
|
|
||||||
case p.Tversion:
|
case Tversion:
|
||||||
srv.version(req)
|
srv.version(req)
|
||||||
|
|
||||||
case p.Tauth:
|
case Tauth:
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
srv.auth(req)
|
srv.auth(req)
|
||||||
|
|
||||||
case p.Tattach:
|
case Tattach:
|
||||||
srv.attach(req)
|
srv.attach(req)
|
||||||
|
|
||||||
case p.Tflush:
|
case Tflush:
|
||||||
srv.flush(req)
|
srv.flush(req)
|
||||||
|
|
||||||
case p.Twalk:
|
case Twalk:
|
||||||
srv.walk(req)
|
srv.walk(req)
|
||||||
|
|
||||||
case p.Topen:
|
case Topen:
|
||||||
srv.open(req)
|
srv.open(req)
|
||||||
|
|
||||||
case p.Tcreate:
|
case Tcreate:
|
||||||
srv.create(req)
|
srv.create(req)
|
||||||
|
|
||||||
case p.Tread:
|
case Tread:
|
||||||
srv.read(req)
|
srv.read(req)
|
||||||
|
|
||||||
case p.Twrite:
|
case Twrite:
|
||||||
srv.write(req)
|
srv.write(req)
|
||||||
|
|
||||||
case p.Tclunk:
|
case Tclunk:
|
||||||
srv.clunk(req)
|
srv.clunk(req)
|
||||||
|
|
||||||
case p.Tremove:
|
case Tremove:
|
||||||
srv.remove(req)
|
srv.remove(req)
|
||||||
|
|
||||||
case p.Tstat:
|
case Tstat:
|
||||||
srv.stat(req)
|
srv.stat(req)
|
||||||
|
|
||||||
case p.Twstat:
|
case Twstat:
|
||||||
srv.wstat(req)
|
srv.wstat(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs the post processing required if the (*Req) Process() method
|
// Performs the post processing required if the (*SrvReq) Process() method
|
||||||
// is called for a request. The file server implementer should call it
|
// is called for a request. The file server implementer should call it
|
||||||
// only if the file server implements the ReqProcessOps within the
|
// only if the file server implements the SrvReqProcessOps within the
|
||||||
// ReqRespond operation.
|
// SrvReqRespond operation.
|
||||||
func (req *Req) PostProcess() {
|
func (req *SrvReq) PostProcess() {
|
||||||
srv := req.Conn.Srv
|
srv := req.Conn.Srv
|
||||||
|
|
||||||
/* call the post-handlers (if needed) */
|
/* call the post-handlers (if needed) */
|
||||||
switch req.Tc.Type {
|
switch req.Tc.Type {
|
||||||
case p.Tauth:
|
case Tauth:
|
||||||
srv.authPost(req)
|
srv.authPost(req)
|
||||||
|
|
||||||
case p.Tattach:
|
case Tattach:
|
||||||
srv.attachPost(req)
|
srv.attachPost(req)
|
||||||
|
|
||||||
case p.Twalk:
|
case Twalk:
|
||||||
srv.walkPost(req)
|
srv.walkPost(req)
|
||||||
|
|
||||||
case p.Topen:
|
case Topen:
|
||||||
srv.openPost(req)
|
srv.openPost(req)
|
||||||
|
|
||||||
case p.Tcreate:
|
case Tcreate:
|
||||||
srv.createPost(req)
|
srv.createPost(req)
|
||||||
|
|
||||||
case p.Tread:
|
case Tread:
|
||||||
srv.readPost(req)
|
srv.readPost(req)
|
||||||
|
|
||||||
case p.Tclunk:
|
case Tclunk:
|
||||||
srv.clunkPost(req)
|
srv.clunkPost(req)
|
||||||
|
|
||||||
case p.Tremove:
|
case Tremove:
|
||||||
srv.removePost(req)
|
srv.removePost(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,8 +376,8 @@ func (req *Req) PostProcess() {
|
||||||
// should be initialized and contain valid 9P2000 message. In most cases
|
// should be initialized and contain valid 9P2000 message. In most cases
|
||||||
// the file server implementer shouldn't call this method directly. Instead
|
// the file server implementer shouldn't call this method directly. Instead
|
||||||
// one of the RespondR* methods should be used.
|
// one of the RespondR* methods should be used.
|
||||||
func (req *Req) Respond() {
|
func (req *SrvReq) Respond() {
|
||||||
var flushreqs *Req
|
var flushreqs *SrvReq
|
||||||
|
|
||||||
conn := req.Conn
|
conn := req.Conn
|
||||||
req.Lock()
|
req.Lock()
|
||||||
|
@ -425,7 +397,7 @@ func (req *Req) Respond() {
|
||||||
nextreq.next = nil
|
nextreq.next = nil
|
||||||
// if there are flush requests, move them to the next request
|
// if there are flush requests, move them to the next request
|
||||||
if req.flushreq != nil {
|
if req.flushreq != nil {
|
||||||
var p *Req = nil
|
var p *SrvReq = nil
|
||||||
r := nextreq.flushreq
|
r := nextreq.flushreq
|
||||||
for ; r != nil; p, r = r, r.flushreq {
|
for ; r != nil; p, r = r, r.flushreq {
|
||||||
}
|
}
|
||||||
|
@ -433,7 +405,7 @@ func (req *Req) Respond() {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
nextreq.flushreq = req.flushreq
|
nextreq.flushreq = req.flushreq
|
||||||
} else {
|
} else {
|
||||||
p.next = req.flushreq
|
nextreq = req.flushreq
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,8 +416,8 @@ func (req *Req) Respond() {
|
||||||
}
|
}
|
||||||
conn.Unlock()
|
conn.Unlock()
|
||||||
|
|
||||||
if rop, ok := (req.Conn.Srv.ops).(ReqProcessOps); ok {
|
if rop, ok := (req.Conn.Srv.ops).(SrvReqProcessOps); ok {
|
||||||
rop.ReqRespond(req)
|
rop.SrvReqRespond(req)
|
||||||
} else {
|
} else {
|
||||||
req.PostProcess()
|
req.PostProcess()
|
||||||
}
|
}
|
||||||
|
@ -469,18 +441,18 @@ func (req *Req) Respond() {
|
||||||
|
|
||||||
// Should be called to cancel a request. Should only be called
|
// Should be called to cancel a request. Should only be called
|
||||||
// from the Flush operation if the FlushOp is implemented.
|
// from the Flush operation if the FlushOp is implemented.
|
||||||
func (req *Req) Flush() {
|
func (req *SrvReq) Flush() {
|
||||||
req.Lock()
|
req.Lock()
|
||||||
req.status |= reqFlush
|
req.status |= reqFlush
|
||||||
req.Unlock()
|
req.Unlock()
|
||||||
req.Respond()
|
req.Respond()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup a Fid struct based on the 32-bit identifier sent over the wire.
|
// Lookup a SrvFid struct based on the 32-bit identifier sent over the wire.
|
||||||
// Returns nil if the fid is not found. Increases the reference count of
|
// Returns nil if the fid is not found. Increases the reference count of
|
||||||
// the returned fid. The user is responsible to call DecRef once it no
|
// the returned fid. The user is responsible to call DecRef once it no
|
||||||
// longer needs it.
|
// longer needs it.
|
||||||
func (conn *Conn) FidGet(fidno uint32) *Fid {
|
func (conn *Conn) FidGet(fidno uint32) *SrvFid {
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
fid, present := conn.fidpool[fidno]
|
fid, present := conn.fidpool[fidno]
|
||||||
conn.Unlock()
|
conn.Unlock()
|
||||||
|
@ -491,10 +463,10 @@ func (conn *Conn) FidGet(fidno uint32) *Fid {
|
||||||
return fid
|
return fid
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new Fid struct for the fidno integer. Returns nil
|
// Creates a new SrvFid struct for the fidno integer. Returns nil
|
||||||
// if the Fid for that number already exists. The returned fid
|
// if the SrvFid for that number already exists. The returned fid
|
||||||
// has reference count set to 1.
|
// has reference count set to 1.
|
||||||
func (conn *Conn) FidNew(fidno uint32) *Fid {
|
func (conn *Conn) FidNew(fidno uint32) *SrvFid {
|
||||||
conn.Lock()
|
conn.Lock()
|
||||||
_, present := conn.fidpool[fidno]
|
_, present := conn.fidpool[fidno]
|
||||||
if present {
|
if present {
|
||||||
|
@ -502,7 +474,7 @@ func (conn *Conn) FidNew(fidno uint32) *Fid {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fid := new(Fid)
|
fid := new(SrvFid)
|
||||||
fid.fid = fidno
|
fid.fid = fidno
|
||||||
fid.refcount = 1
|
fid.refcount = 1
|
||||||
fid.Fconn = conn
|
fid.Fconn = conn
|
||||||
|
@ -517,7 +489,7 @@ func (conn *Conn) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase the reference count for the fid.
|
// Increase the reference count for the fid.
|
||||||
func (fid *Fid) IncRef() {
|
func (fid *SrvFid) IncRef() {
|
||||||
fid.Lock()
|
fid.Lock()
|
||||||
fid.refcount++
|
fid.refcount++
|
||||||
fid.Unlock()
|
fid.Unlock()
|
||||||
|
@ -525,7 +497,7 @@ func (fid *Fid) IncRef() {
|
||||||
|
|
||||||
// Decrease the reference count for the fid. When the
|
// Decrease the reference count for the fid. When the
|
||||||
// reference count reaches 0, the fid is no longer valid.
|
// reference count reaches 0, the fid is no longer valid.
|
||||||
func (fid *Fid) DecRef() {
|
func (fid *SrvFid) DecRef() {
|
||||||
fid.Lock()
|
fid.Lock()
|
||||||
fid.refcount--
|
fid.refcount--
|
||||||
n := fid.refcount
|
n := fid.refcount
|
||||||
|
@ -540,7 +512,7 @@ func (fid *Fid) DecRef() {
|
||||||
delete(conn.fidpool, fid.fid)
|
delete(conn.fidpool, fid.fid)
|
||||||
conn.Unlock()
|
conn.Unlock()
|
||||||
|
|
||||||
if fop, ok := (conn.Srv.ops).(FidOps); ok {
|
if fop, ok := (conn.Srv.ops).(SrvFidOps); ok {
|
||||||
fop.FidDestroy(fid)
|
fop.FidDestroy(fid)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,17 @@
|
||||||
// +build httpstats
|
// +build httpstats
|
||||||
|
|
||||||
package srv
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mux sync.RWMutex
|
var mux sync.RWMutex
|
||||||
var stat map[string]http.Handler
|
var stat map[string]http.Handler
|
||||||
var once sync.Once
|
var httponce sync.Once
|
||||||
|
|
||||||
func register(s string, h http.Handler) {
|
func register(s string, h http.Handler) {
|
||||||
mux.Lock()
|
mux.Lock()
|
||||||
|
@ -28,7 +27,7 @@ func register(s string, h http.Handler) {
|
||||||
mux.Unlock()
|
mux.Unlock()
|
||||||
}
|
}
|
||||||
func (srv *Srv) statsRegister() {
|
func (srv *Srv) statsRegister() {
|
||||||
once.Do(func() {
|
httponce.Do(func() {
|
||||||
http.HandleFunc("/go9p/", StatsHandler)
|
http.HandleFunc("/go9p/", StatsHandler)
|
||||||
go http.ListenAndServe(":6060", nil)
|
go http.ListenAndServe(":6060", nil)
|
||||||
})
|
})
|
||||||
|
@ -85,7 +84,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
|
||||||
fs := conn.Srv.Log.Filter(conn, DbgLogFcalls)
|
fs := conn.Srv.Log.Filter(conn, DbgLogFcalls)
|
||||||
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
|
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
|
||||||
for i, l := range fs {
|
for i, l := range fs {
|
||||||
fc := l.Data.(*p.Fcall)
|
fc := l.Data.(*Fcall)
|
||||||
if fc.Type == 0 {
|
if fc.Type == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -94,7 +93,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
|
||||||
if fc.Type%2 == 0 {
|
if fc.Type%2 == 0 {
|
||||||
// try to find the response for the T message
|
// try to find the response for the T message
|
||||||
for j := i + 1; j < len(fs); j++ {
|
for j := i + 1; j < len(fs); j++ {
|
||||||
rc := fs[j].Data.(*p.Fcall)
|
rc := fs[j].Data.(*Fcall)
|
||||||
if rc.Tag == fc.Tag {
|
if rc.Tag == fc.Tag {
|
||||||
lbl = fmt.Sprintf("<a href='#fc%d'>➴</a>", j)
|
lbl = fmt.Sprintf("<a href='#fc%d'>➴</a>", j)
|
||||||
break
|
break
|
||||||
|
@ -103,7 +102,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
|
||||||
} else {
|
} else {
|
||||||
// try to find the request for the R message
|
// try to find the request for the R message
|
||||||
for j := i - 1; j >= 0; j-- {
|
for j := i - 1; j >= 0; j-- {
|
||||||
tc := fs[j].Data.(*p.Fcall)
|
tc := fs[j].Data.(*Fcall)
|
||||||
if tc.Tag == fc.Tag {
|
if tc.Tag == fc.Tag {
|
||||||
lbl = fmt.Sprintf("<a href='#fc%d'>➶</a>", j)
|
lbl = fmt.Sprintf("<a href='#fc%d'>➶</a>", j)
|
||||||
break
|
break
|
|
@ -0,0 +1,6 @@
|
||||||
|
package go9p
|
||||||
|
|
||||||
|
type StatsOps interface {
|
||||||
|
statsRegister()
|
||||||
|
statsUnregister()
|
||||||
|
}
|
|
@ -2,51 +2,49 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package ufs
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"k8s.io/minikube/third_party/go9p/p/srv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Fid struct {
|
type ufsFid struct {
|
||||||
path string
|
path string
|
||||||
file *os.File
|
file *os.File
|
||||||
dirs []os.FileInfo
|
dirs []os.FileInfo
|
||||||
diroffset uint64
|
direntends []int
|
||||||
st os.FileInfo
|
dirents []byte
|
||||||
|
diroffset uint64
|
||||||
|
st os.FileInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ufs struct {
|
type Ufs struct {
|
||||||
srv.Srv
|
Srv
|
||||||
|
Root string
|
||||||
}
|
}
|
||||||
|
|
||||||
var addr string
|
func toError(err error) *Error {
|
||||||
var debug int
|
|
||||||
var root string
|
|
||||||
var Enoent = &p.Error{"file not found", p.ENOENT}
|
|
||||||
|
|
||||||
func toError(err error) *p.Error {
|
|
||||||
var ecode uint32
|
var ecode uint32
|
||||||
|
|
||||||
ename := err.Error()
|
ename := err.Error()
|
||||||
if e, ok := err.(syscall.Errno); ok {
|
if e, ok := err.(syscall.Errno); ok {
|
||||||
ecode = uint32(e)
|
ecode = uint32(e)
|
||||||
} else {
|
} else {
|
||||||
ecode = p.EIO
|
ecode = EIO
|
||||||
}
|
}
|
||||||
|
|
||||||
return &p.Error{ename, ecode}
|
return &Error{ename, ecode}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fid *Fid) stat() *p.Error {
|
func (fid *ufsFid) stat() *Error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
fid.st, err = os.Lstat(fid.path)
|
fid.st, err = os.Lstat(fid.path)
|
||||||
|
@ -60,24 +58,24 @@ func (fid *Fid) stat() *p.Error {
|
||||||
func omode2uflags(mode uint8) int {
|
func omode2uflags(mode uint8) int {
|
||||||
ret := int(0)
|
ret := int(0)
|
||||||
switch mode & 3 {
|
switch mode & 3 {
|
||||||
case p.OREAD:
|
case OREAD:
|
||||||
ret = os.O_RDONLY
|
ret = os.O_RDONLY
|
||||||
break
|
break
|
||||||
|
|
||||||
case p.ORDWR:
|
case ORDWR:
|
||||||
ret = os.O_RDWR
|
ret = os.O_RDWR
|
||||||
break
|
break
|
||||||
|
|
||||||
case p.OWRITE:
|
case OWRITE:
|
||||||
ret = os.O_WRONLY
|
ret = os.O_WRONLY
|
||||||
break
|
break
|
||||||
|
|
||||||
case p.OEXEC:
|
case OEXEC:
|
||||||
ret = os.O_RDONLY
|
ret = os.O_RDONLY
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&p.OTRUNC != 0 {
|
if mode&OTRUNC != 0 {
|
||||||
ret |= os.O_TRUNC
|
ret |= os.O_TRUNC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +85,11 @@ func omode2uflags(mode uint8) int {
|
||||||
func dir2QidType(d os.FileInfo) uint8 {
|
func dir2QidType(d os.FileInfo) uint8 {
|
||||||
ret := uint8(0)
|
ret := uint8(0)
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
ret |= p.QTDIR
|
ret |= QTDIR
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Mode()&os.ModeSymlink != 0 {
|
if d.Mode()&os.ModeSymlink != 0 {
|
||||||
ret |= p.QTSYMLINK
|
ret |= QTSYMLINK
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
@ -100,33 +98,33 @@ func dir2QidType(d os.FileInfo) uint8 {
|
||||||
func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
|
func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
|
||||||
ret := uint32(d.Mode() & 0777)
|
ret := uint32(d.Mode() & 0777)
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
ret |= p.DMDIR
|
ret |= DMDIR
|
||||||
}
|
}
|
||||||
|
|
||||||
if dotu {
|
if dotu {
|
||||||
mode := d.Mode()
|
mode := d.Mode()
|
||||||
if mode&os.ModeSymlink != 0 {
|
if mode&os.ModeSymlink != 0 {
|
||||||
ret |= p.DMSYMLINK
|
ret |= DMSYMLINK
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&os.ModeSocket != 0 {
|
if mode&os.ModeSocket != 0 {
|
||||||
ret |= p.DMSOCKET
|
ret |= DMSOCKET
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&os.ModeNamedPipe != 0 {
|
if mode&os.ModeNamedPipe != 0 {
|
||||||
ret |= p.DMNAMEDPIPE
|
ret |= DMNAMEDPIPE
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&os.ModeDevice != 0 {
|
if mode&os.ModeDevice != 0 {
|
||||||
ret |= p.DMDEVICE
|
ret |= DMDEVICE
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&os.ModeSetuid != 0 {
|
if mode&os.ModeSetuid != 0 {
|
||||||
ret |= p.DMSETUID
|
ret |= DMSETUID
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode&os.ModeSetgid != 0 {
|
if mode&os.ModeSetgid != 0 {
|
||||||
ret |= p.DMSETGID
|
ret |= DMSETGID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,48 +133,47 @@ func dir2Npmode(d os.FileInfo, dotu bool) uint32 {
|
||||||
|
|
||||||
// Dir is an instantiation of the p.Dir structure
|
// Dir is an instantiation of the p.Dir structure
|
||||||
// that can act as a receiver for local methods.
|
// that can act as a receiver for local methods.
|
||||||
type Dir struct {
|
type ufsDir struct {
|
||||||
p.Dir
|
Dir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) ConnOpened(conn *srv.Conn) {
|
func (*Ufs) ConnOpened(conn *Conn) {
|
||||||
if conn.Srv.Debuglevel > 0 {
|
if conn.Srv.Debuglevel > 0 {
|
||||||
log.Println("connected")
|
log.Println("connected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) ConnClosed(conn *srv.Conn) {
|
func (*Ufs) ConnClosed(conn *Conn) {
|
||||||
if conn.Srv.Debuglevel > 0 {
|
if conn.Srv.Debuglevel > 0 {
|
||||||
log.Println("disconnected")
|
log.Println("disconnected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) FidDestroy(sfid *srv.Fid) {
|
func (*Ufs) FidDestroy(sfid *SrvFid) {
|
||||||
var fid *Fid
|
var fid *ufsFid
|
||||||
|
|
||||||
if sfid.Aux == nil {
|
if sfid.Aux == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fid = sfid.Aux.(*Fid)
|
fid = sfid.Aux.(*ufsFid)
|
||||||
if fid.file != nil {
|
if fid.file != nil {
|
||||||
fid.file.Close()
|
fid.file.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Attach(req *srv.Req) {
|
func (ufs *Ufs) Attach(req *SrvReq) {
|
||||||
if req.Afid != nil {
|
if req.Afid != nil {
|
||||||
req.RespondError(srv.Enoauth)
|
req.RespondError(Enoauth)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
fid := new(Fid)
|
fid := new(ufsFid)
|
||||||
if len(tc.Aname) == 0 {
|
// You can think of the ufs.Root as a 'chroot' of a sort.
|
||||||
fid.path = root
|
// clients attach are not allowed to go outside the
|
||||||
} else {
|
// directory represented by ufs.Root
|
||||||
fid.path = tc.Aname
|
fid.path = path.Join(ufs.Root, tc.Aname)
|
||||||
}
|
|
||||||
|
|
||||||
req.Fid.Aux = fid
|
req.Fid.Aux = fid
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
|
@ -189,10 +186,10 @@ func (*Ufs) Attach(req *srv.Req) {
|
||||||
req.RespondRattach(qid)
|
req.RespondRattach(qid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Flush(req *srv.Req) {}
|
func (*Ufs) Flush(req *SrvReq) {}
|
||||||
|
|
||||||
func (*Ufs) Walk(req *srv.Req) {
|
func (*Ufs) Walk(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
|
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
|
@ -202,11 +199,11 @@ func (*Ufs) Walk(req *srv.Req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Newfid.Aux == nil {
|
if req.Newfid.Aux == nil {
|
||||||
req.Newfid.Aux = new(Fid)
|
req.Newfid.Aux = new(ufsFid)
|
||||||
}
|
}
|
||||||
|
|
||||||
nfid := req.Newfid.Aux.(*Fid)
|
nfid := req.Newfid.Aux.(*ufsFid)
|
||||||
wqids := make([]p.Qid, len(tc.Wname))
|
wqids := make([]Qid, len(tc.Wname))
|
||||||
path := fid.path
|
path := fid.path
|
||||||
i := 0
|
i := 0
|
||||||
for ; i < len(tc.Wname); i++ {
|
for ; i < len(tc.Wname); i++ {
|
||||||
|
@ -229,8 +226,8 @@ func (*Ufs) Walk(req *srv.Req) {
|
||||||
req.RespondRwalk(wqids[0:i])
|
req.RespondRwalk(wqids[0:i])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Open(req *srv.Req) {
|
func (*Ufs) Open(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -248,8 +245,8 @@ func (*Ufs) Open(req *srv.Req) {
|
||||||
req.RespondRopen(dir2Qid(fid.st), 0)
|
req.RespondRopen(dir2Qid(fid.st), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Create(req *srv.Req) {
|
func (*Ufs) Create(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -261,13 +258,13 @@ func (*Ufs) Create(req *srv.Req) {
|
||||||
var e error = nil
|
var e error = nil
|
||||||
var file *os.File = nil
|
var file *os.File = nil
|
||||||
switch {
|
switch {
|
||||||
case tc.Perm&p.DMDIR != 0:
|
case tc.Perm&DMDIR != 0:
|
||||||
e = os.Mkdir(path, os.FileMode(tc.Perm&0777))
|
e = os.Mkdir(path, os.FileMode(tc.Perm&0777))
|
||||||
|
|
||||||
case tc.Perm&p.DMSYMLINK != 0:
|
case tc.Perm&DMSYMLINK != 0:
|
||||||
e = os.Symlink(tc.Ext, path)
|
e = os.Symlink(tc.Ext, path)
|
||||||
|
|
||||||
case tc.Perm&p.DMLINK != 0:
|
case tc.Perm&DMLINK != 0:
|
||||||
n, e := strconv.ParseUint(tc.Ext, 10, 0)
|
n, e := strconv.ParseUint(tc.Ext, 10, 0)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
break
|
break
|
||||||
|
@ -275,25 +272,25 @@ func (*Ufs) Create(req *srv.Req) {
|
||||||
|
|
||||||
ofid := req.Conn.FidGet(uint32(n))
|
ofid := req.Conn.FidGet(uint32(n))
|
||||||
if ofid == nil {
|
if ofid == nil {
|
||||||
req.RespondError(srv.Eunknownfid)
|
req.RespondError(Eunknownfid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
e = os.Link(ofid.Aux.(*Fid).path, path)
|
e = os.Link(ofid.Aux.(*ufsFid).path, path)
|
||||||
ofid.DecRef()
|
ofid.DecRef()
|
||||||
|
|
||||||
case tc.Perm&p.DMNAMEDPIPE != 0:
|
case tc.Perm&DMNAMEDPIPE != 0:
|
||||||
case tc.Perm&p.DMDEVICE != 0:
|
case tc.Perm&DMDEVICE != 0:
|
||||||
req.RespondError(&p.Error{"not implemented", p.EIO})
|
req.RespondError(&Error{"not implemented", EIO})
|
||||||
return
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var mode uint32 = tc.Perm & 0777
|
var mode uint32 = tc.Perm & 0777
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
if tc.Perm&p.DMSETUID > 0 {
|
if tc.Perm&DMSETUID > 0 {
|
||||||
mode |= syscall.S_ISUID
|
mode |= syscall.S_ISUID
|
||||||
}
|
}
|
||||||
if tc.Perm&p.DMSETGID > 0 {
|
if tc.Perm&DMSETGID > 0 {
|
||||||
mode |= syscall.S_ISGID
|
mode |= syscall.S_ISGID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,8 +317,8 @@ func (*Ufs) Create(req *srv.Req) {
|
||||||
req.RespondRcreate(dir2Qid(fid.st), 0)
|
req.RespondRcreate(dir2Qid(fid.st), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Read(req *srv.Req) {
|
func (*Ufs) Read(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
rc := req.Rc
|
rc := req.Rc
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
|
@ -330,67 +327,83 @@ func (*Ufs) Read(req *srv.Req) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.InitRread(rc, tc.Count)
|
InitRread(rc, tc.Count)
|
||||||
var count int
|
var count int
|
||||||
var e error
|
var e error
|
||||||
if fid.st.IsDir() {
|
if fid.st.IsDir() {
|
||||||
b := rc.Data
|
|
||||||
if tc.Offset == 0 {
|
if tc.Offset == 0 {
|
||||||
|
var e error
|
||||||
|
// If we got here, it was open. Can't really seek
|
||||||
|
// in most cases, just close and reopen it.
|
||||||
fid.file.Close()
|
fid.file.Close()
|
||||||
fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0)
|
if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil {
|
||||||
if e != nil {
|
|
||||||
req.RespondError(toError(e))
|
req.RespondError(toError(e))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fid.dirs, e = fid.file.Readdir(-1); e != nil {
|
||||||
|
req.RespondError(toError(e))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fid.dirents = nil
|
||||||
|
fid.direntends = nil
|
||||||
|
for i := 0; i < len(fid.dirs); i++ {
|
||||||
|
path := fid.path + "/" + fid.dirs[i].Name()
|
||||||
|
st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
|
||||||
|
if st == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b := PackDir(st, req.Conn.Dotu)
|
||||||
|
fid.dirents = append(fid.dirents, b...)
|
||||||
|
count += len(b)
|
||||||
|
fid.direntends = append(fid.direntends, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case tc.Offset > uint64(len(fid.dirents)):
|
||||||
|
count = 0
|
||||||
|
case len(fid.dirents[tc.Offset:]) > int(tc.Count):
|
||||||
|
count = int(tc.Count)
|
||||||
|
default:
|
||||||
|
count = len(fid.dirents[tc.Offset:])
|
||||||
|
}
|
||||||
|
|
||||||
|
if !*Akaros {
|
||||||
|
nextend := sort.SearchInts(fid.direntends, int(tc.Offset)+count)
|
||||||
|
if nextend < len(fid.direntends) {
|
||||||
|
if fid.direntends[nextend] > int(tc.Offset)+count {
|
||||||
|
if nextend > 0 {
|
||||||
|
count = fid.direntends[nextend-1] - int(tc.Offset)
|
||||||
|
} else {
|
||||||
|
count = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 && int(tc.Offset) < len(fid.dirents) && len(fid.dirents) > 0 {
|
||||||
|
req.RespondError(&Error{"too small read size for dir entry", EINVAL})
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for len(b) > 0 {
|
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count])
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var i int
|
|
||||||
for i = 0; i < len(fid.dirs); i++ {
|
|
||||||
path := fid.path + "/" + fid.dirs[i].Name()
|
|
||||||
st := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
|
|
||||||
sz := p.PackDir(st, b, req.Conn.Dotu)
|
|
||||||
if sz == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
b = b[sz:]
|
|
||||||
count += sz
|
|
||||||
}
|
|
||||||
|
|
||||||
if i < len(fid.dirs) {
|
|
||||||
fid.dirs = fid.dirs[i:]
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
fid.dirs = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset))
|
count, e = fid.file.ReadAt(rc.Data, int64(tc.Offset))
|
||||||
if e != nil && e != io.EOF {
|
if e != nil && e != io.EOF {
|
||||||
req.RespondError(toError(e))
|
req.RespondError(toError(e))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.SetRreadCount(rc, uint32(count))
|
SetRreadCount(rc, uint32(count))
|
||||||
req.Respond()
|
req.Respond()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Write(req *srv.Req) {
|
func (*Ufs) Write(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
tc := req.Tc
|
tc := req.Tc
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -407,10 +420,10 @@ func (*Ufs) Write(req *srv.Req) {
|
||||||
req.RespondRwrite(uint32(n))
|
req.RespondRwrite(uint32(n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Clunk(req *srv.Req) { req.RespondRclunk() }
|
func (*Ufs) Clunk(req *SrvReq) { req.RespondRclunk() }
|
||||||
|
|
||||||
func (*Ufs) Remove(req *srv.Req) {
|
func (*Ufs) Remove(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -426,25 +439,30 @@ func (*Ufs) Remove(req *srv.Req) {
|
||||||
req.RespondRremove()
|
req.RespondRremove()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Stat(req *srv.Req) {
|
func (*Ufs) Stat(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
st := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
|
st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
|
||||||
|
if st == nil {
|
||||||
|
req.RespondError(derr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
req.RespondRstat(st)
|
req.RespondRstat(st)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookup(uid string, group bool) (uint32, *p.Error) {
|
func lookup(uid string, group bool) (uint32, *Error) {
|
||||||
if uid == "" {
|
if uid == "" {
|
||||||
return p.NOUID, nil
|
return NOUID, nil
|
||||||
}
|
}
|
||||||
usr, e := user.Lookup(uid)
|
usr, e := user.Lookup(uid)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return p.NOUID, toError(e)
|
return NOUID, toError(e)
|
||||||
}
|
}
|
||||||
conv := usr.Uid
|
conv := usr.Uid
|
||||||
if group {
|
if group {
|
||||||
|
@ -452,23 +470,12 @@ func lookup(uid string, group bool) (uint32, *p.Error) {
|
||||||
}
|
}
|
||||||
u, e := strconv.Atoi(conv)
|
u, e := strconv.Atoi(conv)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return p.NOUID, toError(e)
|
return NOUID, toError(e)
|
||||||
}
|
}
|
||||||
return uint32(u), nil
|
return uint32(u), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartServer(addrVal string, debugVal int, rootVal string) {
|
/* enables "Akaros" capabilities, which right now means
|
||||||
addr = addrVal
|
* a sane error message format.
|
||||||
debug = debugVal
|
*/
|
||||||
root = rootVal
|
var Akaros = flag.Bool("akaros", false, "Akaros extensions")
|
||||||
ufs := new(Ufs)
|
|
||||||
ufs.Dotu = true
|
|
||||||
ufs.Id = "ufs"
|
|
||||||
ufs.Debuglevel = debug
|
|
||||||
ufs.Start(ufs)
|
|
||||||
|
|
||||||
err := ufs.StartNetListener("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package ufs
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"k8s.io/minikube/third_party/go9p/p/srv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func atime(stat *syscall.Stat_t) time.Time {
|
func atime(stat *syscall.Stat_t) time.Time {
|
||||||
|
@ -25,16 +23,18 @@ func atime(stat *syscall.Stat_t) time.Time {
|
||||||
func isBlock(d os.FileInfo) bool {
|
func isBlock(d os.FileInfo) bool {
|
||||||
stat := d.Sys().(*syscall.Stat_t)
|
stat := d.Sys().(*syscall.Stat_t)
|
||||||
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsChar reports if the file is a character device
|
// IsChar reports if the file is a character device
|
||||||
func isChar(d os.FileInfo) bool {
|
func isChar(d os.FileInfo) bool {
|
||||||
stat := d.Sys().(*syscall.Stat_t)
|
stat := d.Sys().(*syscall.Stat_t)
|
||||||
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func dir2Qid(d os.FileInfo) *p.Qid {
|
func dir2Qid(d os.FileInfo) *Qid {
|
||||||
var qid p.Qid
|
var qid Qid
|
||||||
|
|
||||||
qid.Path = d.Sys().(*syscall.Stat_t).Ino
|
qid.Path = d.Sys().(*syscall.Stat_t).Ino
|
||||||
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
||||||
|
@ -43,27 +43,34 @@ func dir2Qid(d os.FileInfo) *p.Qid {
|
||||||
return &qid
|
return &qid
|
||||||
}
|
}
|
||||||
|
|
||||||
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
|
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
|
||||||
sysMode := d.Sys().(*syscall.Stat_t)
|
if r := recover(); r != nil {
|
||||||
|
fmt.Print("stat failed: ", r)
|
||||||
|
return nil, &os.PathError{"dir2Dir", path, nil}
|
||||||
|
}
|
||||||
|
sysif := d.Sys()
|
||||||
|
if sysif == nil {
|
||||||
|
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
|
||||||
|
}
|
||||||
|
sysMode := sysif.(*syscall.Stat_t)
|
||||||
|
|
||||||
dir := new(Dir)
|
dir := new(ufsDir)
|
||||||
dir.Qid = *dir2Qid(d)
|
dir.Qid = *dir2Qid(d)
|
||||||
dir.Mode = dir2Npmode(d, dotu)
|
dir.Mode = dir2Npmode(d, dotu)
|
||||||
dir.Atime = uint32(atime(sysMode).Unix())
|
dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
|
||||||
dir.Mtime = uint32(d.ModTime().Unix())
|
dir.Mtime = uint32(d.ModTime().Unix())
|
||||||
dir.Length = uint64(d.Size())
|
dir.Length = uint64(d.Size())
|
||||||
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
||||||
|
|
||||||
if dotu {
|
if dotu {
|
||||||
dir.dotu(path, d, upool, sysMode)
|
dir.dotu(path, d, upool, sysMode)
|
||||||
return &dir.Dir
|
return &dir.Dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unixUid := int(sysMode.Uid)
|
unixUid := int(sysMode.Uid)
|
||||||
unixGid := int(sysMode.Gid)
|
unixGid := int(sysMode.Gid)
|
||||||
dir.Uid = strconv.Itoa(unixUid)
|
dir.Uid = strconv.Itoa(unixUid)
|
||||||
dir.Gid = strconv.Itoa(unixGid)
|
dir.Gid = strconv.Itoa(unixGid)
|
||||||
dir.Muid = "none"
|
|
||||||
|
|
||||||
// BUG(akumar): LookupId will never find names for
|
// BUG(akumar): LookupId will never find names for
|
||||||
// groups, as it only operates on user ids.
|
// groups, as it only operates on user ids.
|
||||||
|
@ -76,10 +83,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
|
||||||
dir.Gid = g.Username
|
dir.Gid = g.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dir.Dir
|
/* For Akaros, we use the Muid as the link value. */
|
||||||
|
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
|
||||||
|
dir.Muid, err = os.Readlink(path)
|
||||||
|
if err == nil {
|
||||||
|
dir.Mode |= DMSYMLINK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &dir.Dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) {
|
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
|
||||||
u := upool.Uid2User(int(sysMode.Uid))
|
u := upool.Uid2User(int(sysMode.Uid))
|
||||||
g := upool.Gid2Group(int(sysMode.Gid))
|
g := upool.Gid2Group(int(sysMode.Gid))
|
||||||
dir.Uid = u.Name()
|
dir.Uid = u.Name()
|
||||||
|
@ -95,7 +109,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
|
||||||
dir.Ext = ""
|
dir.Ext = ""
|
||||||
dir.Uidnum = uint32(u.Id())
|
dir.Uidnum = uint32(u.Id())
|
||||||
dir.Gidnum = uint32(g.Id())
|
dir.Gidnum = uint32(g.Id())
|
||||||
dir.Muidnum = p.NOUID
|
dir.Muidnum = NOUID
|
||||||
if d.Mode()&os.ModeSymlink != 0 {
|
if d.Mode()&os.ModeSymlink != 0 {
|
||||||
var err error
|
var err error
|
||||||
dir.Ext, err = os.Readlink(path)
|
dir.Ext, err = os.Readlink(path)
|
||||||
|
@ -109,8 +123,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Wstat(req *srv.Req) {
|
func (u *Ufs) Wstat(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -121,10 +135,10 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
if dir.Mode != 0xFFFFFFFF {
|
if dir.Mode != 0xFFFFFFFF {
|
||||||
mode := dir.Mode & 0777
|
mode := dir.Mode & 0777
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
if dir.Mode&p.DMSETUID > 0 {
|
if dir.Mode&DMSETUID > 0 {
|
||||||
mode |= syscall.S_ISUID
|
mode |= syscall.S_ISUID
|
||||||
}
|
}
|
||||||
if dir.Mode&p.DMSETGID > 0 {
|
if dir.Mode&DMSETGID > 0 {
|
||||||
mode |= syscall.S_ISGID
|
mode |= syscall.S_ISGID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +149,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uid, gid := p.NOUID, p.NOUID
|
uid, gid := NOUID, NOUID
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
uid = dir.Uidnum
|
uid = dir.Uidnum
|
||||||
gid = dir.Gidnum
|
gid = dir.Gidnum
|
||||||
|
@ -159,7 +173,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if uid != p.NOUID || gid != p.NOUID {
|
if uid != NOUID || gid != NOUID {
|
||||||
e := os.Chown(fid.path, int(uid), int(gid))
|
e := os.Chown(fid.path, int(uid), int(gid))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
req.RespondError(toError(e))
|
req.RespondError(toError(e))
|
||||||
|
@ -168,13 +182,25 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir.Name != "" {
|
if dir.Name != "" {
|
||||||
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
|
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
|
||||||
err := syscall.Rename(fid.path, path)
|
// if first char is / it is relative to root, else relative to
|
||||||
|
// cwd.
|
||||||
|
var destpath string
|
||||||
|
if dir.Name[0] == '/' {
|
||||||
|
destpath = path.Join(u.Root, dir.Name)
|
||||||
|
fmt.Printf("/ results in %s\n", destpath)
|
||||||
|
} else {
|
||||||
|
fiddir, _ := path.Split(fid.path)
|
||||||
|
destpath = path.Join(fiddir, dir.Name)
|
||||||
|
fmt.Printf("rel results in %s\n", destpath)
|
||||||
|
}
|
||||||
|
err := syscall.Rename(fid.path, destpath)
|
||||||
|
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(toError(err))
|
req.RespondError(toError(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fid.path = path
|
fid.path = destpath
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
||||||
|
@ -199,7 +225,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
case true:
|
case true:
|
||||||
mt = st.ModTime()
|
mt = st.ModTime()
|
||||||
default:
|
default:
|
||||||
at = atime(st.Sys().(*syscall.Stat_t))
|
//at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e := os.Chtimes(fid.path, at, mt)
|
e := os.Chtimes(fid.path, at, mt)
|
|
@ -1,20 +1,14 @@
|
||||||
// Copyright 2012 The go9p Authors. All rights reserved.
|
package go9p
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ufs
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"k8s.io/minikube/third_party/go9p/p/srv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func atime(stat *syscall.Stat_t) time.Time {
|
func atime(stat *syscall.Stat_t) time.Time {
|
||||||
|
@ -25,16 +19,18 @@ func atime(stat *syscall.Stat_t) time.Time {
|
||||||
func isBlock(d os.FileInfo) bool {
|
func isBlock(d os.FileInfo) bool {
|
||||||
stat := d.Sys().(*syscall.Stat_t)
|
stat := d.Sys().(*syscall.Stat_t)
|
||||||
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsChar reports if the file is a character device
|
// IsChar reports if the file is a character device
|
||||||
func isChar(d os.FileInfo) bool {
|
func isChar(d os.FileInfo) bool {
|
||||||
stat := d.Sys().(*syscall.Stat_t)
|
stat := d.Sys().(*syscall.Stat_t)
|
||||||
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func dir2Qid(d os.FileInfo) *p.Qid {
|
func dir2Qid(d os.FileInfo) *Qid {
|
||||||
var qid p.Qid
|
var qid Qid
|
||||||
|
|
||||||
qid.Path = d.Sys().(*syscall.Stat_t).Ino
|
qid.Path = d.Sys().(*syscall.Stat_t).Ino
|
||||||
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
||||||
|
@ -43,27 +39,34 @@ func dir2Qid(d os.FileInfo) *p.Qid {
|
||||||
return &qid
|
return &qid
|
||||||
}
|
}
|
||||||
|
|
||||||
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
|
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
|
||||||
sysMode := d.Sys().(*syscall.Stat_t)
|
if r := recover(); r != nil {
|
||||||
|
fmt.Print("stat failed: ", r)
|
||||||
|
return nil, &os.PathError{"dir2Dir", path, nil}
|
||||||
|
}
|
||||||
|
sysif := d.Sys()
|
||||||
|
if sysif == nil {
|
||||||
|
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
|
||||||
|
}
|
||||||
|
sysMode := sysif.(*syscall.Stat_t)
|
||||||
|
|
||||||
dir := new(Dir)
|
dir := new(ufsDir)
|
||||||
dir.Qid = *dir2Qid(d)
|
dir.Qid = *dir2Qid(d)
|
||||||
dir.Mode = dir2Npmode(d, dotu)
|
dir.Mode = dir2Npmode(d, dotu)
|
||||||
dir.Atime = uint32(atime(sysMode).Unix())
|
dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
|
||||||
dir.Mtime = uint32(d.ModTime().Unix())
|
dir.Mtime = uint32(d.ModTime().Unix())
|
||||||
dir.Length = uint64(d.Size())
|
dir.Length = uint64(d.Size())
|
||||||
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
||||||
|
|
||||||
if dotu {
|
if dotu {
|
||||||
dir.dotu(path, d, upool, sysMode)
|
dir.dotu(path, d, upool, sysMode)
|
||||||
return &dir.Dir
|
return &dir.Dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unixUid := int(sysMode.Uid)
|
unixUid := int(sysMode.Uid)
|
||||||
unixGid := int(sysMode.Gid)
|
unixGid := int(sysMode.Gid)
|
||||||
dir.Uid = strconv.Itoa(unixUid)
|
dir.Uid = strconv.Itoa(unixUid)
|
||||||
dir.Gid = strconv.Itoa(unixGid)
|
dir.Gid = strconv.Itoa(unixGid)
|
||||||
dir.Muid = "none"
|
|
||||||
|
|
||||||
// BUG(akumar): LookupId will never find names for
|
// BUG(akumar): LookupId will never find names for
|
||||||
// groups, as it only operates on user ids.
|
// groups, as it only operates on user ids.
|
||||||
|
@ -76,10 +79,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
|
||||||
dir.Gid = g.Username
|
dir.Gid = g.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dir.Dir
|
/* For Akaros, we use the Muid as the link value. */
|
||||||
|
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
|
||||||
|
dir.Muid, err = os.Readlink(path)
|
||||||
|
if err == nil {
|
||||||
|
dir.Mode |= DMSYMLINK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &dir.Dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) {
|
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
|
||||||
u := upool.Uid2User(int(sysMode.Uid))
|
u := upool.Uid2User(int(sysMode.Uid))
|
||||||
g := upool.Gid2Group(int(sysMode.Gid))
|
g := upool.Gid2Group(int(sysMode.Gid))
|
||||||
dir.Uid = u.Name()
|
dir.Uid = u.Name()
|
||||||
|
@ -95,7 +105,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
|
||||||
dir.Ext = ""
|
dir.Ext = ""
|
||||||
dir.Uidnum = uint32(u.Id())
|
dir.Uidnum = uint32(u.Id())
|
||||||
dir.Gidnum = uint32(g.Id())
|
dir.Gidnum = uint32(g.Id())
|
||||||
dir.Muidnum = p.NOUID
|
dir.Muidnum = NOUID
|
||||||
if d.Mode()&os.ModeSymlink != 0 {
|
if d.Mode()&os.ModeSymlink != 0 {
|
||||||
var err error
|
var err error
|
||||||
dir.Ext, err = os.Readlink(path)
|
dir.Ext, err = os.Readlink(path)
|
||||||
|
@ -109,8 +119,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Wstat(req *srv.Req) {
|
func (u *Ufs) Wstat(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -121,10 +131,10 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
if dir.Mode != 0xFFFFFFFF {
|
if dir.Mode != 0xFFFFFFFF {
|
||||||
mode := dir.Mode & 0777
|
mode := dir.Mode & 0777
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
if dir.Mode&p.DMSETUID > 0 {
|
if dir.Mode&DMSETUID > 0 {
|
||||||
mode |= syscall.S_ISUID
|
mode |= syscall.S_ISUID
|
||||||
}
|
}
|
||||||
if dir.Mode&p.DMSETGID > 0 {
|
if dir.Mode&DMSETGID > 0 {
|
||||||
mode |= syscall.S_ISGID
|
mode |= syscall.S_ISGID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +145,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uid, gid := p.NOUID, p.NOUID
|
uid, gid := NOUID, NOUID
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
uid = dir.Uidnum
|
uid = dir.Uidnum
|
||||||
gid = dir.Gidnum
|
gid = dir.Gidnum
|
||||||
|
@ -159,7 +169,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if uid != p.NOUID || gid != p.NOUID {
|
if uid != NOUID || gid != NOUID {
|
||||||
e := os.Chown(fid.path, int(uid), int(gid))
|
e := os.Chown(fid.path, int(uid), int(gid))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
req.RespondError(toError(e))
|
req.RespondError(toError(e))
|
||||||
|
@ -168,13 +178,25 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir.Name != "" {
|
if dir.Name != "" {
|
||||||
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
|
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
|
||||||
err := syscall.Rename(fid.path, path)
|
// if first char is / it is relative to root, else relative to
|
||||||
|
// cwd.
|
||||||
|
var destpath string
|
||||||
|
if dir.Name[0] == '/' {
|
||||||
|
destpath = path.Join(u.Root, dir.Name)
|
||||||
|
fmt.Printf("/ results in %s\n", destpath)
|
||||||
|
} else {
|
||||||
|
fiddir, _ := path.Split(fid.path)
|
||||||
|
destpath = path.Join(fiddir, dir.Name)
|
||||||
|
fmt.Printf("rel results in %s\n", destpath)
|
||||||
|
}
|
||||||
|
err := syscall.Rename(fid.path, destpath)
|
||||||
|
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(toError(err))
|
req.RespondError(toError(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fid.path = path
|
fid.path = destpath
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
||||||
|
@ -199,7 +221,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
case true:
|
case true:
|
||||||
mt = st.ModTime()
|
mt = st.ModTime()
|
||||||
default:
|
default:
|
||||||
at = atime(st.Sys().(*syscall.Stat_t))
|
//at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e := os.Chtimes(fid.path, at, mt)
|
e := os.Chtimes(fid.path, at, mt)
|
|
@ -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
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// http://golang.org/src/os/stat_windows.go
|
package go9p
|
||||||
|
|
||||||
package ufs
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/minikube/third_party/go9p/p"
|
|
||||||
"k8s.io/minikube/third_party/go9p/p/srv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// type Win32FileAttributeData struct {
|
|
||||||
// FileAttributes uint32
|
|
||||||
// CreationTime Filetime
|
|
||||||
// LastAccessTime Filetime
|
|
||||||
// LastWriteTime Filetime
|
|
||||||
// FileSizeHigh uint32
|
|
||||||
// FileSizeLow uint32
|
|
||||||
// }
|
|
||||||
|
|
||||||
// A FileInfo describes a file and is returned by Stat and Lstat.
|
|
||||||
// type FileInfo interface {
|
|
||||||
// Name() string // base name of the file
|
|
||||||
// Size() int64 // length in bytes for regular files; system-dependent for others
|
|
||||||
// Mode() FileMode // file mode bits
|
|
||||||
// ModTime() time.Time // modification time
|
|
||||||
// IsDir() bool // abbreviation for Mode().IsDir()
|
|
||||||
// Sys() interface{} // underlying data source (can return nil)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func atime(fi os.FileInfo) time.Time {
|
func atime(fi os.FileInfo) time.Time {
|
||||||
return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsBlock reports if the file is a block device
|
// IsBlock reports if the file is a block device
|
||||||
func isBlock(d os.FileInfo) bool {
|
func isBlock(d os.FileInfo) bool {
|
||||||
// return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
// stat := d.Sys().(*syscall.Stat_t)
|
||||||
// stat := d.Sys().(os.FileInfo)
|
|
||||||
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsChar reports if the file is a character device
|
// IsChar reports if the file is a character device
|
||||||
func isChar(d os.FileInfo) bool {
|
func isChar(d os.FileInfo) bool {
|
||||||
// stat := d.Sys().(os.FileInfo)
|
// stat := d.Sys().(*syscall.Stat_t)
|
||||||
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
// return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func dir2Qid(d os.FileInfo) *p.Qid {
|
func dir2Qid(d os.FileInfo) *Qid {
|
||||||
var qid p.Qid
|
var qid Qid
|
||||||
|
|
||||||
// d.Sys().(*syscall.Win32FileAttributeData)
|
|
||||||
qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow)
|
qid.Path = uint64(d.Sys().(*syscall.Win32FileAttributeData).FileSizeLow)
|
||||||
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
|
||||||
qid.Type = dir2QidType(d)
|
qid.Type = dir2QidType(d)
|
||||||
|
@ -65,20 +41,28 @@ func dir2Qid(d os.FileInfo) *p.Qid {
|
||||||
return &qid
|
return &qid
|
||||||
}
|
}
|
||||||
|
|
||||||
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
|
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
|
||||||
// sysMode := d.Sys().(os.FileInfo)
|
if r := recover(); r != nil {
|
||||||
|
fmt.Print("stat failed: ", r)
|
||||||
|
return nil, &os.PathError{"dir2Dir", path, nil}
|
||||||
|
}
|
||||||
|
sysif := d.Sys()
|
||||||
|
if sysif == nil {
|
||||||
|
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
|
||||||
|
}
|
||||||
|
sysMode := sysif.(*syscall.Win32FileAttributeData)
|
||||||
|
|
||||||
dir := new(Dir)
|
dir := new(ufsDir)
|
||||||
dir.Qid = *dir2Qid(d)
|
dir.Qid = *dir2Qid(d)
|
||||||
dir.Mode = dir2Npmode(d, dotu)
|
dir.Mode = dir2Npmode(d, dotu)
|
||||||
// dir.Atime = uint32(atime(sysMode).Unix())
|
// dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
|
||||||
// dir.Mtime = uint32(d.ModTime().Unix())
|
// dir.Mtime = uint32(d.ModTime().Unix())
|
||||||
dir.Length = uint64(d.Size())
|
dir.Length = uint64(d.Size())
|
||||||
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
dir.Name = path[strings.LastIndex(path, "/")+1:]
|
||||||
|
|
||||||
if dotu {
|
if dotu {
|
||||||
// dir.dotu(path, d, upool, sysMode)
|
dir.dotu(path, d, upool, sysMode)
|
||||||
return &dir.Dir
|
return &dir.Dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// unixUid := int(sysMode.Uid)
|
// unixUid := int(sysMode.Uid)
|
||||||
|
@ -101,10 +85,18 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
|
||||||
// dir.Gid = g.Username
|
// dir.Gid = g.Username
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return &dir.Dir
|
var err error
|
||||||
|
/* For Akaros, we use the Muid as the link value. */
|
||||||
|
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
|
||||||
|
dir.Muid, err = os.Readlink(path)
|
||||||
|
if err == nil {
|
||||||
|
dir.Mode |= DMSYMLINK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &dir.Dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
|
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) {
|
||||||
// u := upool.Uid2User(int(sysMode.Uid))
|
// u := upool.Uid2User(int(sysMode.Uid))
|
||||||
// g := upool.Gid2Group(int(sysMode.Gid))
|
// g := upool.Gid2Group(int(sysMode.Gid))
|
||||||
// dir.Uid = u.Name()
|
// dir.Uid = u.Name()
|
||||||
|
@ -120,7 +112,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
|
||||||
// dir.Ext = ""
|
// dir.Ext = ""
|
||||||
// dir.Uidnum = uint32(u.Id())
|
// dir.Uidnum = uint32(u.Id())
|
||||||
// dir.Gidnum = uint32(g.Id())
|
// dir.Gidnum = uint32(g.Id())
|
||||||
// dir.Muidnum = p.NOUID
|
// dir.Muidnum = NOUID
|
||||||
// if d.Mode()&os.ModeSymlink != 0 {
|
// if d.Mode()&os.ModeSymlink != 0 {
|
||||||
// var err error
|
// var err error
|
||||||
// dir.Ext, err = os.Readlink(path)
|
// dir.Ext, err = os.Readlink(path)
|
||||||
|
@ -137,12 +129,12 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users) {
|
||||||
dir.Muid = "none"
|
dir.Muid = "none"
|
||||||
dir.Uidnum = 0
|
dir.Uidnum = 0
|
||||||
dir.Gidnum = 0
|
dir.Gidnum = 0
|
||||||
dir.Muidnum = p.NOUID
|
dir.Muidnum = NOUID
|
||||||
dir.Ext = ""
|
dir.Ext = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Ufs) Wstat(req *srv.Req) {
|
func (u *Ufs) Wstat(req *SrvReq) {
|
||||||
fid := req.Fid.Aux.(*Fid)
|
fid := req.Fid.Aux.(*ufsFid)
|
||||||
err := fid.stat()
|
err := fid.stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(err)
|
req.RespondError(err)
|
||||||
|
@ -153,10 +145,10 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
if dir.Mode != 0xFFFFFFFF {
|
if dir.Mode != 0xFFFFFFFF {
|
||||||
mode := dir.Mode & 0777
|
mode := dir.Mode & 0777
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
if dir.Mode&p.DMSETUID > 0 {
|
if dir.Mode&DMSETUID > 0 {
|
||||||
mode |= syscall.S_ISUID
|
mode |= syscall.S_ISUID
|
||||||
}
|
}
|
||||||
if dir.Mode&p.DMSETGID > 0 {
|
if dir.Mode&DMSETGID > 0 {
|
||||||
mode |= syscall.S_ISGID
|
mode |= syscall.S_ISGID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,7 +159,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uid, gid := p.NOUID, p.NOUID
|
uid, gid := NOUID, NOUID
|
||||||
if req.Conn.Dotu {
|
if req.Conn.Dotu {
|
||||||
uid = dir.Uidnum
|
uid = dir.Uidnum
|
||||||
gid = dir.Gidnum
|
gid = dir.Gidnum
|
||||||
|
@ -191,7 +183,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if uid != p.NOUID || gid != p.NOUID {
|
if uid != NOUID || gid != NOUID {
|
||||||
e := os.Chown(fid.path, int(uid), int(gid))
|
e := os.Chown(fid.path, int(uid), int(gid))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
req.RespondError(toError(e))
|
req.RespondError(toError(e))
|
||||||
|
@ -200,13 +192,25 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir.Name != "" {
|
if dir.Name != "" {
|
||||||
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
|
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
|
||||||
err := syscall.Rename(fid.path, path)
|
// if first char is / it is relative to root, else relative to
|
||||||
|
// cwd.
|
||||||
|
var destpath string
|
||||||
|
if dir.Name[0] == '/' {
|
||||||
|
destpath = path.Join(u.Root, dir.Name)
|
||||||
|
fmt.Printf("/ results in %s\n", destpath)
|
||||||
|
} else {
|
||||||
|
fiddir, _ := path.Split(fid.path)
|
||||||
|
destpath = path.Join(fiddir, dir.Name)
|
||||||
|
fmt.Printf("rel results in %s\n", destpath)
|
||||||
|
}
|
||||||
|
err := syscall.Rename(fid.path, destpath)
|
||||||
|
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
req.RespondError(toError(err))
|
req.RespondError(toError(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fid.path = path
|
fid.path = destpath
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
if dir.Length != 0xFFFFFFFFFFFFFFFF {
|
||||||
|
@ -231,7 +235,7 @@ func (*Ufs) Wstat(req *srv.Req) {
|
||||||
// case true:
|
// case true:
|
||||||
// mt = st.ModTime()
|
// mt = st.ModTime()
|
||||||
// default:
|
// default:
|
||||||
// at = atime(st.Sys().(os.FileInfo))
|
// //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// e := os.Chtimes(fid.path, at, mt)
|
// e := os.Chtimes(fid.path, at, mt)
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package p
|
package go9p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -77,9 +77,14 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
|
||||||
goto szerror
|
goto szerror
|
||||||
}
|
}
|
||||||
|
|
||||||
fc.Unamenum = NOUID
|
if dotu {
|
||||||
if dotu && len(p) > 0 {
|
if len(p) > 0 {
|
||||||
fc.Unamenum, p = gint32(p)
|
fc.Unamenum, p = gint32(p)
|
||||||
|
} else {
|
||||||
|
fc.Unamenum = NOUID
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fc.Unamenum = NOUID
|
||||||
}
|
}
|
||||||
|
|
||||||
case Rauth, Rattach:
|
case Rauth, Rattach:
|
||||||
|
@ -101,9 +106,12 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
|
||||||
goto szerror
|
goto szerror
|
||||||
}
|
}
|
||||||
|
|
||||||
fc.Unamenum = NOUID
|
if dotu {
|
||||||
if dotu && len(p) > 0 {
|
if len(p) > 0 {
|
||||||
fc.Unamenum, p = gint32(p)
|
fc.Unamenum, p = gint32(p)
|
||||||
|
} else {
|
||||||
|
fc.Unamenum = NOUID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case Rerror:
|
case Rerror:
|
||||||
|
@ -193,15 +201,15 @@ func Unpack(buf []byte, dotu bool) (fc *Fcall, err error, fcsz int) {
|
||||||
|
|
||||||
case Rstat:
|
case Rstat:
|
||||||
m, p = gint16(p)
|
m, p = gint16(p)
|
||||||
p = gstat(p, &fc.Dir, dotu)
|
p, err = gstat(p, &fc.Dir, dotu)
|
||||||
if p == nil {
|
if err != nil {
|
||||||
goto szerror
|
return nil, err, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
case Twstat:
|
case Twstat:
|
||||||
fc.Fid, p = gint32(p)
|
fc.Fid, p = gint32(p)
|
||||||
m, p = gint16(p)
|
m, p = gint16(p)
|
||||||
p = gstat(p, &fc.Dir, dotu)
|
p, _ = gstat(p, &fc.Dir, dotu)
|
||||||
|
|
||||||
case Rflush, Rclunk, Rremove, Rwstat:
|
case Rflush, Rclunk, Rremove, Rwstat:
|
||||||
}
|
}
|
Loading…
Reference in New Issue