# The Storage Kit: BDirectory

Derived from: BNode, BEntryList

Declared in: be/storage/Directory.h

Library: libbe.so

## Overview

A BDirectory object gives you access to the contents of a directory. A BDirectory's primary features are:

- It can iteratively retrieve the entries in the directory. The entries are returned as BEntry objects, `entry_refs`, or `dirent` structures (`GetNextEntry()`, `GetNextRef()`, `GetNextDirents()`).

- It can find a specific entry. You can ask if the entry exists (`Contains()`), and you can retrieve the entry as a BEntry (`FindEntry()`).

- It can create new entries. Through the aptly named `CreateFile()`, `CreateDirectory()` and `CreateSymLink()` functions.

Unlike the other BNode classes, a BDirectory knows its own entry (`GetEntry()`)`,` and can be initialized with a `node_ref` structure.

### Retrieving Entries

The BDirectory functions that let you iterate over a directory's entries are inherited from BEntryList:

|  | status_t `GetNextEntry(`BEntry *entry, bool traverse = `true)`; status_t `GetNextRef(`entry_ref *ref`)`; int32 `GetNextDirents(`dirent *buf, size_t length, int32 count = INT_MAX`)`

For the basic story on these functions, see the BEntryList class and the function descriptions below. In addition to the info you'll find there, you should be aware of the following:

- Entries are returned in "directory order". This is, roughly, the ASCII order of their names.

