Returns true when the block was successfully copied. The passed buffer must be large enough to accommodate the block.
(ctx context.Context, srcName string, srcOffset int64, state copyBlocksState, ffs fs.Filesystem, block protocol.BlockInfo, buf []byte)
| 1464 | // Returns true when the block was successfully copied. |
| 1465 | // The passed buffer must be large enough to accommodate the block. |
| 1466 | func (f *sendReceiveFolder) copyBlockFromFile(ctx context.Context, srcName string, srcOffset int64, state copyBlocksState, ffs fs.Filesystem, block protocol.BlockInfo, buf []byte) bool { |
| 1467 | fd, err := ffs.Open(srcName) |
| 1468 | if err != nil { |
| 1469 | f.sl.DebugContext(ctx, "Failed to open source file for block copy", slogutil.FilePath(srcName), "blockHash", block.Hash, slogutil.Error(err)) |
| 1470 | return false |
| 1471 | } |
| 1472 | defer fd.Close() |
| 1473 | |
| 1474 | _, err = fd.ReadAt(buf, srcOffset) |
| 1475 | if err != nil { |
| 1476 | f.sl.DebugContext(ctx, "Failed to read block from file", slogutil.FilePath(srcName), "blockHash", block.Hash, slogutil.Error(err)) |
| 1477 | return false |
| 1478 | } |
| 1479 | |
| 1480 | // Hash is not SHA256 as it's an encrypted hash token. In that |
| 1481 | // case we can't verify the block integrity so we'll take it on |
| 1482 | // trust. (The other side can and will verify.) |
| 1483 | if f.Type != config.FolderTypeReceiveEncrypted { |
| 1484 | if err := f.verifyBuffer(buf, block); err != nil { |
| 1485 | f.sl.DebugContext(ctx, "Failed to verify block buffer", slogutil.Error(err)) |
| 1486 | return false |
| 1487 | } |
| 1488 | } |
| 1489 | |
| 1490 | dstFd, err := state.tempFile() |
| 1491 | if err != nil { |
| 1492 | // State is already marked as failed when an error is returned here. |
| 1493 | return false |
| 1494 | } |
| 1495 | |
| 1496 | if f.CopyRangeMethod != config.CopyRangeMethodStandard { |
| 1497 | err = f.withLimiter(ctx, func() error { |
| 1498 | dstFd.mut.Lock() |
| 1499 | defer dstFd.mut.Unlock() |
| 1500 | return fs.CopyRange(f.CopyRangeMethod.ToFS(), fd, dstFd.fd, srcOffset, block.Offset, int64(block.Size)) |
| 1501 | }) |
| 1502 | } else { |
| 1503 | err = f.limitedWriteAt(ctx, dstFd, buf, block.Offset) |
| 1504 | } |
| 1505 | if err != nil { |
| 1506 | state.fail(fmt.Errorf("dst write: %w", err)) |
| 1507 | return false |
| 1508 | } |
| 1509 | return true |
| 1510 | } |
| 1511 | |
| 1512 | func (*sendReceiveFolder) verifyBuffer(buf []byte, block protocol.BlockInfo) error { |
| 1513 | if len(buf) != block.Size { |
no test coverage detected