lib9p

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

fs.go (3246B)


      1 // Package diskfs provides a glue layer between OS's file system and
      2 // 9P file system. It can be used to export OS's file tree via 9P protocol.
      3 package diskfs
      4 
      5 import (
      6 	"fmt"
      7 	"io/fs"
      8 	"os"
      9 	"os/user"
     10 	"path"
     11 	"path/filepath"
     12 
     13 	"git.mtkn.jp/lib9p"
     14 )
     15 
     16 // FS is a file system to export OS's file system via 9P protocol.
     17 type FS struct {
     18 	rootPath string  // slash-separated.
     19 	qidPool  *QidPool
     20 }
     21 
     22 // Open opens OS's file tree as *FS rooted at name.
     23 // Name is either os.PathSeparator-separated or slash-separated.
     24 func Open(name string) (*FS, error) {
     25 	f, err := os.Open(name)
     26 	if err != nil {
     27 		return nil, err
     28 	}
     29 	defer f.Close()
     30 	fi, err := f.Stat()
     31 	if err != nil {
     32 		return nil, err
     33 	}
     34 	if !fi.IsDir() {
     35 		return nil, fmt.Errorf("not a directory")
     36 	}
     37 	root := &File{
     38 		path: ".",
     39 	}
     40 	fsys := &FS{
     41 		rootPath: filepath.ToSlash(name),
     42 		qidPool:  newQidPool(),
     43 	}
     44 	root.fs = fsys
     45 	return fsys, nil
     46 }
     47 
     48 // OpenFile opens the named file with specified omode by calling os.OpenFile.
     49 // Name is slash separated.
     50 func (fsys *FS) OpenFile(name string, flag int) (lib9p.File, error) {
     51 	if !fs.ValidPath(name) {
     52 		return nil, &fs.PathError{
     53 			Op:   "openfile",
     54 			Path: name,
     55 			Err:  fs.ErrInvalid,
     56 		}
     57 	}
     58 	osf, err := os.OpenFile(path.Join(fsys.rootPath, name), flag, 0)
     59 	if err != nil {
     60 		return nil, &fs.PathError{
     61 			Op:   "openfile",
     62 			Path: name,
     63 			Err:  err,
     64 		}
     65 	}
     66 	return &File{fs: fsys, path: name, file: osf}, nil
     67 }
     68 
     69 // Name is slash-separated.
     70 func (fsys *FS) Create(name string, uid string, omode lib9p.OpenMode, perm lib9p.FileMode) (lib9p.File, error) {
     71 	usr, err := user.Current()
     72 	if err != nil {
     73 		return nil, &fs.PathError{
     74 			Op:   "create",
     75 			Path: name,
     76 			Err:  err,
     77 		}
     78 	}
     79 	if usr.Username != uid {
     80 		return nil, &fs.PathError{
     81 			Op:   "create",
     82 			Path: name,
     83 			Err:  fmt.Errorf("file creation by a user other than the server's " +
     84 				"uid is not implemented"),
     85 		}
     86 	}
     87 	if !fs.ValidPath(name) {
     88 		return nil, &fs.PathError{
     89 			Op:   "create",
     90 			Path: name,
     91 			Err:  fs.ErrInvalid,
     92 		}
     93 	}
     94 	ospath := path.Join(fsys.rootPath, name)
     95 	var flag int
     96 	switch omode & 3 {
     97 	case lib9p.OREAD, lib9p.OEXEC:
     98 		flag = os.O_RDONLY
     99 	case lib9p.OWRITE:
    100 		flag = os.O_WRONLY
    101 	case lib9p.ORDWR:
    102 		flag = os.O_RDWR
    103 	}
    104 	if omode&lib9p.OTRUNC != 0 {
    105 		flag |= os.O_TRUNC
    106 	}
    107 	// ORCLOSE is handled by the library.
    108 	var osfile *os.File
    109 	if perm&os.ModeDir != 0 {
    110 		if err := os.Mkdir(ospath, perm); err != nil {
    111 			return nil, &fs.PathError{
    112 				Op:   "create",
    113 				Path: name,
    114 				Err:  fmt.Errorf("mkdir: %v", err),
    115 			}
    116 		}
    117 		osfile, err = os.OpenFile(ospath, flag, 0)
    118 		if err != nil {
    119 			return nil, &fs.PathError{
    120 				Op:   "create",
    121 				Path: name,
    122 				Err:  err,
    123 			}
    124 		}
    125 	} else {
    126 		flag |= os.O_CREATE
    127 		osfile, err = os.OpenFile(ospath, flag, perm)
    128 		if err != nil {
    129 			return nil, &fs.PathError{
    130 				Op:   "create",
    131 				Path: name,
    132 				Err:  err,
    133 			}
    134 		}
    135 	}
    136 	return &File{
    137 		fs:   fsys,
    138 		path: name,
    139 		file: osfile,
    140 	}, nil
    141 }
    142 
    143 func (fsys *FS) Remove(name string) error {
    144 	ospath := path.Join(fsys.rootPath, name)
    145 	return os.Remove(ospath)
    146 }
    147 
    148 func (fsys *FS) IsGroupLeader(group, uid string) bool {
    149 	return isGroupLeader(group, uid)
    150 }
    151 
    152 func (fsys *FS) IsGroupMember(group, uid string) bool {
    153 	return isGroupMember(group, uid)
    154 }