@@ -255,15 +255,14 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
255
255
}
256
256
fileID := f .fileTableEntry .ID
257
257
defer f .fileTableEntry .IDLock .RUnlock ()
258
-
259
- var written uint32
258
+ // Handle payload data
260
259
status := fuse .OK
261
260
dataBuf := bytes .NewBuffer (data )
262
261
blocks := f .contentEnc .ExplodePlainRange (uint64 (off ), uint64 (len (data )))
263
- for _ , b := range blocks {
264
-
262
+ writeChain := make ([][]byte , len (blocks ))
263
+ var numOutBytes int
264
+ for i , b := range blocks {
265
265
blockData := dataBuf .Next (int (b .Length ))
266
-
267
266
// Incomplete block -> Read-Modify-Write
268
267
if b .IsPartial () {
269
268
// Read
@@ -272,38 +271,41 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
272
271
oldData , status = f .doRead (o , f .contentEnc .PlainBS ())
273
272
if status != fuse .OK {
274
273
tlog .Warn .Printf ("ino%d fh%d: RMW read failed: %s" , f .devIno .ino , f .intFd (), status .String ())
275
- return written , status
274
+ return 0 , status
276
275
}
277
276
// Modify
278
277
blockData = f .contentEnc .MergeBlocks (oldData , blockData , int (b .Skip ))
279
278
tlog .Debug .Printf ("len(oldData)=%d len(blockData)=%d" , len (oldData ), len (blockData ))
280
279
}
281
-
282
280
// Encrypt
283
- blockOffset := b .BlockCipherOff ()
284
281
blockData = f .contentEnc .EncryptBlock (blockData , b .BlockNo , fileID )
285
282
tlog .Debug .Printf ("ino%d: Writing %d bytes to block #%d" ,
286
283
f .devIno .ino , uint64 (len (blockData ))- f .contentEnc .BlockOverhead (), b .BlockNo )
287
-
288
- // Prevent partially written (=corrupt) blocks by preallocating the space beforehand
289
- err := syscallcompat .EnospcPrealloc (int (f .fd .Fd ()), int64 (blockOffset ), int64 (len (blockData )))
290
- if err != nil {
291
- tlog .Warn .Printf ("ino%d fh%d: doWrite: prealloc failed: %s" , f .devIno .ino , f .intFd (), err .Error ())
292
- status = fuse .ToStatus (err )
293
- break
294
- }
295
-
296
- // Write
297
- _ , err = f .fd .WriteAt (blockData , int64 (blockOffset ))
298
-
299
- if err != nil {
300
- tlog .Warn .Printf ("doWrite: Write failed: %s" , err .Error ())
301
- status = fuse .ToStatus (err )
302
- break
303
- }
304
- written += uint32 (b .Length )
284
+ // Store output data in the writeChain
285
+ writeChain [i ] = blockData
286
+ numOutBytes += len (blockData )
287
+ }
288
+ // Concatenenate all elements in the writeChain into one contigous buffer
289
+ tmp := make ([]byte , numOutBytes )
290
+ writeBuf := bytes .NewBuffer (tmp [:0 ])
291
+ for _ , w := range writeChain {
292
+ writeBuf .Write (w )
293
+ }
294
+ // Preallocate so we cannot run out of space in the middle of the write.
295
+ // This prevents partially written (=corrupt) blocks.
296
+ cOff := blocks [0 ].BlockCipherOff ()
297
+ err := syscallcompat .EnospcPrealloc (int (f .fd .Fd ()), int64 (cOff ), int64 (writeBuf .Len ()))
298
+ if err != nil {
299
+ tlog .Warn .Printf ("ino%d fh%d: doWrite: prealloc failed: %s" , f .devIno .ino , f .intFd (), err .Error ())
300
+ return 0 , fuse .ToStatus (err )
301
+ }
302
+ // Write
303
+ _ , err = f .fd .WriteAt (writeBuf .Bytes (), int64 (cOff ))
304
+ if err != nil {
305
+ tlog .Warn .Printf ("doWrite: Write failed: %s" , err .Error ())
306
+ return 0 , fuse .ToStatus (err )
305
307
}
306
- return written , status
308
+ return uint32 ( len ( data )), fuse . OK
307
309
}
308
310
309
311
// isConsecutiveWrite returns true if the current write
0 commit comments