read_write.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. package vfs
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "sync"
  7. "github.com/rclone/rclone/fs"
  8. "github.com/rclone/rclone/fs/log"
  9. "github.com/rclone/rclone/vfs/vfscache"
  10. )
  11. // RWFileHandle is a handle that can be open for read and write.
  12. //
  13. // It will be open to a temporary file which, when closed, will be
  14. // transferred to the remote.
  15. type RWFileHandle struct {
  16. // read only variables
  17. file *File
  18. d *Dir
  19. flags int // open flags
  20. item *vfscache.Item // cached file item
  21. // read write variables protected by mutex
  22. mu sync.Mutex
  23. offset int64 // file pointer offset
  24. closed bool // set if handle has been closed
  25. opened bool
  26. writeCalled bool // if any Write() methods have been called
  27. }
  28. // Lock performs Unix locking, not supported
  29. func (fh *RWFileHandle) Lock() error {
  30. return os.ErrInvalid
  31. }
  32. // Unlock performs Unix unlocking, not supported
  33. func (fh *RWFileHandle) Unlock() error {
  34. return os.ErrInvalid
  35. }
  36. func newRWFileHandle(d *Dir, f *File, flags int) (fh *RWFileHandle, err error) {
  37. defer log.Trace(f.Path(), "")("err=%v", &err)
  38. // get an item to represent this from the cache
  39. item := d.vfs.cache.Item(f.Path())
  40. exists := f.exists() || (item.Exists() && !item.WrittenBack())
  41. // if O_CREATE and O_EXCL are set and if path already exists, then return EEXIST
  42. if flags&(os.O_CREATE|os.O_EXCL) == os.O_CREATE|os.O_EXCL && exists {
  43. return nil, EEXIST
  44. }
  45. fh = &RWFileHandle{
  46. file: f,
  47. d: d,
  48. flags: flags,
  49. item: item,
  50. }
  51. // truncate immediately if O_TRUNC is set or O_CREATE is set and file doesn't exist
  52. if !fh.readOnly() && (fh.flags&os.O_TRUNC != 0 || (fh.flags&os.O_CREATE != 0 && !exists)) {
  53. err = fh.Truncate(0)
  54. if err != nil {
  55. return nil, fmt.Errorf("cache open with O_TRUNC: failed to truncate: %w", err)
  56. }
  57. // we definitely need to write back the item even if we don't write to it
  58. item.Dirty()
  59. }
  60. if !fh.readOnly() {
  61. fh.file.addWriter(fh)
  62. }
  63. return fh, nil
  64. }
  65. // readOnly returns whether flags say fh is read only
  66. func (fh *RWFileHandle) readOnly() bool {
  67. return (fh.flags & accessModeMask) == os.O_RDONLY
  68. }
  69. // writeOnly returns whether flags say fh is write only
  70. func (fh *RWFileHandle) writeOnly() bool {
  71. return (fh.flags & accessModeMask) == os.O_WRONLY
  72. }
  73. // openPending opens the file if there is a pending open
  74. //
  75. // call with the lock held
  76. func (fh *RWFileHandle) openPending() (err error) {
  77. if fh.opened {
  78. return nil
  79. }
  80. defer log.Trace(fh.logPrefix(), "")("err=%v", &err)
  81. fh.file.muRW.Lock()
  82. defer fh.file.muRW.Unlock()
  83. o := fh.file.getObject()
  84. err = fh.item.Open(o)
  85. if err != nil {
  86. return fmt.Errorf("open RW handle failed to open cache file: %w", err)
  87. }
  88. size := fh._size() // update size in file and read size
  89. if fh.flags&os.O_APPEND != 0 {
  90. fh.offset = size
  91. fs.Debugf(fh.logPrefix(), "open at offset %d", fh.offset)
  92. } else {
  93. fh.offset = 0
  94. }
  95. fh.opened = true
  96. fh.d.addObject(fh.file) // make sure the directory has this object in it now
  97. return nil
  98. }
  99. // String converts it to printable
  100. func (fh *RWFileHandle) String() string {
  101. if fh == nil {
  102. return "<nil *RWFileHandle>"
  103. }
  104. if fh.file == nil {
  105. return "<nil *RWFileHandle.file>"
  106. }
  107. return fh.file.String() + " (rw)"
  108. }
  109. // Node returns the Node associated with this - satisfies Noder interface
  110. func (fh *RWFileHandle) Node() Node {
  111. fh.mu.Lock()
  112. defer fh.mu.Unlock()
  113. return fh.file
  114. }
  115. // updateSize updates the size of the file if necessary
  116. //
  117. // Must be called with fh.mu held
  118. func (fh *RWFileHandle) updateSize() {
  119. // If read only or not opened then ignore
  120. if fh.readOnly() || !fh.opened {
  121. return
  122. }
  123. size := fh._size()
  124. fh.file.setSize(size)
  125. }
  126. // close the file handle returning EBADF if it has been
  127. // closed already.
  128. //
  129. // Must be called with fh.mu held.
  130. //
  131. // Note that we leave the file around in the cache on error conditions
  132. // to give the user a chance to recover it.
  133. func (fh *RWFileHandle) close() (err error) {
  134. defer log.Trace(fh.logPrefix(), "")("err=%v", &err)
  135. fh.file.muRW.Lock()
  136. defer fh.file.muRW.Unlock()
  137. if fh.closed {
  138. return ECLOSED
  139. }
  140. fh.closed = true
  141. fh.updateSize()
  142. if fh.opened {
  143. err = fh.item.Close(fh.file.setObject)
  144. fh.opened = false
  145. } else {
  146. // apply any pending mod times if any
  147. _ = fh.file.applyPendingModTime()
  148. }
  149. if !fh.readOnly() {
  150. fh.file.delWriter(fh)
  151. }
  152. return err
  153. }
  154. // Close closes the file
  155. func (fh *RWFileHandle) Close() error {
  156. fh.mu.Lock()
  157. defer fh.mu.Unlock()
  158. return fh.close()
  159. }
  160. // Flush is called each time the file or directory is closed.
  161. // Because there can be multiple file descriptors referring to a
  162. // single opened file, Flush can be called multiple times.
  163. func (fh *RWFileHandle) Flush() error {
  164. fh.mu.Lock()
  165. fs.Debugf(fh.logPrefix(), "RWFileHandle.Flush")
  166. fh.updateSize()
  167. fh.mu.Unlock()
  168. return nil
  169. }
  170. // Release is called when we are finished with the file handle
  171. //
  172. // It isn't called directly from userspace so the error is ignored by
  173. // the kernel
  174. func (fh *RWFileHandle) Release() error {
  175. fh.mu.Lock()
  176. defer fh.mu.Unlock()
  177. fs.Debugf(fh.logPrefix(), "RWFileHandle.Release")
  178. if fh.closed {
  179. // Don't return an error if called twice
  180. return nil
  181. }
  182. err := fh.close()
  183. if err != nil {
  184. fs.Errorf(fh.logPrefix(), "RWFileHandle.Release error: %v", err)
  185. }
  186. return err
  187. }
  188. // _size returns the size of the underlying file and also sets it in
  189. // the owning file
  190. //
  191. // call with the lock held
  192. func (fh *RWFileHandle) _size() int64 {
  193. size, err := fh.item.GetSize()
  194. if err != nil {
  195. o := fh.file.getObject()
  196. if o != nil {
  197. size = o.Size()
  198. } else {
  199. fs.Errorf(fh.logPrefix(), "Couldn't read size of file")
  200. size = 0
  201. }
  202. }
  203. fh.file.setSize(size)
  204. return size
  205. }
  206. // Size returns the size of the underlying file
  207. func (fh *RWFileHandle) Size() int64 {
  208. fh.mu.Lock()
  209. defer fh.mu.Unlock()
  210. return fh._size()
  211. }
  212. // Stat returns info about the file
  213. func (fh *RWFileHandle) Stat() (os.FileInfo, error) {
  214. fh.mu.Lock()
  215. defer fh.mu.Unlock()
  216. return fh.file, nil
  217. }
  218. // _readAt bytes from the file at off
  219. //
  220. // if release is set then it releases the mutex just before doing the IO
  221. //
  222. // call with lock held
  223. func (fh *RWFileHandle) _readAt(b []byte, off int64, release bool) (n int, err error) {
  224. defer log.Trace(fh.logPrefix(), "size=%d, off=%d", len(b), off)("n=%d, err=%v", &n, &err)
  225. if fh.closed {
  226. return n, ECLOSED
  227. }
  228. if fh.writeOnly() {
  229. return n, EBADF
  230. }
  231. if off >= fh._size() {
  232. return n, io.EOF
  233. }
  234. if err = fh.openPending(); err != nil {
  235. return n, err
  236. }
  237. if release {
  238. // Do the writing with fh.mu unlocked
  239. fh.mu.Unlock()
  240. }
  241. n, err = fh.item.ReadAt(b, off)
  242. if release {
  243. fh.mu.Lock()
  244. }
  245. return n, err
  246. }
  247. // ReadAt bytes from the file at off
  248. func (fh *RWFileHandle) ReadAt(b []byte, off int64) (n int, err error) {
  249. fh.mu.Lock()
  250. defer fh.mu.Unlock()
  251. return fh._readAt(b, off, true)
  252. }
  253. // Read bytes from the file
  254. func (fh *RWFileHandle) Read(b []byte) (n int, err error) {
  255. fh.mu.Lock()
  256. defer fh.mu.Unlock()
  257. n, err = fh._readAt(b, fh.offset, false)
  258. fh.offset += int64(n)
  259. return n, err
  260. }
  261. // Seek to new file position
  262. func (fh *RWFileHandle) Seek(offset int64, whence int) (ret int64, err error) {
  263. fh.mu.Lock()
  264. defer fh.mu.Unlock()
  265. if fh.closed {
  266. return 0, ECLOSED
  267. }
  268. if !fh.opened && offset == 0 && whence != 2 {
  269. return 0, nil
  270. }
  271. if err = fh.openPending(); err != nil {
  272. return ret, err
  273. }
  274. switch whence {
  275. case io.SeekStart:
  276. fh.offset = 0
  277. case io.SeekEnd:
  278. fh.offset = fh._size()
  279. }
  280. fh.offset += offset
  281. // we don't check the offset - the next Read will
  282. return fh.offset, nil
  283. }
  284. // _writeAt bytes to the file at off
  285. //
  286. // if release is set then it releases the mutex just before doing the IO
  287. //
  288. // call with lock held
  289. func (fh *RWFileHandle) _writeAt(b []byte, off int64, release bool) (n int, err error) {
  290. defer log.Trace(fh.logPrefix(), "size=%d, off=%d", len(b), off)("n=%d, err=%v", &n, &err)
  291. if fh.closed {
  292. return n, ECLOSED
  293. }
  294. if fh.readOnly() {
  295. return n, EBADF
  296. }
  297. if err = fh.openPending(); err != nil {
  298. return n, err
  299. }
  300. if fh.flags&os.O_APPEND != 0 {
  301. // From open(2): Before each write(2), the file offset is
  302. // positioned at the end of the file, as if with lseek(2).
  303. size := fh._size()
  304. fh.offset = size
  305. off = fh.offset
  306. }
  307. fh.writeCalled = true
  308. if release {
  309. // Do the writing with fh.mu unlocked
  310. fh.mu.Unlock()
  311. }
  312. n, err = fh.item.WriteAt(b, off)
  313. if release {
  314. fh.mu.Lock()
  315. }
  316. if err != nil {
  317. return n, err
  318. }
  319. _ = fh._size()
  320. return n, err
  321. }
  322. // WriteAt bytes to the file at off
  323. func (fh *RWFileHandle) WriteAt(b []byte, off int64) (n int, err error) {
  324. fh.mu.Lock()
  325. n, err = fh._writeAt(b, off, true)
  326. if fh.flags&os.O_APPEND != 0 {
  327. fh.offset += int64(n)
  328. }
  329. fh.mu.Unlock()
  330. return n, err
  331. }
  332. // Write bytes to the file
  333. func (fh *RWFileHandle) Write(b []byte) (n int, err error) {
  334. fh.mu.Lock()
  335. defer fh.mu.Unlock()
  336. n, err = fh._writeAt(b, fh.offset, false)
  337. fh.offset += int64(n)
  338. return n, err
  339. }
  340. // WriteString a string to the file
  341. func (fh *RWFileHandle) WriteString(s string) (n int, err error) {
  342. return fh.Write([]byte(s))
  343. }
  344. // Truncate file to given size
  345. //
  346. // Call with mutex held
  347. func (fh *RWFileHandle) _truncate(size int64) (err error) {
  348. if size == fh._size() {
  349. return nil
  350. }
  351. fh.file.setSize(size)
  352. return fh.item.Truncate(size)
  353. }
  354. // Truncate file to given size
  355. func (fh *RWFileHandle) Truncate(size int64) (err error) {
  356. fh.mu.Lock()
  357. defer fh.mu.Unlock()
  358. if fh.closed {
  359. return ECLOSED
  360. }
  361. if err = fh.openPending(); err != nil {
  362. return err
  363. }
  364. return fh._truncate(size)
  365. }
  366. // Sync commits the current contents of the file to stable storage. Typically,
  367. // this means flushing the file system's in-memory copy of recently written
  368. // data to disk.
  369. func (fh *RWFileHandle) Sync() error {
  370. fh.mu.Lock()
  371. defer fh.mu.Unlock()
  372. if fh.closed {
  373. return ECLOSED
  374. }
  375. if !fh.opened {
  376. return nil
  377. }
  378. if fh.readOnly() {
  379. return nil
  380. }
  381. return fh.item.Sync()
  382. }
  383. func (fh *RWFileHandle) logPrefix() string {
  384. return fmt.Sprintf("%s(%p)", fh.file.Path(), fh)
  385. }
  386. // Chdir changes the current working directory to the file, which must
  387. // be a directory.
  388. func (fh *RWFileHandle) Chdir() error {
  389. return ENOSYS
  390. }
  391. // Chmod changes the mode of the file to mode.
  392. func (fh *RWFileHandle) Chmod(mode os.FileMode) error {
  393. return ENOSYS
  394. }
  395. // Chown changes the numeric uid and gid of the named file.
  396. func (fh *RWFileHandle) Chown(uid, gid int) error {
  397. return ENOSYS
  398. }
  399. // Fd returns the integer Unix file descriptor referencing the open file.
  400. func (fh *RWFileHandle) Fd() uintptr {
  401. return 0xdeadbeef // FIXME
  402. }
  403. // Name returns the name of the file from the underlying Object.
  404. func (fh *RWFileHandle) Name() string {
  405. return fh.file.String()
  406. }
  407. // Readdir reads the contents of the directory associated with file.
  408. func (fh *RWFileHandle) Readdir(n int) ([]os.FileInfo, error) {
  409. return nil, ENOSYS
  410. }
  411. // Readdirnames reads the contents of the directory associated with file.
  412. func (fh *RWFileHandle) Readdirnames(n int) (names []string, err error) {
  413. return nil, ENOSYS
  414. }