# How Croc Handles File Transfer Resume After Interruption

> Discover how croc ensures robust file transfer resume after interruptions. Learn about its receiver-side detection, hash verification, and efficient chunk requesting for seamless transfers.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: internals
- Published: 2026-07-26

---

**Croc implements resumable file transfers at the receiver side by detecting existing partial files, verifying their hashes, calculating missing chunks via `utils.MissingChunks`, and requesting only the remaining data from the sender.**

Croc is a secure, peer-to-peer file transfer tool written in Go that enables seamless resumption of interrupted transfers without restarting from the beginning. Unlike simple append-only resume mechanisms, croc uses a **chunk-oriented protocol** that identifies exactly which portions of a file are missing and requests only those specific chunks. This article examines the resume implementation in the `schollz/croc` repository, focusing on the receiver-side logic in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) and the chunk-level data management system.

## Detecting Existing Files and Calculating Missing Chunks

When a transfer reconnects after interruption, croc first checks whether the destination file already exists. In [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), the function `updateIfRecipientHasFileInfo` (lines 331–351) orchestrates this detection process.

The receiver follows a strict validation sequence:

- **File existence check**: Verifies if a file with the expected name exists at the destination path
- **Size verification**: Compares local file size against the sender's advertised size
- **Hash validation**: Computes the hash of the local file and compares it with the sender's hash

When hashes differ—indicating partial or corrupted data—croc calculates the exact missing segments:

```go
// From src/utils/utils.go
chunkRanges := utils.MissingChunks(filename, chunkSize)
missingChunks := utils.ChunkRangesToChunks(chunkRanges)

```

The `MissingChunks` function scans the local file for empty (zero-filled) sections, while `ChunkRangesToChunks` converts these ranges into a flat list of specific chunk offsets. The chunk size is calculated as `models.TCP_BUFFER_SIZE/2`, optimizing the balance between network efficiency and resume granularity.

## User Confirmation and Resume Negotiation

Unless the `--overwrite` flag is supplied, croc pauses to confirm the resume operation. The system outputs a prompt showing the percentage already received:

```text
Resume 'myfile.txt' (87.3%)? (y/N)   (use --overwrite to omit)

```

When the user confirms (or when `--overwrite` is used), the receiver constructs a resume request containing the list of missing chunk offsets. Using the communication layer in [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go)—specifically `Comm.Send` and `Comm.Receive`—the receiver transmits this control message to the sender via the established secure channel.

The sender's `sendData` routine receives this information and continues streaming data for **all** chunks in sequence. However, the protocol design allows the sender to transmit the complete stream while the receiver selectively processes only the bytes belonging to the missing ranges.

## Chunk-Level Data Writing and Offset Management

The actual data reconstruction occurs in `receiveData` within [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go). As the sender streams chunks, the receiver processes each one using `CurrentFile.WriteAt`:

```go
// Writing at specific offset in src/croc/croc.go
file.WriteAt(chunkData, offset)

```

This random-access approach enables precise resume behavior:

- **Selective writing**: The receiver writes only chunks matching the missing list, discarding data for chunks that already exist locally
- **Exact positioning**: Each chunk is written to its specific byte offset rather than appending sequentially
- **Completion detection**: The transfer finishes when all expected chunks are received, signaled by `Message.TypeCloseSender` from [`src/message/message.go`](https://github.com/schollz/croc/blob/main/src/message/message.go)

## Progress Synchronization and UI Updates

To provide accurate visual feedback during a resumed transfer, croc updates the progress bar to reflect the already-received portion immediately. The code calls:

```go
c.bar.Add64(bytesDone)

```

This fast-forwards the progress indicator to match the percentage of data already present on disk. For example, if 87.3% of the file exists locally, the progress bar begins at 87.3% rather than filling from zero.

## Summary

- **Detection logic**: `updateIfRecipientHasFileInfo` in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) (lines 331–351) identifies existing files and validates integrity through hashing
- **Chunk calculation**: `utils.MissingChunks` and `utils.ChunkRangesToChunks` in [`src/utils/utils.go`](https://github.com/schollz/croc/blob/main/src/utils/utils.go) determine exactly which data requires retransmission
- **Selective I/O**: The receiver uses `CurrentFile.WriteAt` to write only missing chunks at specific offsets while the sender's `sendData` streams all chunks
- **User control**: Resume requires confirmation unless `--overwrite` is specified
- **Progress tracking**: `c.bar.Add64(bytesDone)` synchronizes the UI to show accurate resume progress

## Frequently Asked Questions

### How does croc determine which parts of a file need to be retransmitted?

Croc scans the existing partial file using `utils.MissingChunks` to detect empty (zero-filled) sections, then converts these ranges into specific chunk offsets with `utils.ChunkRangesToChunks`. This process, implemented in [`src/utils/utils.go`](https://github.com/schollz/croc/blob/main/src/utils/utils.go), creates a precise inventory of missing data blocks that the receiver requests from the sender.

### What happens if I move the partially downloaded file to a different location?

Croc only resumes transfers if the partial file exists at the original destination path with the matching filename. If the file is moved, croc will treat the transfer as new. Moving the file back to the original location before restarting will allow the resume detection in `updateIfRecipientHasFileInfo` to function correctly.

### Does using --overwrite affect the resume capability?

Yes, the `--overwrite` flag forces croc to overwrite any existing file completely, starting the transfer from the beginning regardless of how much data was previously received. This bypasses the hash verification and missing chunk calculation entirely, effectively disabling the resume feature for that transfer.

### Is the resume feature compatible with all versions of croc?

The resume mechanism relies on the chunk-oriented protocol and specific message types like `Message.TypeCloseSender` defined in [`src/message/message.go`](https://github.com/schollz/croc/blob/main/src/message/message.go). Both sender and receiver must support the control message protocol for resume to function. The receiver-side implementation in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) handles the detection and negotiation, making resume generally compatible when both parties use standard croc versions.