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