- Try not to alter the directory while you're getting its entries. Entries are delivered on demand. If you do something to change the contents of the directory while you're iterating through those contents (such as change the name of the file "aaa" to "zzz") you could end up seeing an entry more than once (technically, you'll see the same node under the guise of different entries), or you could miss an entry.

- Counting entries uses the same iterator that retrieves entries. You mustn't call `CountEntries()` while you're looping over a GetNext...() function.

### Creating New Directories

To create a new directory, you can use BDirectory's `CreateDirectory()` function. The function creates a single new directory as identified by its argument. The new directory will be a subdirectory of the invoked-upon BDirectory's directory.

You can also create an entire path full of new directories through the global `create_directory()` function. This convenient function attempts to create all "missing" directories along the path that you pass in.

### Finding a Directory

The `find_directory()` function gives you the pathnames for pre-defined directories. These directories, such as those that store Be-supplied applications and user-defined preferences settings, are represented by `directory_which` constants. These constants are not strings; you can't use them directly. You have to pass them through `find_directory()`.

Note that the BDirectory class itself doesn't let you find directories on the basis of the `directory_which` constants--you have to use the `find_directory()` function (which is documented at the end of this class description).

### Node Monitoring a Directory

|  | The following description is a brief, directory-specific view into the Node Monitor. For the full story, see "The Node Monitor" section of this chapter.

You can monitor changes to the contents of a directory by passing a BDirectory's `node_ref` and the `B_WATCH_DIRECTORY` flag to the Node Monitor's `watch_node()` function. As with all invocations of `watch_node()`, you also have to pass a BMessenger (the "target") that will receive the Node Monitor notifications; here, we use `be_app_messenger`:

       BDirectory dir("/boot/home");
       node_ref nref;
       status_t err;

       if (dir.InitCheck() == B_OK) {
          dir.GetNodeRef(&nref);
          err = watch_node(&nref, B_WATCH_DIRECTORY, be_app_messenger);
          if (err != B_OK)
             /* handle the error */
       }

The following changes to the monitored directory cause BMessages to be sent to the target. The `what` field for all Node Monitor messages is `B_NODE_MONITOR`; the "opcode" field (an integer code) describes the activity:

- An entry was created (opcode = `B_ENTRY_CREATED`).

- An entry was moved to a different name in the same directory (`B_ENTRY_RENAMED`).

- An entry was from moved from this directory to a different directory, or vice versa (`B_ENTRY_MOVED`).

- An entry (and the node it represents) was deleted from the file system (`B_ENTRY_REMOVED`).

The `B_WATCH_DIRECTORY` flag (by itself) doesn't monitor changes to the directory's own entry. For example, if you change the name of the directory that you're monitoring, the target isn't sent a message. If you want a BDirectory to watch changes to itself, you have to throw in one of the other Node Monitor flags (`B_WATCH_NAME`, `B_WATCH_STAT`, or `B_WATCH_ATTR`).

The other fields in the Node Monitor message describe the entry that changed. The set of fields depends on the opcode (the following is a summary of the list given in Notification Messages in the Node Monitor documentation):

#### B_ENTRY_CREATED

Field | Type | Description
"device" | `B_INT32_TYPE` | `dev_t` of the directory's device.
"directory" | `B_INT64_TYPE` | `ino_t` (node number) of the directory.
"node" | `B_INT64_TYPE` | `ino_t` of the new entry's node.
"name" | `B_STRING_TYPE` | The name of the new entry.

`

`

#### B_ENTRY_MOVED

The "device", "node", and "name" fields are the same as for `B_ENTRY_CREATED`, plus...

Field | Type | Description
"from_directory" | `B_INT64_TYPE` | The `ino_t` number of the old directory.
"to_directory" | `B_INT64_TYPE` | `The ino_t` number of the new directory.

`

`

#### B_ENTRY_REMOVED

The `B_ENTRY_REMOVED` message takes the same form as `B_ENTRY_CREATED`, but without the "name" field. This, obviously, can be a problem--what good is it if you're told that a file has been removed, but you're not told the file's name? In some cases, simply being told that a file has been removed actually is good enough: You can simply re-read the contents of the directory.

## Constructor and Destructor

### BDirectory()

          BDirectory(const entry_ref *ref)
          BDirectory(const node_ref *nref)
          BDirectory(const BEntry *entry)
          BDirectory(const char *path)
          BDirectory(const BDirectory *dir, const char *path)

          BDirectory(void)
          BDirectory(const BDirectory &directory)

Creates a new BDirectory object that represents the directory as given by the arguments. See the analogous `SetTo()` functions for descriptions of the flavorful constructors.

- The default constructor does nothing; it should be followed by a call to `SetTo()`.

- The copy constructor points the BDirectory to the same directory as is represented by the argument. The two objects have their own entry iterators.

To check to see if an initialization was successful, call `InitCheck()`.

### ~BDirectory()

          virtual ~BDirectory()

Deletes the object.

## Member Functions

### Contains()

          bool Contains(const char *path, int32 nodeFlags = B_ANY_NODE) const
          bool Contains(const BEntry *entry, int32 nodeFlags = B_ANY_NODE) const

Returns `true` if path or entry is contained within this directory, or in any of its subdirectories (no matter how deep). You can use the nodeFlags argument to limit the search to a particular flavor of node:

- `B_FILE_NODE` looks for a "plain" file.
- `B_DIRECTORY_NODE` looks for a directory.
- `B_SYMLINK_NODE` looks for a symbolic link.
- `B_ANY_NODE` (the default) doesn't discriminate between flavors.

### CountEntries() see GetNextEntry()

### CreateDirectory() see CreateFile()

### CreateFile(), CreateDirectory(), CreateSymLink()

          status_t CreateFile(const char *path, BFile *file, bool failIfExists = false)

          status_t CreateDirectory(const char *path, BDirectory *dir)

          status_t CreateSymLink(const char *path, const char *linkToPath, BSymLink *link)

These functions create a new file, directory, or symbolic link. The new node is located at path. If path is relative, it's reckoned off of the directory represented by this BDirectory; if it's absolute, the path of this BDirectory is ignored.

- `CreateFile()` fails if the file already exists and failIfExists is `true`. If the flag is `false` (and the file exists), the old file is clobbered and a new one is created. If successful, the BFile argument that you pass in is opened on the new file in `B_READ_WRITE` mode.

- `CreateDirectory()` and `CreateSymLink()` fail if path already exists--you can't clobber an existing directory or link.

- The linkToPath argument (`CreateSymLink()`) is the path that the new symbolic link will be linked to.

In all cases, the object argument (the BDirectory, BFile, or BSymLink) must be allocated before it's passed in. If the function fails, the argument is `Unset()`.

RETURN CODES

- `B_OK`. Success.
- `B_BAD_VALUE`. Illegal path, file, dir, or link specified; may be `NULL`. path may be empty.
- `B_BUSY`. A busy node could not be accessed.
- `B_ENTRY_NOT_FOUND`. The specified path does not exist or is an empty string.
- `B_FILE_ERROR`. A file system error prevented the operation.
- `B_FILE_EXISTS`. The file specified by path already exists.
- `B_LINK_LIMIT`. A cyclic loop has been detected in the file system.
- `B_NAME_TOO_LONG`. The path specified is too long.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.
- `B_NO_MORE_FDS`. All file descriptors are in use (too many open files).
- `B_IS_A_DIRECTORY`. Can't replace a directory with a file.
- `B_NOT_A_DIRECTORY`. A component of the path is not a directory.
- `B_NOT_ALLOWED`. The volume is read-only.
- `B_PERMISSION_DENIED`. Create access is denied in the specified path.
- `E2BIG`. linkToPath is too long (`CreateSymLink()` only).

### CreateSymLink() see CreateFile()

### FindEntry()

          status_t FindEntry(const char *path, BEntry *entry, bool traverse = false) const

Finds the entry with the given name, and sets the second argument to refer to that entry.

- path must be a relative pathname. It's reckoned off of the BDirectory's directory.

- You are allowed to look for "." and "..". The former represents this directory's entry. The latter refers to this directory's parent.

- The entry argument must be allocated before it's passed in (it needn't be initialized).

- The traverse applies to symbolic links: If the flag is `true`, the link is traversed. If it's `false`, you get the BEntry that points to the link itself.

If path isn't found, the second argument is automatically `Unset()`. To find out why the lookup failed, invoke `InitCheck()` on the entry argument:

       BEntry entry;
       status_t err;

       if (dir.FindEntry("aFile", &entry) != B_OK) {
          err = entry.InitCheck();
       }

The direct return value is also informative, but it may not be as precise as the `InitCheck()` value.

RETURN CODES

- `B_OK`. Success.
- `B_BAD_VALUE`. Invalid path specified; it may be `NULL` or empty.
- `B_ENTRY_NOT_FOUND`. The specified path does not exist.
- `B_NAME_TOO_LONG`. The path specified is too long.
- `B_LINK_LIMIT`. A cyclic loop has been detected in the file system.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.
- `B_FILE_ERROR`. An invalid file prevented the operation.

### GetEntry()

          status_t GetEntry(BEntry *entry) const

Initializes entry to represent this BDirectory. If the initialization fails, entry is `Unset()`.

RETURN CODES

- `B_OK`. Success.
- `B_NAME_TOO_LONG`. The path specified by entry is too long.
- `B_ENTRY_NOT_FOUND`. The specified path does not exist.
- `B_LINK_LIMIT`. A cyclic loop has been detected in the file system.
- `B_BAD_VALUE`. entry is uninitialized.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.
- `B_BUSY`. A busy node could not be accessed.
- `B_FILE_ERROR`. An invalid file prevented the operation.
- `B_NO_MORE_FDS`. All file descriptors are in use (too many open files).
- `B_NOT_A_DIRECTORY`. The path includes non-directory entries.

### GetNextDirents() see GetNextEntry()

### GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries(), Rewind()

          virtual status_t GetNextEntry(BEntry *entry, bool traverse = false)
          virtual status_t GetNextRef(entry_ref *ref)
          virtual int32  GetNextDirents(dirent *buf, size_t bufsize, int32 count = INT_MAX)

          virtual int32 CountEntries(void)

          virtual status_t Rewind(void)

The three `GetNext...()` functions retrieve the "next" entry that lives in the BDirectory and returns it as a BEntry, `entry_ref`, or `dirent` structure.

- `GetNextEntry()` returns the entry as a BEntry object. If traverse is `true` and the entry is a symbolic link, the link is traversed. In other words, entry could end up being in a different directory than the one referred to by `this`. When all entries have been visited, the function returns `B_ENTRY_NOT_FOUND`. The entry argument must be allocated before it's passed in.

- `GetNextRef()` return the next entry in ref. Since an `entry_ref` doesn't supply enough information to determine if the entry is a link, there's no question of traversal: The `entry_ref` points to exactly the next entry. When all entries have been visited, the function returns `B_ENTRY_NOT_FOUND`. The ref argument must be allocated before it's passed in.

- `GetNextDirents()` returns some number of `dirent` structures, either as many as can be stuffed into buf (where bufsize gives the size of buf), or count structures, whichever is smaller. The function returns the number of structures that were stuffed into buf; when all entries have been visited, it returns 0.

|  | Currently, `GetNextDirents()` only reads one dirent at a time, no matter how many you ask for.

`GetNextEntry()` and `GetNextRef()` are reasonably clear; the `dirent` version deserves more explanation. You'll find this explanation (and an example) in the BEntryList class. Also, keep in mind that the set of candidate entries is different for the `dirent` version: `GetNextDirents()` finds all entries, including the entries for "." and "..". The other two versions skip these entries.

When you're done reading the BDirectory's entries, you can rewind the object's entry iterator by calling `Rewind()`.

`CountEntries()` returns the number of entries (not counting "." and "..") in the directory.

|  | Never call `CountEntries()` while you're iterating through the directory. `CountEntries()` does a rewind, iterates through the entries, and then rewinds again.

RETURN CODES

- `B_OK`. Success.
- `B_FILE_ERROR`. BDirectory object has not been properly initialized.
- `B_NOT_A_DIRECTORY`. The directory is invalid.
- `B_NAME_TOO_LONG`. The dirent's name is too long.
- `B_ENTRY_NOT_FOUND`. End of directory reached.
- `B_LINK_LIMIT`. A cyclic loop has been detected in the file system.
- `B_BAD_VALUE`. Invalid input specified, or BDirectory object has not been properly initialized.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.

### GetNextRef() see GetNextEntry()

### GetStatFor()

          status_t GetStatFor(const char *path, stat *st) const

Gets the `stat` structure for the entry designated by path. path must be relative, and is reckoned off of the BDirectory's directory. This is, primarily, a convenience function; but it's also provided for efficiency.

RETURN CODES

- `B_OK`. Success.
- `B_FILE_ERROR`. An invalid file prevented the operation.
- `B_NAME_TOO_LONG`. The path specified is too long.
- `B_ENTRY_NOT_FOUND`. The specified path does not exist.
- `B_LINK_LIMIT`. A cyclic loop has been detected in the file system.
- `B_BAD_VALUE`. Invalid input specified; the path may be `NULL` or empty.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.

### IsRootDirectory()

          bool IsRootDirectory(void) const

Returns `true` if this BDirectory represents a root directory. A root directory is the directory that's at the root of a volume's file hierarchy. Every volume has exactly one root directory; all other files in the volume's hierarchy descend from the root directory.

### Rewind() see GetNextEntry()

### SetTo(), Unset()

          status_t SetTo(const entry_ref *ref)
          status_t SetTo(const node_ref *nref)
          status_t SetTo(const BEntry *entry)
          status_t SetTo(const char *path)
          status_t SetTo(const BDirectory *dir, const char *path)

          void Unset(void)

Closes the BDirectory's current directory (if any), and initializes the object to open the directory as given by the arguments.

- In the path version, path can be absolute or relative, and can contain "." and ".." elements. If path is relative, it's reckoned off of the current working directory.

- In the dir/path version, path must be relative. It's reckoned off of the directory given by dir.

If the specification results in a symbolic link that resolves to a directory, then the linked-to directory is opened. If the specification is (or resolves to) a regular file, the initialization fails.

RETURN CODES

- `B_OK`. Success.
- `B_NAME_TOO_LONG`. The path specified is too long.
- `B_ENTRY_NOT_FOUND`. The directory does not exist.
- `B_LINK_LIMIT`. A cyclic loop has been detected in the file system.
- `B_BAD_VALUE`. Invalid input specified.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.
- `B_BUSY`. A busy node could not be accessed.
- `B_FILE_ERROR`. An invalid file prevented the operation.
- `B_NO_MORE_FDS`. All file descriptors are in use (too many open files).

## Operators

### = (assignment)

          BDirectory& operator=(const BDirectory &directory)

In the expression

       BDirectory a = b;

BDirectory a is initialized to refer to the same directory as b. To gauge the success of the assignment, you should call `InitCheck()` immediately afterwards. Assigning a BDirectory to itself is safe.

Assigning from an uninitialized BDirectory is "successful": The assigned-to BDirectory will also be uninitialized (`B_NO_INIT`).

## C Functions

### create_directory()

          status_t create_directory(const char *path, mode_t mode)

Creates all missing directories along the path specified by path.

- The pathname can be absolute or relative. If it's relative, the path is reckoned of the current working directory. If any symlinks are found in the existing portion of the path, they're traversed.

- path can contain ".", but it may not contain "..".

- mode is the permissions setting (typically expressed as an octal number) that's assigned to all directories that are created. To set the directories to be readable, writable, and "enterable" by all (for example), you would set the mode to 0777.

RETURN CODES

- `B_OK`. path now fully exists (or did in the first place).
- `B_BAD_VALUE`. path is `NULL`, is empty, or contains "..".
- `B_NOT_ALLOWED`. Read-only volume.
- `B_NO_MEMORY`. Insufficient memory to perform the operation.

### find_directory()

          status_t find_directory(directory_which which, dev_t volume, bool create_it,
             char *path_string, int32 length)

          status_t find_directory(directory_which which, BPath *path_obj,
             bool create_it = false, BVolume *volume = NULL)

|  | The first version of this function can be used in either C or C++ code. The second version is for C++ code only.

Finds the path to the directory symbolized by which and copies it into path_string, or uses it to initializes path_obj.

- The create_it argument tells the function to create the function if it doesn't already exist.

- volume identifies the volume (as a dev_t identifier or BVolume object) on which you want to look. The C++ default (`NULL`) means to look in the boot volume.

- The length argument (first version only) gives the length of path.

The `directory_which` constants are described in the The Storage Kit: Global Constants and Defined Types section at the end of this chapter.

RETURN CODES

- `B_OK`. The directory was found.
- Other codes. The directory wasn't found or couldn't be created.

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

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.