BNode

The BNode class gives you access to the data that a file system entry (a file, directory, or symbolic link) contains. There are two parts to this data:

  1. There's the "data portion" itself…

  2. …and then there are the node's attributes.

The content of the data portion depends on the node's flavor:

The content of the attributes, on the other hand, isn't qualified by the node's flavor: Any node can contain any set of attributes.


Nodes are Dumb

Keep in mind that the concept of a "node" designates the data parts (data and attributes) of a file (a file, directory, or link). Contrast this with an "entry," which designates the entity's location within the file system: For example, you can write to a "node" (but not an entry), and you can rename an "entry" (but not a node).

This isn't just a conceptual crutch, it's the law: Nodes really don't know where they're located. For example, you can't ask a node for its name, or for the identity of its parent. This has some serious implications, the most important of which is…

Now that we've got that straight, we'll relax the rules a bit:

This doesn't really change the "store the info" rule. Even if you're dealing exclusively with BDirectory objects, you should keep the generative information around. The primary reason for this is…

The "Node Pool" is Limited (File Descriptors)

Every BNode object consumes a "file descriptor." Your application can only maintain 256 file descriptors at a time. Because of this limit, you shouldn't keep BNodes around that you don't need. Keep in mind that BEntry objects also consumes file descriptors (one per object).

Note
Note

The file descriptor limit will probably be lifted, or at least settable, in a subsequent release. But even then you should be frugal.


Derived Classes and their Uses

BNode has three derived classes: BFile, BDirectory, and BSymLink. The derived classes define functions that let you access the node's data portion in the appropriate style; for example…

If you want to (sensibly) look at a node's data portion, you must create an instance of the appropriate derived class. In other words, if you want to browse a directory, you have to create a BDirectory instance; if you want to write to a file, you create a BFile.

Be aware that it's not (always) an error to create an instance of the "wrong" derived class; setting a BFile to a symbolic link, for example, will traverse the link such that the BFile opens the file that the symbolic link is linked to. See the individual derived class specifications for more information.


BNode Instances

In practice, you almost always want to create an instance of one of the BNode-derived classes; but if, for whatever reason, you find yourself holding a BNode instance, here's what you'll be able to do with it:


Converting a BNode to an Instance of a Derived Class

Note
Note

This section describes situations and presents solutions to problems that are a bit esoteric. If you never create direct instances of BNode (and you never have to), then you should skip this and go to "Node Locking".

There may be times when you find yourself holding on to a BNode (instance) that you want to convert into a BFile, BDirectory, or BSymLink. However, you can't go directly from a BNode instance to an instance of BFile, BDirectory, or BSymLink—you can't tell your BNode to "cast itself" as one of its children.

There are solutions, however…

Converting to BDirectory

Converting from a BNode to a BDirectory, while not transparent, is pretty simple: Grab the node_ref out of the BNode and pass it to the BDirectory constructor or SetTo() function. Regard this example function:

void Node2Directory(BNode *node, BDirectory *dir)
{
   node_ref nref;

   if (!node || !dir) {
      dir.Unset();
      return;
   }

   node.GetNodeRef(&nref);

   /* Set the BDirectory. If nref isn't a directory node,
   * the SetTo() will fail.
   */
   dir.SetTo(&nref);
}

Converting to BFile or BSymLink

Converting a BNode instance to a BFile or BSymLink isn't as neat as the foregoing. Instead, you have to cache the information that you used to initialize the BNode in the first place, and then reuse it to create the BFile or BSymLink.

For example, let's say you receive an entry_ref. You turn it into a BNode, but then decide you need the data-writing power of a BFile. If, in the meantime, you lost the original entry_ref, you're sunk—there's nothing you can do.


Node Locking

Another feature provided by the BNode class is "node locking": Through BNode's Lock() function you can restrict access to the node. The lock is removed when Unlock() is called, or when the BNode object is deleted.

The one exception to the no-file descriptors rule has to do with BEntrys: Let's say you lock a directory, and then you initialize a BEntry to point to an entry within that directory. Even though the BEntry creates a file descriptor to the directory (as explained in the BEntry class), the initialization will succeed.

Implications

For files (and, less importantly, symlinks), the implications of locking are pretty clear: No one else can read or write the file. For directories, it's worth a closer look:

  • Locking a directory means that the contents of the directory can't change: You can't create new nodes in the directory, or rename or remove existing ones. (You can, however, create abstract entries within the directory; see BEntry for more on abstract entries.)

Locking a node does not lock the node's entry: You can't "lock out" entry operations, such as rename, move, and remove. Even if you have a node locked, the entry that acts as the "container" for that node could disappear. If you want to prevent such operations on a node's entry, lock the entry's parent directory.

In general, you should try to avoid locking your nodes. If you must lock, try to make it brief. The primary reason (and, pretty much, the only reason) to lock is if separate elements in the data and/or attributes must be kept in a consistent state. In such a case, you should hold the lock just long enough to ensure consistency.

Warning
Warning

You shouldn't use locks to "privatize" data. Locking isn't meant to be used as a heightened permissions bit.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.