This directory contains example programs demonstrating how to use the BFC (Binary File Container) library.
Demonstrates how to create a new BFC container and add files and directories to it.
Features shown:
- Creating a new container with
bfc_create() - Adding directories with
bfc_add_dir() - Adding files with
bfc_add_file() - Finalizing the container with
bfc_finish() - Proper resource cleanup with
bfc_close()
Usage:
./create_example my_container.bfcDemonstrates how to read from an existing BFC container.
Features shown:
- Opening a container with
bfc_open() - Verifying container integrity with
bfc_verify() - Listing container contents with
bfc_list() - Getting file statistics with
bfc_stat() - Reading file content with
bfc_read() - Partial file reading with offset and length
- Proper resource cleanup with
bfc_close_read()
Usage:
./read_example my_container.bfcDemonstrates how to extract files from a BFC container to the filesystem.
Features shown:
- Opening and listing container contents
- Creating directory structure on extraction
- Extracting files with
bfc_extract_to_fd() - Error handling and cleanup
- File verification after extraction
Usage:
./extract_example my_container.bfc [output_directory]Demonstrates encryption and decryption features using ChaCha20-Poly1305 AEAD encryption (requires libsodium support).
Features shown:
- Password-based encryption with Argon2id key derivation
- Key file encryption with 32-byte raw keys
- Combining encryption with compression
- Secure key handling and memory clearing
- Creating encrypted containers with sensitive data
- Decrypting and verifying container contents
- Error handling for authentication failures
Usage:
# Demo mode (creates test data and shows all encryption methods)
./encrypt_example
# Create encrypted container with password
./encrypt_example create-password secure.bfc mypassword /path/to/files
# Create encrypted container with key file
./encrypt_example create-keyfile secure.bfc secret.key /path/to/files
# Extract encrypted container with password
./encrypt_example extract-password secure.bfc mypassword
# Extract encrypted container with key file
./encrypt_example extract-keyfile secure.bfc secret.keyNote: This example is only available when BFC is built with libsodium support (-DBFC_WITH_SODIUM=ON).
The examples are automatically built when you build the main BFC project:
cmake -S . -B build
cmake --build buildThe example executables will be located in build/examples/.
You can also build the examples as a standalone project if you have BFC installed:
cd examples
mkdir build && cd build
cmake -S .. -B .
cmake --build .Here's a quick demo showing all examples in action:
# Build the project (with encryption support)
cmake -S . -B build -DBFC_WITH_SODIUM=ON -DBFC_WITH_ZSTD=ON
cmake --build build
# Go to examples directory
cd build/examples
# Create a sample container
./create_example demo.bfc
# Read the container contents
./read_example demo.bfc
# Extract all files to a directory
mkdir extracted
./extract_example demo.bfc extracted
# Verify extracted content
ls -la extracted/
cat extracted/README.md
# Encryption demo (if libsodium is available)
if [ -f ./encrypt_example ]; then
echo "Running encryption demo..."
./encrypt_example
fiAll BFC functions return an integer result code. Always check for BFC_OK:
int result = bfc_create("container.bfc", 4096, 0, &writer);
if (result != BFC_OK) {
fprintf(stderr, "Failed to create container: %d\n", result);
return 1;
}Always pair create/open calls with corresponding close calls:
// Writer
bfc_t *writer;
bfc_create(..., &writer);
// ... use writer ...
bfc_close(writer);
// Reader
bfc_t *reader;
bfc_open(..., &reader);
// ... use reader ...
bfc_close_read(reader);Use temporary files or file descriptors for adding content:
// From memory via tmpfile()
FILE *temp = tmpfile();
fwrite(content, 1, content_len, temp);
rewind(temp);
bfc_add_file(writer, "path", temp, mode, mtime, &crc);
fclose(temp);
// Extract to file descriptor
int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
bfc_extract_to_fd(reader, "path", fd);
close(fd);Use callback functions for processing container entries:
static int process_entry(const bfc_entry_t *entry, void *user_data) {
printf("Found: %s (size: %llu)\n", entry->path, entry->size);
return 0; // Continue iteration
}
bfc_list(reader, NULL, process_entry, NULL);Configure compression settings when creating containers:
#include <bfc.h>
// Create container with compression
bfc_t *writer;
int result = bfc_create("archive.bfc", 4096, 0, &writer);
if (result != BFC_OK) return 1;
// Enable ZSTD compression (level 3)
result = bfc_set_compression(writer, BFC_COMP_ZSTD, 3);
if (result != BFC_OK) {
fprintf(stderr, "ZSTD compression not available\n");
// Fall back to no compression
bfc_set_compression(writer, BFC_COMP_NONE, 0);
}
// Only compress files larger than 1KB
bfc_set_compression_threshold(writer, 1024);
// Add files normally - compression is automatic
FILE *file = fopen("large_file.txt", "rb");
bfc_add_file(writer, "large_file.txt", file, 0644, 0, NULL);
fclose(file);
// Check current compression setting
uint8_t comp_type = bfc_get_compression(writer);
printf("Using compression: %s\n", bfc_compress_name(comp_type));
bfc_finish(writer);
bfc_close(writer);Compression workflow:
- Create container with
bfc_create() - Set compression with
bfc_set_compression()(optional) - Set threshold with
bfc_set_compression_threshold()(optional) - Add files normally - BFC handles compression automatically
- Files are compressed based on content analysis and threshold
- Extraction is transparent - decompression happens automatically
Content analysis for automatic compression:
- Files with high zero content (>10% zeros)
- Files with repetitive patterns (>20% repeated bytes)
- Text-like content (>80% printable ASCII)
- Files larger than threshold size (default: 64 bytes minimum)
Example: Checking compression effectiveness
// After adding files, check compression statistics
bfc_entry_t entry;
result = bfc_stat(reader, "large_file.txt", &entry);
if (result == BFC_OK) {
double ratio = bfc_compress_ratio(entry.size, entry.obj_size);
printf("File: %s\n", entry.path);
printf("Original: %llu bytes\n", entry.size);
printf("Stored: %llu bytes\n", entry.obj_size);
printf("Compression: %s\n", bfc_compress_name(entry.comp));
printf("Storage ratio: %.1f%%\n", ratio);
if (entry.comp != BFC_COMP_NONE && entry.size > 0) {
printf("Space saved: %.1f%%\n", (1.0 - ratio/100.0) * 100.0);
}
}When compiling your own programs that use BFC:
# Include the header directory
gcc -I/path/to/bfc/include your_program.c -lbfc -o your_program
# Or with pkg-config (if installed)
gcc $(pkg-config --cflags --libs bfc) your_program.c -o your_programRequired headers:
<bfc.h>- Main BFC API<sys/stat.h>- For file mode constants (S_IFREG, S_IFDIR, etc.)<fcntl.h>- For file descriptor operations (when using extract_to_fd)
Compression support:
- Link with
-lzstdif BFC was built with ZSTD support - Check for
BFC_WITH_ZSTDmacro or testbfc_compress_is_supported(BFC_COMP_ZSTD) - Compression functions are available via
<bfc.h>(no separate header needed)