diff --git a/cmd/p9/export.go b/cmd/p9/export.go index 1964bae..464af52 100644 --- a/cmd/p9/export.go +++ b/cmd/p9/export.go @@ -8,6 +8,7 @@ import ( "os/signal" "github.com/DeedleFake/p9" + "github.com/DeedleFake/p9/internal/util" "github.com/DeedleFake/p9/proto" ) @@ -34,7 +35,7 @@ func (cmd *exportCmd) Run(options GlobalOptions, args []string) error { rw := fset.Bool("rw", false, "Make exported FS writable.") err := fset.Parse(args[1:]) if err != nil { - return fmt.Errorf("parse flags: %w", err) + return util.Errorf("parse flags: %w", err) } args = fset.Args() @@ -51,7 +52,7 @@ func (cmd *exportCmd) Run(options GlobalOptions, args []string) error { lis, err := net.Listen(options.Network, options.Address) if err != nil { - return fmt.Errorf("listen: %w", err) + return util.Errorf("listen: %w", err) } defer lis.Close() @@ -63,7 +64,7 @@ func (cmd *exportCmd) Run(options GlobalOptions, args []string) error { p9.FSConnHandler(fs, uint32(options.MSize)), ) if err != nil { - errC <- fmt.Errorf("serve: %w", err) + errC <- util.Errorf("serve: %w", err) } }() diff --git a/cmd/p9/ls.go b/cmd/p9/ls.go index 89405e4..b51a46e 100644 --- a/cmd/p9/ls.go +++ b/cmd/p9/ls.go @@ -9,6 +9,7 @@ import ( "time" "github.com/DeedleFake/p9" + "github.com/DeedleFake/p9/internal/util" ) type lsCmd struct { @@ -36,7 +37,7 @@ func (cmd *lsCmd) Run(options GlobalOptions, args []string) error { fset.BoolVar(&cmd.showDetails, "l", false, "Show details.") err := fset.Parse(args[1:]) if err != nil { - return fmt.Errorf("parse flags: %w", err) + return util.Errorf("parse flags: %w", err) } args = fset.Args() @@ -52,13 +53,13 @@ func (cmd *lsCmd) Run(options GlobalOptions, args []string) error { d, err := a.Open(arg, p9.OREAD) if err != nil { - return fmt.Errorf("open %q: %w", arg, err) + return util.Errorf("open %q: %w", arg, err) } defer d.Close() fi, err := d.Stat("") if err != nil { - return fmt.Errorf("stat %q: %w", arg, err) + return util.Errorf("stat %q: %w", arg, err) } if !fi.IsDir() { @@ -68,7 +69,7 @@ func (cmd *lsCmd) Run(options GlobalOptions, args []string) error { entries, err := d.Readdir() if err != nil { - return fmt.Errorf("read dir %q: %w", arg, err) + return util.Errorf("read dir %q: %w", arg, err) } sort.Slice(entries, func(i1, i2 int) bool { return entries[i1].EntryName < entries[i2].EntryName diff --git a/cmd/p9/p9.go b/cmd/p9/p9.go index 1f23890..85e0d3e 100644 --- a/cmd/p9/p9.go +++ b/cmd/p9/p9.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/DeedleFake/p9" + "github.com/DeedleFake/p9/internal/util" ) const StandardPort = "564" @@ -106,62 +107,54 @@ func (versionCmd) Run(options GlobalOptions, args []string) error { func attach(options GlobalOptions, f func(*p9.Remote) error) error { c, err := p9.Dial(options.Network, options.Address) if err != nil { - return fmt.Errorf("dial %q, %q: %w", options.Network, options.Address, err) + return err } defer c.Close() _, err = c.Handshake(uint32(options.MSize)) if err != nil { - return fmt.Errorf("handshake: %w", err) + return util.Errorf("handshake: %w", err) } a, err := c.Attach(nil, options.UName, options.AName) if err != nil { - return fmt.Errorf("attach %q: %w", options.AName, err) + return util.Errorf("attach %q: %w", options.AName, err) } defer a.Close() return f(a) } -func parseAddr(addr string) (network, host, port string) { - defer func() { - if (len(host) > 0) && (host[0] == '$') { - network, host, port = getNamespaceHost(network, host, port) - } +func parseAddr(addr string) (network, address string) { + switch { + case strings.HasPrefix(addr, "$"): + return getNamespace(addr[1:]) + + case strings.HasPrefix(addr, "./"), strings.HasPrefix(addr, "/"): + return "unix", addr + } - switch port { - case "9fs", "9p": - port = StandardPort + parts := strings.SplitN(addr, ":", 2) + if len(parts) == 2 { + if (parts[1] == "9p") || (parts[1] == "9fs") { + parts[1] = StandardPort } - }() - if (len(addr) > 0) && (addr[0] == '/') { - return "unix", addr, "" + return "tcp", strings.Join(parts, ":") } - parts := strings.SplitN(addr, "!", 3) + parts = strings.SplitN(addr, "!", 3) switch len(parts) { - case 0: - return "tcp", "localhost", StandardPort - - case 1: - port = StandardPort - sub := strings.SplitN(parts[0], ":", 2) - host = sub[0] - if len(sub) == 2 { - port = sub[1] - } - return "tcp", host, port - case 2: - return parts[0], parts[1], "" - + return parts[0], parts[1] + ":" + StandardPort case 3: - return parts[0], parts[1], parts[2] + if (parts[2] == "9p") || (parts[2] == "9fs") { + parts[2] = StandardPort + } + return parts[0], strings.Join(parts[1:], ":") } - panic("This should never be reached.") + return "tcp", addr + ":" + StandardPort } type GlobalOptions struct { @@ -187,7 +180,7 @@ func main() { flag.StringVar( &options.Address, "addr", - "localhost:"+StandardPort, + "", "When acting as a server, the address to bind to. When acting as a client, the address to connect to.", ) flag.UintVar( @@ -201,15 +194,7 @@ func main() { help := flag.Bool("help", false, "Show this help.") flag.Parse() - n, a, p := parseAddr(options.Address) - if (p == "") && strings.HasPrefix(a, "tcp") { - p = StandardPort - } - options.Network = n - options.Address = a - if p != "" { - options.Address += ":" + p - } + options.Network, options.Address = parseAddr(options.Address) runCommand := func(c Command) { err := c.Run(options, flag.Args()) diff --git a/cmd/p9/p9_other.go b/cmd/p9/p9_other.go index 2b5f501..0db015e 100644 --- a/cmd/p9/p9_other.go +++ b/cmd/p9/p9_other.go @@ -2,6 +2,20 @@ package main -func getNamespaceHost(network, host, port string) (string, string, string) { - return network, host, port +import ( + "os" + "os/user" + "path/filepath" +) + +func getNamespace(name string) (network, addr string) { + u, err := user.Current() + if err != nil { + panic(err) + } + + nsdir := filepath.Join(os.TempDir(), "ns."+u.Username+".:0") + os.MkdirAll(nsdir, 0700) + + return "unix", filepath.Join(nsdir, name) } diff --git a/cmd/p9/p9_unix.go b/cmd/p9/p9_unix.go index e4518fc..039a6fc 100644 --- a/cmd/p9/p9_unix.go +++ b/cmd/p9/p9_unix.go @@ -8,14 +8,14 @@ import ( "path/filepath" ) -func getNamespaceHost(network, host, port string) (string, string, string) { +func getNamespace(name string) (network, addr string) { u, err := user.Current() if err != nil { panic(err) } nsdir := filepath.Join("/", "tmp", "ns."+u.Username+".:0") - _ = os.MkdirAll(nsdir, 0700) + os.MkdirAll(nsdir, 0700) - return "unix", filepath.Join(nsdir, host[1:]), "" + return "unix", filepath.Join(nsdir, name) } diff --git a/cmd/p9/read.go b/cmd/p9/read.go index 4544b38..ad42e1b 100644 --- a/cmd/p9/read.go +++ b/cmd/p9/read.go @@ -9,6 +9,7 @@ import ( "path" "github.com/DeedleFake/p9" + "github.com/DeedleFake/p9/internal/util" ) type readCmd struct { @@ -36,7 +37,7 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { fset.BoolVar(&cmd.tar, "tar", false, "Output files as tar.") err := fset.Parse(args[1:]) if err != nil { - return fmt.Errorf("parse flags: %v", err) + return util.Errorf("parse flags: %v", err) } args = fset.Args() @@ -51,7 +52,7 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { _, err = io.Copy(os.Stdout, f) if err != nil { - return fmt.Errorf("read %q: %w", arg, err) + return util.Errorf("read %q: %w", arg, err) } return nil @@ -66,7 +67,7 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { fi, err := f.Stat("") if err != nil { - return fmt.Errorf("stat %q: %w", arg, err) + return util.Errorf("stat %q: %w", arg, err) } switch { @@ -75,13 +76,13 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { case fi.IsDir(): children, err := f.Readdir() if err != nil { - return fmt.Errorf("read dir %q: %w", arg, err) + return util.Errorf("read dir %q: %w", arg, err) } for _, c := range children { cf, err := f.Open(c.EntryName, p9.OREAD) if err != nil { - return fmt.Errorf("open %q: %w", path.Join(arg, c.EntryName), err) + return util.Errorf("open %q: %w", path.Join(arg, c.EntryName), err) } err = writeFile(path.Join(arg, c.EntryName), cf) @@ -93,7 +94,7 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { default: hdr, err := tar.FileInfoHeader(fi, "") if err != nil { - return fmt.Errorf("file info header for %q: %w", arg, err) + return util.Errorf("file info header for %q: %w", arg, err) } hdr.Name = arg hdr.Uname = fi.UID @@ -101,12 +102,12 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { err = out.WriteHeader(hdr) if err != nil { - return fmt.Errorf("write header for %q: %w", arg, err) + return util.Errorf("write header for %q: %w", arg, err) } _, err = io.Copy(out, f) if err != nil { - return fmt.Errorf("read %q: %w", arg, err) + return util.Errorf("read %q: %w", arg, err) } } @@ -118,7 +119,7 @@ func (cmd *readCmd) Run(options GlobalOptions, args []string) error { for _, arg := range args { f, err := a.Open(arg, p9.OREAD) if err != nil { - return fmt.Errorf("open %q: %w", arg, err) + return util.Errorf("open %q: %w", arg, err) } err = writeFile(arg, f) diff --git a/cmd/p9/stat.go b/cmd/p9/stat.go index 324caf0..93532c8 100644 --- a/cmd/p9/stat.go +++ b/cmd/p9/stat.go @@ -8,6 +8,7 @@ import ( "text/tabwriter" "github.com/DeedleFake/p9" + "github.com/DeedleFake/p9/internal/util" ) type statCmd struct{} @@ -33,7 +34,7 @@ func (cmd *statCmd) Run(options GlobalOptions, args []string) error { format := fset.String("f", "text", "Output format. Supported formats are text and json.") err := fset.Parse(args[1:]) if err != nil { - return fmt.Errorf("parse flags: %w", err) + return util.Errorf("parse flags: %w", err) } p := map[string]func(p9.DirEntry){ @@ -60,7 +61,7 @@ func (cmd *statCmd) Run(options GlobalOptions, args []string) error { for i, arg := range args { fi, err := a.Stat(arg) if err != nil { - return fmt.Errorf("stat %q: %w", arg, err) + return util.Errorf("stat %q: %w", arg, err) } p(fi) diff --git a/cmd/p9/write.go b/cmd/p9/write.go index 0d75e54..f04c719 100644 --- a/cmd/p9/write.go +++ b/cmd/p9/write.go @@ -7,6 +7,7 @@ import ( "os" "github.com/DeedleFake/p9" + "github.com/DeedleFake/p9/internal/util" ) type writeCmd struct{} @@ -37,7 +38,7 @@ func (cmd *writeCmd) Run(options GlobalOptions, args []string) error { ) err := fset.Parse(args[1:]) if err != nil { - return fmt.Errorf("parse flags: %v", err) + return util.Errorf("parse flags: %v", err) } args = fset.Args() @@ -65,20 +66,20 @@ func (cmd *writeCmd) Run(options GlobalOptions, args []string) error { f, err := open() if err != nil { - return fmt.Errorf("open %q: %v", args[0], err) + return util.Errorf("open %q: %v", args[0], err) } defer f.Close() if *app { _, err := f.Seek(0, io.SeekEnd) if err != nil { - return fmt.Errorf("seek %q: %v", args[0], err) + return util.Errorf("seek %q: %v", args[0], err) } } _, err = io.Copy(f, os.Stdin) if err != nil { - return fmt.Errorf("write %q: %v", args[0], err) + return util.Errorf("write %q: %v", args[0], err) } return nil diff --git a/encoding.go b/encoding.go index 5b25d68..7a3ddfa 100644 --- a/encoding.go +++ b/encoding.go @@ -1,7 +1,6 @@ package p9 import ( - "errors" "io" "github.com/DeedleFake/p9/proto" @@ -20,7 +19,7 @@ func ReadDir(r io.Reader) ([]DirEntry, error) { var stat Stat err := proto.Read(r, &stat) if err != nil { - if errors.Is(err, io.EOF) { + if err == io.EOF { err = nil } return entries, err diff --git a/fs.go b/fs.go index b55782f..da51f1c 100644 --- a/fs.go +++ b/fs.go @@ -2,7 +2,6 @@ package p9 import ( "bytes" - "errors" "fmt" "io" "path" @@ -524,7 +523,7 @@ func (h *fsHandler) read(msg Tread) interface{} { // the specification, however, so it's probably not really an // issue. tmp, err := file.dir.Read(buf) - if (err != nil) && !errors.Is(err, io.EOF) { + if (err != nil) && (err != io.EOF) { return Rerror{ Ename: err.Error(), } @@ -533,7 +532,7 @@ func (h *fsHandler) read(msg Tread) interface{} { default: tmp, err := file.file.ReadAt(buf, int64(msg.Offset)) - if (err != nil) && !errors.Is(err, io.EOF) { + if (err != nil) && (err != io.EOF) { return Rerror{ Ename: err.Error(), } diff --git a/internal/util/util.go b/internal/util/util.go index cca30c2..b5708e7 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -1,6 +1,7 @@ package util import ( + "fmt" "io" ) @@ -36,3 +37,16 @@ func (lr *LimitedReader) Read(buf []byte) (int, error) { lr.N -= uint32(n) return n, err } + +// Errorf is a variant of fmt.Errorf that returns an error being +// wrapped directly if it is one of a number of specific values, such +// as nil or io.EOF. +func Errorf(str string, args ...interface{}) error { + for _, arg := range args { + if arg == io.EOF { + return arg.(error) + } + } + + return fmt.Errorf(str, args...) +} diff --git a/proto/client.go b/proto/client.go index 85e9fe8..b4af3d5 100644 --- a/proto/client.go +++ b/proto/client.go @@ -2,7 +2,6 @@ package proto import ( "context" - "errors" "io" "log" "net" @@ -90,7 +89,7 @@ func (c *Client) reader(ctx context.Context) { msg, tag, err := c.p.Receive(c.c, c.Msize()) if err != nil { - if (ctx.Err() != nil) || errors.Is(err, io.EOF) { + if (ctx.Err() != nil) || (err == io.EOF) { return } diff --git a/proto/encoding.go b/proto/encoding.go index 3265308..3070fa1 100644 --- a/proto/encoding.go +++ b/proto/encoding.go @@ -2,11 +2,12 @@ package proto import ( "encoding/binary" - "fmt" "io" "reflect" "time" "unsafe" + + "github.com/DeedleFake/p9/internal/util" ) // Size returns the size of a message after encoding. @@ -101,7 +102,7 @@ func (e *encoder) encode(v reflect.Value) { } default: - e.err = fmt.Errorf("invalid type: %T", v) + e.err = util.Errorf("invalid type: %T", v) } } @@ -173,7 +174,7 @@ func (d *decoder) decode(v reflect.Value) { } default: - d.err = fmt.Errorf("invalid type: %T", v) + d.err = util.Errorf("invalid type: %T", v) } } diff --git a/proto/proto.go b/proto/proto.go index 40ff563..002e855 100644 --- a/proto/proto.go +++ b/proto/proto.go @@ -4,7 +4,6 @@ package proto import ( "errors" - "fmt" "io" "reflect" @@ -66,11 +65,11 @@ func (p Proto) Receive(r io.Reader, msize uint32) (msg interface{}, tag uint16, var size uint32 err = Read(r, &size) if err != nil { - return nil, NoTag, fmt.Errorf("receive: %w", err) + return nil, NoTag, util.Errorf("receive: %w", err) } if (msize > 0) && (size > msize) { - return nil, NoTag, fmt.Errorf("receive: %w", ErrLargeMessage) + return nil, NoTag, util.Errorf("receive: %w", ErrLargeMessage) } lr := &util.LimitedReader{ @@ -86,7 +85,7 @@ func (p Proto) Receive(r io.Reader, msize uint32) (msg interface{}, tag uint16, err = Read(lr, v) if err != nil { - err = fmt.Errorf("receive: %w", err) + err = util.Errorf("receive: %w", err) } } @@ -99,7 +98,7 @@ func (p Proto) Receive(r io.Reader, msize uint32) (msg interface{}, tag uint16, return nil, NoTag, err } - return nil, NoTag, fmt.Errorf("receive: invalid message type: %v", msgType) + return nil, NoTag, util.Errorf("receive: invalid message type: %v", msgType) } tag = NoTag @@ -116,7 +115,7 @@ func (p Proto) Receive(r io.Reader, msize uint32) (msg interface{}, tag uint16, func (p Proto) Send(w io.Writer, tag uint16, msg interface{}) (err error) { msgType, ok := p.IDFromType(reflect.Indirect(reflect.ValueOf(msg)).Type()) if !ok { - return fmt.Errorf("send: invalid message type: %T", msg) + return util.Errorf("send: invalid message type: %T", msg) } write := func(v interface{}) { @@ -126,13 +125,13 @@ func (p Proto) Send(w io.Writer, tag uint16, msg interface{}) (err error) { err = Write(w, v) if err != nil { - err = fmt.Errorf("send: %w", err) + err = util.Errorf("send: %w", err) } } n, err := Size(msg) if err != nil { - return fmt.Errorf("send: %w", err) + return util.Errorf("send: %w", err) } write(4 + 1 + 2 + n) diff --git a/proto/server.go b/proto/server.go index 8de4da2..9d22a84 100644 --- a/proto/server.go +++ b/proto/server.go @@ -1,7 +1,6 @@ package proto import ( - "errors" "io" "log" "net" @@ -70,7 +69,7 @@ func handleMessages(c net.Conn, p Proto, handler MessageHandler) { for { tmsg, tag, err := p.Receive(c, msize) if err != nil { - if errors.Is(err, io.EOF) { + if err == io.EOF { return } diff --git a/remote.go b/remote.go index f3c387f..1fcc39c 100644 --- a/remote.go +++ b/remote.go @@ -3,11 +3,12 @@ package p9 import ( "bufio" "errors" - "fmt" "io" "path" "strings" "sync" + + "github.com/DeedleFake/p9/internal/util" ) // Remote provides a file-like interface for performing operations on @@ -172,7 +173,7 @@ func (file *Remote) Seek(offset int64, whence int) (int64, error) { return npos, nil } - panic(fmt.Errorf("Invalid whence: %v", whence)) + panic(util.Errorf("Invalid whence: %v", whence)) } // Read reads from the file at the internally-tracked offset. For more