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

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

上级 12e41aea
......@@ -26,7 +26,7 @@ import (
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/third_party/go9p/p/srv/examples/ufs"
"k8s.io/minikube/third_party/go9p/ufs"
)
// mountCmd represents the mount command
......@@ -42,6 +42,15 @@ var mountCmd = &cobra.Command{
fmt.Fprintln(os.Stderr, errText)
os.Exit(1)
}
if _, err := os.Stat(args[0]); err != nil {
if os.IsNotExist(err) {
errText := fmt.Sprintf("Cannot find directory %s for mount", args[0])
fmt.Fprintln(os.Stderr, errText)
} else {
errText := fmt.Sprintf("Error accesssing directory %s for mount", args[0])
fmt.Fprintln(os.Stderr, errText)
}
}
var debugVal int
if glog.V(1) {
debugVal = 1 // ufs.StartServer takes int debug param
......
......@@ -30,6 +30,7 @@ gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/minikube-${OS_ARCH} out/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/e2e-${OS_ARCH} out/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox.yaml testdata/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/pvc.yaml testdata/
gsutil cp gs://minikube-builds/${MINIKUBE_LOCATION}/testdata/busybox-mount-test.yaml testdata/
# Set the executable bit on the e2e binary and out binary
chmod +x out/e2e-${OS_ARCH}
......
......@@ -408,6 +408,7 @@ func Mount9pHost(api libmachine.API) error {
if err != nil {
return errors.Wrap(err, "Error getting the host IP address to use from within the VM")
}
host.RunSSHCommand(GetMount9pCleanupCommand())
_, err = host.RunSSHCommand(GetMount9pCommand(ip))
if err != nil {
return err
......
......@@ -77,7 +77,7 @@ func getVMHostIP(host *host.Host) (net.IP, error) {
case "virtualbox":
return net.ParseIP("10.0.2.2"), nil
case "xhyve":
return net.ParseIP("10.0.2.2"), nil
return net.ParseIP("192.168.64.1"), nil
default:
return []byte{}, errors.New("Error, attempted to get host ip address for unsupported driver")
}
......
......@@ -154,7 +154,7 @@ func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) {
flagVals = append(flagVals, "--feature-gates="+kubernetesConfig.FeatureGates)
}
if kubernetesConfig.APIServerName != "" {
if kubernetesConfig.APIServerName != constants.APIServerName {
flagVals = append(flagVals, "--apiserver-name="+kubernetesConfig.APIServerName)
}
......@@ -226,9 +226,16 @@ else
fi
`, constants.LocalkubePIDPath)
func GetMount9pCleanupCommand() string {
return `
sudo umount /mount-9p;
sudo rm -rf /mount-9p;
`
}
func GetMount9pCommand(ip net.IP) string {
return fmt.Sprintf(`
sudo mkdir /mount-9p;
sudo mount -t 9p -o trans=tcp -o port=5640 %s /mount-9p;
sudo mount -t 9p -o trans=tcp -o port=5640 -o uid=1001 -o gid=1001 %s /mount-9p;
sudo chmod 775 /mount-9p;`, ip)
}
......@@ -41,4 +41,5 @@ func TestFunctional(t *testing.T) {
t.Run("Dashboard", testDashboard)
t.Run("ServicesList", testServicesList)
t.Run("Provisioning", testProvisioning)
t.Run("Mounting", testMounting)
}
// +build integration
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package integration
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
"k8s.io/kubernetes/pkg/api"
commonutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/test/integration/util"
)
func testMounting(t *testing.T) {
t.Parallel()
minikubeRunner := util.MinikubeRunner{
Args: *args,
BinaryPath: *binaryPath,
T: t}
tempDir, err := ioutil.TempDir("", "mounttest")
if err != nil {
t.Fatalf("Unexpected error while creating tempDir: %s", err)
}
defer os.RemoveAll(tempDir)
mountCmd := fmt.Sprintf("mount %s", tempDir)
cmd := minikubeRunner.RunDaemon(mountCmd)
defer cmd.Process.Kill()
kubectlRunner := util.NewKubectlRunner(t)
podName := "busybox"
podPath, _ := filepath.Abs("testdata/busybox-mount-test.yaml")
// Write file in mounted dir from host
expected := "test\n"
files := []string{"fromhost", "fromhostremove"}
for _, file := range files {
path := filepath.Join(tempDir, file)
err = ioutil.WriteFile(path, []byte(expected), 0644)
if err != nil {
t.Fatalf("Unexpected error while writing file %s: %s.", path, err)
}
}
mountTest := func() error {
if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil {
return err
}
defer kubectlRunner.RunCommand([]string{"delete", "-f", podPath})
p := &api.Pod{}
for p.Status.Phase != "Running" {
p = kubectlRunner.GetPod(podName, "default")
}
path := filepath.Join(tempDir, "frompod")
out, err := ioutil.ReadFile(path)
if err != nil {
return &commonutil.RetriableError{Err: err}
}
// test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod
if string(out) != expected {
t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
}
// test that file written from host was read in by the pod via cat /mount-9p/fromhost;
if out, err = kubectlRunner.RunCommand([]string{"logs", podName}); err != nil {
return &commonutil.RetriableError{Err: err}
}
if string(out) != expected {
t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
}
// test that fromhostremove was deleted by the pod from the mount via rm /mount-9p/fromhostremove
path = filepath.Join(tempDir, "fromhostremove")
if _, err := os.Stat(path); err == nil {
t.Fatalf("Expected file %s to be removed", path, expected, out)
}
// test that frompodremove can be deleted on the host
path = filepath.Join(tempDir, "frompodremove")
if err := os.Remove(path); err != nil {
t.Fatalf("Unexpected error removing file %s: %s", path, err)
}
return nil
}
if err := commonutil.RetryAfter(40, mountTest, 5*time.Second); err != nil {
t.Fatal("mountTest failed with error:", err)
}
}
apiVersion: v1
kind: Pod
metadata:
name: busybox
spec:
containers:
- image: busybox:glibc
command: [ "/bin/sh", "-c", "--" ]
args: [ "cat /mount-9p/fromhost; echo test > /mount-9p/frompod; rm /mount-9p/fromhostremove; echo test > /mount-9p/frompodremove;" ]
name: busybox
volumeMounts:
- mountPath: /mount-9p
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /mount-9p
......@@ -69,6 +69,17 @@ func (m *MinikubeRunner) RunCommand(command string, checkError bool) string {
return string(stdout)
}
func (m *MinikubeRunner) RunDaemon(command string) *exec.Cmd {
commandArr := strings.Split(command, " ")
path, _ := filepath.Abs(m.BinaryPath)
cmd := exec.Command(path, commandArr...)
err := cmd.Start()
if err != nil {
m.T.Fatalf("Error running command: %s %s", command, err)
}
return cmd
}
func (m *MinikubeRunner) SSH(command string) (string, error) {
path, _ := filepath.Abs(m.BinaryPath)
cmd := exec.Command(path, "ssh", command)
......
# This is the official list of Go9p authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Andrey Mirtchovski <mirtchovski@gmail.com>
Latchesar Ionkov <lionkov@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
# This is the official list of people who can contribute
# (and typically have contributed) code to the Go9p repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# The submission process automatically checks to make sure
# that people submitting code are listed in this file (by email address).
# XXX more bumph here?
# Names should be added to this file like so:
# Name <email address>
# Please keep the list sorted.
Andrey Mirtchovski <mirtchovski@gmail.com>
Latchesar Ionkov <lionkov@gmail.com>
Akshat Kumar <seed@mail.nanosouffle.net>
Roger Peppe <rogpeppe@gmail.com>
This is go9p done in a way that I can understand.
To install:
export GOPATH=~rminnich/go
go get -a /k8s.io/minikube/third_party/go9p
go get -a /k8s.io/minikube/third_party/go9p/ufs
go install -a /k8s.io/minikube/third_party/go9p/ufs
~/go/bin/ufs
......@@ -2,31 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The clnt package provides definitions and functions used to implement
// The clnt package go9provides definitions and functions used to implement
// a 9P2000 file client.
package clnt
package go9p
import (
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"log"
"net"
"sync"
"sync/atomic"
)
// Debug flags
const (
DbgPrintFcalls = (1 << iota) // print all 9P messages on stderr
DbgPrintPackets // print the raw packets on stderr
DbgLogFcalls // keep the last N 9P messages (can be accessed over http)
DbgLogPackets // keep the last N 9P messages (can be accessed over http)
)
type StatsOps interface {
statsRegister()
statsUnregister()
}
// The Clnt type represents a 9P2000 client. The client is connected to
// a 9P2000 file server and its methods can be used to access and manipulate
// the files exported by the server.
......@@ -37,7 +24,7 @@ type Clnt struct {
Dotu bool // If true, 9P2000.u protocol is spoken
Root *Fid // Fid that points to the rood directory
Id string // Used when printing debug messages
Log *p.Logger
Log *Logger
conn net.Conn
tagpool *pool
......@@ -49,7 +36,7 @@ type Clnt struct {
err error
reqchan chan *Req
tchan chan *p.Fcall
tchan chan *Fcall
next, prev *Clnt
}
......@@ -60,33 +47,26 @@ type Fid struct {
sync.Mutex
Clnt *Clnt // Client the fid belongs to
Iounit uint32
p.Qid // The Qid description for the file
Mode uint8 // Open mode (one of p.O* values) (if file is open)
Qid // The Qid description for the file
Mode uint8 // Open mode (one of O* values) (if file is open)
Fid uint32 // Fid number
p.User // The user the fid belongs to
User // The user the fid belongs to
walked bool // true if the fid points to a walked file on the server
}
// The file is similar to the Fid, but is used in the high-level client
// interface.
// interface. We expose the Fid so that client code can use Remove
// on a fid, the same way a kernel can.
type File struct {
fid *Fid
Fid *Fid
offset uint64
}
type pool struct {
sync.Mutex
need int
nchan chan uint32
maxid uint32
imap []byte
}
type Req struct {
sync.Mutex
Clnt *Clnt
Tc *p.Fcall
Rc *p.Fcall
Tc *Fcall
Rc *Fcall
Err error
Done chan *Req
tag uint16
......@@ -101,18 +81,18 @@ type ClntList struct {
var clnts *ClntList
var DefaultDebuglevel int
var DefaultLogger *p.Logger
var DefaultLogger *Logger
func (clnt *Clnt) Rpcnb(r *Req) error {
var tag uint16
if r.Tc.Type == p.Tversion {
tag = p.NOTAG
if r.Tc.Type == Tversion {
tag = NOTAG
} else {
tag = r.tag
}
p.SetTag(r.Tc, tag)
SetTag(r.Tc, tag)
clnt.Lock()
if clnt.err != nil {
clnt.Unlock()
......@@ -133,7 +113,7 @@ func (clnt *Clnt) Rpcnb(r *Req) error {
return nil
}
func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
func (clnt *Clnt) Rpc(tc *Fcall) (rc *Fcall, err error) {
r := clnt.ReqAlloc()
r.Tc = tc
r.Done = make(chan *Req)
......@@ -151,13 +131,15 @@ func (clnt *Clnt) Rpc(tc *p.Fcall) (rc *p.Fcall, err error) {
func (clnt *Clnt) recv() {
var err error
var buf []byte
err = nil
buf := make([]byte, clnt.Msize*8)
pos := 0
for {
if len(buf) < int(clnt.Msize) {
b := make([]byte, clnt.Msize*8)
// Connect can change the client Msize.
clntmsize := int(atomic.LoadUint32(&clnt.Msize))
if len(buf) < clntmsize {
b := make([]byte, clntmsize*8)
copy(b, buf[0:pos])
buf = b
b = nil
......@@ -165,7 +147,7 @@ func (clnt *Clnt) recv() {
n, oerr := clnt.conn.Read(buf[pos:])
if oerr != nil || n == 0 {
err = &p.Error{oerr.Error(), p.EIO}
err = &Error{oerr.Error(), EIO}
clnt.Lock()
clnt.err = err
clnt.Unlock()
......@@ -174,10 +156,10 @@ func (clnt *Clnt) recv() {
pos += n
for pos > 4 {
sz, _ := p.Gint32(buf)
sz, _ := Gint32(buf)
if pos < int(sz) {
if len(buf) < int(sz) {
b := make([]byte, clnt.Msize*8)
b := make([]byte, atomic.LoadUint32(&clnt.Msize)*8)
copy(b, buf[0:pos])
buf = b
b = nil
......@@ -186,7 +168,7 @@ func (clnt *Clnt) recv() {
break
}
fc, err, fcsize := p.Unpack(buf, clnt.Dotu)
fc, err, fcsize := Unpack(buf, clnt.Dotu)
clnt.Lock()
if err != nil {
clnt.err = err
......@@ -214,7 +196,7 @@ func (clnt *Clnt) recv() {
}
if r == nil {
clnt.err = &p.Error{"unexpected response", p.EINVAL}
clnt.err = &Error{"unexpected response", EINVAL}
clnt.conn.Close()
clnt.Unlock()
goto closed
......@@ -235,13 +217,13 @@ func (clnt *Clnt) recv() {
clnt.Unlock()
if r.Tc.Type != r.Rc.Type-1 {
if r.Rc.Type != p.Rerror {
r.Err = &p.Error{"invalid response", p.EINVAL}
if r.Rc.Type != Rerror {
r.Err = &Error{"invalid response", EINVAL}
log.Println(fmt.Sprintf("TTT %v", r.Tc))
log.Println(fmt.Sprintf("RRR %v", r.Rc))
} else {
if r.Err == nil {
r.Err = &p.Error{r.Rc.Error, r.Rc.Errornum}
r.Err = &Error{r.Rc.Error, r.Rc.Errornum}
}
}
}
......@@ -335,12 +317,12 @@ func NewClnt(c net.Conn, msize uint32, dotu bool) *Clnt {
clnt.Debuglevel = DefaultDebuglevel
clnt.Log = DefaultLogger
clnt.Id = c.RemoteAddr().String() + ":"
clnt.tagpool = newPool(uint32(p.NOTAG))
clnt.fidpool = newPool(p.NOFID)
clnt.tagpool = newPool(uint32(NOTAG))
clnt.fidpool = newPool(NOFID)
clnt.reqout = make(chan *Req)
clnt.done = make(chan bool)
clnt.reqchan = make(chan *Req, 16)
clnt.tchan = make(chan *p.Fcall, 16)
clnt.tchan = make(chan *Fcall, 16)
go clnt.recv()
go clnt.send()
......@@ -373,8 +355,9 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
ver = "9P2000.u"
}
tc := p.NewFcall(clnt.Msize)
err := p.PackTversion(tc, clnt.Msize, ver)
clntmsize := atomic.LoadUint32(&clnt.Msize)
tc := NewFcall(clntmsize)
err := PackTversion(tc, clntmsize, ver)
if err != nil {
return nil, err
}
......@@ -384,8 +367,8 @@ func Connect(c net.Conn, msize uint32, dotu bool) (*Clnt, error) {
return nil, err
}
if rc.Msize < clnt.Msize {
clnt.Msize = rc.Msize
if rc.Msize < atomic.LoadUint32(&clnt.Msize) {
atomic.StoreUint32(&clnt.Msize, rc.Msize)
}
clnt.Dotu = rc.Version == "9P2000.u" && clnt.Dotu
......@@ -401,17 +384,17 @@ func (clnt *Clnt) FidAlloc() *Fid {
return fid
}
func (clnt *Clnt) NewFcall() *p.Fcall {
func (clnt *Clnt) NewFcall() *Fcall {
select {
case tc := <-clnt.tchan:
return tc
default:
}
return p.NewFcall(clnt.Msize)
return NewFcall(atomic.LoadUint32(&clnt.Msize))
}
func (clnt *Clnt) FreeFcall(fc *p.Fcall) {
if fc != nil && len(fc.Buf) >= int(clnt.Msize) {
func (clnt *Clnt) FreeFcall(fc *Fcall) {
if fc != nil && len(fc.Buf) >= int(atomic.LoadUint32(&clnt.Msize)) {
select {
case clnt.tchan <- fc:
break
......@@ -450,15 +433,7 @@ func (clnt *Clnt) ReqFree(req *Req) {
}
}
func NewFile(f *Fid, offset uint64) *File {
return &File{f, offset}
}
func (f *File) Fid() *Fid {
return f.fid
}
func (clnt *Clnt) logFcall(fc *p.Fcall) {
func (clnt *Clnt) logFcall(fc *Fcall) {
if clnt.Debuglevel&DbgLogPackets != 0 {
pkt := make([]byte, len(fc.Pkt))
copy(pkt, fc.Pkt)
......@@ -466,13 +441,19 @@ func (clnt *Clnt) logFcall(fc *p.Fcall) {
}
if clnt.Debuglevel&DbgLogFcalls != 0 {
f := new(p.Fcall)
f := new(Fcall)
*f = *fc
f.Pkt = nil
clnt.Log.Log(f, clnt, DbgLogFcalls)
}
}
// FidFile returns a File that represents the given Fid, initially at the given
// offset.
func FidFile(fid *Fid, offset uint64) *File {
return &File{fid, offset}
}
func init() {
clnts = new(ClntList)
if sop, ok := (interface{}(clnts)).(StatsOps); ok {
......
......@@ -2,16 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Clunks a fid. Returns nil if successful.
func (clnt *Clnt) Clunk(fid *Fid) (err error) {
err = nil
if fid.walked {
tc := clnt.NewFcall()
err := p.PackTclunk(tc, fid.Fid)
err := PackTclunk(tc, fid.Fid)
if err != nil {
return err
}
......@@ -21,12 +19,12 @@ func (clnt *Clnt) Clunk(fid *Fid) (err error) {
clnt.fidpool.putId(fid.Fid)
fid.walked = false
fid.Fid = p.NOFID
fid.Fid = NOFID
return
}
// Closes a file. Returns nil if successful.
func (file *File) Close() error {
// Should we cancel all pending requests for the File
return file.fid.Clnt.Clunk(file.fid)
return file.Fid.Clnt.Clunk(file.Fid)
}
......@@ -2,19 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"net"
)
// Creates an authentication fid for the specified user. Returns the fid, if
// successful, or an Error.
func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
func (clnt *Clnt) Auth(user User, aname string) (*Fid, error) {
fid := clnt.FidAlloc()
tc := clnt.NewFcall()
err := p.PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
err := PackTauth(tc, fid.Fid, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
if err != nil {
return nil, err
}
......@@ -24,7 +23,6 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
return nil, err
}
fid.Iounit = clnt.Msize - p.IOHDRSZ
fid.User = user
fid.walked = true
return fid, nil
......@@ -33,18 +31,18 @@ func (clnt *Clnt) Auth(user p.User, aname string) (*Fid, error) {
// Creates a fid for the specified user that points to the root
// of the file server's file tree. Returns a Fid pointing to the root,
// if successful, or an Error.
func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) {
func (clnt *Clnt) Attach(afid *Fid, user User, aname string) (*Fid, error) {
var afno uint32
if afid != nil {
afno = afid.Fid
} else {
afno = p.NOFID
afno = NOFID
}
fid := clnt.FidAlloc()
tc := clnt.NewFcall()
err := p.PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
err := PackTattach(tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), clnt.Dotu)
if err != nil {
return nil, err
}
......@@ -61,17 +59,17 @@ func (clnt *Clnt) Attach(afid *Fid, user p.User, aname string) (*Fid, error) {
}
// Connects to a file server and attaches to it as the specified user.
func Mount(ntype, addr, aname string, user p.User) (*Clnt, error) {
func Mount(ntype, addr, aname string, msize uint32, user User) (*Clnt, error) {
c, e := net.Dial(ntype, addr)
if e != nil {
return nil, &p.Error{e.Error(), p.EIO}
return nil, &Error{e.Error(), EIO}
}
return MountConn(c, aname, user)
return MountConn(c, aname, msize, user)
}
func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
clnt, err := Connect(c, 8192+p.IOHDRSZ, true)
func MountConn(c net.Conn, aname string, msize uint32, user User) (*Clnt, error) {
clnt, err := Connect(c, msize+IOHDRSZ, true)
if err != nil {
return nil, err
}
......@@ -89,7 +87,7 @@ func MountConn(c net.Conn, aname string, user p.User) (*Clnt, error) {
// Closes the connection to the file sever.
func (clnt *Clnt) Unmount() {
clnt.Lock()
clnt.err = &p.Error{"connection closed", p.EIO}
clnt.err = &Error{"connection closed", EIO}
clnt.conn.Close()
clnt.Unlock()
}
......@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"strings"
)
......@@ -13,7 +12,7 @@ import (
// the operation is successful.
func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
tc := clnt.NewFcall()
err := p.PackTopen(tc, fid.Fid, mode)
err := PackTopen(tc, fid.Fid, mode)
if err != nil {
return err
}
......@@ -25,8 +24,8 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
fid.Qid = rc.Qid
fid.Iounit = rc.Iounit
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ {
fid.Iounit = clnt.Msize - p.IOHDRSZ
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
fid.Iounit = clnt.Msize - IOHDRSZ
}
fid.Mode = mode
return nil
......@@ -36,7 +35,7 @@ func (clnt *Clnt) Open(fid *Fid, mode uint8) error {
// if the operation is successful.
func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
tc := clnt.NewFcall()
err := p.PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu)
err := PackTcreate(tc, fid.Fid, name, perm, mode, ext, clnt.Dotu)
if err != nil {
return err
}
......@@ -48,8 +47,8 @@ func (clnt *Clnt) Create(fid *Fid, name string, perm uint32, mode uint8, ext str
fid.Qid = rc.Qid
fid.Iounit = rc.Iounit
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-p.IOHDRSZ {
fid.Iounit = clnt.Msize - p.IOHDRSZ
if fid.Iounit == 0 || fid.Iounit > clnt.Msize-IOHDRSZ {
fid.Iounit = clnt.Msize - IOHDRSZ
}
fid.Mode = mode
return nil
......
......@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import "sync"
var m2id = [...]uint8{
0, 1, 0, 2, 0, 1, 0, 3,
......@@ -39,6 +41,14 @@ var m2id = [...]uint8{
0, 1, 0, 2, 0, 1, 0, 0,
}
type pool struct {
sync.Mutex
need int
nchan chan uint32
maxid uint32
imap []byte
}
func newPool(maxid uint32) *pool {
p := new(pool)
p.maxid = maxid
......
......@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"io"
"k8s.io/minikube/third_party/go9p/p"
)
// Reads count bytes starting from offset from the file associated with the fid.
......@@ -18,7 +17,7 @@ func (clnt *Clnt) Read(fid *Fid, offset uint64, count uint32) ([]byte, error) {
}
tc := clnt.NewFcall()
err := p.PackTread(tc, fid.Fid, offset, count)
err := PackTread(tc, fid.Fid, offset, count)
if err != nil {
return nil, err
}
......@@ -45,7 +44,7 @@ func (file *File) Read(buf []byte) (int, error) {
// Reads up to len(buf) bytes from the file starting from offset.
// Returns the number of bytes read, or an Error.
func (file *File) ReadAt(buf []byte, offset int64) (int, error) {
b, err := file.fid.Clnt.Read(file.fid, uint64(offset), uint32(len(buf)))
b, err := file.Fid.Clnt.Read(file.Fid, uint64(offset), uint32(len(buf)))
if err != nil {
return 0, err
}
......@@ -85,10 +84,14 @@ func (file *File) Readn(buf []byte, offset uint64) (int, error) {
// Returns an array of maximum num entries (if num is 0, returns
// all entries from the directory). If the operation fails, returns
// an Error.
func (file *File) Readdir(num int) ([]*p.Dir, error) {
buf := make([]byte, file.fid.Clnt.Msize-p.IOHDRSZ)
dirs := make([]*p.Dir, 32)
func (file *File) Readdir(num int) ([]*Dir, error) {
buf := make([]byte, file.Fid.Clnt.Msize-IOHDRSZ)
dirs := make([]*Dir, 32)
pos := 0
offset := file.offset
defer func() {
file.offset = offset
}()
for {
n, err := file.Read(buf)
if err != nil && err != io.EOF {
......@@ -100,14 +103,20 @@ func (file *File) Readdir(num int) ([]*p.Dir, error) {
}
for b := buf[0:n]; len(b) > 0; {
d, perr := p.UnpackDir(b, file.fid.Clnt.Dotu)
d, _, _, perr := UnpackDir(b, file.Fid.Clnt.Dotu)
if perr != nil {
// If we have unpacked anything, it is almost certainly
// a too-short buffer. So return what we got.
if pos > 0 {
return dirs[0:pos], nil
}
return nil, perr
}
b = b[d.Size+2:]
offset += uint64(d.Size + 2)
if pos >= len(dirs) {
s := make([]*p.Dir, len(dirs)+32)
s := make([]*Dir, len(dirs)+32)
copy(s, dirs)
dirs = s
}
......
......@@ -2,22 +2,20 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Removes the file associated with the Fid. Returns nil if the
// operation is successful.
func (clnt *Clnt) Remove(fid *Fid) error {
tc := clnt.NewFcall()
err := p.PackTremove(tc, fid.Fid)
err := PackTremove(tc, fid.Fid)
if err != nil {
return err
}
_, err = clnt.Rpc(tc)
clnt.fidpool.putId(fid.Fid)
fid.Fid = p.NOFID
fid.Fid = NOFID
return err
}
......
......@@ -2,14 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Returns the metadata for the file associated with the Fid, or an Error.
func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
func (clnt *Clnt) Stat(fid *Fid) (*Dir, error) {
tc := clnt.NewFcall()
err := p.PackTstat(tc, fid.Fid)
err := PackTstat(tc, fid.Fid)
if err != nil {
return nil, err
}
......@@ -23,7 +21,7 @@ func (clnt *Clnt) Stat(fid *Fid) (*p.Dir, error) {
}
// Returns the metadata for a named file, or an Error.
func (clnt *Clnt) FStat(path string) (*p.Dir, error) {
func (clnt *Clnt) FStat(path string) (*Dir, error) {
fid, err := clnt.FWalk(path)
if err != nil {
return nil, err
......@@ -35,9 +33,9 @@ func (clnt *Clnt) FStat(path string) (*p.Dir, error) {
}
// Modifies the data of the file associated with the Fid, or an Error.
func (clnt *Clnt) Wstat(fid *Fid, dir *p.Dir) error {
func (clnt *Clnt) Wstat(fid *Fid, dir *Dir) error {
tc := clnt.NewFcall()
err := p.PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
err := PackTwstat(tc, fid.Fid, dir, clnt.Dotu)
if err != nil {
return err
}
......
// +build httpstats
package clnt
package go9p
import (
"fmt"
"io"
"k8s.io/minikube/third_party/go9p/p"
"net/http"
)
......@@ -18,7 +17,7 @@ func (clnt *Clnt) ServeHTTP(c http.ResponseWriter, r *http.Request) {
fs := clnt.Log.Filter(clnt, DbgLogFcalls)
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
for _, l := range fs {
fc := l.Data.(*p.Fcall)
fc := l.Data.(*Fcall)
if fc.Type != 0 {
io.WriteString(c, fmt.Sprintf("<br>%s", fc))
}
......
......@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
type Tag struct {
clnt *Clnt
......@@ -54,22 +52,22 @@ func (tag *Tag) reqproc() {
case r := <-tag.respchan:
rc := r.Rc
fid := r.fid
err := r.Rc.Type == p.Rerror
err := r.Rc.Type == Rerror
switch r.Tc.Type {
case p.Tauth:
case Tauth:
if err {
fid.User = nil
}
case p.Tattach:
case Tattach:
if !err {
fid.Qid = rc.Qid
} else {
fid.User = nil
}
case p.Twalk:
case Twalk:
if !err {
fid.walked = true
if len(rc.Wqid) > 0 {
......@@ -79,8 +77,8 @@ func (tag *Tag) reqproc() {
fid.User = nil
}
case p.Topen:
case p.Tcreate:
case Topen:
case Tcreate:
if !err {
fid.Iounit = rc.Iounit
fid.Qid = rc.Qid
......@@ -88,8 +86,8 @@ func (tag *Tag) reqproc() {
fid.Mode = 0
}
case p.Tclunk:
case p.Tremove:
case Tclunk:
case Tremove:
tag.clnt.fidpool.putId(fid.Fid)
}
......@@ -98,10 +96,10 @@ func (tag *Tag) reqproc() {
}
}
func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
func (tag *Tag) Auth(afid *Fid, user User, aname string) error {
req := tag.reqAlloc()
req.fid = afid
err := p.PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
err := PackTauth(req.Tc, afid.Fid, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
if err != nil {
return err
}
......@@ -110,18 +108,18 @@ func (tag *Tag) Auth(afid *Fid, user p.User, aname string) error {
return tag.clnt.Rpcnb(req)
}
func (tag *Tag) Attach(fid, afid *Fid, user p.User, aname string) error {
func (tag *Tag) Attach(fid, afid *Fid, user User, aname string) error {
var afno uint32
if afid != nil {
afno = afid.Fid
} else {
afno = p.NOFID
afno = NOFID
}
req := tag.reqAlloc()
req.fid = fid
err := p.PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
err := PackTattach(req.Tc, fid.Fid, afno, user.Name(), aname, uint32(user.Id()), tag.clnt.Dotu)
if err != nil {
return err
}
......@@ -137,7 +135,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
newfid.Qid = fid.Qid
}
err := p.PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames)
err := PackTwalk(req.Tc, fid.Fid, newfid.Fid, wnames)
if err != nil {
return err
}
......@@ -149,7 +147,7 @@ func (tag *Tag) Walk(fid *Fid, newfid *Fid, wnames []string) error {
func (tag *Tag) Open(fid *Fid, mode uint8) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTopen(req.Tc, fid.Fid, mode)
err := PackTopen(req.Tc, fid.Fid, mode)
if err != nil {
return err
}
......@@ -161,7 +159,7 @@ func (tag *Tag) Open(fid *Fid, mode uint8) error {
func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext string) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu)
err := PackTcreate(req.Tc, fid.Fid, name, perm, mode, ext, tag.clnt.Dotu)
if err != nil {
return err
}
......@@ -173,7 +171,7 @@ func (tag *Tag) Create(fid *Fid, name string, perm uint32, mode uint8, ext strin
func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTread(req.Tc, fid.Fid, offset, count)
err := PackTread(req.Tc, fid.Fid, offset, count)
if err != nil {
return err
}
......@@ -184,7 +182,7 @@ func (tag *Tag) Read(fid *Fid, offset uint64, count uint32) error {
func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data)
err := PackTwrite(req.Tc, fid.Fid, offset, uint32(len(data)), data)
if err != nil {
return err
}
......@@ -195,7 +193,7 @@ func (tag *Tag) Write(fid *Fid, data []byte, offset uint64) error {
func (tag *Tag) Clunk(fid *Fid) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTclunk(req.Tc, fid.Fid)
err := PackTclunk(req.Tc, fid.Fid)
if err != nil {
return err
}
......@@ -206,7 +204,7 @@ func (tag *Tag) Clunk(fid *Fid) error {
func (tag *Tag) Remove(fid *Fid) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTremove(req.Tc, fid.Fid)
err := PackTremove(req.Tc, fid.Fid)
if err != nil {
return err
}
......@@ -217,7 +215,7 @@ func (tag *Tag) Remove(fid *Fid) error {
func (tag *Tag) Stat(fid *Fid) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTstat(req.Tc, fid.Fid)
err := PackTstat(req.Tc, fid.Fid)
if err != nil {
return err
}
......@@ -225,10 +223,10 @@ func (tag *Tag) Stat(fid *Fid) error {
return tag.clnt.Rpcnb(req)
}
func (tag *Tag) Wstat(fid *Fid, dir *p.Dir) error {
func (tag *Tag) Wstat(fid *Fid, dir *Dir) error {
req := tag.reqAlloc()
req.fid = fid
err := p.PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu)
err := PackTwstat(req.Tc, fid.Fid, dir, tag.clnt.Dotu)
if err != nil {
return err
}
......
......@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"strings"
)
......@@ -13,9 +12,9 @@ import (
// sequence and associates the resulting file with newfid. If no wnames
// were walked successfully, an Error is returned. Otherwise a slice with a
// Qid for each walked name is returned.
func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]p.Qid, error) {
func (clnt *Clnt) Walk(fid *Fid, newfid *Fid, wnames []string) ([]Qid, error) {
tc := clnt.NewFcall()
err := p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
err := PackTwalk(tc, fid.Fid, newfid.Fid, wnames)
if err != nil {
return nil, err
}
......@@ -66,12 +65,12 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
}
tc := clnt.NewFcall()
err = p.PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n])
err = PackTwalk(tc, fid.Fid, newfid.Fid, wnames[0:n])
if err != nil {
goto error
}
var rc *p.Fcall
var rc *Fcall
rc, err = clnt.Rpc(tc)
if err != nil {
goto error
......@@ -79,7 +78,7 @@ func (clnt *Clnt) FWalk(path string) (*Fid, error) {
newfid.walked = true
if len(rc.Wqid) != n {
err = &p.Error{"file not found", p.ENOENT}
err = &Error{"file not found", ENOENT}
goto error
}
......
......@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import "k8s.io/minikube/third_party/go9p/p"
package go9p
// Write up to len(data) bytes starting from offset. Returns the
// number of bytes written, or an Error.
......@@ -14,7 +12,7 @@ func (clnt *Clnt) Write(fid *Fid, data []byte, offset uint64) (int, error) {
}
tc := clnt.NewFcall()
err := p.PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data)
err := PackTwrite(tc, fid.Fid, offset, uint32(len(data)), data)
if err != nil {
return 0, err
}
......@@ -41,7 +39,7 @@ func (file *File) Write(buf []byte) (int, error) {
// Writes up to len(buf) bytes starting from offset. Returns the number
// of bytes written, or an Error.
func (file *File) WriteAt(buf []byte, offset int64) (int, error) {
return file.fid.Clnt.Write(file.fid, buf, uint64(offset))
return file.Fid.Clnt.Write(file.Fid, buf, uint64(offset))
}
// Writes exactly len(buf) bytes starting from offset. Returns the number of
......
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
// license that can be found in the LICENSE file.
package p
package go9p
import "fmt"
......
package p
package go9p
type Log struct {
Data interface{}
......
......@@ -2,38 +2,33 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
import (
"os/user"
"strconv"
"sync"
)
import "sync"
var once sync.Once
type osUser struct {
*user.User
uid int
gid int
}
type osUsers struct {
users map[int]*osUser
groups map[int]*osGroup
sync.Mutex
}
// Simple Users implementation that defers to os/user and fakes
// looking up groups by gid only.
// Simple Users implementation that fakes looking up users and groups
// by uid only. The names and groups memberships are empty
var OsUsers *osUsers
func (u *osUser) Name() string { return u.Username }
func (u *osUser) Name() string { return "" }
func (u *osUser) Id() int { return u.uid }
func (u *osUser) Groups() []Group { return []Group{OsUsers.Gid2Group(u.gid)} }
func (u *osUser) Groups() []Group { return nil }
func (u *osUser) IsMember(g Group) bool { return u.gid == g.Id() }
func (u *osUser) IsMember(g Group) bool { return false }
type osGroup struct {
gid int
......@@ -47,33 +42,28 @@ func (g *osGroup) Members() []User { return nil }
func initOsusers() {
OsUsers = new(osUsers)
OsUsers.users = make(map[int]*osUser)
OsUsers.groups = make(map[int]*osGroup)
}
func newUser(u *user.User) *osUser {
uid, uerr := strconv.Atoi(u.Uid)
gid, gerr := strconv.Atoi(u.Gid)
if uerr != nil || gerr != nil {
/* non-numeric uid/gid => unsupported system */
return nil
}
return &osUser{u, uid, gid}
}
func (up *osUsers) Uid2User(uid int) User {
u, err := user.LookupId(strconv.Itoa(uid))
if err != nil {
return nil
once.Do(initOsusers)
OsUsers.Lock()
defer OsUsers.Unlock()
user, present := OsUsers.users[uid]
if present {
return user
}
return newUser(u)
user = new(osUser)
user.uid = uid
OsUsers.users[uid] = user
return user
}
func (up *osUsers) Uname2User(uname string) User {
u, err := user.Lookup(uname)
if err != nil {
// unimplemented
return nil
}
return newUser(u)
}
func (up *osUsers) Gid2Group(gid int) Group {
......
package main
// An interactive client for 9P servers.
import (
"bufio"
"flag"
"fmt"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"os"
"path"
"strings"
)
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
var ouser = flag.String("user", "", "user to connect as")
var cmdfile = flag.String("file", "", "read commands from file")
var prompt = flag.String("prompt", "9p> ", "prompt for interactive client")
var debug = flag.Bool("d", false, "enable debugging (fcalls)")
var debugall = flag.Bool("D", false, "enable debugging (raw packets)")
var cwd = "/"
var cfid *clnt.Fid
type Cmd struct {
fun func(c *clnt.Clnt, s []string)
help string
}
var cmds map[string]*Cmd
func init() {
cmds = make(map[string]*Cmd)
cmds["write"] = &Cmd{cmdwrite, "write file string [...]\t«write the unmodified string to file, create file if necessary»"}
cmds["echo"] = &Cmd{cmdecho, "echo file string [...]\t«echo string to file (newline appended)»"}
cmds["stat"] = &Cmd{cmdstat, "stat file [...]\t«stat file»"}
cmds["ls"] = &Cmd{cmdls, "ls [-l] file [...]\t«list contents of directory or file»"}
cmds["cd"] = &Cmd{cmdcd, "cd dir\t«change working directory»"}
cmds["cat"] = &Cmd{cmdcat, "cat file [...]\t«print the contents of file»"}
cmds["mkdir"] = &Cmd{cmdmkdir, "mkdir dir [...]\t«create dir on remote server»"}
cmds["get"] = &Cmd{cmdget, "get file [local]\t«get file from remote server»"}
cmds["put"] = &Cmd{cmdput, "put file [remote]\t«put file on the remote server as 'file'»"}
cmds["pwd"] = &Cmd{cmdpwd, "pwd\t«print working directory»"}
cmds["rm"] = &Cmd{cmdrm, "rm file [...]\t«remove file from remote server»"}
cmds["help"] = &Cmd{cmdhelp, "help [cmd]\t«print available commands or help on cmd»"}
cmds["quit"] = &Cmd{cmdquit, "quit\t«exit»"}
cmds["exit"] = &Cmd{cmdquit, "exit\t«quit»"}
}
// normalize user-supplied path. path starting with '/' is left untouched, otherwise is considered
// local from cwd
func normpath(s string) string {
if len(s) > 0 {
if s[0] == '/' {
return path.Clean(s)
}
return path.Clean(cwd + "/" + s)
}
return "/"
}
func b(mode uint32, s uint8) string {
var bits = []string{"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}
return bits[(mode>>s)&7]
}
// Convert file mode bits to string representation
func modetostr(mode uint32) string {
d := "-"
if mode&p.DMDIR != 0 {
d = "d"
} else if mode&p.DMAPPEND != 0 {
d = "a"
}
return fmt.Sprintf("%s%s%s%s", d, b(mode, 6), b(mode, 3), b(mode, 0))
}
// Write the string s to remote file f. Create f if it doesn't exist
func writeone(c *clnt.Clnt, f, s string) {
fname := normpath(f)
file, oserr := c.FCreate(fname, 0666, p.OWRITE)
if oserr != nil {
file, oserr = c.FOpen(fname, p.OWRITE|p.OTRUNC)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error opening %s: %v\n", fname, oserr)
return
}
}
defer file.Close()
m, oserr := file.Write([]byte(s))
if oserr != nil {
fmt.Fprintf(os.Stderr, "error writing to %s: %v\n", fname, oserr)
return
}
if m != len(s) {
fmt.Fprintf(os.Stderr, "short write %s\n", fname)
return
}
}
// Write s[1:] (with appended spaces) to the file s[0]
func cmdwrite(c *clnt.Clnt, s []string) {
fname := normpath(s[0])
str := strings.Join(s[1:], " ")
writeone(c, fname, str)
}
// Echo (append newline) s[1:] to s[0]
func cmdecho(c *clnt.Clnt, s []string) {
fname := normpath(s[0])
str := strings.Join(s[1:], " ") + "\n"
writeone(c, fname, str)
}
// Stat the remote file f
func statone(c *clnt.Clnt, f string) {
fname := normpath(f)
stat, oserr := c.FStat(fname)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error in stat %s: %v\n", fname, oserr)
return
}
fmt.Fprintf(os.Stdout, "%s\n", stat)
}
func cmdstat(c *clnt.Clnt, s []string) {
for _, f := range s {
statone(c, normpath(f))
}
}
func dirtostr(d *p.Dir) string {
return fmt.Sprintf("%s %s %s %-8d\t\t%s", modetostr(d.Mode), d.Uid, d.Gid, d.Length, d.Name)
}
func lsone(c *clnt.Clnt, s string, long bool) {
st, oserr := c.FStat(normpath(s))
if oserr != nil {
fmt.Fprintf(os.Stderr, "error stat: %v\n", oserr)
return
}
if st.Mode&p.DMDIR != 0 {
file, oserr := c.FOpen(s, p.OREAD)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error opening dir: %s\n", oserr)
return
}
defer file.Close()
for {
d, oserr := file.Readdir(0)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error reading dir: %v\n", oserr)
}
if d == nil || len(d) == 0 {
break
}
for _, dir := range d {
if long {
fmt.Fprintf(os.Stdout, "%s\n", dirtostr(dir))
} else {
os.Stdout.WriteString(dir.Name + "\n")
}
}
}
} else {
fmt.Fprintf(os.Stdout, "%s\n", dirtostr(st))
}
}
func cmdls(c *clnt.Clnt, s []string) {
long := false
if len(s) > 0 && s[0] == "-l" {
long = true
s = s[1:]
}
if len(s) == 0 {
lsone(c, cwd, long)
} else {
for _, d := range s {
lsone(c, cwd+d, long)
}
}
}
func walkone(c *clnt.Clnt, s string, fileok bool) {
ncwd := normpath(s)
fid, err := c.FWalk(ncwd)
defer c.Clunk(fid)
if err != nil {
fmt.Fprintf(os.Stderr, "walk error: %s\n", err)
return
}
if fileok != true && (fid.Type&p.QTDIR == 0) {
fmt.Fprintf(os.Stderr, "can't cd to file [%s]\n", ncwd)
return
}
cwd = ncwd
}
func cmdcd(c *clnt.Clnt, s []string) {
if s != nil {
walkone(c, strings.Join(s, "/"), false)
}
}
// Print the contents of f
func cmdcat(c *clnt.Clnt, s []string) {
buf := make([]byte, 8192)
Outer:
for _, f := range s {
fname := normpath(f)
file, oserr := c.FOpen(fname, p.OREAD)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error opening %s: %v\n", f, oserr)
continue Outer
}
defer file.Close()
for {
n, oserr := file.Read(buf)
if oserr != nil && oserr != io.EOF {
fmt.Fprintf(os.Stderr, "error reading %s: %v\n", f, oserr)
}
if n == 0 {
break
}
os.Stdout.Write(buf[0:n])
}
}
}
// Create a single directory on remote server
func mkone(c *clnt.Clnt, s string) {
fname := normpath(s)
file, oserr := c.FCreate(fname, 0777|p.DMDIR, p.OWRITE)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error creating directory %s: %v\n", fname, oserr)
return
}
file.Close()
}
// Create directories on remote server
func cmdmkdir(c *clnt.Clnt, s []string) {
for _, f := range s {
mkone(c, f)
}
}
// Copy a remote file to local filesystem
func cmdget(c *clnt.Clnt, s []string) {
var from, to string
switch len(s) {
case 1:
from = normpath(s[0])
_, to = path.Split(s[0])
case 2:
from, to = normpath(s[0]), s[1]
default:
fmt.Fprintf(os.Stderr, "from arguments; usage: get from to\n")
}
tofile, err := os.Create(to)
if err != nil {
fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err)
return
}
defer tofile.Close()
file, ferr := c.FOpen(from, p.OREAD)
if ferr != nil {
fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err)
return
}
defer file.Close()
buf := make([]byte, 8192)
for {
n, oserr := file.Read(buf)
if oserr != nil {
fmt.Fprintf(os.Stderr, "error reading %s: %s\n", from, oserr)
return
}
if n == 0 {
break
}
m, err := tofile.Write(buf[0:n])
if err != nil {
fmt.Fprintf(os.Stderr, "error writing %s: %s\n", to, err)
return
}
if m != n {
fmt.Fprintf(os.Stderr, "short write %s\n", to)
return
}
}
}
// Copy a local file to remote server
func cmdput(c *clnt.Clnt, s []string) {
var from, to string
switch len(s) {
case 1:
_, to = path.Split(s[0])
to = normpath(to)
from = s[0]
case 2:
from, to = s[0], normpath(s[1])
default:
fmt.Fprintf(os.Stderr, "incorrect arguments; usage: put local [remote]\n")
}
fromfile, err := os.Open(from)
if err != nil {
fmt.Fprintf(os.Stderr, "error opening %s for reading: %s\n", from, err)
return
}
defer fromfile.Close()
file, ferr := c.FOpen(to, p.OWRITE|p.OTRUNC)
if ferr != nil {
file, ferr = c.FCreate(to, 0666, p.OWRITE)
if ferr != nil {
fmt.Fprintf(os.Stderr, "error opening %s for writing: %s\n", to, err)
return
}
}
defer file.Close()
buf := make([]byte, 8192)
for {
n, oserr := fromfile.Read(buf)
if oserr != nil && oserr != io.EOF {
fmt.Fprintf(os.Stderr, "error reading %s: %s\n", from, oserr)
return
}
if n == 0 {
break
}
m, oserr := file.Write(buf[0:n])
if oserr != nil {
fmt.Fprintf(os.Stderr, "error writing %s: %v\n", to, oserr)
return
}
if m != n {
fmt.Fprintf(os.Stderr, "short write %s\n", to)
return
}
}
}
func cmdpwd(c *clnt.Clnt, s []string) { fmt.Fprintf(os.Stdout, cwd+"\n") }
// Remove f from remote server
func rmone(c *clnt.Clnt, f string) {
fname := normpath(f)
err := c.FRemove(fname)
if err != nil {
fmt.Fprintf(os.Stderr, "error in stat %s", err)
return
}
}
// Remove one or more files from the server
func cmdrm(c *clnt.Clnt, s []string) {
for _, f := range s {
rmone(c, normpath(f))
}
}
// Print available commands
func cmdhelp(c *clnt.Clnt, s []string) {
cmdstr := ""
if len(s) > 0 {
for _, h := range s {
v, ok := cmds[h]
if ok {
cmdstr = cmdstr + v.help + "\n"
} else {
cmdstr = cmdstr + "unknown command: " + h + "\n"
}
}
} else {
cmdstr = "available commands: "
for k := range cmds {
cmdstr = cmdstr + " " + k
}
cmdstr = cmdstr + "\n"
}
fmt.Fprintf(os.Stdout, "%s", cmdstr)
}
func cmdquit(c *clnt.Clnt, s []string) { os.Exit(0) }
func cmd(c *clnt.Clnt, cmd string) {
ncmd := strings.Fields(cmd)
if len(ncmd) <= 0 {
return
}
v, ok := cmds[ncmd[0]]
if ok == false {
fmt.Fprintf(os.Stderr, "unknown command: %s\n", ncmd[0])
return
}
v.fun(c, ncmd[1:])
return
}
func interactive(c *clnt.Clnt) {
reader := bufio.NewReaderSize(os.Stdin, 8192)
for {
fmt.Print(*prompt)
line, err := reader.ReadSlice('\n')
if err != nil {
fmt.Fprintf(os.Stderr, "exiting...\n")
break
}
str := strings.TrimSpace(string(line))
// TODO: handle larger input lines by doubling buffer
in := strings.Split(str, "\n")
for i := range in {
if len(in[i]) > 0 {
cmd(c, in[i])
}
}
}
}
func main() {
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
flag.Parse()
if *ouser == "" {
user = p.OsUsers.Uid2User(os.Geteuid())
} else {
user = p.OsUsers.Uname2User(*ouser)
}
naddr := *addr
if strings.LastIndex(naddr, ":") == -1 {
naddr = naddr + ":5640"
}
c, err = clnt.Mount("tcp", naddr, "", user)
if err != nil {
fmt.Fprintf(os.Stderr, "error mounting %s: %s\n", naddr, err)
os.Exit(1)
}
if *debug {
c.Debuglevel = 1
}
if *debugall {
c.Debuglevel = 2
}
walkone(c, "/", false)
if file != nil {
//process(c)
fmt.Sprint(os.Stderr, "file reading unimplemented\n")
} else if flag.NArg() > 0 {
flags := flag.Args()
for _, uc := range flags {
cmd(c, uc)
}
} else {
interactive(c)
}
return
}
package main
import (
"flag"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
var d []*p.Dir
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err = clnt.Mount("tcp", *addr, "", user)
if err != nil {
log.Fatal(err)
}
lsarg := "/"
if flag.NArg() == 1 {
lsarg = flag.Arg(0)
} else if flag.NArg() > 1 {
log.Fatal("error: only one argument expected")
}
file, err = c.FOpen(lsarg, p.OREAD)
if err != nil {
log.Fatal(err)
}
for {
d, err = file.Readdir(0)
if d == nil || len(d) == 0 || err != nil {
break
}
for i := 0; i < len(d); i++ {
os.Stdout.WriteString(d[i].Name + "\n")
}
}
file.Close()
if err != nil && err != io.EOF {
log.Fatal(err)
}
return
}
package main
import (
"flag"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var n int
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
var buf []byte
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err = clnt.Mount("tcp", *addr, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
file, err = c.FOpen(flag.Arg(0), p.OREAD)
if err != nil {
goto error
}
buf = make([]byte, 8192)
for {
n, err = file.Read(buf)
if n == 0 {
break
}
os.Stdout.Write(buf[0:n])
}
file.Close()
if err != nil && err != io.EOF {
goto error
}
return
error:
log.Println("Error", err)
}
package main
import (
"flag"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
"strings"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var user p.User
var ba [][]byte
var nreqs int
var rchan chan *clnt.Req
var tag *clnt.Tag
var fid *clnt.Fid
var wnames []string
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err := clnt.Mount("tcp", *addr, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
ba = make([][]byte, 100)
for i := 0; i < len(ba); i++ {
ba[i] = make([]byte, 8192)
}
nreqs = 0
rchan = make(chan *clnt.Req)
tag = c.TagAlloc(rchan)
// walk the file
wnames = strings.Split(flag.Arg(0), "/")
for wnames[0] == "" {
wnames = wnames[1:]
}
fid = c.FidAlloc()
for root := c.Root; len(wnames) > 0; root = fid {
n := len(wnames)
if n > 8 {
n = 8
}
err = tag.Walk(root, fid, wnames[0:n])
if err != nil {
goto error
}
nreqs++
wnames = wnames[n:]
}
err = tag.Open(fid, p.OREAD)
if err != nil {
goto error
}
for i := 0; i < len(ba); i++ {
err = tag.Read(fid, uint64(i*8192), 8192)
if err != nil {
goto error
}
nreqs++
}
err = tag.Clunk(fid)
// now start reading...
for nreqs > 0 {
r := <-rchan
if r.Tc.Type == p.Tread {
i := r.Tc.Offset / 8192
copy(ba[i], r.Rc.Data)
ba[i] = ba[i][0:r.Rc.Count]
}
nreqs--
}
for i := 0; i < len(ba); i++ {
os.Stdout.Write(ba[i])
}
return
error:
log.Println("error: ", err)
}
// Connects to a server over TLS and lists the specified directory
package main
import (
"crypto/rand"
"crypto/tls"
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var user p.User
var file *clnt.File
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, oerr := tls.Dial("tcp", *addr, &tls.Config{
Rand: rand.Reader,
InsecureSkipVerify: true,
})
if oerr != nil {
log.Println("can't dial", oerr)
return
}
clnt, err := clnt.MountConn(c, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
file, oerr = clnt.FOpen(flag.Arg(0), p.OREAD)
if oerr != nil {
goto oerror
}
for {
d, oerr := file.Readdir(0)
if oerr != nil {
goto oerror
}
if d == nil || len(d) == 0 {
break
}
for i := 0; i < len(d); i++ {
os.Stdout.WriteString(d[i].Name + "\n")
}
}
file.Close()
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
return
oerror:
log.Println("Error", oerr)
}
package main
import (
"flag"
"io"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/clnt"
"log"
"os"
)
var debuglevel = flag.Int("d", 0, "debuglevel")
var addr = flag.String("addr", "127.0.0.1:5640", "network address")
func main() {
var n, m int
var user p.User
var err error
var c *clnt.Clnt
var file *clnt.File
var buf []byte
flag.Parse()
user = p.OsUsers.Uid2User(os.Geteuid())
clnt.DefaultDebuglevel = *debuglevel
c, err = clnt.Mount("tcp", *addr, "", user)
if err != nil {
goto error
}
if flag.NArg() != 1 {
log.Println("invalid arguments")
return
}
file, err = c.FOpen(flag.Arg(0), p.OWRITE|p.OTRUNC)
if err != nil {
file, err = c.FCreate(flag.Arg(0), 0666, p.OWRITE)
if err != nil {
goto error
}
}
buf = make([]byte, 8192)
for {
n, err = os.Stdin.Read(buf)
if err != nil && err != io.EOF {
goto error
}
if n == 0 {
break
}
m, err = file.Write(buf[0:n])
if err != nil {
goto error
}
if m != n {
err = &p.Error{"short write", 0}
goto error
}
}
file.Close()
return
error:
log.Println("Error", err)
}
// Copyright 2009 The Go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package clnt
import (
"k8s.io/minikube/third_party/go9p/p"
)
var Eisdir = &p.Error{"file is a directory", p.EIO}
var Enegoff = &p.Error{"negative i/o offset", p.EIO}
// Seek sets the offset for the next Read or Write to offset,
// interpreted according to whence: 0 means relative to the origin of
// the file, 1 means relative to the current offset, and 2 means
// relative to the end. Seek returns the new offset and an error, if
// any.
//
// Seeking to a negative offset is an error, and results in Enegoff.
// Seeking to 0 in a directory is only valid if whence is 0. Seek returns
// Eisdir otherwise.
func (f *File) Seek(offset int64, whence int) (int64, error) {
var off int64
switch whence {
case 0:
// origin
off = offset
if f.fid.Qid.Type&p.QTDIR > 0 && off != 0 {
return 0, Eisdir
}
case 1:
// current
if f.fid.Qid.Type&p.QTDIR > 0 {
return 0, Eisdir
}
off = offset + int64(f.offset)
case 2:
// end
if f.fid.Qid.Type&p.QTDIR > 0 {
return 0, Eisdir
}
dir, err := f.fid.Clnt.Stat(f.fid)
if err != nil {
return 0, &p.Error{"stat error in seek: " + err.Error(), p.EIO}
}
off = int64(dir.Length) + offset
default:
return 0, &p.Error{"bad whence in seek", p.EIO}
}
if off < 0 {
return 0, Enegoff
}
f.offset = uint64(off)
return off, nil
}
// Copyright 2009 The Go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// A synthetic filesystem emulating a persistent cloning interface
// from Plan 9. Reading the /clone file creates new entries in the filesystem
// each containing unique information/data. Clone files remember what it written
// to them. Removing a clone file does what is expected.
package main
import (
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"os"
"strconv"
"time"
)
type ClFile struct {
srv.File
created string
id int
data []byte
}
type Clone struct {
srv.File
clones int
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Bool("d", false, "print debug messages")
var root *srv.File
func (cl *ClFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
var b []byte
if len(cl.data) == 0 {
str := strconv.Itoa(cl.id) + " created on:" + cl.created
b = []byte(str)
} else {
b = cl.data
}
n := len(b)
if offset >= uint64(n) {
return 0, nil
}
b = b[int(offset):n]
n -= int(offset)
if len(buf) < n {
n = len(buf)
}
copy(buf[offset:int(offset)+n], b[offset:])
return n, nil
}
func (cl *ClFile) Write(fid *srv.FFid, data []byte, offset uint64) (int, error) {
n := uint64(len(cl.data))
nlen := offset + uint64(len(data))
if nlen > n {
ndata := make([]byte, nlen)
copy(ndata, cl.data[0:n])
cl.data = ndata
}
copy(cl.data[offset:], data[offset:])
return len(data), nil
}
func (cl *ClFile) Wstat(fid *srv.FFid, dir *p.Dir) error {
return nil
}
func (cl *ClFile) Remove(fid *srv.FFid) error {
return nil
}
func (cl *Clone) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
// we only allow a single read from us, change the offset and we're done
if offset > uint64(0) {
return 0, nil
}
cl.clones += 1
ncl := new(ClFile)
ncl.id = cl.clones
ncl.created = time.Now().String()
name := strconv.Itoa(ncl.id)
err := ncl.Add(root, name, p.OsUsers.Uid2User(os.Geteuid()), nil, 0666, ncl)
if err != nil {
return 0, &p.Error{"can not create file", 0}
}
b := []byte(name)
if len(buf) < len(b) {
// cleanup
ncl.File.Remove()
return 0, &p.Error{"not enough buffer space for result", 0}
}
copy(buf, b)
return len(b), nil
}
func main() {
var err error
var cl *Clone
var s *srv.Fsrv
flag.Parse()
user := p.OsUsers.Uid2User(os.Geteuid())
root = new(srv.File)
err = root.Add(nil, "/", user, nil, p.DMDIR|0777, nil)
if err != nil {
goto error
}
cl = new(Clone)
err = cl.Add(root, "clone", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, cl)
if err != nil {
goto error
}
s = srv.NewFileSrv(root)
s.Dotu = true
if *debug {
s.Debuglevel = 1
}
s.Start(s)
err = s.StartNetListener("tcp", *addr)
if err != nil {
goto error
}
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
}
// Copyright 2009 The Go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"os"
)
type Ramfs struct {
srv *srv.Fsrv
user p.User
group p.Group
blksz int
blkchan chan []byte
zero []byte // blksz array of zeroes
}
type RFile struct {
srv.File
data [][]byte
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Int("d", 0, "debuglevel")
var blksize = flag.Int("b", 8192, "block size")
var logsz = flag.Int("l", 2048, "log size")
var rsrv Ramfs
func (f *RFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
if offset > f.Length {
return 0, nil
}
count := uint32(len(buf))
if offset+uint64(count) > f.Length {
count = uint32(f.Length - offset)
}
for n, off, b := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz), buf[0:count]; len(b) > 0; n++ {
m := rsrv.blksz - int(off)
if m > len(b) {
m = len(b)
}
blk := rsrv.zero
if len(f.data[n]) != 0 {
blk = f.data[n]
}
// log.Stderr("read block", n, "off", off, "len", m, "l", len(blk), "ll", len(b))
copy(b, blk[off:off+uint64(m)])
b = b[m:]
off = 0
}
return int(count), nil
}
func (f *RFile) Write(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
// make sure the data array is big enough
sz := offset + uint64(len(buf))
if f.Length < sz {
f.expand(sz)
}
count := 0
for n, off := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz); len(buf) > 0; n++ {
blk := f.data[n]
if len(blk) == 0 {
select {
case blk = <-rsrv.blkchan:
break
default:
blk = make([]byte, rsrv.blksz)
}
// if off>0 {
copy(blk, rsrv.zero /*[0:off]*/)
// }
f.data[n] = blk
}
m := copy(blk[off:], buf)
buf = buf[m:]
count += m
off = 0
}
return count, nil
}
func (f *RFile) Create(fid *srv.FFid, name string, perm uint32) (*srv.File, error) {
ff := new(RFile)
err := ff.Add(&f.File, name, rsrv.user, rsrv.group, perm, ff)
return &ff.File, err
}
func (f *RFile) Remove(fid *srv.FFid) error {
f.trunc(0)
return nil
}
func (f *RFile) Wstat(fid *srv.FFid, dir *p.Dir) error {
var uid, gid uint32
f.Lock()
defer f.Unlock()
up := rsrv.srv.Upool
uid = dir.Uidnum
gid = dir.Gidnum
if uid == p.NOUID && dir.Uid != "" {
user := up.Uname2User(dir.Uid)
if user == nil {
return srv.Enouser
}
f.Uidnum = uint32(user.Id())
}
if gid == p.NOUID && dir.Gid != "" {
group := up.Gname2Group(dir.Gid)
if group == nil {
return srv.Enouser
}
f.Gidnum = uint32(group.Id())
}
if dir.Mode != 0xFFFFFFFF {
f.Mode = (f.Mode &^ 0777) | (dir.Mode & 0777)
}
if dir.Name != "" {
if err := f.Rename(dir.Name); err != nil {
return err
}
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
f.trunc(dir.Length)
}
return nil
}
// called with f locked
func (f *RFile) trunc(sz uint64) {
if f.Length == sz {
return
}
if f.Length > sz {
f.shrink(sz)
} else {
f.expand(sz)
}
}
// called with f lock held
func (f *RFile) shrink(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
off := sz % uint64(rsrv.blksz)
if off > 0 {
if len(f.data[blknum]) > 0 {
copy(f.data[blknum][off:], rsrv.zero)
}
blknum++
}
for i := blknum; i < uint64(len(f.data)); i++ {
if len(f.data[i]) == 0 {
continue
}
select {
case rsrv.blkchan <- f.data[i]:
break
default:
}
}
f.data = f.data[0:blknum]
f.Length = sz
}
func (f *RFile) expand(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
if sz%uint64(rsrv.blksz) != 0 {
blknum++
}
data := make([][]byte, blknum)
if f.data != nil {
copy(data, f.data)
}
f.data = data
f.Length = sz
}
func main() {
var err error
var l *p.Logger
flag.Parse()
rsrv.user = p.OsUsers.Uid2User(os.Geteuid())
rsrv.group = p.OsUsers.Gid2Group(os.Getegid())
rsrv.blksz = *blksize
rsrv.blkchan = make(chan []byte, 2048)
rsrv.zero = make([]byte, rsrv.blksz)
root := new(RFile)
err = root.Add(nil, "/", rsrv.user, nil, p.DMDIR|0777, root)
if err != nil {
goto error
}
l = p.NewLogger(*logsz)
rsrv.srv = srv.NewFileSrv(&root.File)
rsrv.srv.Dotu = true
rsrv.srv.Debuglevel = *debug
rsrv.srv.Start(rsrv.srv)
rsrv.srv.Id = "ramfs"
rsrv.srv.Log = l
err = rsrv.srv.StartNetListener("tcp", *addr)
if err != nil {
goto error
}
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
}
// Copyright 2009 The Go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"os"
"time"
)
type Time struct {
srv.File
}
type InfTime struct {
srv.File
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Bool("d", false, "print debug messages")
var debugall = flag.Bool("D", false, "print packets as well as debug messages")
func (*InfTime) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
// push out time ignoring offset (infinite read)
t := time.Now().String() + "\n"
b := []byte(t)
ml := len(b)
if ml > len(buf) {
ml = len(buf)
}
copy(buf, b[0:ml])
return ml, nil
}
func (*Time) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
b := []byte(time.Now().String())
have := len(b)
off := int(offset)
if off >= have {
return 0, nil
}
return copy(buf, b[off:]), nil
}
func main() {
var err error
var tm *Time
var ntm *InfTime
var s *srv.Fsrv
flag.Parse()
user := p.OsUsers.Uid2User(os.Geteuid())
root := new(srv.File)
err = root.Add(nil, "/", user, nil, p.DMDIR|0555, nil)
if err != nil {
goto error
}
tm = new(Time)
err = tm.Add(root, "time", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, tm)
if err != nil {
goto error
}
ntm = new(InfTime)
err = ntm.Add(root, "inftime", p.OsUsers.Uid2User(os.Geteuid()), nil, 0444, ntm)
if err != nil {
goto error
}
s = srv.NewFileSrv(root)
s.Dotu = true
if *debug {
s.Debuglevel = 1
}
if *debugall {
s.Debuglevel = 2
}
s.Start(s)
err = s.StartNetListener("tcp", *addr)
if err != nil {
goto error
}
return
error:
log.Println(fmt.Sprintf("Error: %s", err))
}
// Copyright 2009 The Go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Listen on SSL connection, can be used as an example with p/clnt/examples/tls.go
// Sample certificate was copied from the Go source code
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"encoding/hex"
"flag"
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
"log"
"math/big"
"os"
)
type Ramfs struct {
srv *srv.Fsrv
user p.User
group p.Group
blksz int
blkchan chan []byte
zero []byte // blksz array of zeroes
}
type RFile struct {
srv.File
data [][]byte
}
var addr = flag.String("addr", ":5640", "network address")
var debug = flag.Int("d", 0, "debuglevel")
var blksize = flag.Int("b", 8192, "block size")
var logsz = flag.Int("l", 2048, "log size")
var rsrv Ramfs
func (f *RFile) Read(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
if offset > f.Length {
return 0, nil
}
count := uint32(len(buf))
if offset+uint64(count) > f.Length {
count = uint32(f.Length - offset)
}
for n, off, b := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz), buf[0:count]; len(b) > 0; n++ {
m := rsrv.blksz - int(off)
if m > len(b) {
m = len(b)
}
blk := rsrv.zero
if len(f.data[n]) != 0 {
blk = f.data[n]
}
// log.Stderr("read block", n, "off", off, "len", m, "l", len(blk), "ll", len(b))
copy(b, blk[off:off+uint64(m)])
b = b[m:]
off = 0
}
return int(count), nil
}
func (f *RFile) Write(fid *srv.FFid, buf []byte, offset uint64) (int, error) {
f.Lock()
defer f.Unlock()
// make sure the data array is big enough
sz := offset + uint64(len(buf))
if f.Length < sz {
f.expand(sz)
}
count := 0
for n, off := offset/uint64(rsrv.blksz), offset%uint64(rsrv.blksz); len(buf) > 0; n++ {
blk := f.data[n]
if len(blk) == 0 {
select {
case blk = <-rsrv.blkchan:
break
default:
blk = make([]byte, rsrv.blksz)
}
// if off>0 {
copy(blk, rsrv.zero /*[0:off]*/)
// }
f.data[n] = blk
}
m := copy(blk[off:], buf)
buf = buf[m:]
count += m
off = 0
}
return count, nil
}
func (f *RFile) Create(fid *srv.FFid, name string, perm uint32) (*srv.File, error) {
ff := new(RFile)
err := ff.Add(&f.File, name, rsrv.user, rsrv.group, perm, ff)
return &ff.File, err
}
func (f *RFile) Remove(fid *srv.FFid) error {
f.trunc(0)
return nil
}
func (f *RFile) Wstat(fid *srv.FFid, dir *p.Dir) error {
var uid, gid uint32
f.Lock()
defer f.Unlock()
up := rsrv.srv.Upool
uid = dir.Uidnum
gid = dir.Gidnum
if uid == p.NOUID && dir.Uid != "" {
user := up.Uname2User(dir.Uid)
if user == nil {
return srv.Enouser
}
f.Uidnum = uint32(user.Id())
}
if gid == p.NOUID && dir.Gid != "" {
group := up.Gname2Group(dir.Gid)
if group == nil {
return srv.Enouser
}
f.Gidnum = uint32(group.Id())
}
if dir.Mode != 0xFFFFFFFF {
f.Mode = (f.Mode &^ 0777) | (dir.Mode & 0777)
}
if dir.Name != "" {
if err := f.Rename(dir.Name); err != nil {
return err
}
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
f.trunc(dir.Length)
}
return nil
}
// called with f locked
func (f *RFile) trunc(sz uint64) {
if f.Length == sz {
return
}
if f.Length > sz {
f.shrink(sz)
} else {
f.expand(sz)
}
}
// called with f lock held
func (f *RFile) shrink(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
off := sz % uint64(rsrv.blksz)
if off > 0 {
if len(f.data[blknum]) > 0 {
copy(f.data[blknum][off:], rsrv.zero)
}
blknum++
}
for i := blknum; i < uint64(len(f.data)); i++ {
if len(f.data[i]) == 0 {
continue
}
select {
case rsrv.blkchan <- f.data[i]:
break
default:
}
}
f.data = f.data[0:blknum]
f.Length = sz
}
func (f *RFile) expand(sz uint64) {
blknum := sz / uint64(rsrv.blksz)
if sz%uint64(rsrv.blksz) != 0 {
blknum++
}
data := make([][]byte, blknum)
if f.data != nil {
copy(data, f.data)
}
f.data = data
f.Length = sz
}
func main() {
var err error
flag.Parse()
rsrv.user = p.OsUsers.Uid2User(os.Geteuid())
rsrv.group = p.OsUsers.Gid2Group(os.Getegid())
rsrv.blksz = *blksize
rsrv.blkchan = make(chan []byte, 2048)
rsrv.zero = make([]byte, rsrv.blksz)
root := new(RFile)
err = root.Add(nil, "/", rsrv.user, nil, p.DMDIR|0777, root)
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}
l := p.NewLogger(*logsz)
rsrv.srv = srv.NewFileSrv(&root.File)
rsrv.srv.Dotu = true
rsrv.srv.Debuglevel = *debug
rsrv.srv.Start(rsrv.srv)
rsrv.srv.Id = "ramfs"
rsrv.srv.Log = l
cert := make([]tls.Certificate, 1)
cert[0].Certificate = [][]byte{testCertificate}
cert[0].PrivateKey = testPrivateKey
ls, oerr := tls.Listen("tcp", *addr, &tls.Config{
Rand: rand.Reader,
Certificates: cert,
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA},
InsecureSkipVerify: true,
})
if oerr != nil {
log.Println("can't listen:", oerr)
return
}
err = rsrv.srv.StartListener(ls)
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}
return
}
// Copied from crypto/tls/handshake_server_test.go from the Go repository
func bigFromString(s string) *big.Int {
ret := new(big.Int)
ret.SetString(s, 10)
return ret
}
func fromHex(s string) []byte {
b, _ := hex.DecodeString(s)
return b
}
var testCertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9")
var testPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
E: 65537,
},
D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
Primes: []*big.Int{
bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
},
}
......@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The p9 package provides the definitions and functions used to implement
// The p9 package go9provides the definitions and functions used to implement
// the 9P2000 protocol.
package p
// TODO.
// All the packet conversion code in this file is crap and needs a rewrite.
package go9p
import (
"fmt"
......@@ -44,7 +46,7 @@ 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
PORT = 564 // default port for 9P file servers
)
......@@ -301,11 +303,12 @@ func gint64(buf []byte) (uint64, []byte) {
func gstr(buf []byte) (string, []byte) {
var n uint16
if buf == nil {
if buf == nil || len(buf) < 2 {
return "", nil
}
n, buf = gint16(buf)
if int(n) > len(buf) {
return "", nil
}
......@@ -321,7 +324,8 @@ func gqid(buf []byte, qid *Qid) []byte {
return buf
}
func gstat(buf []byte, d *Dir, dotu bool) []byte {
func gstat(buf []byte, d *Dir, dotu bool) ([]byte, error) {
sz := len(buf)
d.Size, buf = gint16(buf)
d.Type, buf = gint16(buf)
d.Dev, buf = gint32(buf)
......@@ -332,27 +336,29 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
d.Length, buf = gint64(buf)
d.Name, buf = gstr(buf)
if buf == nil {
return nil
s := fmt.Sprintf("Buffer too short for basic 9p: need %d, have %d",
49, sz)
return nil, &Error{s, EINVAL}
}
d.Uid, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Uid failed", EINVAL}
}
d.Gid, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Gid failed", EINVAL}
}
d.Muid, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Muid failed", EINVAL}
}
if dotu {
d.Ext, buf = gstr(buf)
if buf == nil {
return nil
return nil, &Error{"d.Ext failed", EINVAL}
}
d.Uidnum, buf = gint32(buf)
......@@ -364,7 +370,7 @@ func gstat(buf []byte, d *Dir, dotu bool) []byte {
d.Muidnum = NOUID
}
return buf
return buf, nil
}
func pint8(val uint8, buf []byte) []byte {
......@@ -449,20 +455,17 @@ func pstat(d *Dir, buf []byte, dotu bool) []byte {
// Converts a Dir value to its on-the-wire representation and writes it to
// the buf. Returns the number of bytes written, 0 if there is not enough space.
func PackDir(d *Dir, buf []byte, dotu bool) int {
func PackDir(d *Dir, dotu bool) []byte {
sz := statsz(d, dotu)
if sz > len(buf) {
return 0
}
buf = pstat(d, buf, dotu)
return sz
buf := make([]byte, sz)
pstat(d, buf, dotu)
return buf
}
// Converts the on-the-wire representation of a stat to Stat value.
// Returns an error if the conversion is impossible, otherwise
// a pointer to a Stat value.
func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
func UnpackDir(buf []byte, dotu bool) (d *Dir, b []byte, amt int, err error) {
sz := 2 + 2 + 4 + 13 + 4 + /* size[2] type[2] dev[4] qid[13] mode[4] */
4 + 4 + 8 + /* atime[4] mtime[4] length[8] */
2 + 2 + 2 + 2 /* name[s] uid[s] gid[s] muid[s] */
......@@ -472,19 +475,17 @@ func UnpackDir(buf []byte, dotu bool) (d *Dir, err error) {
}
if len(buf) < sz {
goto szerror
s := fmt.Sprintf("short buffer: Need %d and have %v", sz, len(buf))
return nil, nil, 0, &Error{s, EINVAL}
}
d = new(Dir)
buf = gstat(buf, d, dotu)
if buf == nil {
goto szerror
b, err = gstat(buf, d, dotu)
if err != nil {
return nil, nil, 0, err
}
return d, nil
szerror:
return nil, &Error{"short buffer", EINVAL}
return d, b, len(buf) - len(b), nil
}
......@@ -522,7 +523,7 @@ func packCommon(fc *Fcall, size int, id uint8) ([]byte, error) {
func (err *Error) Error() string {
if err != nil {
return fmt.Sprintf("%s: %d", err.Err, err.Errornum)
return err.Err
}
return ""
......
......@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
import "fmt"
// Create a Rversion message in the specified Fcall.
func PackRversion(fc *Fcall, msize uint32, version string) error {
......@@ -34,9 +36,17 @@ func PackRauth(fc *Fcall, aqid *Qid) error {
}
// Create a Rerror message in the specified Fcall. If dotu is true,
// the function will create a 9P2000.u message. If false, nerror is
// the function will create a 9P2000.u message. If false, errornum is
// ignored.
// The Akaros global is hurl-inducing but this whole blob of code
// needs a redo. dotu is even worse, since it bakes in ONE PARTICULAR
// EXTENSION ...
func PackRerror(fc *Fcall, error string, errornum uint32, dotu bool) error {
if *Akaros {
error = fmt.Sprintf("%04X %v", errornum, error)
}
size := 2 + len(error) /* ename[s] */
if dotu {
size += 4 /* ecode[4] */
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
package go9p
// Create a Tversion message in the specified Fcall.
func PackTversion(fc *Fcall, msize uint32, version string) error {
......
......@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import (
"fmt"
"k8s.io/minikube/third_party/go9p/p"
"log"
"net"
)
......@@ -18,11 +17,11 @@ func (srv *Srv) NewConn(c net.Conn) {
conn.Dotu = srv.Dotu
conn.Debuglevel = srv.Debuglevel
conn.conn = c
conn.fidpool = make(map[uint32]*Fid)
conn.reqs = make(map[uint16]*Req)
conn.reqout = make(chan *Req, srv.Maxpend)
conn.fidpool = make(map[uint32]*SrvFid)
conn.reqs = make(map[uint16]*SrvReq)
conn.reqout = make(chan *SrvReq, srv.Maxpend)
conn.done = make(chan bool)
conn.rchan = make(chan *p.Fcall, 64)
conn.rchan = make(chan *Fcall, 64)
srv.Lock()
if srv.conns == nil {
......@@ -58,7 +57,7 @@ func (conn *Conn) close() {
}
/* call FidDestroy for all remaining fids */
if op, ok := (conn.Srv.ops).(FidOps); ok {
if op, ok := (conn.Srv.ops).(SrvFidOps); ok {
for _, fid := range conn.fidpool {
op.FidDestroy(fid)
}
......@@ -87,7 +86,7 @@ func (conn *Conn) recv() {
pos += n
for pos > 4 {
sz, _ := p.Gint32(buf)
sz, _ := Gint32(buf)
if sz > conn.Msize {
log.Println("bad client connection: ", conn.conn.RemoteAddr())
conn.conn.Close()
......@@ -104,7 +103,7 @@ func (conn *Conn) recv() {
break
}
fc, err, fcsize := p.Unpack(buf, conn.Dotu)
fc, err, fcsize := Unpack(buf, conn.Dotu)
if err != nil {
log.Println(fmt.Sprintf("invalid packet : %v %v", err, buf))
conn.conn.Close()
......@@ -113,12 +112,12 @@ func (conn *Conn) recv() {
}
tag := fc.Tag
req := new(Req)
req := new(SrvReq)
select {
case req.Rc = <-conn.rchan:
break
default:
req.Rc = p.NewFcall(conn.Msize)
req.Rc = NewFcall(conn.Msize)
}
req.Conn = conn
......@@ -151,15 +150,22 @@ func (conn *Conn) recv() {
}
conn.Unlock()
if 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:]
pos -= fcsize
}
}
panic("unreached")
}
func (conn *Conn) send() {
......@@ -169,7 +175,7 @@ func (conn *Conn) send() {
return
case req := <-conn.reqout:
p.SetTag(req.Rc, req.Tc.Tag)
SetTag(req.Rc, req.Tc.Tag)
conn.Lock()
conn.rsz += uint64(req.Rc.Size)
conn.npend--
......@@ -216,7 +222,7 @@ func (conn *Conn) LocalAddr() net.Addr {
return conn.conn.LocalAddr()
}
func (conn *Conn) logFcall(fc *p.Fcall) {
func (conn *Conn) logFcall(fc *Fcall) {
if conn.Debuglevel&DbgLogPackets != 0 {
pkt := make([]byte, len(fc.Pkt))
copy(pkt, fc.Pkt)
......@@ -224,7 +230,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
}
if conn.Debuglevel&DbgLogFcalls != 0 {
f := new(p.Fcall)
f := new(Fcall)
*f = *fc
f.Pkt = nil
conn.Srv.Log.Log(f, conn, DbgLogFcalls)
......@@ -234,7 +240,7 @@ func (conn *Conn) logFcall(fc *p.Fcall) {
func (srv *Srv) StartNetListener(ntype, addr string) error {
l, err := net.Listen(ntype, addr)
if err != nil {
return &p.Error{err.Error(), p.EIO}
return &Error{err.Error(), EIO}
}
return srv.StartListener(l)
......@@ -248,7 +254,7 @@ func (srv *Srv) StartListener(l net.Listener) error {
for {
c, err := l.Accept()
if err != nil {
return &p.Error{err.Error(), p.EIO}
return &Error{err.Error(), EIO}
}
srv.NewConn(c)
......
......@@ -2,20 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import (
"runtime"
import "runtime"
"k8s.io/minikube/third_party/go9p/p"
)
func (srv *Srv) version(req *Req) {
func (srv *Srv) version(req *SrvReq) {
tc := req.Tc
conn := req.Conn
if tc.Msize < p.IOHDRSZ {
req.RespondError(&p.Error{"msize too small", p.EINVAL})
if tc.Msize < IOHDRSZ {
req.RespondError(&Error{"msize too small", EINVAL})
return
}
......@@ -32,7 +28,7 @@ func (srv *Srv) version(req *Req) {
/* make sure that the responses of all current requests will be ignored */
conn.Lock()
for tag, r := range conn.reqs {
if tag == p.NOTAG {
if tag == NOTAG {
continue
}
......@@ -47,10 +43,10 @@ func (srv *Srv) version(req *Req) {
req.RespondRversion(conn.Msize, ver)
}
func (srv *Srv) auth(req *Req) {
func (srv *Srv) auth(req *SrvReq) {
tc := req.Tc
conn := req.Conn
if tc.Afid == p.NOFID {
if tc.Afid == NOFID {
req.RespondError(Eunknownfid)
return
}
......@@ -61,8 +57,8 @@ func (srv *Srv) auth(req *Req) {
return
}
var user p.User = nil
if tc.Unamenum != p.NOUID || conn.Dotu {
var user User = nil
if tc.Unamenum != NOUID || conn.Dotu {
user = srv.Upool.Uid2User(int(tc.Unamenum))
} else if tc.Uname != "" {
user = srv.Upool.Uname2User(tc.Uname)
......@@ -76,13 +72,13 @@ func (srv *Srv) auth(req *Req) {
}
req.Afid.User = user
req.Afid.Type = p.QTAUTH
req.Afid.Type = QTAUTH
if aop, ok := (srv.ops).(AuthOps); ok {
aqid, err := aop.AuthInit(req.Afid, tc.Aname)
if err != nil {
req.RespondError(err)
} else {
aqid.Type |= p.QTAUTH // just in case
aqid.Type |= QTAUTH // just in case
req.RespondRauth(aqid)
}
} else {
......@@ -91,16 +87,16 @@ func (srv *Srv) auth(req *Req) {
}
func (srv *Srv) authPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rauth {
func (srv *Srv) authPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rauth {
req.Afid.IncRef()
}
}
func (srv *Srv) attach(req *Req) {
func (srv *Srv) attach(req *SrvReq) {
tc := req.Tc
conn := req.Conn
if tc.Fid == p.NOFID {
if tc.Fid == NOFID {
req.RespondError(Eunknownfid)
return
}
......@@ -111,15 +107,15 @@ func (srv *Srv) attach(req *Req) {
return
}
if tc.Afid != p.NOFID {
if tc.Afid != NOFID {
req.Afid = conn.FidGet(tc.Afid)
if req.Afid == nil {
req.RespondError(Eunknownfid)
}
}
var user p.User = nil
if tc.Unamenum != p.NOUID || conn.Dotu {
var user User = nil
if tc.Unamenum != NOUID || conn.Dotu {
user = srv.Upool.Uid2User(int(tc.Unamenum))
} else if tc.Uname != "" {
user = srv.Upool.Uname2User(tc.Uname)
......@@ -141,20 +137,20 @@ func (srv *Srv) attach(req *Req) {
}
}
(srv.ops).(ReqOps).Attach(req)
(srv.ops).(SrvReqOps).Attach(req)
}
func (srv *Srv) attachPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rattach {
func (srv *Srv) attachPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rattach {
req.Fid.Type = req.Rc.Qid.Type
req.Fid.IncRef()
}
}
func (srv *Srv) flush(req *Req) {
func (srv *Srv) flush(req *SrvReq) {
conn := req.Conn
tag := req.Tc.Oldtag
p.PackRflush(req.Rc)
PackRflush(req.Rc)
conn.Lock()
r := conn.reqs[tag]
if r != nil {
......@@ -186,13 +182,13 @@ func (srv *Srv) flush(req *Req) {
}
}
func (srv *Srv) walk(req *Req) {
func (srv *Srv) walk(req *SrvReq) {
conn := req.Conn
tc := req.Tc
fid := req.Fid
/* we can't walk regular files, only clone them */
if len(tc.Wname) > 0 && (fid.Type&p.QTDIR) == 0 {
if len(tc.Wname) > 0 && (fid.Type&QTDIR) == 0 {
req.RespondError(Enotdir)
return
}
......@@ -217,12 +213,12 @@ func (srv *Srv) walk(req *Req) {
req.Newfid.IncRef()
}
(req.Conn.Srv.ops).(ReqOps).Walk(req)
(req.Conn.Srv.ops).(SrvReqOps).Walk(req)
}
func (srv *Srv) walkPost(req *Req) {
func (srv *Srv) walkPost(req *SrvReq) {
rc := req.Rc
if rc == nil || rc.Type != p.Rwalk || req.Newfid == nil {
if rc == nil || rc.Type != Rwalk || req.Newfid == nil {
return
}
......@@ -243,7 +239,7 @@ func (srv *Srv) walkPost(req *Req) {
}
}
func (srv *Srv) open(req *Req) {
func (srv *Srv) open(req *SrvReq) {
fid := req.Fid
tc := req.Tc
if fid.opened {
......@@ -251,22 +247,22 @@ func (srv *Srv) open(req *Req) {
return
}
if (fid.Type&p.QTDIR) != 0 && tc.Mode != p.OREAD {
if (fid.Type&QTDIR) != 0 && tc.Mode != OREAD {
req.RespondError(Eperm)
return
}
fid.Omode = tc.Mode
(req.Conn.Srv.ops).(ReqOps).Open(req)
(req.Conn.Srv.ops).(SrvReqOps).Open(req)
}
func (srv *Srv) openPost(req *Req) {
func (srv *Srv) openPost(req *SrvReq) {
if req.Fid != nil {
req.Fid.opened = req.Rc != nil && req.Rc.Type == p.Ropen
req.Fid.opened = req.Rc != nil && req.Rc.Type == Ropen
}
}
func (srv *Srv) create(req *Req) {
func (srv *Srv) create(req *SrvReq) {
fid := req.Fid
tc := req.Tc
if fid.opened {
......@@ -274,47 +270,47 @@ func (srv *Srv) create(req *Req) {
return
}
if (fid.Type & p.QTDIR) == 0 {
if (fid.Type & QTDIR) == 0 {
req.RespondError(Enotdir)
return
}
/* can't open directories for other than reading */
if (tc.Perm&p.DMDIR) != 0 && tc.Mode != p.OREAD {
if (tc.Perm&DMDIR) != 0 && tc.Mode != OREAD {
req.RespondError(Eperm)
return
}
/* can't create special files if not 9P2000.u */
if (tc.Perm&(p.DMNAMEDPIPE|p.DMSYMLINK|p.DMLINK|p.DMDEVICE|p.DMSOCKET)) != 0 && !req.Conn.Dotu {
if (tc.Perm&(DMNAMEDPIPE|DMSYMLINK|DMLINK|DMDEVICE|DMSOCKET)) != 0 && !req.Conn.Dotu {
req.RespondError(Eperm)
return
}
fid.Omode = tc.Mode
(req.Conn.Srv.ops).(ReqOps).Create(req)
(req.Conn.Srv.ops).(SrvReqOps).Create(req)
}
func (srv *Srv) createPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rcreate && req.Fid != nil {
func (srv *Srv) createPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rcreate && req.Fid != nil {
req.Fid.Type = req.Rc.Qid.Type
req.Fid.opened = true
}
}
func (srv *Srv) read(req *Req) {
func (srv *Srv) read(req *SrvReq) {
tc := req.Tc
fid := req.Fid
if tc.Count+p.IOHDRSZ > req.Conn.Msize {
if tc.Count+IOHDRSZ > req.Conn.Msize {
req.RespondError(Etoolarge)
return
}
if (fid.Type & p.QTAUTH) != 0 {
if (fid.Type & QTAUTH) != 0 {
var n int
rc := req.Rc
err := p.InitRread(rc, tc.Count)
err := InitRread(rc, tc.Count)
if err != nil {
req.RespondError(err)
return
......@@ -327,7 +323,7 @@ func (srv *Srv) read(req *Req) {
return
}
p.SetRreadCount(rc, uint32(n))
SetRreadCount(rc, uint32(n))
req.Respond()
} else {
req.RespondError(Enotimpl)
......@@ -336,28 +332,27 @@ func (srv *Srv) read(req *Req) {
return
}
if (fid.Type & p.QTDIR) != 0 {
if (fid.Type & QTDIR) != 0 {
if tc.Offset == 0 {
fid.Diroffset = 0
} else if tc.Offset != fid.Diroffset {
req.RespondError(Ebadoffset)
return
fid.Diroffset = tc.Offset
}
}
(req.Conn.Srv.ops).(ReqOps).Read(req)
(req.Conn.Srv.ops).(SrvReqOps).Read(req)
}
func (srv *Srv) readPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rread && (req.Fid.Type&p.QTDIR) != 0 {
func (srv *Srv) readPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rread && (req.Fid.Type&QTDIR) != 0 {
req.Fid.Diroffset += uint64(req.Rc.Count)
}
}
func (srv *Srv) write(req *Req) {
func (srv *Srv) write(req *SrvReq) {
fid := req.Fid
tc := req.Tc
if (fid.Type & p.QTAUTH) != 0 {
if (fid.Type & QTAUTH) != 0 {
tc := req.Tc
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
n, err := op.AuthWrite(req.Fid, tc.Offset, tc.Data)
......@@ -373,22 +368,22 @@ func (srv *Srv) write(req *Req) {
return
}
if !fid.opened || (fid.Type&p.QTDIR) != 0 || (fid.Omode&3) == p.OREAD {
if !fid.opened || (fid.Type&QTDIR) != 0 || (fid.Omode&3) == OREAD {
req.RespondError(Ebaduse)
return
}
if tc.Count+p.IOHDRSZ > req.Conn.Msize {
if tc.Count+IOHDRSZ > req.Conn.Msize {
req.RespondError(Etoolarge)
return
}
(req.Conn.Srv.ops).(ReqOps).Write(req)
(req.Conn.Srv.ops).(SrvReqOps).Write(req)
}
func (srv *Srv) clunk(req *Req) {
func (srv *Srv) clunk(req *SrvReq) {
fid := req.Fid
if (fid.Type & p.QTAUTH) != 0 {
if (fid.Type & QTAUTH) != 0 {
if op, ok := (req.Conn.Srv.ops).(AuthOps); ok {
op.AuthDestroy(fid)
req.RespondRclunk()
......@@ -399,26 +394,26 @@ func (srv *Srv) clunk(req *Req) {
return
}
(req.Conn.Srv.ops).(ReqOps).Clunk(req)
(req.Conn.Srv.ops).(SrvReqOps).Clunk(req)
}
func (srv *Srv) clunkPost(req *Req) {
if req.Rc != nil && req.Rc.Type == p.Rclunk && req.Fid != nil {
func (srv *Srv) clunkPost(req *SrvReq) {
if req.Rc != nil && req.Rc.Type == Rclunk && req.Fid != nil {
req.Fid.DecRef()
}
}
func (srv *Srv) remove(req *Req) { (req.Conn.Srv.ops).(ReqOps).Remove(req) }
func (srv *Srv) remove(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Remove(req) }
func (srv *Srv) removePost(req *Req) {
func (srv *Srv) removePost(req *SrvReq) {
if req.Rc != nil && req.Fid != nil {
req.Fid.DecRef()
}
}
func (srv *Srv) stat(req *Req) { (req.Conn.Srv.ops).(ReqOps).Stat(req) }
func (srv *Srv) stat(req *SrvReq) { (req.Conn.Srv.ops).(SrvReqOps).Stat(req) }
func (srv *Srv) wstat(req *Req) {
func (srv *Srv) wstat(req *SrvReq) {
/*
fid := req.Fid
d := &req.Tc.Dir
......@@ -428,12 +423,12 @@ func (srv *Srv) wstat(req *Req) {
return
}
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&p.QTDIR) != 0 && (d.Mode&p.DMDIR) == 0) ||
((d.Type&p.QTDIR) == 0 && (d.Mode&p.DMDIR) != 0)) {
if (d.Mode != 0xFFFFFFFF) && (((fid.Type&QTDIR) != 0 && (d.Mode&DMDIR) == 0) ||
((d.Type&QTDIR) == 0 && (d.Mode&DMDIR) != 0)) {
req.RespondError(Edirchange)
return
}
*/
(req.Conn.Srv.ops).(ReqOps).Wstat(req)
(req.Conn.Srv.ops).(SrvReqOps).Wstat(req)
}
......@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import (
"k8s.io/minikube/third_party/go9p/p"
"log"
"sync"
"time"
......@@ -13,18 +12,18 @@ import (
// The FStatOp interface provides a single operation (Stat) that will be
// called before a file stat is sent back to the client. If implemented,
// the operation should update the data in the File struct.
// the operation should update the data in the srvFile struct.
type FStatOp interface {
Stat(fid *FFid) error
}
// The FWstatOp interface provides a single operation (Wstat) that will be
// called when the client requests the File metadata to be modified. If
// called when the client requests the srvFile metadata to be modified. If
// implemented, the operation will be called when Twstat message is received.
// If not implemented, "permission denied" error will be sent back. If the
// operation returns an Error, the error is send back to the client.
type FWstatOp interface {
Wstat(*FFid, *p.Dir) error
Wstat(*FFid, *Dir) error
}
// If the FReadOp interface is implemented, the Read operation will be called
......@@ -44,16 +43,16 @@ type FWriteOp interface {
}
// If the FCreateOp interface is implemented, the Create operation will be called
// when the client attempts to create a file in the File implementing the interface.
// when the client attempts to create a file in the srvFile implementing the interface.
// If not implemented, "permission denied" error will be send back. If successful,
// the operation should call (*File)Add() to add the created file to the directory.
// The operation returns the created file, or the error occured while creating it.
type FCreateOp interface {
Create(fid *FFid, name string, perm uint32) (*File, error)
Create(fid *FFid, name string, perm uint32) (*srvFile, error)
}
// If the FRemoveOp interface is implemented, the Remove operation will be called
// when the client attempts to create a file in the File implementing the interface.
// when the client attempts to create a file in the srvFile implementing the interface.
// If not implemented, "permission denied" error will be send back.
// The operation returns nil if successful, or the error that occured while removing
// the file.
......@@ -79,39 +78,40 @@ const (
Fremoved FFlags = 1 << iota
)
// The File type represents a file (or directory) served by the file server.
type File struct {
// The srvFile type represents a file (or directory) served by the file server.
type srvFile struct {
sync.Mutex
p.Dir
Dir
flags FFlags
Parent *File // parent
next, prev *File // siblings, guarded by parent.Lock
cfirst, clast *File // children (if directory)
Ops interface{}
Parent *srvFile // parent
next, prev *srvFile // siblings, guarded by parent.Lock
cfirst, clast *srvFile // children (if directory)
ops interface{}
}
type FFid struct {
F *File
Fid *Fid
dirs []*File // used for readdir
F *srvFile
Fid *SrvFid
dirs []*srvFile // used for readdir
dirents []byte // serialized version of dirs
}
// The Fsrv can be used to create file servers that serve
// simple trees of synthetic files.
type Fsrv struct {
Srv
Root *File
Root *srvFile
}
var lock sync.Mutex
var qnext uint64
var Eexist = &p.Error{"file already exists", p.EEXIST}
var Enoent = &p.Error{"file not found", p.ENOENT}
var Enotempty = &p.Error{"directory not empty", p.EPERM}
var Eexist = &Error{"file already exists", EEXIST}
var Enoent = &Error{"file not found", ENOENT}
var Enotempty = &Error{"directory not empty", EPERM}
// Creates a file server with root as root directory
func NewFileSrv(root *File) *Fsrv {
func NewsrvFileSrv(root *srvFile) *Fsrv {
srv := new(Fsrv)
srv.Root = root
root.Parent = root // make sure we can .. in root
......@@ -121,7 +121,7 @@ func NewFileSrv(root *File) *Fsrv {
// Initializes the fields of a file and add it to a directory.
// Returns nil if successful, or an error.
func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32, ops interface{}) error {
func (f *srvFile) Add(dir *srvFile, name string, uid User, gid Group, mode uint32, ops interface{}) error {
lock.Lock()
qpath := qnext
......@@ -141,7 +141,7 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Uidnum = uint32(uid.Id())
} else {
f.Uid = "none"
f.Uidnum = p.NOUID
f.Uidnum = NOUID
}
if gid != nil {
......@@ -149,11 +149,11 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Gidnum = uint32(gid.Id())
} else {
f.Gid = "none"
f.Gidnum = p.NOUID
f.Gidnum = NOUID
}
f.Muid = ""
f.Muidnum = p.NOUID
f.Muidnum = NOUID
f.Ext = ""
if dir != nil {
......@@ -180,12 +180,12 @@ func (f *File) Add(dir *File, name string, uid p.User, gid p.Group, mode uint32,
f.Parent = f
}
f.Ops = ops
f.ops = ops
return nil
}
// Removes a file from its parent directory.
func (f *File) Remove() {
func (f *srvFile) Remove() {
f.Lock()
if (f.flags & Fremoved) != 0 {
f.Unlock()
......@@ -214,7 +214,7 @@ func (f *File) Remove() {
p.Unlock()
}
func (f *File) Rename(name string) error {
func (f *srvFile) Rename(name string) error {
p := f.Parent
p.Lock()
defer p.Unlock()
......@@ -229,8 +229,8 @@ func (f *File) Rename(name string) error {
}
// Looks for a file in a directory. Returns nil if the file is not found.
func (p *File) Find(name string) *File {
var f *File
func (p *srvFile) Find(name string) *srvFile {
var f *srvFile
p.Lock()
for f = p.cfirst; f != nil; f = f.next {
......@@ -244,8 +244,8 @@ func (p *File) Find(name string) *File {
// Checks if the specified user has permission to perform
// certain operation on a file. Perm contains one or more
// of p.DMREAD, p.DMWRITE, and p.DMEXEC.
func (f *File) CheckPerm(user p.User, perm uint32) bool {
// of DMREAD, DMWRITE, and DMEXEC.
func (f *srvFile) CheckPerm(user User, perm uint32) bool {
if user == nil {
return false
}
......@@ -285,7 +285,7 @@ func (f *File) CheckPerm(user p.User, perm uint32) bool {
return false
}
func (s *Fsrv) Attach(req *Req) {
func (s *Fsrv) Attach(req *SrvReq) {
fid := new(FFid)
fid.F = s.Root
fid.Fid = req.Fid
......@@ -293,7 +293,7 @@ func (s *Fsrv) Attach(req *Req) {
req.RespondRattach(&s.Root.Qid)
}
func (*Fsrv) Walk(req *Req) {
func (*Fsrv) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
tc := req.Tc
......@@ -304,7 +304,7 @@ func (*Fsrv) Walk(req *Req) {
}
nfid := req.Newfid.Aux.(*FFid)
wqids := make([]p.Qid, len(tc.Wname))
wqids := make([]Qid, len(tc.Wname))
i := 0
f := fid.F
for ; i < len(tc.Wname); i++ {
......@@ -314,8 +314,8 @@ func (*Fsrv) Walk(req *Req) {
wqids[i] = f.Qid
continue
}
if (wqids[i].Type & p.QTDIR) > 0 {
if !f.CheckPerm(req.Fid.User, p.DMEXEC) {
if (wqids[i].Type & QTDIR) > 0 {
if !f.CheckPerm(req.Fid.User, DMEXEC) {
break
}
}
......@@ -342,22 +342,22 @@ func mode2Perm(mode uint8) uint32 {
var perm uint32 = 0
switch mode & 3 {
case p.OREAD:
perm = p.DMREAD
case p.OWRITE:
perm = p.DMWRITE
case p.ORDWR:
perm = p.DMREAD | p.DMWRITE
case OREAD:
perm = DMREAD
case OWRITE:
perm = DMWRITE
case ORDWR:
perm = DMREAD | DMWRITE
}
if (mode & p.OTRUNC) != 0 {
perm |= p.DMWRITE
if (mode & OTRUNC) != 0 {
perm |= DMWRITE
}
return perm
}
func (*Fsrv) Open(req *Req) {
func (*Fsrv) Open(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
tc := req.Tc
......@@ -366,7 +366,7 @@ func (*Fsrv) Open(req *Req) {
return
}
if op, ok := (fid.F.Ops).(FOpenOp); ok {
if op, ok := (fid.F.ops).(FOpenOp); ok {
err := op.Open(fid, tc.Mode)
if err != nil {
req.RespondError(err)
......@@ -376,17 +376,17 @@ func (*Fsrv) Open(req *Req) {
req.RespondRopen(&fid.F.Qid, 0)
}
func (*Fsrv) Create(req *Req) {
func (*Fsrv) Create(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
tc := req.Tc
dir := fid.F
if !dir.CheckPerm(req.Fid.User, p.DMWRITE) {
if !dir.CheckPerm(req.Fid.User, DMWRITE) {
req.RespondError(Eperm)
return
}
if cop, ok := (dir.Ops).(FCreateOp); ok {
if cop, ok := (dir.ops).(FCreateOp); ok {
f, err := cop.Create(fid, tc.Name, tc.Perm)
if err != nil {
req.RespondError(err)
......@@ -399,55 +399,48 @@ func (*Fsrv) Create(req *Req) {
}
}
func (*Fsrv) Read(req *Req) {
var i, n int
func (*Fsrv) Read(req *SrvReq) {
var n int
var err error
fid := req.Fid.Aux.(*FFid)
f := fid.F
tc := req.Tc
rc := req.Rc
p.InitRread(rc, tc.Count)
InitRread(rc, tc.Count)
if f.Mode&p.DMDIR != 0 {
// directory
if f.Mode&DMDIR != 0 {
// Get all the directory entries and
// serialize them all into an output buffer.
// This greatly simplifies the directory read.
if tc.Offset == 0 {
var g *File
var g *srvFile
fid.dirents = nil
f.Lock()
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
}
fid.dirs = make([]*File, n)
fid.dirs = make([]*srvFile, n)
for n, g = 0, f.cfirst; g != nil; n, g = n+1, g.next {
fid.dirs[n] = g
fid.dirents = append(fid.dirents,
PackDir(&g.Dir, req.Conn.Dotu)...)
}
f.Unlock()
}
switch {
case tc.Offset > uint64(len(fid.dirents)):
n = 0
b := rc.Data
for i = 0; i < len(fid.dirs); i++ {
g := fid.dirs[i]
g.Lock()
if (g.flags & Fremoved) != 0 {
g.Unlock()
continue
}
sz := p.PackDir(&g.Dir, b, req.Conn.Dotu)
g.Unlock()
if sz == 0 {
break
}
b = b[sz:]
n += sz
case len(fid.dirents[tc.Offset:]) > int(tc.Size):
n = int(tc.Size)
default:
n = len(fid.dirents[tc.Offset:])
}
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+1+n])
fid.dirs = fid.dirs[i:]
} else {
// file
if rop, ok := f.Ops.(FReadOp); ok {
if rop, ok := f.ops.(FReadOp); ok {
n, err = rop.Read(fid, rc.Data, tc.Offset)
if err != nil {
req.RespondError(err)
......@@ -459,16 +452,16 @@ func (*Fsrv) Read(req *Req) {
}
}
p.SetRreadCount(rc, uint32(n))
SetRreadCount(rc, uint32(n))
req.Respond()
}
func (*Fsrv) Write(req *Req) {
func (*Fsrv) Write(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
f := fid.F
tc := req.Tc
if wop, ok := (f.Ops).(FWriteOp); ok {
if wop, ok := (f.ops).(FWriteOp); ok {
n, err := wop.Write(fid, tc.Data, tc.Offset)
if err != nil {
req.RespondError(err)
......@@ -481,10 +474,10 @@ func (*Fsrv) Write(req *Req) {
}
func (*Fsrv) Clunk(req *Req) {
func (*Fsrv) Clunk(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
if op, ok := (fid.F.Ops).(FClunkOp); ok {
if op, ok := (fid.F.ops).(FClunkOp); ok {
err := op.Clunk(fid)
if err != nil {
req.RespondError(err)
......@@ -493,7 +486,7 @@ func (*Fsrv) Clunk(req *Req) {
req.RespondRclunk()
}
func (*Fsrv) Remove(req *Req) {
func (*Fsrv) Remove(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
f := fid.F
f.Lock()
......@@ -504,7 +497,7 @@ func (*Fsrv) Remove(req *Req) {
}
f.Unlock()
if rop, ok := (f.Ops).(FRemoveOp); ok {
if rop, ok := (f.ops).(FRemoveOp); ok {
err := rop.Remove(fid)
if err != nil {
req.RespondError(err)
......@@ -518,11 +511,11 @@ func (*Fsrv) Remove(req *Req) {
}
}
func (*Fsrv) Stat(req *Req) {
func (*Fsrv) Stat(req *SrvReq) {
fid := req.Fid.Aux.(*FFid)
f := fid.F
if sop, ok := (f.Ops).(FStatOp); ok {
if sop, ok := (f.ops).(FStatOp); ok {
err := sop.Stat(fid)
if err != nil {
req.RespondError(err)
......@@ -534,12 +527,12 @@ func (*Fsrv) Stat(req *Req) {
}
}
func (*Fsrv) Wstat(req *Req) {
func (*Fsrv) Wstat(req *SrvReq) {
tc := req.Tc
fid := req.Fid.Aux.(*FFid)
f := fid.F
if wop, ok := (f.Ops).(FWstatOp); ok {
if wop, ok := (f.ops).(FWstatOp); ok {
err := wop.Wstat(fid, &tc.Dir)
if err != nil {
req.RespondError(err)
......@@ -551,7 +544,7 @@ func (*Fsrv) Wstat(req *Req) {
}
}
func (*Fsrv) FidDestroy(ffid *Fid) {
func (*Fsrv) FidDestroy(ffid *SrvFid) {
if ffid.Aux == nil {
return
}
......@@ -562,7 +555,7 @@ func (*Fsrv) FidDestroy(ffid *Fid) {
return // otherwise errs in bad walks
}
if op, ok := (f.Ops).(FDestroyOp); ok {
if op, ok := (f.ops).(FDestroyOp); ok {
op.FidDestroy(fid)
}
}
// Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package go9p
import (
"log"
"os"
"strconv"
"syscall"
)
type pipeFid struct {
path string
file *os.File
dirs []os.FileInfo
dirents []byte
diroffset uint64
st os.FileInfo
data []uint8
eof bool
}
type Pipefs struct {
Srv
Root string
}
func (fid *pipeFid) stat() *Error {
var err error
fid.st, err = os.Lstat(fid.path)
if err != nil {
return toError(err)
}
return nil
}
// Dir is an instantiation of the p.Dir structure
// that can act as a receiver for local methods.
type pipeDir struct {
Dir
}
func (*Pipefs) ConnOpened(conn *Conn) {
if conn.Srv.Debuglevel > 0 {
log.Println("connected")
}
}
func (*Pipefs) ConnClosed(conn *Conn) {
if conn.Srv.Debuglevel > 0 {
log.Println("disconnected")
}
}
func (*Pipefs) FidDestroy(sfid *SrvFid) {
var fid *pipeFid
if sfid.Aux == nil {
return
}
fid = sfid.Aux.(*pipeFid)
if fid.file != nil {
fid.file.Close()
}
}
func (pipe *Pipefs) Attach(req *SrvReq) {
if req.Afid != nil {
req.RespondError(Enoauth)
return
}
tc := req.Tc
fid := new(pipeFid)
if len(tc.Aname) == 0 {
fid.path = pipe.Root
} else {
fid.path = tc.Aname
}
req.Fid.Aux = fid
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
qid := dir2Qid(fid.st)
req.RespondRattach(qid)
}
func (*Pipefs) Flush(req *SrvReq) {}
func (*Pipefs) Walk(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
if req.Newfid.Aux == nil {
req.Newfid.Aux = new(pipeFid)
}
nfid := req.Newfid.Aux.(*pipeFid)
wqids := make([]Qid, len(tc.Wname))
path := fid.path
i := 0
for ; i < len(tc.Wname); i++ {
p := path + "/" + tc.Wname[i]
st, err := os.Lstat(p)
if err != nil {
if i == 0 {
req.RespondError(Enoent)
return
}
break
}
wqids[i] = *dir2Qid(st)
path = p
}
nfid.path = path
req.RespondRwalk(wqids[0:i])
}
func (*Pipefs) Open(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
var e error
fid.file, e = os.OpenFile(fid.path, omode2uflags(tc.Mode), 0)
if e != nil {
req.RespondError(toError(e))
return
}
req.RespondRopen(dir2Qid(fid.st), 0)
}
func (*Pipefs) Create(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
path := fid.path + "/" + tc.Name
var e error = nil
var file *os.File = nil
switch {
case tc.Perm&DMDIR != 0:
e = os.Mkdir(path, os.FileMode(tc.Perm&0777))
case tc.Perm&DMSYMLINK != 0:
e = os.Symlink(tc.Ext, path)
case tc.Perm&DMLINK != 0:
n, e := strconv.ParseUint(tc.Ext, 10, 0)
if e != nil {
break
}
ofid := req.Conn.FidGet(uint32(n))
if ofid == nil {
req.RespondError(Eunknownfid)
return
}
e = os.Link(ofid.Aux.(*pipeFid).path, path)
ofid.DecRef()
case tc.Perm&DMNAMEDPIPE != 0:
case tc.Perm&DMDEVICE != 0:
req.RespondError(&Error{"not implemented", EIO})
return
default:
var mode uint32 = tc.Perm & 0777
if req.Conn.Dotu {
if tc.Perm&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if tc.Perm&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
file, e = os.OpenFile(path, omode2uflags(tc.Mode)|os.O_CREATE, os.FileMode(mode))
}
if file == nil && e == nil {
file, e = os.OpenFile(path, omode2uflags(tc.Mode), 0)
}
if e != nil {
req.RespondError(toError(e))
return
}
fid.path = path
fid.file = file
err = fid.stat()
if err != nil {
req.RespondError(err)
return
}
req.RespondRcreate(dir2Qid(fid.st), 0)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func (*Pipefs) Read(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
rc := req.Rc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
InitRread(rc, tc.Count)
var count int
var e error
if fid.st.IsDir() {
if tc.Offset == 0 {
var e error
// If we got here, it was open. Can't really seek
// in most cases, just close and reopen it.
fid.file.Close()
if fid.file, e = os.OpenFile(fid.path, omode2uflags(req.Fid.Omode), 0); e != nil {
req.RespondError(toError(e))
return
}
if fid.dirs, e = fid.file.Readdir(-1); e != nil {
req.RespondError(toError(e))
return
}
fid.dirents = nil
for i := 0; i < len(fid.dirs); i++ {
path := fid.path + "/" + fid.dirs[i].Name()
st, _ := dir2Dir(path, fid.dirs[i], req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
continue
}
b := PackDir(st, req.Conn.Dotu)
fid.dirents = append(fid.dirents, b...)
count += len(b)
}
}
switch {
case tc.Offset > uint64(len(fid.dirents)):
count = 0
case len(fid.dirents[tc.Offset:]) > int(tc.Count):
count = int(tc.Count)
default:
count = len(fid.dirents[tc.Offset:])
}
copy(rc.Data, fid.dirents[tc.Offset:int(tc.Offset)+count])
} else {
if fid.eof {
req.RespondError(toError(e))
return
}
length := min(len(rc.Data), len(fid.data))
count = length
copy(rc.Data, fid.data[:length])
fid.data = fid.data[length:]
}
SetRreadCount(rc, uint32(count))
req.Respond()
}
func (*Pipefs) Write(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
tc := req.Tc
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
fid.data = append(fid.data, tc.Data...)
req.RespondRwrite(uint32(len(tc.Data)))
}
func (*Pipefs) Clunk(req *SrvReq) { req.RespondRclunk() }
func (*Pipefs) Remove(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
e := os.Remove(fid.path)
if e != nil {
req.RespondError(toError(e))
return
}
req.RespondRremove()
}
func (*Pipefs) Stat(req *SrvReq) {
fid := req.Fid.Aux.(*pipeFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
return
}
st, derr := dir2Dir(fid.path, fid.st, req.Conn.Dotu, req.Conn.Srv.Upool)
if st == nil {
req.RespondError(derr)
return
}
req.RespondRstat(st)
}
func (*Pipefs) Wstat(req *SrvReq) {
req.RespondError(Eperm)
}
// Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package go9p
import (
"fmt"
"os"
"syscall"
)
func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
if dir.Uid == "" {
dir.Uid = "none"
}
dir.Gid = g.Name()
if dir.Gid == "" {
dir.Gid = "none"
}
dir.Muid = "none"
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
if err != nil {
dir.Ext = ""
}
} else if isBlock(d) {
dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
} else if isChar(d) {
dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
}
}
// Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package go9p
import (
"fmt"
"os"
"syscall"
)
func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
if dir.Uid == "" {
dir.Uid = "none"
}
dir.Gid = g.Name()
if dir.Gid == "" {
dir.Gid = "none"
}
dir.Muid = "none"
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
if err != nil {
dir.Ext = ""
}
} else if isBlock(d) {
dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
} else if isChar(d) {
dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
}
}
// Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package go9p
import (
"os"
"syscall"
)
func (dir *pipeDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Win32FileAttributeData) {
// u := upool.Uid2User(int(sysMode.Uid))
// g := upool.Gid2Group(int(sysMode.Gid))
// dir.Uid = u.Name()
// if dir.Uid == "" {
// dir.Uid = "none"
// }
// dir.Gid = g.Name()
// if dir.Gid == "" {
// dir.Gid = "none"
// }
// dir.Muid = "none"
// dir.Ext = ""
// dir.Uidnum = uint32(u.Id())
// dir.Gidnum = uint32(g.Id())
// dir.Muidnum = NOUID
// if d.Mode()&os.ModeSymlink != 0 {
// var err error
// dir.Ext, err = os.Readlink(path)
// if err != nil {
// dir.Ext = ""
// }
// } else if isBlock(d) {
// dir.Ext = fmt.Sprintf("b %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
// } else if isChar(d) {
// dir.Ext = fmt.Sprintf("c %d %d", sysMode.Rdev>>24, sysMode.Rdev&0xFFFFFF)
// }
dir.Uid = "none"
dir.Gid = "none"
dir.Muid = "none"
dir.Uidnum = 0
dir.Gidnum = 0
dir.Muidnum = NOUID
dir.Ext = ""
}
......@@ -2,28 +2,42 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package srv
package go9p
import "fmt"
import "k8s.io/minikube/third_party/go9p/p"
// SrvRequest operations. This interface should be implemented by all file servers.
// The operations correspond directly to most of the 9P2000 message types.
type SrvReqOps interface {
Attach(*SrvReq)
Walk(*SrvReq)
Open(*SrvReq)
Create(*SrvReq)
Read(*SrvReq)
Write(*SrvReq)
Clunk(*SrvReq)
Remove(*SrvReq)
Stat(*SrvReq)
Wstat(*SrvReq)
}
// Respond to the request with Rerror message
func (req *Req) RespondError(err interface{}) {
func (req *SrvReq) RespondError(err interface{}) {
switch e := err.(type) {
case *p.Error:
p.PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
case *Error:
PackRerror(req.Rc, e.Error(), uint32(e.Errornum), req.Conn.Dotu)
case error:
p.PackRerror(req.Rc, e.Error(), uint32(p.EIO), req.Conn.Dotu)
PackRerror(req.Rc, e.Error(), uint32(EIO), req.Conn.Dotu)
default:
p.PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(p.EIO), req.Conn.Dotu)
PackRerror(req.Rc, fmt.Sprintf("%v", e), uint32(EIO), req.Conn.Dotu)
}
req.Respond()
}
// Respond to the request with Rversion message
func (req *Req) RespondRversion(msize uint32, version string) {
err := p.PackRversion(req.Rc, msize, version)
func (req *SrvReq) RespondRversion(msize uint32, version string) {
err := PackRversion(req.Rc, msize, version)
if err != nil {
req.RespondError(err)
} else {
......@@ -32,8 +46,8 @@ func (req *Req) RespondRversion(msize uint32, version string) {
}
// Respond to the request with Rauth message
func (req *Req) RespondRauth(aqid *p.Qid) {
err := p.PackRauth(req.Rc, aqid)
func (req *SrvReq) RespondRauth(aqid *Qid) {
err := PackRauth(req.Rc, aqid)
if err != nil {
req.RespondError(err)
} else {
......@@ -42,8 +56,8 @@ func (req *Req) RespondRauth(aqid *p.Qid) {
}
// Respond to the request with Rflush message
func (req *Req) RespondRflush() {
err := p.PackRflush(req.Rc)
func (req *SrvReq) RespondRflush() {
err := PackRflush(req.Rc)
if err != nil {
req.RespondError(err)
} else {
......@@ -52,8 +66,8 @@ func (req *Req) RespondRflush() {
}
// Respond to the request with Rattach message
func (req *Req) RespondRattach(aqid *p.Qid) {
err := p.PackRattach(req.Rc, aqid)
func (req *SrvReq) RespondRattach(aqid *Qid) {
err := PackRattach(req.Rc, aqid)
if err != nil {
req.RespondError(err)
} else {
......@@ -62,8 +76,8 @@ func (req *Req) RespondRattach(aqid *p.Qid) {
}
// Respond to the request with Rwalk message
func (req *Req) RespondRwalk(wqids []p.Qid) {
err := p.PackRwalk(req.Rc, wqids)
func (req *SrvReq) RespondRwalk(wqids []Qid) {
err := PackRwalk(req.Rc, wqids)
if err != nil {
req.RespondError(err)
} else {
......@@ -72,8 +86,8 @@ func (req *Req) RespondRwalk(wqids []p.Qid) {
}
// Respond to the request with Ropen message
func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
err := p.PackRopen(req.Rc, qid, iounit)
func (req *SrvReq) RespondRopen(qid *Qid, iounit uint32) {
err := PackRopen(req.Rc, qid, iounit)
if err != nil {
req.RespondError(err)
} else {
......@@ -82,8 +96,8 @@ func (req *Req) RespondRopen(qid *p.Qid, iounit uint32) {
}
// Respond to the request with Rcreate message
func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
err := p.PackRcreate(req.Rc, qid, iounit)
func (req *SrvReq) RespondRcreate(qid *Qid, iounit uint32) {
err := PackRcreate(req.Rc, qid, iounit)
if err != nil {
req.RespondError(err)
} else {
......@@ -92,8 +106,8 @@ func (req *Req) RespondRcreate(qid *p.Qid, iounit uint32) {
}
// Respond to the request with Rread message
func (req *Req) RespondRread(data []byte) {
err := p.PackRread(req.Rc, data)
func (req *SrvReq) RespondRread(data []byte) {
err := PackRread(req.Rc, data)
if err != nil {
req.RespondError(err)
} else {
......@@ -102,8 +116,8 @@ func (req *Req) RespondRread(data []byte) {
}
// Respond to the request with Rwrite message
func (req *Req) RespondRwrite(count uint32) {
err := p.PackRwrite(req.Rc, count)
func (req *SrvReq) RespondRwrite(count uint32) {
err := PackRwrite(req.Rc, count)
if err != nil {
req.RespondError(err)
} else {
......@@ -112,8 +126,8 @@ func (req *Req) RespondRwrite(count uint32) {
}
// Respond to the request with Rclunk message
func (req *Req) RespondRclunk() {
err := p.PackRclunk(req.Rc)
func (req *SrvReq) RespondRclunk() {
err := PackRclunk(req.Rc)
if err != nil {
req.RespondError(err)
} else {
......@@ -122,8 +136,8 @@ func (req *Req) RespondRclunk() {
}
// Respond to the request with Rremove message
func (req *Req) RespondRremove() {
err := p.PackRremove(req.Rc)
func (req *SrvReq) RespondRremove() {
err := PackRremove(req.Rc)
if err != nil {
req.RespondError(err)
} else {
......@@ -132,8 +146,8 @@ func (req *Req) RespondRremove() {
}
// Respond to the request with Rstat message
func (req *Req) RespondRstat(st *p.Dir) {
err := p.PackRstat(req.Rc, st, req.Conn.Dotu)
func (req *SrvReq) RespondRstat(st *Dir) {
err := PackRstat(req.Rc, st, req.Conn.Dotu)
if err != nil {
req.RespondError(err)
} else {
......@@ -142,8 +156,8 @@ func (req *Req) RespondRstat(st *p.Dir) {
}
// Respond to the request with Rwstat message
func (req *Req) RespondRwstat() {
err := p.PackRwstat(req.Rc)
func (req *SrvReq) RespondRwstat() {
err := PackRwstat(req.Rc)
if err != nil {
req.RespondError(err)
} else {
......
// +build httpstats
package srv
package go9p
import (
"fmt"
"io"
"k8s.io/minikube/third_party/go9p/p"
"net/http"
"sync"
)
var mux sync.RWMutex
var stat map[string]http.Handler
var once sync.Once
var httponce sync.Once
func register(s string, h http.Handler) {
mux.Lock()
......@@ -28,7 +27,7 @@ func register(s string, h http.Handler) {
mux.Unlock()
}
func (srv *Srv) statsRegister() {
once.Do(func() {
httponce.Do(func() {
http.HandleFunc("/go9p/", StatsHandler)
go http.ListenAndServe(":6060", nil)
})
......@@ -85,7 +84,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
fs := conn.Srv.Log.Filter(conn, DbgLogFcalls)
io.WriteString(c, fmt.Sprintf("<h2>Last %d 9P messages</h2>", len(fs)))
for i, l := range fs {
fc := l.Data.(*p.Fcall)
fc := l.Data.(*Fcall)
if fc.Type == 0 {
continue
}
......@@ -94,7 +93,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
if fc.Type%2 == 0 {
// try to find the response for the T message
for j := i + 1; j < len(fs); j++ {
rc := fs[j].Data.(*p.Fcall)
rc := fs[j].Data.(*Fcall)
if rc.Tag == fc.Tag {
lbl = fmt.Sprintf("<a href='#fc%d'>&#10164;</a>", j)
break
......@@ -103,7 +102,7 @@ func (conn *Conn) ServeHTTP(c http.ResponseWriter, r *http.Request) {
} else {
// try to find the request for the R message
for j := i - 1; j >= 0; j-- {
tc := fs[j].Data.(*p.Fcall)
tc := fs[j].Data.(*Fcall)
if tc.Tag == fc.Tag {
lbl = fmt.Sprintf("<a href='#fc%d'>&#10166;</a>", j)
break
......
package go9p
type StatsOps interface {
statsRegister()
statsUnregister()
}
// Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ufs
import (
"fmt"
"log"
"k8s.io/minikube/third_party/go9p"
)
func StartServer(addrVal string, debugVal int, rootVal string) {
ufs := new(go9p.Ufs)
ufs.Dotu = true
ufs.Id = "ufs"
ufs.Root = rootVal
ufs.Debuglevel = debugVal
ufs.Start(ufs)
fmt.Print("ufs starting\n")
// determined by build tags
//extraFuncs()
err := ufs.StartNetListener("tcp", addrVal)
if err != nil {
log.Println(err)
}
}
// Copyright 2012 The go9p Authors. All rights reserved.
// Copyright 2009 The go9p Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ufs
package go9p
import (
"fmt"
"os"
"os/user"
"path"
"strconv"
"strings"
"syscall"
"time"
"k8s.io/minikube/third_party/go9p/p"
"k8s.io/minikube/third_party/go9p/p/srv"
)
func atime(stat *syscall.Stat_t) time.Time {
......@@ -25,16 +23,18 @@ func atime(stat *syscall.Stat_t) time.Time {
func isBlock(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFBLK
return true
}
// IsChar reports if the file is a character device
func isChar(d os.FileInfo) bool {
stat := d.Sys().(*syscall.Stat_t)
return (stat.Mode & syscall.S_IFMT) == syscall.S_IFCHR
return true
}
func dir2Qid(d os.FileInfo) *p.Qid {
var qid p.Qid
func dir2Qid(d os.FileInfo) *Qid {
var qid Qid
qid.Path = d.Sys().(*syscall.Stat_t).Ino
qid.Version = uint32(d.ModTime().UnixNano() / 1000000)
......@@ -43,27 +43,34 @@ func dir2Qid(d os.FileInfo) *p.Qid {
return &qid
}
func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
sysMode := d.Sys().(*syscall.Stat_t)
func dir2Dir(path string, d os.FileInfo, dotu bool, upool Users) (*Dir, error) {
if r := recover(); r != nil {
fmt.Print("stat failed: ", r)
return nil, &os.PathError{"dir2Dir", path, nil}
}
sysif := d.Sys()
if sysif == nil {
return nil, &os.PathError{"dir2Dir: sysif is nil", path, nil}
}
sysMode := sysif.(*syscall.Stat_t)
dir := new(Dir)
dir := new(ufsDir)
dir.Qid = *dir2Qid(d)
dir.Mode = dir2Npmode(d, dotu)
dir.Atime = uint32(atime(sysMode).Unix())
dir.Atime = uint32(0 /*atime(sysMode).Unix()*/)
dir.Mtime = uint32(d.ModTime().Unix())
dir.Length = uint64(d.Size())
dir.Name = path[strings.LastIndex(path, "/")+1:]
if dotu {
dir.dotu(path, d, upool, sysMode)
return &dir.Dir
return &dir.Dir, nil
}
unixUid := int(sysMode.Uid)
unixGid := int(sysMode.Gid)
dir.Uid = strconv.Itoa(unixUid)
dir.Gid = strconv.Itoa(unixGid)
dir.Muid = "none"
// BUG(akumar): LookupId will never find names for
// groups, as it only operates on user ids.
......@@ -76,10 +83,17 @@ func dir2Dir(path string, d os.FileInfo, dotu bool, upool p.Users) *p.Dir {
dir.Gid = g.Username
}
return &dir.Dir
/* For Akaros, we use the Muid as the link value. */
if *Akaros && (d.Mode()&os.ModeSymlink != 0) {
dir.Muid, err = os.Readlink(path)
if err == nil {
dir.Mode |= DMSYMLINK
}
}
return &dir.Dir, nil
}
func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall.Stat_t) {
func (dir *ufsDir) dotu(path string, d os.FileInfo, upool Users, sysMode *syscall.Stat_t) {
u := upool.Uid2User(int(sysMode.Uid))
g := upool.Gid2Group(int(sysMode.Gid))
dir.Uid = u.Name()
......@@ -95,7 +109,7 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
dir.Ext = ""
dir.Uidnum = uint32(u.Id())
dir.Gidnum = uint32(g.Id())
dir.Muidnum = p.NOUID
dir.Muidnum = NOUID
if d.Mode()&os.ModeSymlink != 0 {
var err error
dir.Ext, err = os.Readlink(path)
......@@ -109,8 +123,8 @@ func (dir *Dir) dotu(path string, d os.FileInfo, upool p.Users, sysMode *syscall
}
}
func (*Ufs) Wstat(req *srv.Req) {
fid := req.Fid.Aux.(*Fid)
func (u *Ufs) Wstat(req *SrvReq) {
fid := req.Fid.Aux.(*ufsFid)
err := fid.stat()
if err != nil {
req.RespondError(err)
......@@ -121,10 +135,10 @@ func (*Ufs) Wstat(req *srv.Req) {
if dir.Mode != 0xFFFFFFFF {
mode := dir.Mode & 0777
if req.Conn.Dotu {
if dir.Mode&p.DMSETUID > 0 {
if dir.Mode&DMSETUID > 0 {
mode |= syscall.S_ISUID
}
if dir.Mode&p.DMSETGID > 0 {
if dir.Mode&DMSETGID > 0 {
mode |= syscall.S_ISGID
}
}
......@@ -135,7 +149,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
uid, gid := p.NOUID, p.NOUID
uid, gid := NOUID, NOUID
if req.Conn.Dotu {
uid = dir.Uidnum
gid = dir.Gidnum
......@@ -159,7 +173,7 @@ func (*Ufs) Wstat(req *srv.Req) {
}
}
if uid != p.NOUID || gid != p.NOUID {
if uid != NOUID || gid != NOUID {
e := os.Chown(fid.path, int(uid), int(gid))
if e != nil {
req.RespondError(toError(e))
......@@ -168,13 +182,25 @@ func (*Ufs) Wstat(req *srv.Req) {
}
if dir.Name != "" {
path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name
err := syscall.Rename(fid.path, path)
fmt.Printf("Rename %s to %s\n", fid.path, dir.Name)
// if first char is / it is relative to root, else relative to
// cwd.
var destpath string
if dir.Name[0] == '/' {
destpath = path.Join(u.Root, dir.Name)
fmt.Printf("/ results in %s\n", destpath)
} else {
fiddir, _ := path.Split(fid.path)
destpath = path.Join(fiddir, dir.Name)
fmt.Printf("rel results in %s\n", destpath)
}
err := syscall.Rename(fid.path, destpath)
fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err)
if err != nil {
req.RespondError(toError(err))
return
}
fid.path = path
fid.path = destpath
}
if dir.Length != 0xFFFFFFFFFFFFFFFF {
......@@ -199,7 +225,7 @@ func (*Ufs) Wstat(req *srv.Req) {
case true:
mt = st.ModTime()
default:
at = atime(st.Sys().(*syscall.Stat_t))
//at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t))
}
}
e := os.Chtimes(fid.path, at, mt)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册