commit 394806bf11cc201fdb8abcc731966460e485d3dd
parent 8a667df91124da092c26a83a212afbbdd731d72c
Author: Matsuda Kenji <info@mtkn.jp>
Date: Thu, 4 Jan 2024 14:00:02 +0900
delete testfs (wip)
Diffstat:
M | client/client_test.go | | | 83 | +++++++++++++++++-------------------------------------------------------------- |
A | client/conn_test.go | | | 52 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | client/file_test.go | | | 59 | ++++++++++++++++++++++------------------------------------- |
A | client/fs_test.go | | | 254 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | testfs/conn.go | | | 51 | --------------------------------------------------- |
D | testfs/fs.go | | | 254 | ------------------------------------------------------------------------------- |
6 files changed, 346 insertions(+), 407 deletions(-)
diff --git a/client/client_test.go b/client/client_test.go
@@ -1,4 +1,4 @@
-package client_test
+package client
import (
"context"
@@ -6,97 +6,50 @@ import (
"testing"
"git.mtkn.jp/lib9p"
- "git.mtkn.jp/lib9p/client"
- "git.mtkn.jp/lib9p/testfs"
)
-const (
- mSize = 8192
- uname = "kenji"
-)
-
-// the following tests are test for both client and server.
-// should be moved to propper file.
-func TestTransaction(t *testing.T) {
- conn := testfs.SetupConn()
- defer conn.Close()
- bg := context.Background()
- rmsize, rversion, err := conn.C.Version(bg, 0, mSize, "9P2000")
- if err != nil {
- t.Log(err)
- } else {
- t.Log(&lib9p.RVersion{Msize: rmsize, Version: rversion})
- }
- rauth, err := conn.C.Auth(bg, 0, 0, "kenji", "")
- if err != nil {
- t.Log(err)
- } else {
- t.Log(rauth)
- }
- rattach, err := conn.C.Attach(bg, 0, 0, lib9p.NOFID, "kenji", "")
- if err != nil {
- t.Log(err)
- } else {
- t.Log(rattach)
- }
-}
-
-func TestClient2(t *testing.T) {
+func setupClient(fs lib9p.FS) (*Client, context.CancelFunc) {
cr, sw := io.Pipe()
sr, cw := io.Pipe()
- server := lib9p.NewServer(testfs.Fsys)
- //server.Chatty()
- go server.Serve(context.Background(), sr, sw)
- fs, err := client.Mount(cr, cw, "kenji", "")
- if err != nil {
- t.Errorf("mount: %v", err)
- }
- a0, err := fs.OpenFile("a", lib9p.OREAD)
- if err != nil {
- t.Errorf("open: %v", err)
- }
- t.Log(a0)
- a := a0.(*client.File)
- b := make([]byte, 64)
- n, err := a.Read(b)
- if err != nil {
- t.Errorf("read: %v", err)
- }
- t.Log(string(b[:n]))
+ s := lib9p.NewServer(fs)
+ ctx, cancel := context.WithCancel(context.Background())
+ go s.Serve(ctx, sr, sw)
+ c := NewClient(8*1024, "kenji", cr, cw)
+ return c, cancel
}
func TestDupTag(t *testing.T) {
- conn := testfs.SetupConn()
- defer conn.Close()
- testfs.Fsys.Slow = true
- defer func() { testfs.Fsys.Slow = false }()
+ c, cancel := setupClient(testfs)
+ defer cancel()
+ testfs.slow = true
+ defer func() { testfs.slow = false }()
bg := context.Background()
- _, _, err := conn.C.Version(bg, 0, 8*1024, "9P2000")
+ _, _, err := c.Version(bg, 0, 8*1024, "9P2000")
if err != nil {
t.Fatal(err)
}
- _, err = conn.C.Attach(bg, 0, 0, lib9p.NOFID, "kenji", "")
+ _, err = c.Attach(bg, 0, 0, lib9p.NOFID, "kenji", "")
if err != nil {
t.Fatal(err)
}
wname := []string{"a"}
- wqid, err := conn.C.Walk(bg, 0, 0, 1, wname)
+ wqid, err := c.Walk(bg, 0, 0, 1, wname)
if err != nil {
t.Fatal(err)
} else if len(wqid) != len(wname) {
t.Fatal("file not found")
}
- _, _, err = conn.C.Open(bg, 0, 1, lib9p.OREAD)
+ _, _, err = c.Open(bg, 0, 1, lib9p.OREAD)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithCancel(bg)
defer cancel()
go func() {
- _, err = conn.C.Read(ctx, 0, 1, 0, 1024)
+ _, err = c.Read(ctx, 0, 1, 0, 1024)
}()
- <-testfs.Fsys.Waitc
- _, err = conn.C.Stat(bg, 0, 1)
+ <-testfs.waitc
+ _, err = c.Stat(bg, 0, 1)
if err == nil {
t.Error("dup tag not reported")
}
diff --git a/client/conn_test.go b/client/conn_test.go
@@ -0,0 +1,51 @@
+package client
+/*
+import (
+ "context"
+ "io"
+
+ "git.mtkn.jp/lib9p"
+)
+
+type Conn struct {
+ S *lib9p.Server
+ C *Client
+ cr, sr *io.PipeReader
+ cw, sw *io.PipeWriter
+ cancel context.CancelFunc
+}
+
+// SetupTestConn setups a connection between a server and a client and
+// returns those.
+func SetupConn() *Conn {
+ const (
+ mSize = 8 * 1024
+ uname = "kenji"
+ )
+ cr, sw := io.Pipe()
+ sr, cw := io.Pipe()
+ // TODO: fix the inconsistency of server and client api.
+ s := lib9p.NewServer(Fsys)
+ clnt := NewClient(mSize, uname, cr, cw)
+ ctx, cancel := context.WithCancel(context.Background())
+ go s.Serve(ctx, sr, sw)
+ return &Conn{
+ S: s,
+ C: clnt,
+ cr: cr,
+ cw: cw,
+ sr: sr,
+ sw: sw,
+ cancel: cancel,
+ }
+}
+
+func (conn *Conn) Close() {
+ conn.cancel()
+ conn.C.Stop()
+ conn.cw.Close()
+ conn.cr.Close()
+ conn.sw.Close()
+ conn.sr.Close()
+}
+*/
+\ No newline at end of file
diff --git a/client/file_test.go b/client/file_test.go
@@ -1,65 +1,50 @@
-package client_test
+package client
import (
"context"
+ "fmt"
"io"
"path"
"testing"
"git.mtkn.jp/lib9p"
- "git.mtkn.jp/lib9p/client"
- "git.mtkn.jp/lib9p/testfs"
)
-type FS struct {
- *client.FS
- cr, sr *io.PipeReader
- cw, sw *io.PipeWriter
- cancel context.CancelFunc
-}
-
-func mountTestFS(t *testing.T) *FS {
+// cancel is to stop the server.
+func mount(fs lib9p.FS) (cfs *FS, cancel context.CancelFunc, err error) {
cr, sw := io.Pipe()
sr, cw := io.Pipe()
- s := lib9p.NewServer(testfs.Fsys)
+ s := lib9p.NewServer(fs)
ctx, cancel := context.WithCancel(context.Background())
go s.Serve(ctx, sr, sw)
- fsys, err := client.Mount(cr, cw, "ken", "")
+ cfs, err = Mount(cr, cw, "glenda", "")
if err != nil {
- t.Fatal(err)
+ return nil, nil, fmt.Errorf("mount: %v", err)
}
- return &FS{fsys, cr, sr, cw, sw, cancel}
-}
-
-func (fsys *FS) unmount() {
- fsys.Unmount()
- fsys.cancel()
- fsys.cr.Close()
- fsys.cw.Close()
- fsys.sr.Close()
- fsys.sw.Close()
+ return cfs, cancel, nil
}
// TestStat tests whether Stat returns the same lib9p.Stat as testfs.Fsys defines.
// TODO: work in progress.
func TestStat(t *testing.T) {
- fsys := mountTestFS(t)
- defer fsys.unmount()
-
}
// TestReadDir tests whether ReadDir returns the same dir entries as testfs.Fsys
// has.
func TestReadDir(t *testing.T) {
- fsys := mountTestFS(t)
- defer fsys.unmount()
- testReadDir(t, fsys, testfs.Fsys, ".")
+ cfs, cancel, err := mount(testfs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cancel()
+ defer cfs.Unmount()
+ testReadDir(t, cfs, testfs, ".")
}
-func testReadDir(t *testing.T, cfs *FS, tfs *testfs.FS, cwd string) {
+func testReadDir(t *testing.T, cfs *FS, tfs *testFS, cwd string) {
cf, err := cfs.Open(cwd)
if err != nil {
- t.Fatalf("open: %v", err)
+ t.Fatalf("open %s: %v", cwd, err)
}
defer cf.Close()
st, err := cf.Stat()
@@ -69,7 +54,7 @@ func testReadDir(t *testing.T, cfs *FS, tfs *testfs.FS, cwd string) {
if !st.IsDir() {
return
}
- de, err := cf.(*client.File).ReadDir(-1)
+ de, err := cf.(*File).ReadDir(-1)
if err != nil && err != io.EOF {
t.Fatalf("readdir: %v", err)
}
@@ -77,14 +62,14 @@ func testReadDir(t *testing.T, cfs *FS, tfs *testfs.FS, cwd string) {
if err != nil {
t.Fatalf("open: %v", err)
}
- if len(de) != len(tf.(*testfs.File).Children) {
+ if len(de) != len(tf.(*testFile).children) {
t.Fatalf("number of directory entries does not match.: %d != %d",
- len(de), len(tf.(*testfs.File).Children))
+ len(de), len(tf.(*testFile).children))
}
L:
for _, f := range de {
- for _, c := range tf.(*testfs.File).Children {
- if c.St.Name == f.Name() {
+ for _, c := range tf.(*testFile).children {
+ if c.stat.Name == f.Name() {
childPath := path.Join(cwd, f.Name())
testReadDir(t, cfs, tfs, childPath)
continue L
diff --git a/client/fs_test.go b/client/fs_test.go
@@ -0,0 +1,254 @@
+package client
+
+import (
+ "bytes"
+ "fmt"
+ "io/fs"
+ "strings"
+
+ "git.mtkn.jp/lib9p"
+)
+
+type testFile struct {
+ // fsys is the testFS this testFile belongs to.
+ fsys *testFS
+ // parent is the parent directory this testFile located at.
+ parent *testFile
+ // children is the child files this testFile has.
+ // It is nil if this testFile is not a directory
+ children []*testFile
+ // content is the content of this testFile.
+ // It is nil if this testFile is a directory
+ content []byte
+ // r is used if this testFile is not a directory and
+ // when this testFile is read.
+ // It contains content.
+ r *bytes.Reader
+ // stat is the Stat of this testFile.
+ stat lib9p.Stat
+}
+
+func (f *testFile) Stat() (*lib9p.FileInfo, error) {
+ return &lib9p.FileInfo{Stat: f.stat}, nil
+}
+
+func (f *testFile) Close() error {
+ f.r = nil
+ return nil
+}
+
+func (f *testFile) Read(b []byte) (int, error) {
+ if f.fsys.slow {
+ f.fsys.waitc <- struct{}{}
+ <-f.fsys.waitc
+ }
+ return f.r.Read(b)
+}
+
+func (f *testFile) ReadAt(b []byte, off int64) (n int, err error) {
+ if f.fsys.slow {
+ f.fsys.waitc <- struct{}{}
+ <-f.fsys.waitc
+ }
+ return f.r.ReadAt(b, off)
+}
+
+func (f *testFile) ReadDir(n int) ([]fs.DirEntry, error) {
+ de := make([]fs.DirEntry, len(f.children))
+ for i, c := range f.children {
+ info, _ := c.Stat()
+ de[i] = info
+ }
+ return de, nil
+}
+
+func (f *testFile) WriteAt(p []byte, off int64) (int, error) {
+ if f.fsys.slow {
+ f.fsys.waitc <- struct{}{}
+ }
+ if f.r == nil {
+ return 0, fmt.Errorf("not open")
+ }
+ if off < 0 || off > int64(len(f.content)) {
+ return 0, fmt.Errorf("bad offset")
+ }
+ if off+int64(len(p)) > int64(len(f.content)) {
+ newcon := make([]byte, off+int64(len(p)))
+ copy(newcon, f.content)
+ f.content = newcon
+ }
+ copy(f.content[off:], p)
+ f.r.Reset(f.content)
+ if f.fsys.slow {
+ <-f.fsys.waitc
+ }
+ return len(p), nil
+}
+
+type testFS struct {
+ // root is the root testFile of this file system.
+ root *testFile
+ // If slow is true, each function on files of this testFS waits for
+ // something arrives on waitc.
+ slow bool
+ // waitc is used to wait some timing to emulate slow response.
+ waitc chan struct{}
+ // groups holds the information of groups and it leader and members.
+ groups map[string]group
+}
+
+type group struct {
+ leader string
+ members map[string]bool
+}
+
+func (fs *testFS) OpenFile(path string, omode lib9p.OpenMode) (lib9p.File, error) {
+ wnames := strings.Split(path, "/")
+ f, err := fs.Walk(wnames)
+ if err != nil {
+ return nil, fmt.Errorf("walk: %v", err)
+ }
+ f.r = bytes.NewReader(f.content)
+ return f, nil
+}
+
+func (fs *testFS) IsGroupLeader(gid, uid string) bool {
+ g, ok := fs.groups[gid]
+ if !ok {
+ return false
+ }
+ return g.leader == uid
+}
+
+func (fs *testFS) IsGroupMember(gid, uid string) bool {
+ g, ok := fs.groups[gid]
+ if !ok {
+ return false
+ }
+ return g.members[uid]
+}
+
+func (fs *testFS) Walk(wnames []string) (*testFile, error) {
+ if len(wnames) == 1 && (wnames[0] == "." || wnames[0] == "") {
+ return fs.root, nil
+ }
+ cwd := fs.root
+L:
+ for i, name := range wnames {
+ for _, child := range cwd.children {
+ if child.stat.Name == name {
+ cwd = child
+ continue L
+ }
+ }
+ return nil, fmt.Errorf("%s not found", strings.Join(wnames[:i+1], "/"))
+ }
+ return cwd, nil
+}
+
+func (fs *testFS) WalkPath(pathname string) (*testFile, error) {
+ wnames := strings.Split(pathname, "/")
+ return fs.Walk(wnames)
+}
+
+var testfs *testFS
+
+func init() {
+ testfs = &testFS{
+ root: &testFile{
+ stat: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 0, Type: lib9p.QTDIR},
+ Mode: lib9p.FileMode(fs.ModeDir | 0755),
+ Name: "root",
+ Uid: "glenda",
+ Gid: "glenda",
+ Muid: "glenda",
+ },
+ children: []*testFile{
+ &testFile{
+ content: []byte("a\n"),
+ stat: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 1, Type: lib9p.QTFILE},
+ Mode: lib9p.FileMode(0644),
+ Name: "a",
+ Uid: "glenda",
+ Gid: "glenda",
+ Muid: "glenda",
+ },
+ },
+ &testFile{
+ content: []byte("b\n"),
+ stat: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 2, Type: lib9p.QTFILE},
+ Mode: lib9p.FileMode(0600),
+ Name: "b",
+ Uid: "ken",
+ Gid: "ken",
+ Muid: "ken",
+ },
+ },
+ &testFile{
+ stat: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 3, Type: lib9p.QTDIR},
+ Mode: lib9p.FileMode(fs.ModeDir | 0755),
+ Name: "dir",
+ Uid: "rob",
+ Gid: "rob",
+ Muid: "rob",
+ },
+ children: []*testFile{
+ &testFile{
+ content: []byte("unko\n"),
+ stat: lib9p.Stat{
+ Qid: lib9p.Qid{Path: 4, Type: lib9p.QTFILE},
+ Mode: lib9p.FileMode(0666),
+ Name: "file",
+ Uid: "brian",
+ Gid: "brian",
+ Muid: "dennis",
+ },
+ },
+ },
+ },
+ },
+ },
+ waitc: make(chan struct{}),
+ groups: map[string]group{
+ "bell": group{
+ leader: "glenda",
+ members: map[string]bool{
+ "glenda": true,
+ "ken": true,
+ "dennis": true,
+ "brian": true,
+ "rob": true,
+ },
+ },
+ "kessoku": group{
+ leader: "ijichi",
+ members: map[string]bool{
+ "ijichi": true,
+ "yamada": true,
+ "gotoh": true,
+ "kita": true,
+ },
+ },
+ },
+ }
+ SetfsysAndparent(testfs, nil)
+}
+
+// SetfsysAndparent sets file.fsys and file.parent for every file in the fsys.
+// Pass nil as file to setup entire file system.
+func SetfsysAndparent(fsys *testFS, file *testFile) {
+ if file == nil {
+ file = fsys.root
+ file.parent = fsys.root
+ file.fsys = fsys
+ }
+ for _, child := range file.children {
+ child.parent = file
+ child.fsys = fsys
+ SetfsysAndparent(fsys, child)
+ }
+}
diff --git a/testfs/conn.go b/testfs/conn.go
@@ -1,51 +0,0 @@
-package testfs
-
-import (
- "context"
- "io"
-
- "git.mtkn.jp/lib9p"
- "git.mtkn.jp/lib9p/client"
-)
-
-type Conn struct {
- S *lib9p.Server
- C *client.Client
- cr, sr *io.PipeReader
- cw, sw *io.PipeWriter
- cancel context.CancelFunc
-}
-
-// SetupTestConn setups a connection between a server and a client and
-// returns those.
-func SetupConn() *Conn {
- const (
- mSize = 8 * 1024
- uname = "kenji"
- )
- cr, sw := io.Pipe()
- sr, cw := io.Pipe()
- // TODO: fix the inconsistency of server and client api.
- s := lib9p.NewServer(Fsys)
- clnt := client.NewClient(mSize, uname, cr, cw)
- ctx, cancel := context.WithCancel(context.Background())
- go s.Serve(ctx, sr, sw)
- return &Conn{
- S: s,
- C: clnt,
- cr: cr,
- cw: cw,
- sr: sr,
- sw: sw,
- cancel: cancel,
- }
-}
-
-func (conn *Conn) Close() {
- conn.cancel()
- conn.C.Stop()
- conn.cw.Close()
- conn.cr.Close()
- conn.sw.Close()
- conn.sr.Close()
-}
diff --git a/testfs/fs.go b/testfs/fs.go
@@ -1,254 +0,0 @@
-package testfs
-
-import (
- "bytes"
- "fmt"
- "io/fs"
- "strings"
-
- "git.mtkn.jp/lib9p"
-)
-
-type File struct {
- // Fsys is the FS this File belongs to.
- Fsys *FS
- // Parent is the parent directory this File located at.
- Parent *File
- // Children is the child files this File has.
- // It is nil if this File is not a directory
- Children []*File
- // Content is the content of this File.
- // It is nil if this File is a directory
- Content []byte
- // Reader is used if this File is not a directory and
- // when this File is read.
- // It contains Content.
- Reader *bytes.Reader
- // St is the Stat of this File.
- St lib9p.Stat
-}
-
-func (f *File) Stat() (*lib9p.FileInfo, error) {
- return &lib9p.FileInfo{Stat: f.St}, nil
-}
-
-func (f *File) Close() error {
- f.Reader = nil
- return nil
-}
-
-func (f *File) Read(b []byte) (int, error) {
- if f.Fsys.Slow {
- f.Fsys.Waitc <- struct{}{}
- <-f.Fsys.Waitc
- }
- return f.Reader.Read(b)
-}
-
-func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
- if f.Fsys.Slow {
- f.Fsys.Waitc <- struct{}{}
- <-f.Fsys.Waitc
- }
- return f.Reader.ReadAt(b, off)
-}
-
-func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
- de := make([]fs.DirEntry, len(f.Children))
- for i, c := range f.Children {
- info, _ := c.Stat()
- de[i] = info
- }
- return de, nil
-}
-
-func (f *File) WriteAt(p []byte, off int64) (int, error) {
- if f.Fsys.Slow {
- f.Fsys.Waitc <- struct{}{}
- }
- if f.Reader == nil {
- return 0, fmt.Errorf("not open")
- }
- if off < 0 || off > int64(len(f.Content)) {
- return 0, fmt.Errorf("bad offset")
- }
- if off+int64(len(p)) > int64(len(f.Content)) {
- newcon := make([]byte, off+int64(len(p)))
- copy(newcon, f.Content)
- f.Content = newcon
- }
- copy(f.Content[off:], p)
- f.Reader.Reset(f.Content)
- if f.Fsys.Slow {
- <-f.Fsys.Waitc
- }
- return len(p), nil
-}
-
-type FS struct {
- // Root is the root File of this file system.
- Root *File
- // If Slow is true, each function on files of this FS waits for
- // something arrives on Waitc.
- Slow bool
- // Waitc is used to wait some timing to emulate slow response.
- Waitc chan struct{}
- // groups holds the information of groups and it leader and members.
- groups map[string]group
-}
-
-type group struct {
- leader string
- members map[string]bool
-}
-
-func (fs *FS) OpenFile(path string, omode lib9p.OpenMode) (lib9p.File, error) {
- wnames := strings.Split(path, "/")
- f, err := fs.Walk(wnames)
- if err != nil {
- return nil, fmt.Errorf("walk: %v", err)
- }
- f.Reader = bytes.NewReader(f.Content)
- return f, nil
-}
-
-func (fs *FS) IsGroupLeader(gid, uid string) bool {
- g, ok := fs.groups[gid]
- if !ok {
- return false
- }
- return g.leader == uid
-}
-
-func (fs *FS) IsGroupMember(gid, uid string) bool {
- g, ok := fs.groups[gid]
- if !ok {
- return false
- }
- return g.members[uid]
-}
-
-func (fs *FS) Walk(wnames []string) (*File, error) {
- if len(wnames) == 1 && (wnames[0] == "." || wnames[0] == "") {
- return fs.Root, nil
- }
- cwd := fs.Root
-L:
- for i, name := range wnames {
- for _, child := range cwd.Children {
- if child.St.Name == name {
- cwd = child
- continue L
- }
- }
- return nil, fmt.Errorf("%s not found", strings.Join(wnames[:i+1], "/"))
- }
- return cwd, nil
-}
-
-func (fs *FS) WalkPath(pathname string) (*File, error) {
- wnames := strings.Split(pathname, "/")
- return fs.Walk(wnames)
-}
-
-var Fsys *FS
-
-func init() {
- Fsys = &FS{
- Root: &File{
- St: lib9p.Stat{
- Qid: lib9p.Qid{Path: 0, Type: lib9p.QTDIR},
- Mode: lib9p.FileMode(fs.ModeDir | 0755),
- Name: "root",
- Uid: "glenda",
- Gid: "glenda",
- Muid: "glenda",
- },
- Children: []*File{
- &File{
- Content: []byte("a\n"),
- St: lib9p.Stat{
- Qid: lib9p.Qid{Path: 1, Type: lib9p.QTFILE},
- Mode: lib9p.FileMode(0644),
- Name: "a",
- Uid: "glenda",
- Gid: "glenda",
- Muid: "glenda",
- },
- },
- &File{
- Content: []byte("b\n"),
- St: lib9p.Stat{
- Qid: lib9p.Qid{Path: 2, Type: lib9p.QTFILE},
- Mode: lib9p.FileMode(0600),
- Name: "b",
- Uid: "ken",
- Gid: "ken",
- Muid: "ken",
- },
- },
- &File{
- St: lib9p.Stat{
- Qid: lib9p.Qid{Path: 3, Type: lib9p.QTDIR},
- Mode: lib9p.FileMode(fs.ModeDir | 0755),
- Name: "dir",
- Uid: "rob",
- Gid: "rob",
- Muid: "rob",
- },
- Children: []*File{
- &File{
- Content: []byte("unko\n"),
- St: lib9p.Stat{
- Qid: lib9p.Qid{Path: 4, Type: lib9p.QTFILE},
- Mode: lib9p.FileMode(0666),
- Name: "file",
- Uid: "brian",
- Gid: "brian",
- Muid: "dennis",
- },
- },
- },
- },
- },
- },
- Waitc: make(chan struct{}),
- groups: map[string]group{
- "bell": group{
- leader: "glenda",
- members: map[string]bool{
- "glenda": true,
- "ken": true,
- "dennis": true,
- "brian": true,
- "rob": true,
- },
- },
- "kessoku": group{
- leader: "ijichi",
- members: map[string]bool{
- "ijichi": true,
- "yamada": true,
- "gotoh": true,
- "kita": true,
- },
- },
- },
- }
- SetFsysAndParent(Fsys, nil)
-}
-
-// SetFsysAndParent sets file.fsys and file.parent for every file in the fsys.
-// Pass nil as file to setup entire file system.
-func SetFsysAndParent(fsys *FS, file *File) {
- if file == nil {
- file = fsys.Root
- file.Parent = fsys.Root
- file.Fsys = fsys
- }
- for _, child := range file.Children {
- child.Parent = file
- child.Fsys = fsys
- SetFsysAndParent(fsys, child)
- }
-}