The Storage Kit: BDirectory

Derived from: BNode, BEntryList

Declared in: be/StorageKit/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()).

Find a specific entry. You can ask if the entry exists ( Contains()), and you can retreive the entry as a BEntry ( FindEntry()).

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 it 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.

The entry list is dynamic. You're not stepping through a static list; 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. In general, you shouldn't alter the directory while you're iterating through its contents.

Counting entries uses the iterator. You mustn't call CountEntries() while you're iterating through the directory.

Setting up a Node Monitor on every entry you get while iterating is useful, but it can result in a race condition. You can end up with "zombie" nodes; this is explained in "Zombies."


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."

After you've created a BDirectory, you may want (or need) to monitor changes that are made to its contents. By using the Node Monitor, you can ask to be notified if an entry is...

  • created,
  • renamed,
  • moved (out of or into this directory),
  • or removed (expunged from the file system).
  • You can monitor changes to 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/lbj");
       node_ref nref;
       status_t err;
       
       if (dir.InitCheck() == B_NO_ERROR) {
          dir.GetNodeRef(&nref);
          err = watch_node(&nref, B_WATCH_DIRECTORY, be_app_messenger);
          if (err != B_NO_ERROR)
             /* 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 (and the node it represents) was deleted from the file system ( B_ENTRY_REMOVED ).
  • The B_WATCH_DIRECTORY flag (by itself ) doesn't monitor these sorts of changes that are made to the directory itself. 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).

    Other fields

    The other fields in the BMessage 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 :

  • "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 :

  • "device", "node", and "name" as above.
  • "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 :

  • Same as for B_ENTRY_CREATED , but without the "name" field.

  • Zombies

    <forthcoming>


    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)
          bool Contains(const BEntry *entry, int32 nodeFlags = B_ANY_NODE)

    Returns true if path or entry is contained within the 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.
  • RETURN VALUES

  • <forthcoming>

  • CreateFile(), CreateDirectory() , CreateSymLink()

    
          status_t CreateFile(const char *path, 
             BFile *file,
             bool failIfExists)
    
          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, where path must be relative and is reckoned off of the directory represented by this BDirectory.

    In all cases, the passed back object (the BDirectory, BFile, or BSymLink) must be allocated.

    RETURN VALUES

  • <forthcoming>

  • FindEntry(), FindFile(), FindDirectory(), FindSymLink()

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

    The traverse argument is missing in AADR9.

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

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

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

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

    RETURN VALUES

  • <forthcoming>

  • GetEntry()

    
          status_t GetEntry(BEntry *entry)

    Initializes entry to represent this BDirectory.

    RETURN VALUES

  • <forthcoming>
  • If the initialization fails, entry is Unset().


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

    
          status_t GetNextEntry(BEntry *entry, bool traverse = TRUE) const
    
          status_t GetNextRef(entry_ref *ref) const
    
          int32  GetNextDirents(dirent *buf, size_t bufsize, int32 count = MAX_INT) const
    
          int32 CountEntries(void) const
    
          status_t Rewind(void)

    The traverse argument (to GetNextEntry()) is missing in AADR9.

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

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

    The first two are reasonably clear; the dirent version deserves more explanation. You'll find this explanation (and an example) in " Threads." 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 BDirectory.

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

    RETURN VALUES

  • <forthcoming>

  • 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 VALUES

  • <forthcoming>

  • InitCheck()

    
          status_t InitCheck(void) const

    Returns the status of the previous construction, assignment operation, or SetTo() call.

    RETURN VALUES

  • B_NO_ERROR. The initialization was successful.
  • B_NO_INIT. The object is uninitialized (this includes Unset()).
  • See SetTo() for other errors.

  • IsRootDirectory()

    
          bool IsRootDirectory(void)

    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.


    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.

    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 VALUES

  • <forthcoming>

  • 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).


    ==, != (comparison)

    
             bool operator==(const BDirectory &directory) const
             bool operator!=(const BDirectory &directory) const

    Two BDirectory objects are said to be equal if they refer to the same directory, or if they're both uninitialized.






    The Be Book, HTML Edition, for Developer Release 9 of the Be OS.

    Copyright © 1997 Be, Inc. All rights reserved.

    Be, the Be logo, BeBox, BeOS, BeWare, and GeekPort are trademarks of Be, Inc.

    Last modified