# The Storage Kit: BStatable

Derived from: none

Declared in: be/storage/Statable.h

Library: libbe.so

## Overview

BStatable is a pure abstract class that provides functionality for its two derived class, BEntry and BNode. The BStatable functions let you get and set "statistical" information about a node in the file system. You can...

- Determine whether the node is a file, directory, or symbolic link.
- Get and set an node's owner, group, and permissions.
- Get and set the node's creation, modification, and access times.
- Get the size of the node's data (not counting attributes).
- Get a BVolume object for the node's volume.
- Get the `node_ref` of the node (and pass it to `watch_node()`, most likely).

### Nodes and Entries

Technically, BStatable information pertains to nodes, not entries. The fact that BEntry implements the BStatable functions is a (slightly confusing) convenience: When you invoke a BStatable function on a BEntry object, what you're really doing is asking for information about the node that corresponds to the object.

#### Abstract Entries

As explained in BEntry, it's possible to create "abstract" BEntry objects; in other words, objects that don't correspond to actual files (nodes) on the disk. You can't get (or set) BStatable information for abstract entries. The BStatable functions return `B_BAD_VALUE` if the invoked-upon entry is abstract.

### Relationship to stat()

The BStatable functions are covers for the POSIX `stat()` call. `stat()` retrieves a file-specific `stat` structure, which records the statistics listed above (and then some). Although BStatable was designed to hide `stat` details, you can get the `stat` structure through the `GetStat()` function. The `stat` structure is described in The stat Structure at the end of this specification.

`stat()` is notorious for being expensive. Furthermore, the `stat` structure is stale as soon as it gets back from the `stat()` call. If you're concerned with efficiency, be aware that every BStatable function (the "setters" as well as the "getters") performs a `stat()`. For example, calling `GetOwner()` and then `GetGroup()` results in two `stat()` calls. If you want to look at lot of fields (within the same `stat` structure) all at once, you might consider using BStatable's `GetStat()` function.

As for integrity, BStatable info-getting functions are obviously in the same boat as the `stat()` call itself: The retrieved data isn't guaranteed to be in sync with the actual state of the `stat()`'d item.

The BDirectory class also defines a `stat`-retrieving function that, in some cases, can be more efficient than the `GetStat()` function defined here:

- The `BDirectory::GetStatFor()` function retrieves the `stat` structure for the node of a named entry within a directory. If you're interested in getting `stat` information for a series of nodes within the same directory, you should use this function. You have to call it iteratively (once for each named entry), but the accumulation of the iterated calls will be faster than the `GetStat()` calls made on the analogous BEntry objects.

### Accessing Unreadable and Unwritable Entries

BStatable isn't thwarted by file permissions: If you can construct a valid BEntry or BNode to an item, then you can invoke any of the info-getting BStatable functions on that object:

- The BStatable functions aren't denied even if the node that you're looking at is read-protected. However, you can only invoke the info-setting functions if the node allows writing.

- Similarly, you can get `stat` info for a locked node, but you won't be able to write the info (through functions such as `SetOwner()`) unless your object holds the lock. See BNode for more on locking.

### Other Details

You rarely set `stat information.` In practice, you rarely use BStatable's info-setting functions. Setting information such as when a file was created, who owns it, or how big it is, is the responsibility of the system and the privilege of the user. For example, when you `Write()` to a BFile object, the system automatically updates the size and modification date for the file.

## Member Functions

### GetAccessTime() see GetCreationTime()

### GetCreationTime(), SetCreationTime(), GetModificationTime(), SetModificationTime(), GetAccessTime(), SetAccessTime()

          status_t GetCreationTime(time_t *ctime) const
          status_t SetCreationTime(time_t ctime)

          status_t GetModificationTime(time_t *mtime) const
          status_t SetModificationTime(time_t mtime)

          status_t GetAccessTime(time_t *atime) const
          status_t SetAccessTime(time_t atime)

|  | Access time is currently unused.

These function let you get and set the time at which the item was created, last modified, and last accessed (opened). The measure of time is given as seconds since (the beginning of ) January 1, 1970.

|  | The time quanta that `stat` uses is seconds; the rest of the BeOS measures time in microseconds (`bigtime_t`).

RETURN CODES

- `B_NO_ERROR`. Success.
- `B_NOT_ALLOWED`. You tried to set a time field for a file on a read-only volume.
- `B_NO_MEMORY`. Couldn't get the necessary resources to complete the transaction.
- `B_BAD_VALUE`. The node doesn't exist (abstract entry).

### GetGroup() see GetOwner()

### GetNodeRef()

          status_t GetNodeRef(node_ref *nref) const

Copies the item's `node_ref` structure into the nref argument, which must be allocated.

Typically, you use an node's `node_ref` as a key to the Node Monitor by passing the `node_ref` structure to the `watch_node()` function. The Node Monitor watches the node for specific changes; see "The Node Monitor" section of this chapter for details.

As a convenience, you can use a `node_ref` structure to initialize a BDirectory object (through the constructor or `BDirectory::SetTo()` function).

RETURN CODES

- `B_NO_ERROR`. Success.
- `B_NO_MEMORY`. Couldn't get the necessary resources to complete the transaction.
- `B_BAD_VALUE`. The node doesn't exist (abstract entry).

### GetModificationTime() see GetCreationTime()

