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
2 changes: 1 addition & 1 deletion .ci/build-n-run.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash

function build_mod()
{
{
make all || exit 1
}

Expand Down
76 changes: 76 additions & 0 deletions .ci/check-commentflow.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env bash

# Reflow comments to the column limit, or check that they already are.
#
# clang-format breaks a comment line that runs past ColumnLimit but never
# refills a short-wrapped one, so comment width is the one part of the house
# style no other gate settles. commentflow reads the same ColumnLimit from
# .clang-format, which keeps comment width and code width on one number.
#
# The selection below is shared by --write and the default check, so what gets
# rewritten is what gets checked.
#
# Exit codes: 0 clean, 1 files would change, 2 the check could not run.

set -u -o pipefail

cd "$(dirname "${BASH_SOURCE[0]}")/.." || exit 2

case "${1:-}" in
"" | --check) write=0 ;;
--write) write=1 ;;
*)
echo "usage: $0 [--check | --write]" >&2
exit 2
;;
esac

COMMENTFLOW="${COMMENTFLOW:-commentflow}"

if ! command -v "$COMMENTFLOW" > /dev/null 2>&1; then
echo "Error: $COMMENTFLOW not found" >&2
echo "Install it from https://github.com/sysprog21/commentflow" >&2
exit 2
fi

# Untracked but non-ignored files are included, so a new file is covered before
# it is staged. A while-read loop because macOS ships bash 3.2 (no mapfile).
# Enumerated before the loop so a failing git is an error, not an empty list.
list=$(mktemp)
trap 'rm -f "$list"' EXIT
git ls-files -z --cached --others --exclude-standard \
-- '*.c' '*.h' '*.sh' > "$list" || exit 2
files=()
while IFS= read -r -d '' f; do
# A tracked file deleted from the worktree is not a reflow target.
[ -e "$f" ] && files+=("$f")
done < "$list"

if [ "${#files[@]}" -eq 0 ]; then
echo "Error: no files selected; the pathspec no longer matches the tree" >&2
exit 2
fi

printf ' CFLOW %d files\n' "${#files[@]}"

if [ "$write" -eq 1 ]; then
exec "$COMMENTFLOW" "${files[@]}"
fi

status=0
"$COMMENTFLOW" --check "${files[@]}" || status=$?

if [ "$status" -eq 0 ]; then
echo "Comment reflow clean."
exit 0
fi

# Exit 1 means "these files would change"; anything else is the tool failing to
# read them, which must not be reported as a style violation.
if [ "$status" -ne 1 ]; then
echo "Error: $COMMENTFLOW exited $status (I/O or parse error)" >&2
exit "$status"
fi

echo "Run '$0 --write' to reflow, or '$COMMENTFLOW --diff <file>' to see one." >&2
exit 1
71 changes: 56 additions & 15 deletions .ci/check-format.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,62 @@
#!/usr/bin/env bash

SOURCES=$(find $(git rev-parse --show-toplevel) | egrep "\.(cpp|cc|c|h)\$")

CLANG_FORMAT=$(which clang-format-12)
if [ $? -ne 0 ]; then
CLANG_FORMAT=$(which clang-format)
if [ $? -ne 0 ]; then
echo "[!] clang-format not installed. Unable to check source file format policy." >&2
exit 1
# Verify clang-format conformance for all tracked C/H files. The repository's
# .clang-format is calibrated against clang-format-20; other versions produce
# different output and are rejected to keep CI deterministic.
#
# Exit codes, matching .ci/check-commentflow.sh: 0 clean, 1 files differ from
# the style, 2 the check could not run.

set -u -o pipefail

cd "$(dirname "${BASH_SOURCE[0]}")/.." || exit 2

if [ -z "${CLANG_FORMAT:-}" ]; then
if command -v clang-format-20 > /dev/null 2>&1; then
CLANG_FORMAT="clang-format-20"
else
CLANG_FORMAT="clang-format"
fi
fi

set -x
# The pin is checked on whatever binary was resolved, an explicit CLANG_FORMAT
# included, so it cannot be bypassed by naming one.
if ! "$CLANG_FORMAT" --version 2> /dev/null | grep -qE 'version 20\.'; then
echo "Error: clang-format 20 is required (other versions differ in style)" >&2
exit 2
fi

expected=$(mktemp)
trap 'rm -f "$expected"' EXIT

# Enumerate first, NUL-delimited: a failing git inside a process substitution
# would be indistinguishable from "no files" and pass the gate.
list=$(mktemp)
trap 'rm -f "$expected" "$list"' EXIT
git ls-files -z -- '*.c' '*.h' > "$list" || exit 2
if [ ! -s "$list" ]; then
echo "Error: no C sources tracked; the pathspec no longer matches" >&2
exit 2
fi

# A tool failure (2) outranks a style difference (1).
rc=0
while IFS= read -r -d '' file; do
# A tracked file deleted from the worktree is not a style defect.
[ -e "$file" ] || continue
if ! "$CLANG_FORMAT" "$file" > "$expected"; then
echo "Error: $CLANG_FORMAT failed on $file" >&2
rc=2
continue
fi
st=0
diff -u -p --label="$file" --label="expected coding style" \
"$file" "$expected" || st=$?
if [ "$st" -gt 1 ]; then
rc=2
elif [ "$st" -eq 1 ] && [ "$rc" -eq 0 ]; then
rc=1
fi
done < "$list"

for file in ${SOURCES};
do
$CLANG_FORMAT ${file} > expected-format
diff -u -p --label="${file}" --label="expected coding style" ${file} expected-format
done
exit $($CLANG_FORMAT --output-replacements-xml ${SOURCES} | egrep -c "</replacement>")
exit "$rc"
4 changes: 3 additions & 1 deletion .ci/check-newline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ set -e -u -o pipefail

ret=0
show=0
# Reference: https://medium.com/@alexey.inkin/how-to-force-newline-at-end-of-files-and-why-you-should-do-it-fdf76d1d090e

# Reference:
# https://medium.com/@alexey.inkin/how-to-force-newline-at-end-of-files-and-why-you-should-do-it-fdf76d1d090e
while IFS= read -rd '' f; do
if file --mime-encoding "$f" | grep -qv binary; then
tail -c1 < "$f" | read -r _ || show=1
Expand Down
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
65 changes: 46 additions & 19 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,64 @@ name: main

on: [push, pull_request]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
simplefs:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: install-dependencies
run: |
sudo apt-get install build-essential
- name: automated test
run: |
.ci/build-n-run.sh
shell: bash
- name: checkout code
uses: actions/checkout@v7
- name: install dependencies
run: sudo apt-get update && sudo apt-get install -y build-essential
- name: automated test
run: .ci/build-n-run.sh
shell: bash

coding_style:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: checkout code
uses: actions/checkout@v4
- name: coding convention
uses: actions/checkout@v7
- name: newline at end of file
run: .ci/check-newline.sh
# commentflow ships as a release binary, not an apt package. The bytes
# are checked against the sha256 GitHub records for the asset, read from
# the API in the same step, so no hash is kept in this file.
- name: install commentflow
env:
ASSET: commentflow-x86_64-unknown-linux-gnu.tar.gz
GH_TOKEN: ${{ github.token }}
run: |
sudo apt-get install -q -y clang-format
.ci/check-newline.sh
.ci/check-format.sh
shell: bash
set -euo pipefail
meta=$(gh api repos/sysprog21/commentflow/releases/tags/latest)
Comment thread
jserv marked this conversation as resolved.
Resolved
read -r digest url < <(jq -r --arg n "$ASSET" \
'.assets[] | select(.name == $n) | "\(.digest) \(.browser_download_url)"' <<< "$meta")
if [ -z "${digest:-}" ] || [ -z "${url:-}" ] || [ "$digest" = null ]; then
echo "no digest or download URL recorded for $ASSET" >&2
exit 1
fi
curl -fsSL -o /tmp/commentflow.tar.gz "$url"
echo "${digest#sha256:} /tmp/commentflow.tar.gz" | sha256sum -c -
sudo tar -xzf /tmp/commentflow.tar.gz -C /usr/local/bin commentflow
- name: comment reflow
run: .ci/check-commentflow.sh
# The major version must match the one .ci/check-format.sh requires.
- name: install clang-format 20
run: pipx install 'clang-format==20.1.8'
- name: clang-format
run: .ci/check-format.sh

mkfs_macos:
runs-on: macos-latest
steps:
- name: checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: test mkfs.simplefs on macOS
run: |
.ci/test-mkfs-macos.sh
run: .ci/test-mkfs-macos.sh
shell: bash
9 changes: 7 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,15 @@ However, participation requires adherence to fundamental ground rules:
This variant should be considered the standard for all documentation efforts.
For instance, opt for "initialize" over "initialise" and "color" rather than "colour".

Software requirement: [clang-format](https://clang.llvm.org/docs/ClangFormat.html) version 18 or later.
Software requirements:
* [clang-format](https://clang.llvm.org/docs/ClangFormat.html) version 20.
`.ci/check-format.sh` rejects other versions, because their output differs.
* [commentflow](https://github.com/sysprog21/commentflow), which reflows comments to the column limit.
Do not hand-wrap comment text; run `.ci/check-commentflow.sh --write` and let it place the breaks.

This repository consistently contains an up-to-date `.clang-format` file with rules that match the explained ones.
For maintaining a uniform coding style, execute the command `clang-format -i *.{c,h}`.
For maintaining a uniform coding style, run `.ci/check-commentflow.sh --write` first, then clang-format 20 (`-i *.{c,h}`).
The order matters: clang-format never refills a short-wrapped comment, and commentflow settles that before clang-format normalizes indentation.

## Coding Style for Modern C

Expand Down
15 changes: 8 additions & 7 deletions bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

#include "simplefs.h"

/* Returns the first bit found and clears the following 'len' consecutive
* free bits (sets them to 1) in a given in-memory bitmap spanning multiple
* blocks. Returns 0 if an adequate number of free bits were not found.
* Assumes the first bit is never free (reserved for the superblock and the
* root inode), allowing the use of 0 as an error value.
/* Returns the first bit found and clears the following 'len' consecutive free
* bits (sets them to 1) in a given in-memory bitmap spanning multiple blocks.
*
* Returns 0 if an adequate number of free bits were not found. Assumes the
* first bit is never free (reserved for the superblock and the root inode),
* allowing the use of 0 as an error value.
*/
static inline uint32_t get_first_free_bits(unsigned long *freemap,
unsigned long size,
Expand Down Expand Up @@ -39,8 +40,8 @@ static inline uint32_t get_free_inode(struct simplefs_sb_info *sbi)
return ret;
}

/* Return 'len' unused block(s) number and mark it used.
* Clean the block content.
/* Return 'len' unused block(s) number and mark it used. Clean the block
* content.
* Return 0 if no enough free block(s) were found.
*/
static inline uint32_t get_free_blocks(struct super_block *sb, uint32_t len)
Expand Down
8 changes: 4 additions & 4 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

#include "simplefs.h"

/* Iterate over the files contained in dir and commit them to @ctx.
* This function is called by the VFS as ctx->pos changes.
/* Iterate over the files contained in dir and commit them to @ctx. This
* function is called by the VFS as ctx->pos changes.
* Returns 0 on success.
*/
static int simplefs_iterate(struct file *dir, struct dir_context *ctx)
Expand All @@ -26,8 +26,8 @@ static int simplefs_iterate(struct file *dir, struct dir_context *ctx)
if (!S_ISDIR(inode->i_mode))
return -ENOTDIR;

/* Check that ctx->pos is not bigger than what we can handle (including
* . and ..)
/* Check that ctx->pos is not bigger than what we can handle (including .
* and ..)
*/
if (ctx->pos > SIMPLEFS_MAX_SUBFILES + 2)
return 0;
Expand Down
10 changes: 5 additions & 5 deletions extent.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

#include "simplefs.h"

/* Search for the extent containing the target block. Binary search is used
* for efficiency.
/* Search for the extent containing the target block. Binary search is used for
* efficiency.
*
* Returns the first unused file index if not found.
* Returns -1 if the target block is out of range.
*/
uint32_t simplefs_ext_search(struct simplefs_file_ei_block *index,
uint32_t iblock)
{
/* First, find the first unused file index with binary search.
* It will be our right boundary for actual binary search and the return
* value when the file index is not found.
/* First, find the first unused file index with binary search. It will be
* our right boundary for actual binary search and the return value when the
* file index is not found.
*/
uint32_t start = 0;
uint32_t end = SIMPLEFS_MAX_EXTENTS - 1;
Expand Down
13 changes: 6 additions & 7 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ static int simplefs_writepage(struct page *page, struct writeback_control *wbc)
#endif

/* Called by the VFS when a write() syscall is made on a file, before writing
* the data into the page cache. This function checks if the write operation
* can complete and allocates the necessary blocks through block_write_begin().
* the data into the page cache. This function checks if the write operation can
* complete and allocates the necessary blocks through block_write_begin().
*/
#if SIMPLEFS_AT_LEAST(6, 15, 0)
static int simplefs_write_begin(const struct kiocb *iocb,
Expand Down Expand Up @@ -299,11 +299,10 @@ static int simplefs_write_end(struct file *file,
return ret;
}

/*
* Called when a file is opened in the simplefs.
* It checks the flags associated with the file opening mode (O_WRONLY, O_RDWR,
* O_TRUNC) and performs truncation if the file is being opened for write or
* read/write and the O_TRUNC flag is set.
/* Called when a file is opened in the simplefs. It checks the flags associated
* with the file opening mode (O_WRONLY, O_RDWR, O_TRUNC) and performs
* truncation if the file is being opened for write or read/write and the
* O_TRUNC flag is set.
*
* Truncation is achieved by reading the file's index block from disk, iterating
* over the data block pointers, releasing the associated data blocks, and
Expand Down
Loading
Loading