Release Notes v0.7.0¶
Released: 2026-10-12
Highlights¶
A cancellable file lock, directory sync and owner-only permission checks in
fs, so modules can stop keeping platform-specific files of their own, and a
test that enforces that oscompat itself has no dependencies.
New Features¶
fs.Lock¶
Problem solved: mutual exclusion between processes on a file needs
syscall.Flock on Unix and LockFileEx on Windows, which means a
_unix.go, a _windows.go and a stub for everything else in every module that
needs it.
Solution:
import "github.com/grokify/oscompat/fs"
unlock, err := fs.Lock(ctx, "/var/lib/myapp/state.lock")
if err != nil {
return err // the context's error, or fs.ErrLockUnsupported
}
defer unlock()
| Behavior | Detail |
|---|---|
| Waiting | Polls until the lock is free or the context ends, then returns the context's error |
| Release | Calling the returned function releases it, and is safe to call twice; the operating system also releases it if the process exits, however it exits |
| Scope | Two calls in one process exclude each other, as two processes do |
| Advisory | It excludes only callers that also take it |
| Unsupported platform | fs.ErrLockUnsupported, so a caller can fail closed rather than proceed unlocked |
The lock file is created with owner-only permissions.
fs.SyncDir¶
Problem solved: after writing a file to a temporary name and renaming it
over the target, the rename is only durable once the directory is flushed.
Unix lets you open a directory and Sync it; Windows does not.
Solution:
On Windows, and on platforms with no way to ask, it does nothing and returns nil, because there a rename is atomic and nothing stronger is available.
Permission checks¶
Problem solved: code that refuses a world-readable key file, and tests that
assert 0600, are wrong on Windows, where modes are not enforced.
if fs.PermissionsEnforced() { /* false on Windows */ }
info, _ := os.Stat(path)
if err := fs.CheckPrivate(info); errors.Is(err, fs.ErrNotPrivate) {
// group or others can access it
}
err := fs.ChmodPrivate(f) // 0600 on an open file
| Function | Behavior |
|---|---|
PermissionsEnforced() |
Whether the platform enforces mode bits |
IsPrivate(info) |
Owner-only; always true where modes are not enforced |
CheckPrivate(info) |
An error matching ErrNotPrivate that names the mode; nil where modes are not enforced |
ChmodPrivate(f) |
Restricts an open file to its owner; a failure is ignored where modes are not enforced |
Policy test¶
The module imports the standard library and itself, and nothing else, so any
module can import it. policy_test.go fails on a require, replace or tool
directive, a go.sum, or an import from outside the standard library and the
module. See the policy.
Documentation¶
- A MkDocs site with a guide for each package.
- The portable tests guide covers permission
assertions with
fs.PermissionsEnforced(), closing handles in simulated-crash tests, and the lock and directory sync.
Installation¶
Compatibility¶
No breaking changes. The module still has no dependencies outside the standard
library, and fs.Lock and fs.SyncDir use only syscall.