### GetOwner(), SetOwner(), GetGroup(), SetGroup(), GetPermissions(), SetPermissions()

          status_t GetOwner(uid_t *owner) const
          status_t SetOwner(uid_t owner)

          status_t GetGroup(gid_t *group) const
          status_t SetGroup(gid_t group)

          status_t GetPermissions(mode_t *perms) const
          status_t SetPermissions(mode_t perms)

These functions set and get the owner, group, and read/write/execute permissions for the node:

- The owner identifier encodes the identity of the user that "owns" the file.

- The group identifier encodes the "group" that is permitted group access to the file (as declared by the permissions).

- The permissions value records nine "permission facts": Whether the file can be read, written, and executed by the node's owner, by users in the node's group, and by everybody else (read/write/execute * owner/group/others = 9 items).

The `uid_t`, `gid_t`, and `mode_t` types used here are standard POSIX types. All three are 32-bit unsigned integers and are defined in posix/sys/types.h.

The owner and group encodings must match values found in the system's user and group files (which are as currently unimplemented).

The permissions value is a combination of the following bitfield constants (defined in posix/sys/stat.h):

- `S_IRUSR` owner's read bit.
- `S_IWUSR` owner's write bit.
- `S_IXUSR` owner's execute bit.
- `S_IRGRP` group's read bit.
- `S_IWGRP` group's write bit.
- `S_IXGRP` group's execute bit.
- `S_IROTH` others' read bit.
- `S_IWOTH` others' write bit.
- `S_IXOTH` others' execute bit.

For example:

       /* Is a file readable by everybody? */
       mode_t perms;
       if (node.GetPermissions(&perms) < B_NO_ERROR)
          /* handle the error... */

       if (perms & S_ISROTH)
          // Yes it is
       else
          // No it isn't

RETURN CODES

- `B_NO_ERROR`. Success.
- `B_NOT_ALLOWED`. You tried to set permissions on a read-only volume.
- `B_BAD_VALUE`. The node doesn't exist (abstract entry).

### GetPermissions() see GetOwner()

### GetSize()

          status_t GetSize(off_t *size) const

Sets the size of the node's data portion (in bytes). Only the "used" portions of the node's file blocks are counted; the amount of storage the node actually requires (i.e. the number of blocks the node consumes) may be larger than the size given here.

The size measurement doesn't include the node's attributes.

RETURN CODES

- `B_NO_ERROR`. Success.
- `B_NO_MEMORY`. Couldn't get the necessary resources to complete the transaction.
- `B_BAD_VALUE`. The node doesn't exist (abstract entry).

### GetStat()

          virtual status_t GetStat(struct stat *st) const

`GetStat()` returns the `stat` structure for the node. The structure is copied into the st argument, which must be allocated. The `stat` structure is described in The stat Structure, below. The BStatable object does not cache the `stat` structure; every time you call `GetStat()`, fresh `stat` information is retrieved.

RETURN CODES

- `B_NO_ERROR`. Success.
- `B_NO_MEMORY`. Couldn't get the necessary resources to complete the transaction.
- `B_BAD_VALUE`. The node doesn't exist (abstract entry).

### SetAccessTime() see GetCreationTime()

### SetCreationTime() see GetCreationTime()

### SetGroup() see GetOwner()

### SetModificationTime() see GetCreationTime()

### SetOwner() see GetOwner()

### SetPermissions() see GetOwner()

## The stat Structure

Declared in: posix/sys/stat.h

The `stat` structure looks like this:

       struct stat {
           dev_t         st_dev;
           ino_t         st_ino;
           mode_t         st_mode;
           nlink_t         st_nlink;
           uid_t         st_uid;
           gid_t         st_gid;
           off_t         st_size;
           dev_t         st_rdev;
           size_t         st_blksize;
           time_t         st_atime;
           time_t         st_mtime;
           time_t         st_ctime;
       } stat;

And the fields are...

- `st_dev` identifies the node's device.
- `st_ino` is the node's "inode" number.

By combining `st_dev` and `st_ino` you can roll your own `node_ref`:

       node_ref nref;
       stat st;

       if (file.GetStat(&st) == B_NO_ERROR) {
          nref.dev = st.st_dev;
          nref.node = st.st_ino;
       }

Meanwhile...

- `st_mode` describes the node's flavor: plain file, directory or symbolic link. To test the field, pass it to the `S_ISREG()`, `S_ISDIR()`, and `S_ISLNK()` boolean macros:

       if (S_ISREG(st.st_mode))
          /* it's a "regular" file */
          else if (S_ISDIR(st.st_mode))
             /* it's a directory */
             else if (S_ISLNK(st.st_mode))
                /* it's a symbolic link */

- `st_nlink` is the number of "hard links" that point to this node.

- `st_uid` and `st_gid` are the user (owner) and group ids that were described in the `GetOwner()` function.

- `st_rdev` is, well, no one really knows. It's provided for System V compatibility (hold your applause), but it's unused.

- `st_blksize` is the "preferred block size" that's used during copying. The `cp` command line program and `BFile::CopyTo()` functions allocate buffers of this size when they're copying the file's data.

- `st_atime`, `st_mtime`, and `st_ctime` are the access, modification, and creation times in seconds since January 1, 1970. Access time (`st_atime`) is currently unused.

The Be Book, in lovely HTML, for BeOS Release 3.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.