lib9p

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

fid.go (3657B)


      1 package lib9p
      2 
      3 import (
      4 	"fmt"
      5 	"io/fs"
      6 	"sync"
      7 )
      8 
      9 // An OpenMode is the mode of an open file.
     10 // This is used by fid structure.
     11 // If the file is not open, the mode must be -1.
     12 type OpenMode int8
     13 
     14 const (
     15 	OREAD  OpenMode = 0
     16 	OWRITE          = 1
     17 	ORDWR           = 2
     18 	OEXEC           = 3
     19 
     20 	OTRUNC  = 16
     21 	ORCLOSE = 64
     22 )
     23 
     24 // ModeToFlag converts OpenMode (OREAD etc.) to open flag (O_RDONLY etc.).
     25 // ORCLOSE is not implemented and ignored silently.
     26 // O_APPEND, O_CREATE, O_EXCL, O_SYNC can't be specified.
     27 func ModeToFlag(m OpenMode) int {
     28 	var flag int
     29 	switch m & 3 {
     30 	case OREAD, OEXEC:
     31 		flag = O_RDONLY
     32 	case OWRITE:
     33 		flag = O_WRONLY
     34 	case ORDWR:
     35 		flag = O_RDWR
     36 	}
     37 	if m&OTRUNC != 0 {
     38 		flag |= O_TRUNC
     39 	}
     40 	// ORCLOSE is delt by the library in sClunk.
     41 	return flag
     42 }
     43 
     44 // FlugToMode converts open flag (O_RDONLY etc.) to OpenMode (OREAD etc.).
     45 // O_APPEND, O_CREATE, O_EXCL, O_SYNC are not implemented and ignored silently.
     46 // ORCLOSE can't be specified.
     47 func FlagToMode(f int) OpenMode {
     48 	var m OpenMode
     49 	switch {
     50 	case f&O_RDONLY != 0:
     51 		m = OREAD
     52 	case f&O_WRONLY != 0:
     53 		m = OWRITE
     54 	case f&O_RDWR != 0:
     55 		m = ORDWR
     56 	}
     57 	if f&O_TRUNC != 0 {
     58 		m |= OTRUNC
     59 	}
     60 	return m
     61 }
     62 
     63 // An fid represents an fid defined by 9P.
     64 // It is used as the identifier of a file in 9P session.
     65 // It is specified by the client and the server connects it to a file in the
     66 // file system.
     67 // Multiple fids can be connected to a single file.
     68 // On the other hand, a Qid is the Identifier in the file system itself,
     69 // and does not change between 9P sessions.
     70 type fid struct {
     71 	fid       uint32
     72 	omode     OpenMode /* -1 = not open */
     73 	path      string   // The path from the root of the FS.
     74 	qidpath   uint64
     75 	fs        FS            // The associated FS.
     76 	file      File          // The associated File.
     77 	uid       string        // The user id derived from the attach message.
     78 	dirOffset uint64        // Used when reading directory.
     79 	dirIndex  int           // Used when reading directory.
     80 	dirEnts   []fs.DirEntry // DirEntry cache.
     81 }
     82 
     83 // NOFID is used in afid field of Tattach message when no authentication
     84 // is required.
     85 const NOFID = ^uint32(0)
     86 
     87 // NewFid returns an fid with fid set to id and omode set to -1.
     88 // Other fields should be set propperly after aquiring the fid.
     89 func newFid(id uint32) *fid {
     90 	return &fid{
     91 		fid:   id,
     92 		omode: -1,
     93 	}
     94 }
     95 
     96 func (f *fid) String() string {
     97 	fid := int64(f.fid)
     98 	if uint32(fid) == NOFID {
     99 		fid = -1
    100 	}
    101 	return fmt.Sprintf("%d", fid)
    102 }
    103 
    104 // An fidPool is a pool of fid.
    105 // It is used to track the fids of each 9P connection (not of each session).
    106 // It is safe for concurrent use by multiple goroutines except the String method.
    107 type fidPool struct {
    108 	m map[uint32]*fid
    109 	*sync.Mutex
    110 }
    111 
    112 // newFidPool allocates an fidPool.
    113 func newFidPool() *fidPool {
    114 	return &fidPool{
    115 		make(map[uint32]*fid),
    116 		new(sync.Mutex),
    117 	}
    118 }
    119 
    120 func (pool *fidPool) lookup(id uint32) (*fid, bool) {
    121 	pool.Lock()
    122 	defer pool.Unlock()
    123 	f, ok := pool.m[id]
    124 	return f, ok
    125 }
    126 
    127 func (pool *fidPool) add(id uint32) (*fid, error) {
    128 	pool.Lock()
    129 	defer pool.Unlock()
    130 	if _, ok := pool.m[id]; ok {
    131 		return nil, fmt.Errorf("fid already in use.")
    132 	}
    133 	f := newFid(id)
    134 	pool.m[id] = f
    135 	return f, nil
    136 }
    137 
    138 func (pool *fidPool) delete(id uint32) {
    139 	pool.Lock()
    140 	defer pool.Unlock()
    141 	delete(pool.m, id)
    142 }
    143 
    144 // not safe for concurrent use.
    145 func (pool *fidPool) String() string {
    146 	s := "&fidPool{\n"
    147 	for fnum, fstruct := range pool.m {
    148 		if fstruct.file == nil {
    149 			s += fmt.Sprintf(" %d: <nil>\n", fnum)
    150 			continue
    151 		}
    152 		st, err := fstruct.file.Stat()
    153 		if err != nil {
    154 			panic(err)
    155 		}
    156 		s += fmt.Sprintf(" %d: %v\n", fnum, st.Sys().(*Stat))
    157 	}
    158 	s += "}"
    159 	return s
    160 }