Haiku BStatable: Node Metadata, Permissions, and Freshness Checks
Use Haiku BStatable to inspect node type, ownership, permissions, size, and timestamps without mistaking metadata snapshots for stable identity.
BStatable is an abstract Storage Kit interface shared by objects such as BEntry and BNode. It wraps common stat-style operations: identifying a file, directory, or symlink; retrieving a node reference; reading owner, group, permissions, size, and timestamps; and obtaining the containing volume. It gives application code a consistent way to inspect filesystem state, but it does not turn those values into a lock, a durable identity token, or a guarantee that a later open refers to the same object.
The most reliable way to use it is to treat each getter as a checked observation and each setter as a separate mutation with its own result. A successful GetStat() records what the node looked like at that call. Another process can rename, replace, truncate, or update the node immediately afterward. Use an already-open BNode or BFile when an operation needs to continue against the same open object, and revalidate by an appropriate identity when working by path later.
Choose BEntry or BNode for the operation
BStatable itself is a common base, not an object you construct directly. BEntry represents a directory entry and is useful for path-oriented operations. BNode is appropriate when you need node-oriented access to attributes or other node operations. Both expose stat-like methods, but their initialization and lifetime contracts differ. Check each object’s InitCheck() before calling methods and preserve the object that matches the task.
BEntry entry(path, true);
status_t status = entry.InitCheck();
if (status != B_OK)
return status;
struct stat st;
status = entry.GetStat(&st);
if (status != B_OK)
return status;
if (S_ISDIR(st.st_mode)) {
// Apply directory-specific policy using this observed state.
}
This example illustrates a checked snapshot. If the application needs a symlink-specific policy, call IsSymLink() or inspect the relevant stat mode, but do not confuse the link object with the target it names. Decide explicitly whether the operation should follow a link. BStatable::IsFile(), IsDirectory(), and IsSymLink() return Boolean observations; a false result can also mean the object is not initialized or the test did not match, so they are not a substitute for status-bearing initialization checks.
Keep identity, size, and attributes distinct
GetNodeRef() provides a node_ref that can be used with node monitoring APIs. It is not a content checksum, pathname, or promise that a file will remain mounted. Combine it with volume context when reconciling asynchronous notifications, and revalidate after unmount/remount transitions. If content identity matters, open the node and calculate an application-level digest under an explicit consistency policy.
GetSize() reports the node data size and does not include BFS attributes, according to the official reference. Do not use it as a total storage footprint or a proxy for metadata growth. A directory’s size is not necessarily a recursive sum of its children. Use a traversal with error handling if the user asks for a subtree total, and state whether the result is a live estimate or a stable snapshot.
Attributes have their own API and semantics. A change to an attribute is not the same thing as a change to the file’s primary data stream. Likewise, a change to st_size does not prove that all named attributes are intact. When a user reports lost metadata, inspect BNode attribute operations separately from the BStatable fields.
Read permissions as policy inputs, not authorization proof
GetOwner(), GetGroup(), and GetPermissions() read ownership and mode data. Their setter counterparts request updates. Check status from each call and report permission failures distinctly from missing files or invalid objects. A UI that displays mode bits should use the platform’s mode definitions and explain the scope of the bits rather than presenting an ambiguous octal value alone.
Do not implement authorization as “check permissions now, then use the path later.” That pattern races another process and may not account for the effective credentials at the later operation. Attempt the actual operation and handle its result. For destructive changes, show the target and requested change to the user, then verify the node again before applying it. A successful mode update does not guarantee that every filesystem implements identical permission behavior or that a parent directory permits access.
If changing owner, group, or permissions is part of a migration, record the original values and apply mutations in a controlled sequence. Some writes can succeed before a later call fails. Either restore the old state and verify the rollback or produce a clear report of partial completion. Do not silently treat unsupported setters as if they succeeded.
Interpret timestamps carefully
BStatable exposes modification, creation, and access time getters and setters. These fields are useful for display, sorting, and application workflows, but they are not monotonic clocks. Access-time updates may depend on filesystem behavior and policy; modification time may be changed by applications; and creation time is not a universal historical audit record. Use a dedicated monotonic timer for measuring durations.
Timestamps may have different resolution or persistence characteristics across filesystems. When comparing two values, account for granularity and conversion to local time. Avoid a synchronization rule such as “this timestamp is newer, therefore the corresponding content is newer” unless your application controls every writer and update path. For conflict resolution, store a separate revision or digest when the consequence of a false ordering would be data loss.
Setting timestamps intentionally changes user-visible metadata and may affect backup tools or synchronization software. Do not touch a modification time merely to preserve a copy operation’s appearance without understanding the downstream behavior. Test the specific volume types the product supports and verify the result by reopening the node.
Use GetStat() for related fields, but not as a transaction
When several stat fields need to describe one observation, prefer one successful GetStat() call and copy the fields you need from that returned struct stat. This reduces inconsistencies from making several separate getter calls. It still does not freeze the node after the call. For workflows that must compare a before/after state, capture both observations and report that another writer may have changed the object between them.
Validate output pointers before calling wrappers and do not inspect fields after a failed status. Avoid keeping pointers to stack struct stat beyond their scope. If an operation is queued to a worker, carry the checked value data and a suitable node reference, then resolve and re-check the target in the worker. A stale UI snapshot should not authorize a background deletion.
Failure-oriented verification
Test a missing entry, renamed entry, symlink, inaccessible parent, read-only volume, unsupported metadata mutation, permission denial, and volume removal while a worker is queued. Verify each status is handled and that the UI distinguishes an observed false type check from failed initialization. Exercise a file whose contents and attributes change concurrently to expose assumptions about freshness.
Acceptance tests should verify data size separately from attribute size, read and write access with the actual operation, node-reference reconciliation after mount changes, and timestamp behavior on the filesystems the application supports. Capture the volume type and Haiku revision in reports; do not generalize one volume’s behavior to all supported volumes.
Acceptance criteria
Accept a BStatable workflow when initialization and status are checked, observations are treated as snapshots, identity-sensitive operations retain or revalidate the correct node, and every setter has a partial-failure plan. Keep permission checks separate from authorization decisions and timestamps separate from duration measurement.
BStatable centralizes node metadata operations; it does not provide transactional filesystem access, content integrity, or a universal security policy.
Related:
- Haiku BNode Attributes: Typed Metadata Reads and Writes
- Haiku BVolume: Capacity, Free-Space Snapshots, and Filesystem Capabilities
Sources: