Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .agents/rules/coding-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
trigger: model_decision
description: After generating or editing code
---

# F3 Coding Style

## 1. General Principles
- **Language**: C (C17 standard as specified in the Makefile).
- **Line Length**: Maximum 80 columns. The only exception is for literal strings to facilitate grep-ability of output messages.
- **Portability**: Uses POSIX features and includes OS-specific blocks (e.g., `__APPLE__`, `__OpenBSD__`, `__CYGWIN__`) where necessary.

## 2. Formatting and Indentation
- **Indentation**: Uses **Tabs** for indentation.
- **Braces**: K&R style. Opening braces `{` are on the same line as the statement (`if`, `while`, `for`, `switch`, `struct`, and function definitions).
- **Whitespace**:
- Space after keywords (`if`, `while`, `for`, `switch`, `do`).
- No space between function name and the opening parenthesis `(`.
- Pointers: `char *ptr` (space before the asterisk, not after).
- Alignment: Struct member assignments and function parameters are often aligned using tabs when spanning multiple lines.

## 3. Naming Conventions
- **Files**: Lowercase with `snake_case` (e.g., `f3read.c`, `libutils.h`).
- **Variables and Functions**: `snake_case` (e.g., `check_chunk`, `bytes_read`).
- **Types (structs, enums, typedefs)**: `snake_case` (e.g., `struct block_stats`, `enum block_state`).
- **Macros and Constants**: `UPPER_CASE` (e.g., `SECTOR_ORDER`, `UNUSED`).
- **Enum Members**: Lowercase with a short prefix (e.g., `bs_unknown`, `bs_good`).

## 4. Functions and Variables
- **Scope**: Internal helper functions are marked `static`. Small, performance-critical functions are marked `static inline`.
- **Declarations**: Variables are declared at the beginning of their scope.
- **Initialization**: Structs are often initialized using designated initializers or `memset`.

## 5. Macros
- **Safety**: Multi-line macros use the `do { ... } while (0)` idiom.
- **Parentheses**: Arguments and the final expression are wrapped in parentheses to prevent precedence issues.
- **Alignment**: Backslashes `\` in multi-line macros are aligned.

## 6. Error Handling and Correctness
- **Assertions**: Heavy use of `assert()` for internal state verification and "can't happen" cases.
- **Error Propagation**: Uses `goto out` patterns for resource cleanup or direct returns of error codes (e.g., `errno`).
- **Safety**: Prefers `snprintf` over `sprintf`.

## 7. Headers and Includes
- **Include Guards**: Format `HEADER_FILENAME_H` (e.g., `#ifndef HEADER_LIBUTILS_H`).
- **Order**: Standard library headers followed by local project headers.
- **Documentation**: Comments in headers are often aligned using tabs for readability.

## 8. Comments
- **Style**: Uses C-style comments `/* ... */`.
- **Placement**: Comments are placed above the code they describe or as trailing comments aligned with tabs.
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
cscope.out

*.swp
*~

doc/_build

build/
a/
cscope.out
perf.data
perf.data.old
3 changes: 3 additions & 0 deletions .vscode/gdb-sudo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
#sudo /usr/bin/gdb "$@"
pkexec /usr/bin/gdb "$@"
66 changes: 66 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "f3brew test",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/f3brew",
"args": ["--debug", "test"],
"MIMode": "gdb",
},
{
"name": "f3probe unit-test",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/f3probe",
"args": ["--debug-unit-test", "test"],
"MIMode": "gdb",
},
{
"name": "f3probe simple test",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/f3probe",
"args": ["--debug", "--destructive", "--verbose", "test"],
"MIMode": "gdb",
},
{
"name": "f3probe test",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/f3probe",
"args": ["--debug-real-size=1G", "--debug-fake-size=1T", "--debug-wrap=40", "--debug-cache-order=21", "--debug-strict-cache", "--destructive", "--verbose", "test"],
"MIMode": "gdb",
// Uncomment the following line to run under sudo:
//"miDebuggerPath": "${workspaceFolder}/.vscode/gdb-sudo.sh"
},
{
// Create folder "a" before launching.
"name": "f3write a",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/f3write",
"args": ["--end-at=5", "a"],
"MIMode": "gdb",
},
{
// Create folder "a" before launching.
"name": "f3read a",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/f3read",
"args": ["a"],
"MIMode": "gdb",
}
]
}
29 changes: 29 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"makefile.launchConfigurations": [
{
"cwd": "${workspaceFolder}",
"binaryPath": "${workspaceFolder}/build/f3brew",
"binaryArgs": []
},
{
"cwd": "${workspaceFolder}",
"binaryPath": "${workspaceFolder}/build/f3fix",
"binaryArgs": []
},
{
"cwd": "${workspaceFolder}",
"binaryPath": "${workspaceFolder}/build/f3probe",
"binaryArgs": []
},
{
"cwd": "${workspaceFolder}",
"binaryPath": "${workspaceFolder}/build/f3read",
"binaryArgs": []
},
{
"cwd": "${workspaceFolder}",
"binaryPath": "${workspaceFolder}/build/f3write",
"binaryArgs": []
}
]
}
18 changes: 18 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make",
"type": "shell",
"command": "make",
"args": ["all", "extra"],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$gcc"
}
]
}
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ The files of the stable version of F3 are
`here <https://github.com/AltraMayor/f3/tags>`__. The
following command uncompresses the files::

$ unzip f3-9.0.zip
$ unzip f3-10.0.zip

.. highlight:: bash

Expand Down
8 changes: 8 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
Version 10.0 - Apr 29, 2026

* f3probe: New probing algorithm and --verbose flag
* f3brew: Progress report and rate limiting (i.e., --max-write-rate and --max-read-rate)
* f3write/f3read: Report per-file min/max and average speeds
* GitHub Actions: FreeBSD and OpenBSD support
* Move codebase from C99 to C17 and refactor project

Version 9.0 - Mar 27, 2025

* f3read/f3write: Avoid the execution stack to list files
Expand Down
4 changes: 2 additions & 2 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
# built documents.
#
# The short X.Y version.
version = '9.0'
version = '10.0'
# The full version, including alpha/beta/rc tags.
release = '9.0'
release = '10.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
30 changes: 15 additions & 15 deletions doc/contribute.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@ How can you help?
an article about fake flash. The media has not been covering this
subject, and having more users aware that fake flash exists will make
counterfeiters' life harder.
- If you own fake flash, consider donating them to me. I've been
working on ``f3probe`` to tell in a few seconds if a flash drive is
fake or not. I expect that ``f3probe`` will be a game changer, but I
lack a diverse set of fake flash samples to check my hypotheses.
Before you mail me the card, e-mail me the output you got from
``f3write``, ``f3read``, and (if possible) ``f3probe`` as well as the
size the card was expected to be; I'm trying to amass a diverse set
of fake flash, not necessarily a large number of them.
- If you own fake flash, consider opening an issue on GitHub to offer
donating it to anyone willing to help with the development of F3.
Even if having someone accepting your offer is a long shot,
it's a bet in the right direction: growing our community.
To help someone identify how your fake drive can support their tests,
include in the issue the output you got from ``f3write``, ``f3read``, and
(if possible) ``f3probe`` as well as the size the card was expected to be.
The output of ``f3probe`` is particularly useful when you use the parameters
``--verbose``, ``--destructive``, and ``--time-ops``.
- Improve this documentation. New users would benefit from your perspective
on how F3 works and how to use it. Create a pull request with your
improvements and I'll prioritize reviewing it.
- If you know how to use F3 well on your platform, write a blog entry
about it, and let me know the link so I can post it on this page. You
can also send me your name and e-mail to publish on this page as
someone that can help other users of your platform.
- (New) If you have a dual-boot machine with Windows and Linux, write a
blog entry that compares h2testw, f3write/f3read, FakeFlashTest.exe,
and f3probe. If you do this comparison, please send me the link to
- If you have a dual-boot machine with Windows and Linux, write a
blog entry that compares h2testw vs f3write/f3read, FakeFlashTest.exe and
ValiDrive vs f3probe. If you do this comparison, please send me the link to
publish it on this page.
- If you are able to test F3 on your platform, send me your name and
e-mail, and I'll send to you a request to test new code when it is
available on GitHub before I release it as stable to everyone. I only
have Linux boxes, so other platforms are specially helpful.
- If you are able to code, improve F3. I want to keep the code small to
easily audit it, so focus on things that will either address a real
need, for example, users' requests, or to simplify the code, or fix
Expand Down
6 changes: 3 additions & 3 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ in the example below (please use the correct device!):

$ sudo build/f3probe --destructive --time-ops /dev/sdb
[sudo] password for michel:
F3 probe 9.0
F3 probe 10.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

Expand Down Expand Up @@ -674,7 +674,7 @@ outputs:

$ sudo build/f3probe --time-ops /dev/sdc
[sudo] password for michel:
F3 probe 9.0
F3 probe 10.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

Expand Down Expand Up @@ -734,7 +734,7 @@ The execution of ``f3fix`` on my fake drive went as follows:
::

$ sudo build/f3fix --last-sec=16477878 /dev/sdb
F3 fix 9.0
F3 fix 10.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

Expand Down
2 changes: 1 addition & 1 deletion man/f3read.1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.\"Text automatically generated by txt2man
.TH F3 "1" "October 2020" "F3 9.0" "test real flash memory capacity"
.TH F3 "1" "October 2020" "F3 10.0" "test real flash memory capacity"
.SH NAME
\fBf3write, f3read \fP- test real flash memory capacity
.SH SYNOPSIS
Expand Down
10 changes: 6 additions & 4 deletions src/f3brew.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ static void write_blocks(struct device *dev, struct flow *fw,
measure(fw, blocks_to_write, NULL);
first_pos = next_pos;
}
end_measurement(fw, false);
end_measurement(fw);
dbuf_free(&dbuf);
}

Expand All @@ -314,6 +314,7 @@ static void test_write_blocks(struct device *dev,
fflush(stdout);

init_flow(&fw, block_order, total_blocks, max_write_rate,
FW_MAX_BLOCKS_PER_DELAY_NONE,
show_progress ? printf_flush_cb : dummy_cb, 0);

write_blocks(dev, &fw, first_block, last_block);
Expand Down Expand Up @@ -452,7 +453,7 @@ static void read_blocks(struct device *dev, struct flow *fw,
measure(fw, blocks_to_read, NULL);
first_pos = next_pos;
}
end_measurement(fw, false);
end_measurement(fw);
dbuf_free(&dbuf);

if (range.state != bs_unknown)
Expand All @@ -475,6 +476,7 @@ static void test_read_blocks(struct device *dev,
first_block != last_block ? "s" : "", first_block, last_block);

init_flow(&fw, block_order, total_blocks, max_read_rate,
FW_MAX_BLOCKS_PER_DELAY_NONE,
show_progress ? printf_flush_cb : dummy_cb, 0);

read_blocks(dev, &fw, first_block, last_block, &stats);
Expand All @@ -501,8 +503,8 @@ int main(int argc, char **argv)
.strict_cache = false,
.first_block = 0,
.last_block = -1ULL,
.max_read_rate = 0,
.max_write_rate = 0,
.max_read_rate = FW_MAX_PROCESS_RATE_NONE,
.max_write_rate = FW_MAX_PROCESS_RATE_NONE,
/* If stdout isn't a terminal, suppress progress. */
.show_progress = isatty(STDOUT_FILENO),
};
Expand Down
4 changes: 2 additions & 2 deletions src/f3probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,8 @@ int main(int argc, char **argv)
.verbose = false,
/* If stdout isn't a terminal, suppress progress. */
.show_progress = isatty(STDOUT_FILENO),
.max_read_rate = 0,
.max_write_rate = 0,
.max_read_rate = FW_MAX_PROCESS_RATE_NONE,
.max_write_rate = FW_MAX_PROCESS_RATE_NONE,
.real_size_byte = 1ULL << 31,
.fake_size_byte = 1ULL << 34,
.wrap = 31,
Expand Down
Loading
Loading