How Croc Handles File Metadata and Integrity Verification: A Deep Dive into the Source Code

Croc ensures file integrity by computing cryptographic hashes on the sender side, embedding them in a FileInfo metadata structure, and validating them against real-time recomputed hashes on the receiver side after transfer.

Croc is a secure, cross-platform file transfer tool written in Go that prioritizes data integrity alongside end-to-end encryption. Understanding how croc handles file metadata and integrity verification requires examining its core data structures and validation flows implemented in the source code.

The FileInfo Struct: Croc's Metadata Container

Every file transfer begins with the FileInfo struct defined in src/croc/croc.go. This compact envelope captures everything needed to reconstruct a file accurately on the remote system.

The struct contains the following critical fields:

  • Name: Base filename or directory name
  • FolderRemote and FolderSource: Destination and source relative paths
  • Hash: Cryptographic checksum of file contents
  • Size: File size in bytes
  • ModTime: Original modification timestamp (time.Time)
  • IsCompressed and IsEncrypted: Boolean flags indicating transmission transformations
  • Symlink: Target path for symbolic links

Hash Algorithm Selection

Before transmission, the sender computes hashes using helper functions in src/utils/utils.go. Croc supports multiple algorithms selected by the user: MD5HashFile, XXHashFile, IMOHashFile, and HighwayHashFile. The chosen algorithm and resulting hash populate the Hash field before the metadata transmits to the receiver via a TypeFileInfo message (defined in src/message/message.go).

Sender-Side Metadata Preparation

When initiating a transfer, the CLI invokes GetFilesInfoWithExactExclusions (src/cli/cli.go, lines 512-563) to walk source paths. This function constructs FileInfo instances for each item, computes content hashes using the selected algorithm, and packages empty directories separately for reconstruction.

// CLI preparation - building file list with hashes
fi, empty, total, err := croc.GetFilesInfoWithExactExclusions(
    []string{"mydir/"}, false, true, []string{}, []string{})
if err != nil { log.Fatal(err) }

client := croc.NewClient(opts)          // opts includes HashAlgorithm = "md5"
client.Send(fi, empty, total)          // metadata (including hash) is sent automatically

Receiver-Side Validation and Security

Upon receiving metadata, croc immediately validates incoming data to prevent directory traversal attacks and ensure completeness. The validation logic in src/croc/croc.go (lines 674-690) performs three critical checks:

  1. Rejects paths containing ".." components that would escape the receive directory
  2. Discards empty-folder metadata that would resolve outside the intended destination
  3. Ensures required fields (Name, Size, Hash) are present and non-empty

These checks run before any file data transfers, protecting the receiver's filesystem from hostile metadata.

Real-Time Integrity Verification During Transfer

During the actual file transfer, integrity verification happens concurrently with the download. The receiver streams bytes to disk while recomputing the hash using the same algorithm advertised by the sender. After the final byte writes, croc compares the computed hash against the metadata hash at lines 2590-2608:

// Inside client.processMessageFileInfo (receiver)
computedHash, err := utils.HashFile(pathToTmp, fileInfo.HashAlgorithm)
if err != nil { return false, err }

if !bytes.Equal(fileInfo.Hash, computedHash) {
    return false, fmt.Errorf("hash mismatch for %s", fileInfo.Name)
}
os.Chtimes(filepath.Join(fileInfo.FolderRemote, fileInfo.Name),
            fileInfo.ModTime, fileInfo.ModTime)

If bytes.Equal returns false, the transfer aborts immediately with a hash mismatch error. This mechanism catches corruption from network errors, storage failures, or malicious tampering.

Handling Compressed and Encrypted Files

For compressed or encrypted transfers, croc computes and verifies hashes after applying these transformations. This validates the exact byte stream written to disk, ensuring end-to-end integrity of the transmitted data rather than the original uncompressed content.

Preserving File Attributes After Verification

Successful transfers preserve original metadata using os.Chtimes (src/croc/croc.go, lines 2655-2659). The receiver applies the ModTime from the FileInfo struct to the newly written file, maintaining accurate timestamps across systems. This occurs only after the hash verification succeeds, ensuring corrupted files never receive authentic metadata.

Summary

  • Croc uses the FileInfo struct in src/croc/croc.go to encapsulate file metadata including cryptographic hashes, paths, and timestamps
  • Senders compute hashes using MD5, xxhash, imohash, or highwayhash via helper functions in src/utils/utils.go
  • The receiver validates metadata using security checks at lines 674-690 to prevent directory traversal and ensure required fields exist
  • Integrity verification occurs during download with final comparison at lines 2590-2608, aborting on any hash mismatch
  • Original modification times are preserved using os.Chtimes only after successful verification

Frequently Asked Questions

What hash algorithms does croc support for integrity verification?

Croc supports four cryptographic hash functions: MD5, xxhash, imohash, and highwayhash. The sender selects the algorithm during transfer initiation via configuration options, and both sides use the same method for valid comparison. These implementations reside in src/utils/utils.go.

How does croc prevent directory traversal attacks via metadata?

Croc inspects incoming FileInfo paths in src/croc/croc.go (lines 674-690) and rejects any containing ".." components or paths that would resolve outside the designated receive directory. Test cases in src/croc/croc_test.go verify that hostile metadata triggers appropriate errors without touching the filesystem.

Does croc verify integrity before or after compression and encryption?

Croc computes and verifies hashes after compression and encryption are applied. This ensures the integrity check validates the exact byte stream transmitted over the network and written to disk, guaranteeing end-to-end integrity of the actual transferred payload.

What happens if a file fails the hash verification check?

If the recomputed hash does not match the metadata hash at lines 2590-2608, croc immediately aborts the transfer and returns a hash mismatch error. The partially downloaded file is discarded, preventing corrupted data from being committed to the filesystem or retaining incorrect timestamps.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →