Skip to content

feat: add IsReadable and IsWritable - #7

Merged
christiangda merged 1 commit into
mainfrom
add-readable-writable-predicates
Aug 18, 2026
Merged

feat: add IsReadable and IsWritable#7
christiangda merged 1 commit into
mainfrom
add-readable-writable-predicates

Conversation

@christiangda

Copy link
Copy Markdown
Contributor

What

Two predicates for the question fsx cannot currently answer: not what a path is, but what you may do with it.

fsx.IsReadable(path)   // regular file, owner-read bit set
fsx.IsWritable(path)   // regular file, owner-write bit set

Why

The motivating case is a tool that validates a path it will later rewrite — a configuration file, a lock file — and would rather refuse at validation time than fail halfway through a write. Exists and IsFile both pass a read-only file happily, so a validator built from them reports success and the write fails later, in a worse place.

Found while adopting fsx in aizon-shared/machete, which needed exactly this for its --config.file check and had to keep a local helper for it. Everything else it needed, fsx already had — including HasExtension, which is better than the hardcoded suffix check it replaced.

Mode bits, not effective access — and the docs say so

Both inspect the file mode, not the calling process's effective access. That is the portable answer the standard library can give: os.Stat exposes mode bits on every platform, while asking "can I open this?" requires access(2) or an attempted open, neither available portably without cgo or a build tag.

Rather than paper over that, the doc comments state it and point a caller who needs certainty at opening the file — noting that the answer can change between any check and the open regardless. A predicate cannot promise more than the mode bits it read, and a name like IsWritable is a footgun if the limitation isn't written down.

Consistency

Follows the existing conventions:

  • paths expanded via ExpandPath first, like every other function
  • empty path, missing path, and non-regular file all report false
  • shared hasOwnerBits helper, so the two cannot drift
  • doc.go gains a "Permission Predicates" section

Tests

Table-driven in the existing style, covering empty / readable / write-only / read-only / directory / missing for both, plus HOME and ~ expansion. One Example and one Benchmark.

gofmt, go vet and go test ./... clean.

Two predicates for the question the package could not answer: not what a path *is*, but
what you may do with it.

The motivating case is a tool that validates a path it will later rewrite — a
configuration file, a lock file — and would rather refuse at validation time than fail
halfway through a write. `Exists` and `IsFile` both pass a read-only file happily.

Both inspect the file mode rather than the calling process's effective access, and the
documentation says so plainly. That is the portable answer the standard library can give:
os.Stat exposes mode bits on every platform, while asking "can I open this?" requires
access(2) or an attempted open — neither available portably without cgo or a build tag.
The doc comments point a caller who needs certainty at opening the file instead, and note
that the answer can change between any check and the open anyway.

Consistent with the rest of the package: paths are expanded first, and an empty path, a
missing path and a non-regular file all report false.

Tests cover both predicates across empty/readable/write-only/read-only/directory/missing,
plus HOME expansion. One example and one benchmark, matching the existing style.
@christiangda christiangda self-assigned this Aug 18, 2026
@christiangda
christiangda merged commit 95a9053 into main Aug 18, 2026
4 checks passed
@christiangda
christiangda deleted the add-readable-writable-predicates branch August 18, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant