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:
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