lib9p

Go 9P library.
Log | Files | Refs | LICENSE

commit 63cee6f48d6426cf99b7aa3a527f2e28e69dc487
parent d32705f63386c6e1f251a5e43f0f8421fae4a768
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Thu, 11 Jan 2024 07:52:52 +0900

change FS interface to use integer flag in OpenFile

Diffstat:
Mexport_fs.go | 2+-
Mfid.go | 17+++++++++++++++++
Mfile_test.go | 2+-
Mfs.go | 18++++++++++++++++--
Mfs_test.go | 2+-
Mreq_test.go | 2+-
Mserver.go | 22++++++++++------------
Mserver_test.go | 4++--
8 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/export_fs.go b/export_fs.go @@ -11,7 +11,7 @@ type ExportFS struct { } func (fsys ExportFS) Open(name string) (fs.File, error) { - f, err := fsys.OpenFile(name, OREAD) + f, err := fsys.OpenFile(name, O_RDONLY) return ExportFile{f}, err } diff --git a/fid.go b/fid.go @@ -21,6 +21,23 @@ const ( ORCLOSE = 64 ) +func modeToFlag(m OpenMode) int { + var flag int + switch m&3 { + case OREAD, OEXEC: + flag = O_RDONLY + case OWRITE: + flag = O_WRONLY + case ORDWR: + flag = O_RDWR + } + if m&OTRUNC != 0 { + flag |= O_TRUNC + } + // ORCLOSE is delt by the library in sClunk. + return flag +} + // An fid represents an fid defined by 9P. // It is used as the identifier of a file in 9P session. // It is specified by the client and the server connects it to a file in the diff --git a/file_test.go b/file_test.go @@ -16,7 +16,7 @@ func BenchmarkRead(b *testing.B) { b.Fatal(err) } fid.omode = OREAD - fid.file, err = testfs.OpenFile("dir/file", OREAD) + fid.file, err = testfs.OpenFile("dir/file", O_RDONLY) if err != nil { b.Fatal(err) } diff --git a/fs.go b/fs.go @@ -2,11 +2,12 @@ package lib9p import ( "io/fs" + "os" ) // An FS is an file system to be exported by 9P server. type FS interface { - // OpenFile opens file named name with omode. + // OpenFile opens file named name with specified flag (O_RDONLY etc.). // // When OpenFile returns an error, it should be of type *fs.PathError // with the Op field set to "openfile", the Path field set to name, @@ -15,9 +16,22 @@ type FS interface { // Open should reject attempts to open names that do not satisfy // fs.ValidPath(name), returning a *fs.PathError with Err set to // fs.ErrInvalid or fs.ErrNotExist. - OpenFile(name string, omode OpenMode) (File, error) + OpenFile(name string, flag int) (File, error) } +const ( + // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified. + O_RDONLY int = os.O_RDONLY // open the file read-only. + O_WRONLY int = os.O_WRONLY // open the file write-only. + O_RDWR int = os.O_RDWR // open the file read-write. + // The remaining values may be or'ed in to control behavior. + O_APPEND int = os.O_APPEND // append data to the file when writing. + O_CREATE int = os.O_CREATE // create a new file if none exists. + O_EXCL int = os.O_EXCL // used with O_CREATE, file must not exist. + O_SYNC int = os.O_SYNC // open for synchronous I/O. + O_TRUNC int = os.O_TRUNC // truncate regular writable file when opened. +) + // A GroupFS is an file system with the notion of group. type GroupFS interface { FS diff --git a/fs_test.go b/fs_test.go @@ -127,7 +127,7 @@ type group struct { members map[string]bool } -func (fs *testFS) OpenFile(path string, omode OpenMode) (File, error) { +func (fs *testFS) OpenFile(path string, flag int) (File, error) { wnames := strings.Split(path, "/") f, err := fs.walk(wnames) if err != nil { diff --git a/req_test.go b/req_test.go @@ -30,7 +30,7 @@ func TestFlush(t *testing.T) { if err != nil { t.Fatal(err) } - fid.file, err = testfs.OpenFile("dir/file", OREAD) + fid.file, err = testfs.OpenFile("dir/file", O_RDONLY) fid.path = "dir/file" fid.omode = ORDWR req := &request{ diff --git a/server.go b/server.go @@ -494,10 +494,10 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { return } var ( - p fs.FileMode - err error - qid Qid - fi fs.FileInfo + p fs.FileMode + err error + qid Qid + fi fs.FileInfo ) ifcall := r.ifcall.(*TOpen) r.fid, ok = c.fPool.lookup(ifcall.Fid) @@ -534,8 +534,6 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { goto resp } switch ifcall.Mode & 3 { - default: - panic("invalid mode") case OREAD: p = AREAD case OWRITE: @@ -582,8 +580,8 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { } continue } - r.fid.omode = r.ifcall.(*TOpen).Mode if _, ok := r.fid.file.(*AuthFile); ok { + r.fid.omode = ifcall.Mode select { case c.respChan <- r: case <-ctx.Done(): @@ -591,9 +589,7 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { } continue } - // OTRUNK is implemented by os.OpenFile's flag O_TRUNC, - // so the truncation shold be done by the implementor of FS. - r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, r.fid.omode) + r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, modeToFlag(ifcall.Mode)) if err != nil { setError(r, err) select { @@ -603,6 +599,8 @@ func sOpen(ctx context.Context, c *conn, rc <-chan *request) { } continue } + // omode should be set after successfully opening it. + r.fid.omode = ifcall.Mode select { case c.respChan <- r: case <-ctx.Done(): @@ -751,7 +749,7 @@ func sRead(ctx context.Context, c *conn, rc <-chan *request) { if err = r.fid.file.Close(); err != nil { return } - r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, r.fid.omode) + r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, modeToFlag(r.fid.omode)) if err != nil { return } @@ -1069,7 +1067,7 @@ func sWStat(ctx context.Context, c *conn, rc <-chan *request) { } if r.fid.omode == -1 { var err error - r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, OREAD) + r.fid.file, err = r.fid.fs.OpenFile(r.fid.path, O_RDONLY) if err != nil { r.err = fmt.Errorf("open: %v", err) goto resp diff --git a/server_test.go b/server_test.go @@ -544,7 +544,7 @@ func TestSRead(t *testing.T) { } func testSRead(t *testing.T, pathname string, c *conn, tc, rc chan *request) { - ff, err := testfs.OpenFile(pathname, OREAD) + ff, err := testfs.OpenFile(pathname, O_RDONLY) if err != nil { t.Fatal(err) } @@ -802,7 +802,7 @@ func TestSRemove(t *testing.T) { i, test.want, ofcall) return } - if _, err := testfs.OpenFile(test.pathname, OREAD); err == nil { + if _, err := testfs.OpenFile(test.pathname, O_RDONLY); err == nil { t.Errorf("%d: file not removed", i) testfs.Remove(test.pathname) return