file.go (3393B)
1 package client 2 3 import ( 4 "errors" 5 "io" 6 "io/fs" 7 8 "git.mtkn.jp/lib9p" 9 ) 10 11 // File is a File for Client. 12 type File struct { 13 name string 14 path string // must not contain trailing slash. 15 fid uint32 16 omode lib9p.OpenMode 17 offset uint64 18 qid lib9p.Qid 19 iounit uint32 20 fs *FS 21 dirBuf []fs.DirEntry 22 } 23 24 func (cf *File) Stat() (*lib9p.FileInfo, error) { 25 tag, err := cf.fs.tPool.add() 26 if err != nil { 27 return nil, err 28 } 29 st, err := cf.fs.c.Stat(tag, cf.fid) 30 cf.fs.tPool.delete(tag) 31 if err != nil { 32 return nil, err 33 } 34 return &lib9p.FileInfo{Stat: *st}, nil 35 } 36 37 // TODO: check permission? 38 func (cf *File) WStat(stat *lib9p.Stat) error { 39 tag, err := cf.fs.tPool.add() 40 if err != nil { 41 return err 42 } 43 err = cf.fs.c.Wstat(tag, cf.fid, stat) 44 cf.fs.tPool.delete(tag) 45 return err 46 } 47 48 // Don't use closed file. 49 func (cf *File) Close() error { 50 tag, err := cf.fs.tPool.add() 51 if err != nil { 52 return err 53 } 54 err = cf.fs.c.Clunk(tag, cf.fid) 55 cf.fs.tPool.delete(tag) 56 cf.fs.fPool.delete(cf.fid) 57 cf.fid = lib9p.NOFID 58 return err 59 } 60 61 func (cf *File) Read(b []byte) (int, error) { 62 if cf.omode == -1 { 63 return 0, errors.New("not open") 64 } 65 if len(b) == 0 { 66 return 0, nil 67 } 68 if cf.omode&3 != lib9p.OREAD && cf.omode&3 != lib9p.ORDWR { 69 return 0, lib9p.ErrPerm 70 } 71 count := len(b) 72 cur := 0 73 for count > 0 { 74 var c uint32 75 if uint32(count) > cf.iounit { 76 c = cf.iounit 77 } else { 78 c = uint32(count) 79 } 80 tag, err := cf.fs.tPool.add() 81 if err != nil { 82 return 0, err 83 } 84 buf, err := cf.fs.c.Read(tag, cf.fid, cf.offset, c) 85 cf.fs.tPool.delete(tag) 86 var i int 87 for i = 0; i < len(buf); i++ { 88 b[cur+i] = buf[i] 89 } 90 cf.offset += uint64(i) 91 cur += i 92 if err != nil { 93 return cur, err 94 } 95 count -= int(c) 96 } 97 if cur == 0 { 98 return 0, io.EOF 99 } else { 100 return cur, nil 101 } 102 } 103 104 func (cf *File) Write(b []byte) (int, error) { 105 if cf.omode == -1 { 106 return 0, errors.New("not open") 107 } 108 if len(b) == 0 { 109 return 0, nil 110 } 111 if cf.omode&3 != lib9p.OWRITE && cf.omode&3 != lib9p.ORDWR { 112 return 0, lib9p.ErrPerm 113 } 114 count := len(b) 115 cur := 0 116 for count > 0 { 117 var c uint32 118 if uint32(count) > cf.iounit { 119 c = cf.iounit 120 } else { 121 c = uint32(count) 122 } 123 tag, err := cf.fs.tPool.add() 124 if err != nil { 125 return 0, err 126 } 127 n, err := cf.fs.c.Write(tag, cf.fid, cf.offset, c, b[cur:cur+int(c)]) 128 cf.fs.tPool.delete(tag) 129 cf.offset += uint64(n) 130 cur += int(n) 131 if err != nil { 132 return cur, err 133 } 134 count -= int(c) 135 } 136 return cur, nil 137 } 138 139 func (cf *File) ReadDir(n int) ([]fs.DirEntry, error) { 140 if cf.qid.Type&lib9p.QTDIR == 0 { 141 return nil, errors.New("not a directory") 142 } 143 if cf.omode == -1 { 144 return nil, errors.New("not open") 145 } 146 var ( 147 de []fs.DirEntry 148 err error 149 data []byte 150 tag uint16 151 ) 152 for n <= 0 || len(cf.dirBuf) < n { 153 tag, err = cf.fs.tPool.add() 154 if err != nil { 155 break 156 } 157 data, err = cf.fs.c.Read(tag, cf.fid, cf.offset, cf.iounit) 158 cf.fs.tPool.delete(tag) 159 if err != nil { 160 break 161 } else if len(data) == 0 { 162 break 163 } 164 cf.offset += uint64(len(data)) 165 for len(data) > 0 { 166 st := lib9p.NewStat(data) 167 data = data[2+st.Size():] 168 cf.dirBuf = append(cf.dirBuf, &lib9p.FileInfo{Stat: *st}) 169 } 170 } 171 if 0 < n && n <= len(cf.dirBuf) { 172 de = cf.dirBuf[:n] 173 cf.dirBuf = cf.dirBuf[n:] 174 } else { 175 de = cf.dirBuf 176 cf.dirBuf = nil 177 } 178 if err == nil && len(de) == 0 && n > 0 { 179 err = io.EOF 180 } 181 return de, err 182 }