write_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. package vfs
  2. import (
  3. "context"
  4. "errors"
  5. "io"
  6. "os"
  7. "runtime"
  8. "sync"
  9. "testing"
  10. "time"
  11. "github.com/rclone/rclone/fs"
  12. "github.com/rclone/rclone/fstest"
  13. "github.com/rclone/rclone/lib/random"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. )
  17. // Open a file for write
  18. func writeHandleCreate(t *testing.T) (r *fstest.Run, vfs *VFS, fh *WriteFileHandle) {
  19. r, vfs = newTestVFS(t)
  20. h, err := vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777)
  21. require.NoError(t, err)
  22. fh, ok := h.(*WriteFileHandle)
  23. require.True(t, ok)
  24. return r, vfs, fh
  25. }
  26. // Test write when underlying storage is readonly, must be run as non-root
  27. func TestWriteFileHandleReadonly(t *testing.T) {
  28. if runtime.GOOS == "windows" {
  29. t.Skipf("Skipping test on %s", runtime.GOOS)
  30. }
  31. if *fstest.RemoteName != "" {
  32. t.Skip("Skipping test on non local remote")
  33. }
  34. r, vfs, fh := writeHandleCreate(t)
  35. // Name
  36. assert.Equal(t, "file1", fh.Name())
  37. // Write a file, so underlying remote will be created
  38. _, err := fh.Write([]byte("hello"))
  39. assert.NoError(t, err)
  40. err = fh.Close()
  41. assert.NoError(t, err)
  42. var info os.FileInfo
  43. info, err = os.Stat(r.FremoteName)
  44. assert.NoError(t, err)
  45. // Remove write permission
  46. oldMode := info.Mode()
  47. err = os.Chmod(r.FremoteName, oldMode^(oldMode&0222))
  48. assert.NoError(t, err)
  49. var h Handle
  50. h, err = vfs.OpenFile("file2", os.O_WRONLY|os.O_CREATE, 0777)
  51. require.NoError(t, err)
  52. var ok bool
  53. fh, ok = h.(*WriteFileHandle)
  54. require.True(t, ok)
  55. // error is propagated to Close()
  56. _, err = fh.Write([]byte("hello"))
  57. assert.NoError(t, err)
  58. err = fh.Close()
  59. assert.NotNil(t, err)
  60. // Remove should fail
  61. err = vfs.Remove("file1")
  62. assert.NotNil(t, err)
  63. // Only file1 should exist
  64. _, err = vfs.Stat("file1")
  65. assert.NoError(t, err)
  66. _, err = vfs.Stat("file2")
  67. assert.Equal(t, true, errors.Is(err, os.ErrNotExist))
  68. // Restore old permission
  69. err = os.Chmod(r.FremoteName, oldMode)
  70. assert.NoError(t, err)
  71. }
  72. func TestWriteFileHandleMethods(t *testing.T) {
  73. r, vfs, fh := writeHandleCreate(t)
  74. // String
  75. assert.Equal(t, "file1 (w)", fh.String())
  76. assert.Equal(t, "<nil *WriteFileHandle>", (*WriteFileHandle)(nil).String())
  77. assert.Equal(t, "<nil *WriteFileHandle.file>", new(WriteFileHandle).String())
  78. // Node
  79. node := fh.Node()
  80. assert.Equal(t, "file1", node.Name())
  81. // Offset #1
  82. assert.Equal(t, int64(0), fh.Offset())
  83. assert.Equal(t, int64(0), node.Size())
  84. // Write (smoke test only since heavy lifting done in WriteAt)
  85. n, err := fh.Write([]byte("hello"))
  86. assert.NoError(t, err)
  87. assert.Equal(t, 5, n)
  88. // Offset #2
  89. assert.Equal(t, int64(5), fh.Offset())
  90. assert.Equal(t, int64(5), node.Size())
  91. // Stat
  92. var fi os.FileInfo
  93. fi, err = fh.Stat()
  94. assert.NoError(t, err)
  95. assert.Equal(t, int64(5), fi.Size())
  96. assert.Equal(t, "file1", fi.Name())
  97. // Read
  98. var buf = make([]byte, 16)
  99. _, err = fh.Read(buf)
  100. assert.Equal(t, EPERM, err)
  101. // ReadAt
  102. _, err = fh.ReadAt(buf, 0)
  103. assert.Equal(t, EPERM, err)
  104. // Sync
  105. err = fh.Sync()
  106. assert.NoError(t, err)
  107. // Truncate - can only truncate where the file pointer is
  108. err = fh.Truncate(5)
  109. assert.NoError(t, err)
  110. err = fh.Truncate(6)
  111. assert.Equal(t, EPERM, err)
  112. // Close
  113. assert.NoError(t, fh.Close())
  114. // Check double close
  115. err = fh.Close()
  116. assert.Equal(t, ECLOSED, err)
  117. // check vfs
  118. root, err := vfs.Root()
  119. require.NoError(t, err)
  120. checkListing(t, root, []string{"file1,5,false"})
  121. // check the underlying r.Fremote but not the modtime
  122. file1 := fstest.NewItem("file1", "hello", t1)
  123. fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported)
  124. // Check trying to open the file now it exists then closing it
  125. // immediately is OK
  126. h, err := vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777)
  127. require.NoError(t, err)
  128. assert.NoError(t, h.Close())
  129. checkListing(t, root, []string{"file1,5,false"})
  130. // Check trying to open the file and writing it now it exists
  131. // returns an error
  132. h, err = vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE, 0777)
  133. require.NoError(t, err)
  134. _, err = h.Write([]byte("hello1"))
  135. require.Equal(t, EPERM, err)
  136. assert.NoError(t, h.Close())
  137. checkListing(t, root, []string{"file1,5,false"})
  138. // Check opening the file with O_TRUNC does actually truncate
  139. // it even if we don't write to it
  140. h, err = vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
  141. require.NoError(t, err)
  142. err = h.Close()
  143. if !errors.Is(err, fs.ErrorCantUploadEmptyFiles) {
  144. assert.NoError(t, err)
  145. checkListing(t, root, []string{"file1,0,false"})
  146. }
  147. // Check opening the file with O_TRUNC and writing does work
  148. h, err = vfs.OpenFile("file1", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
  149. require.NoError(t, err)
  150. _, err = h.WriteString("hello12")
  151. require.NoError(t, err)
  152. assert.NoError(t, h.Close())
  153. checkListing(t, root, []string{"file1,7,false"})
  154. }
  155. func TestWriteFileHandleWriteAt(t *testing.T) {
  156. r, vfs, fh := writeHandleCreate(t)
  157. // Preconditions
  158. assert.Equal(t, int64(0), fh.offset)
  159. assert.False(t, fh.writeCalled)
  160. // Write the data
  161. n, err := fh.WriteAt([]byte("hello"), 0)
  162. assert.NoError(t, err)
  163. assert.Equal(t, 5, n)
  164. // After write
  165. assert.Equal(t, int64(5), fh.offset)
  166. assert.True(t, fh.writeCalled)
  167. // Check can't seek
  168. n, err = fh.WriteAt([]byte("hello"), 100)
  169. assert.Equal(t, ESPIPE, err)
  170. assert.Equal(t, 0, n)
  171. // Write more data
  172. n, err = fh.WriteAt([]byte(" world"), 5)
  173. assert.NoError(t, err)
  174. assert.Equal(t, 6, n)
  175. // Close
  176. assert.NoError(t, fh.Close())
  177. // Check can't write on closed handle
  178. n, err = fh.WriteAt([]byte("hello"), 0)
  179. assert.Equal(t, ECLOSED, err)
  180. assert.Equal(t, 0, n)
  181. // check vfs
  182. root, err := vfs.Root()
  183. require.NoError(t, err)
  184. checkListing(t, root, []string{"file1,11,false"})
  185. // check the underlying r.Fremote but not the modtime
  186. file1 := fstest.NewItem("file1", "hello world", t1)
  187. fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported)
  188. }
  189. func TestWriteFileHandleFlush(t *testing.T) {
  190. _, vfs, fh := writeHandleCreate(t)
  191. // Check Flush already creates file for unwritten handles, without closing it
  192. err := fh.Flush()
  193. assert.NoError(t, err)
  194. assert.False(t, fh.closed)
  195. root, err := vfs.Root()
  196. assert.NoError(t, err)
  197. checkListing(t, root, []string{"file1,0,false"})
  198. // Write some data
  199. n, err := fh.Write([]byte("hello"))
  200. assert.NoError(t, err)
  201. assert.Equal(t, 5, n)
  202. // Check Flush closes file if write called
  203. err = fh.Flush()
  204. assert.NoError(t, err)
  205. assert.True(t, fh.closed)
  206. // Check flush does nothing if called again
  207. err = fh.Flush()
  208. assert.NoError(t, err)
  209. assert.True(t, fh.closed)
  210. // Check file was written properly
  211. root, err = vfs.Root()
  212. assert.NoError(t, err)
  213. checkListing(t, root, []string{"file1,5,false"})
  214. }
  215. func TestWriteFileHandleRelease(t *testing.T) {
  216. _, _, fh := writeHandleCreate(t)
  217. // Check Release closes file
  218. err := fh.Release()
  219. if errors.Is(err, fs.ErrorCantUploadEmptyFiles) {
  220. t.Logf("skipping test: %v", err)
  221. return
  222. }
  223. assert.NoError(t, err)
  224. assert.True(t, fh.closed)
  225. // Check Release does nothing if called again
  226. err = fh.Release()
  227. assert.NoError(t, err)
  228. assert.True(t, fh.closed)
  229. }
  230. var (
  231. canSetModTimeOnce sync.Once
  232. canSetModTimeValue = true
  233. )
  234. // returns whether the remote can set modtime
  235. func canSetModTime(t *testing.T, r *fstest.Run) bool {
  236. canSetModTimeOnce.Do(func() {
  237. mtime1 := time.Date(2008, time.November, 18, 17, 32, 31, 0, time.UTC)
  238. _ = r.WriteObject(context.Background(), "time_test", "stuff", mtime1)
  239. obj, err := r.Fremote.NewObject(context.Background(), "time_test")
  240. require.NoError(t, err)
  241. mtime2 := time.Date(2009, time.November, 18, 17, 32, 31, 0, time.UTC)
  242. err = obj.SetModTime(context.Background(), mtime2)
  243. switch err {
  244. case nil:
  245. canSetModTimeValue = true
  246. case fs.ErrorCantSetModTime, fs.ErrorCantSetModTimeWithoutDelete:
  247. canSetModTimeValue = false
  248. default:
  249. require.NoError(t, err)
  250. }
  251. require.NoError(t, obj.Remove(context.Background()))
  252. fs.Debugf(nil, "Can set mod time: %v", canSetModTimeValue)
  253. })
  254. return canSetModTimeValue
  255. }
  256. // tests mod time on open files
  257. func TestWriteFileModTimeWithOpenWriters(t *testing.T) {
  258. r, vfs, fh := writeHandleCreate(t)
  259. if !canSetModTime(t, r) {
  260. t.Skip("can't set mod time")
  261. }
  262. mtime := time.Date(2012, time.November, 18, 17, 32, 31, 0, time.UTC)
  263. _, err := fh.Write([]byte{104, 105})
  264. require.NoError(t, err)
  265. err = fh.Node().SetModTime(mtime)
  266. require.NoError(t, err)
  267. err = fh.Close()
  268. require.NoError(t, err)
  269. info, err := vfs.Stat("file1")
  270. require.NoError(t, err)
  271. if r.Fremote.Precision() != fs.ModTimeNotSupported {
  272. // avoid errors because of timezone differences
  273. assert.Equal(t, info.ModTime().Unix(), mtime.Unix())
  274. }
  275. }
  276. func testFileReadAt(t *testing.T, n int) {
  277. _, vfs, fh := writeHandleCreate(t)
  278. contents := []byte(random.String(n))
  279. if n != 0 {
  280. written, err := fh.Write(contents)
  281. require.NoError(t, err)
  282. assert.Equal(t, n, written)
  283. }
  284. // Close the file without writing to it if n==0
  285. err := fh.Close()
  286. if errors.Is(err, fs.ErrorCantUploadEmptyFiles) {
  287. t.Logf("skipping test: %v", err)
  288. return
  289. }
  290. assert.NoError(t, err)
  291. // read the file back in using ReadAt into a buffer
  292. // this simulates what mount does
  293. rd, err := vfs.OpenFile("file1", os.O_RDONLY, 0)
  294. require.NoError(t, err)
  295. buf := make([]byte, 1024)
  296. read, err := rd.ReadAt(buf, 0)
  297. if err != io.EOF {
  298. assert.NoError(t, err)
  299. }
  300. assert.Equal(t, read, n)
  301. assert.Equal(t, contents, buf[:read])
  302. err = rd.Close()
  303. assert.NoError(t, err)
  304. }
  305. func TestFileReadAtZeroLength(t *testing.T) {
  306. testFileReadAt(t, 0)
  307. }
  308. func TestFileReadAtNonZeroLength(t *testing.T) {
  309. testFileReadAt(t, 100)
  310. }