github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/vfs/write.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "sync" 8 "sync/atomic" 9 "time" 10 11 "github.com/rclone/rclone/fs" 12 "github.com/rclone/rclone/fs/operations" 13 ) 14 15 // WriteFileHandle is an open for write handle on a File 16 type WriteFileHandle struct { 17 baseHandle 18 mu sync.Mutex 19 cond *sync.Cond // cond lock for out of sequence writes 20 closed bool // set if handle has been closed 21 remote string 22 pipeWriter *io.PipeWriter 23 o fs.Object 24 result chan error 25 file *File 26 writeCalled bool // set the first time Write() is called 27 offset int64 28 opened bool 29 flags int 30 truncated bool 31 } 32 33 // Check interfaces 34 var ( 35 _ io.Writer = (*WriteFileHandle)(nil) 36 _ io.WriterAt = (*WriteFileHandle)(nil) 37 _ io.Closer = (*WriteFileHandle)(nil) 38 ) 39 40 func newWriteFileHandle(d *Dir, f *File, remote string, flags int) (*WriteFileHandle, error) { 41 fh := &WriteFileHandle{ 42 remote: remote, 43 flags: flags, 44 result: make(chan error, 1), 45 file: f, 46 } 47 fh.cond = sync.NewCond(&fh.mu) 48 fh.file.addWriter(fh) 49 return fh, nil 50 } 51 52 // returns whether it is OK to truncate the file 53 func (fh *WriteFileHandle) safeToTruncate() bool { 54 return fh.truncated || fh.flags&os.O_TRUNC != 0 || !fh.file.exists() 55 } 56 57 // openPending opens the file if there is a pending open 58 // 59 // call with the lock held 60 func (fh *WriteFileHandle) openPending() (err error) { 61 if fh.opened { 62 return nil 63 } 64 if !fh.safeToTruncate() { 65 fs.Errorf(fh.remote, "WriteFileHandle: Can't open for write without O_TRUNC on existing file without --vfs-cache-mode >= writes") 66 return EPERM 67 } 68 var pipeReader *io.PipeReader 69 pipeReader, fh.pipeWriter = io.Pipe() 70 go func() { 71 // NB Rcat deals with Stats.Transferring etc 72 o, err := operations.Rcat(context.TODO(), fh.file.d.f, fh.remote, pipeReader, time.Now()) 73 if err != nil { 74 fs.Errorf(fh.remote, "WriteFileHandle.New Rcat failed: %v", err) 75 } 76 // Close the pipeReader so the pipeWriter fails with ErrClosedPipe 77 _ = pipeReader.Close() 78 fh.o = o 79 fh.result <- err 80 }() 81 fh.file.setSize(0) 82 fh.truncated = true 83 fh.file.d.addObject(fh.file) // make sure the directory has this object in it now 84 fh.opened = true 85 return nil 86 } 87 88 // String converts it to printable 89 func (fh *WriteFileHandle) String() string { 90 if fh == nil { 91 return "<nil *WriteFileHandle>" 92 } 93 fh.mu.Lock() 94 defer fh.mu.Unlock() 95 if fh.file == nil { 96 return "<nil *WriteFileHandle.file>" 97 } 98 return fh.file.String() + " (w)" 99 } 100 101 // Node returns the Node assocuated with this - satisfies Noder interface 102 func (fh *WriteFileHandle) Node() Node { 103 fh.mu.Lock() 104 defer fh.mu.Unlock() 105 return fh.file 106 } 107 108 // WriteAt writes len(p) bytes from p to the underlying data stream at offset 109 // off. It returns the number of bytes written from p (0 <= n <= len(p)) and 110 // any error encountered that caused the write to stop early. WriteAt must 111 // return a non-nil error if it returns n < len(p). 112 // 113 // If WriteAt is writing to a destination with a seek offset, WriteAt should 114 // not affect nor be affected by the underlying seek offset. 115 // 116 // Clients of WriteAt can execute parallel WriteAt calls on the same 117 // destination if the ranges do not overlap. 118 // 119 // Implementations must not retain p. 120 func (fh *WriteFileHandle) WriteAt(p []byte, off int64) (n int, err error) { 121 fh.mu.Lock() 122 defer fh.mu.Unlock() 123 return fh.writeAt(p, off) 124 } 125 126 // Implementatino of WriteAt - call with lock held 127 func (fh *WriteFileHandle) writeAt(p []byte, off int64) (n int, err error) { 128 // defer log.Trace(fh.remote, "len=%d off=%d", len(p), off)("n=%d, fh.off=%d, err=%v", &n, &fh.offset, &err) 129 if fh.closed { 130 fs.Errorf(fh.remote, "WriteFileHandle.Write: error: %v", EBADF) 131 return 0, ECLOSED 132 } 133 if fh.offset != off { 134 // Set a background timer so we don't wait forever 135 timeout := time.NewTimer(10 * time.Second) 136 done := make(chan struct{}) 137 abort := int32(0) 138 go func() { 139 select { 140 case <-timeout.C: 141 // set abort flag an give all the waiting goroutines a kick on timeout 142 atomic.StoreInt32(&abort, 1) 143 fh.cond.Broadcast() 144 case <-done: 145 } 146 }() 147 // Wait for an in-sequence write or abort 148 for fh.offset != off && atomic.LoadInt32(&abort) == 0 { 149 // fs.Debugf(fh.remote, "waiting for in-sequence write to %d", off) 150 fh.cond.Wait() 151 } 152 // tidy up end timer 153 close(done) 154 timeout.Stop() 155 } 156 if fh.offset != off { 157 fs.Errorf(fh.remote, "WriteFileHandle.Write: can't seek in file without --vfs-cache-mode >= writes") 158 return 0, ESPIPE 159 } 160 if err = fh.openPending(); err != nil { 161 return 0, err 162 } 163 fh.writeCalled = true 164 n, err = fh.pipeWriter.Write(p) 165 fh.offset += int64(n) 166 fh.file.setSize(fh.offset) 167 if err != nil { 168 fs.Errorf(fh.remote, "WriteFileHandle.Write error: %v", err) 169 return 0, err 170 } 171 // fs.Debugf(fh.remote, "WriteFileHandle.Write OK (%d bytes written)", n) 172 fh.cond.Broadcast() // wake everyone up waiting for an in-sequence read 173 return n, nil 174 } 175 176 // Write writes len(p) bytes from p to the underlying data stream. It returns 177 // the number of bytes written from p (0 <= n <= len(p)) and any error 178 // encountered that caused the write to stop early. Write must return a non-nil 179 // error if it returns n < len(p). Write must not modify the slice data, even 180 // temporarily. 181 // 182 // Implementations must not retain p. 183 func (fh *WriteFileHandle) Write(p []byte) (n int, err error) { 184 fh.mu.Lock() 185 defer fh.mu.Unlock() 186 // Since we can't seek, just call WriteAt with the current offset 187 return fh.writeAt(p, fh.offset) 188 } 189 190 // WriteString a string to the file 191 func (fh *WriteFileHandle) WriteString(s string) (n int, err error) { 192 return fh.Write([]byte(s)) 193 } 194 195 // Offset returns the offset of the file pointer 196 func (fh *WriteFileHandle) Offset() (offset int64) { 197 fh.mu.Lock() 198 defer fh.mu.Unlock() 199 return fh.offset 200 } 201 202 // close the file handle returning EBADF if it has been 203 // closed already. 204 // 205 // Must be called with fh.mu held 206 func (fh *WriteFileHandle) close() (err error) { 207 if fh.closed { 208 return ECLOSED 209 } 210 fh.closed = true 211 // leave writer open until file is transferred 212 defer func() { 213 fh.file.delWriter(fh, false) 214 fh.file.finishWriterClose() 215 }() 216 // If file not opened and not safe to truncate then then leave file intact 217 if !fh.opened && !fh.safeToTruncate() { 218 return nil 219 } 220 if err = fh.openPending(); err != nil { 221 return err 222 } 223 writeCloseErr := fh.pipeWriter.Close() 224 err = <-fh.result 225 if err == nil { 226 fh.file.setObject(fh.o) 227 err = writeCloseErr 228 } 229 return err 230 } 231 232 // Close closes the file 233 func (fh *WriteFileHandle) Close() error { 234 fh.mu.Lock() 235 defer fh.mu.Unlock() 236 return fh.close() 237 } 238 239 // Flush is called on each close() of a file descriptor. So if a 240 // filesystem wants to return write errors in close() and the file has 241 // cached dirty data, this is a good place to write back data and 242 // return any errors. Since many applications ignore close() errors 243 // this is not always useful. 244 // 245 // NOTE: The flush() method may be called more than once for each 246 // open(). This happens if more than one file descriptor refers to an 247 // opened file due to dup(), dup2() or fork() calls. It is not 248 // possible to determine if a flush is final, so each flush should be 249 // treated equally. Multiple write-flush sequences are relatively 250 // rare, so this shouldn't be a problem. 251 // 252 // Filesystems shouldn't assume that flush will always be called after 253 // some writes, or that if will be called at all. 254 func (fh *WriteFileHandle) Flush() error { 255 fh.mu.Lock() 256 defer fh.mu.Unlock() 257 if fh.closed { 258 fs.Debugf(fh.remote, "WriteFileHandle.Flush nothing to do") 259 return nil 260 } 261 // fs.Debugf(fh.remote, "WriteFileHandle.Flush") 262 // If Write hasn't been called then ignore the Flush - Release 263 // will pick it up 264 if !fh.writeCalled { 265 fs.Debugf(fh.remote, "WriteFileHandle.Flush unwritten handle, writing 0 bytes to avoid race conditions") 266 _, err := fh.writeAt([]byte{}, fh.offset) 267 return err 268 } 269 err := fh.close() 270 if err != nil { 271 fs.Errorf(fh.remote, "WriteFileHandle.Flush error: %v", err) 272 } else { 273 // fs.Debugf(fh.remote, "WriteFileHandle.Flush OK") 274 } 275 return err 276 } 277 278 // Release is called when we are finished with the file handle 279 // 280 // It isn't called directly from userspace so the error is ignored by 281 // the kernel 282 func (fh *WriteFileHandle) Release() error { 283 fh.mu.Lock() 284 defer fh.mu.Unlock() 285 if fh.closed { 286 fs.Debugf(fh.remote, "WriteFileHandle.Release nothing to do") 287 return nil 288 } 289 fs.Debugf(fh.remote, "WriteFileHandle.Release closing") 290 err := fh.close() 291 if err != nil { 292 fs.Errorf(fh.remote, "WriteFileHandle.Release error: %v", err) 293 } else { 294 // fs.Debugf(fh.remote, "WriteFileHandle.Release OK") 295 } 296 return err 297 } 298 299 // Stat returns info about the file 300 func (fh *WriteFileHandle) Stat() (os.FileInfo, error) { 301 fh.mu.Lock() 302 defer fh.mu.Unlock() 303 return fh.file, nil 304 } 305 306 // Truncate file to given size 307 func (fh *WriteFileHandle) Truncate(size int64) (err error) { 308 fh.mu.Lock() 309 defer fh.mu.Unlock() 310 if fh.closed { 311 return ECLOSED 312 } 313 if size != fh.offset { 314 fs.Errorf(fh.remote, "WriteFileHandle: Truncate: Can't change size without --vfs-cache-mode >= writes") 315 return EPERM 316 } 317 // File is correct size 318 if size == 0 { 319 fh.truncated = true 320 } 321 return nil 322 } 323 324 // Read reads up to len(p) bytes into p. 325 func (fh *WriteFileHandle) Read(p []byte) (n int, err error) { 326 fs.Errorf(fh.remote, "WriteFileHandle: Read: Can't read and write to file without --vfs-cache-mode >= minimal") 327 return 0, EPERM 328 } 329 330 // ReadAt reads len(p) bytes into p starting at offset off in the 331 // underlying input source. It returns the number of bytes read (0 <= 332 // n <= len(p)) and any error encountered. 333 func (fh *WriteFileHandle) ReadAt(p []byte, off int64) (n int, err error) { 334 fs.Errorf(fh.remote, "WriteFileHandle: ReadAt: Can't read and write to file without --vfs-cache-mode >= minimal") 335 return 0, EPERM 336 } 337 338 // Sync commits the current contents of the file to stable storage. Typically, 339 // this means flushing the file system's in-memory copy of recently written 340 // data to disk. 341 func (fh *WriteFileHandle) Sync() error { 342 return nil 343 }