|
Derived from: BStatable
Declared in: be/storage/Entry.h
Library: libbe.so
Summary: more...
The BEntry class defines objects that represent "locations" in the file system hierarchy. Each location (or entry) is given as a name within a directory. For example, when you create a BEntry thus...
BEntry entry("/boot/home/fido");
...you're telling the BEntry object to represent the location of the file called fido within the directory "/boot/home".
A BEntry doesn't care whether the entry you tell it to represent is a plain file, a directory, or a symbolic link—it doesn't even care if the entry even exists (but we'll get to that later in "Abstract Entries"):
- All the BEntry cares about is a name in a directory.
The most important implication of this is the object's attitude towards data. BEntries don't know how to operate on data. You can't use a BEntry to read or write a file's data or attributes. For data operations, you have to turn your BEntry into a BNode.
Nonetheless, it's often convenient to speak of a BEntry as having data; for example, the phrase "the entry's data" really means "the data that lies in the file that's located by the entry."
A properly initialized BEntry object (we'll get to the rules of initialization later) knows the following:
- Location info. A BEntry knows its own (leaf) name (GetName()), its full pathname (GetPath()), and the identity of its parent directory (GetParent()).
- BStatable info. As a descendant of BStatable, a BEntry can return statistical information about the entry's data—its size, creation date, owner, and so on.
- entry_ref identifier. A BEntry can return the entry_ref that globally identifies the entry (GetRef()).
A BEntry can do these things:
- Perform hierarchical operations. A BEntry can change the name of its entry (Rename()), move it to another directory (Move()), and remove it from the file hierarchy (Remove()).
- Initialize BNode objects. The constructors and SetTo() initializers for BNode and its children (BFile, BDirectory, and BSymLink) accept BEntry arguments.
As mentioned above, the most important thing that a BEntry can't do is access its own data: A BEntry can't read or write data or attributes. To do these things you need a BNode object.
(Actually, this isn't entirely true: A BEntry can set the size of its data through the BStatable::SetSize() function. The function only works on plain files.)
To initialize a BEntry, you have to tell it which entry to represent; in other words, you have to identify a directory and a name. You can initialize a BEntry object directly...
- during construction,
- through the SetTo() function,
- or through the assignment operator.
Or you can have some other object initialize your BEntry for you, by passing the BEntry as an argument to...
- BDirectory's FindEntry() or GetEntry() function,
- BEntryList's GetNextEntry() function (implemented by BDirectory and BQuery).
- BEntry's GetParent() function.
In all cases (except the assignment operator) you're asked if you want to "traverse" the entry during initialization. Traversal is used to "resolve" symbolic links:
- If you traverse: The BEntry will point to the entry that the symbolic link is linked to.
- If you don't traverse: The BEntry will point to the symbolic link itself.
For example, let's say /boot/home/fidoLink is linked to /fido, to wit:
$ cd /boot/home
$ ln -s ./fido fidoLink
Now let's make a traversed BEntry for fidoLink:
/* The second argument is the traversal bool. */
BEntry entry("/boot/home/fidoLink", true);
If we ask for the entry's pathname...
BPath path;
entry.GetPath(&path);
printf("Pathname: %sn", path.Path());
...we see
Pathname: /boot/home/fido
In other words, the BEntry refers to fido, not fidoLink.
Traversal resolves nested links—it really wants to find a "real" file (or directory). If the entry that you're initializing to isn't a link, then the traversal flag is ignored.
When should you traverse, and when not? Here are a few rules of thumbs:
- If somebody hands you a file reference—if your app gets a RefsReceived() message—then you probably want to traverse the entry.
- If you're pawing over the contents of a directory (through BDirectory's GetNextEntry()), then you probably don't want to traverse.
- If you're looking at the result of a query (through BQuery's GetNextEntry()), then you almost certainly don't want to traverse. The query finds entries that satisfy certain criteria; if a symbolic link is in the list, it's because the link itself was a winner. If the linked-to file is also a winner, it will show up on its own.
Let's say you create a BEntry (to a symlink) without traversing, but then you decide that you do want to resolve the link. Unfortunately, you can't resolve in-place; instead, you have to initialize another BEntry using info (entry_ref or pathname) that you get from the link entry:
BEntry entry1("/boot/home/fidoLink", false);
BEntry entry2;
entry_ref ref;
/* First we check to see if it's a link. */
if (entry1.IsSymLink()) {
/* Get the link's entry_ref... */
entry1.GetRef(&ref);
/* ...and use it to initialize the other BEntry. */
entry2.SetTo(&ref, true);
}
As we all should know by now, a BEntry identifies a name within a specific directory. The directory that a BEntry identifies must exist, but the entry that corresponds to the name doesn't have to. In other words...
- A BEntry can represent a file that doesn't exist. The entry is said to be "abstract."
For example, the following construction creates a BEntry object based on a BDirectory and a name:
BEntry entry(someDir, "myFile.h");
Let's assume that myFile.h doesn't exist. As long as the directory that's referred to by someDir does exist, then the construction is legal. Some of the BEntry functions (those inherited from BStatable, for instance) won't work, but the object itself is valid.
But validity doesn't equal existence:
- SetTo() and InitCheck() do not tell you if a BEntry's entry actually exists. Don't be confused; a return value of B_OK simply means the object is valid.
If you want to know if a BEntry's entry actually exists, use the Exists() function.
To turn an abstract BEntry into a real entry (or, more accurately, a real node), you have to specify the flavor of node that you want. There are two methods for creating a node; the first is general, the second applies to plain files only.
BDirectory's CreateFile(), CreateDirectory(), and CreateSymLink() functions create nodes of the designated flavor. The functions don't take BEntry arguments directly; instead, you invoke the functions on the BEntry's directory, passing the entry's leaf name as an argument. Here we turn an abstract entry (entry) into a directory:
BPath path;
char name[B_FILE_NAME_LENGTH]; /* A buffer for the name. */
BDirectory parent; /* The parent of our entry. */
BDirectory target_dir; /* The product of the transformation. */
if (!entry.Exists()) {
entry.GetParent(&path);
entry.GetName(name);
parent.SetTo(&path);
parent.CreateDirectory(name, &dir);
}
You can create a plain file by passing the BEntry to the BFile constructor or SetTo() function. To do this, you also have to add B_CREATE_FILE to the "open mode" flags:
BFile file;
if (!entry.Exists())
file.SetTo(&entry, B_CREATE_FILE|B_READ_WRITE);
The following details understand you should, particularly if you want to participate in bedevtalk.
Although it's not intuitively obvious, a BEntry object does consume a file descriptor. The file descriptor is opened on the entry's directory.Your app has a limited number of file descriptors (currently 128, max), so you may not want to cache BEntry objects as your primary means for identifying an entry. If you're going to be dealing with a lot of entries and you want to keep track of them all, it's better to cache entry_ref structures or BPath objects.
One more time: A BEntry identifies an entry as a name in a directory. As described above, the directory is maintained internally as a file descriptor; the name is simply a string. This means that...
- The directory for a given BEntry is persistent. If you move the directory, the file descriptor, and so the BEntry, moves with it.
- The name isn't persistent. If the user renames the leaf that a BEntry is pointing to, the BEntry will become abstract.
For example, take the following BEntry...
BEntry entry("/boot/home/lbj/footFetish.jpeg");
If the user moves the directory...
$ cd /boot/home
$ mv lbj jfk
The BEntry (entry) "moves" with the directory. If you print the pathname and ask if the BEntry's entry exists...
BPath path;
entry.GetPath(&path);
printf("> Foot movie: %sn", path.Path());
printf("> Exists? %sn", entry.Exists()?"Oui":"Non");
...you'll see this:
> Foot movie: /boot/home/jfk/footFetish.jpeg
> Exists? Oui
The same isn't so for the name portion of a BEntry. If the user now moves footFetish.jpeg...
$ cd /boot/home/jfk
$ mv footFetish.jpeg hammerToe.jpeg
...your BEntry will not follow the file (it doesn't "follow the data"). The object will still represent the entry called footFetish.jpeg. The BEntry will, in this case, become abstract.
Don't be confused: The BEntry only "loses track" of a renamed entry if the name change is made behind the object's back. Manipulating the entry name through the BEntry object's Rename() function (for example), doesn't baffle the object. For example:
BPath path;
BEntry entry("/boot/home/lbj/footFetish.jpeg");
entry.Rename("hammerToe.jpeg");
entry.GetPath(&path);
printf("> Foot movie: %sn", path.Path());
printf("> Exists? %sn", entry.Exists()?"Oui":"Non");
...and we see...
> Foot movie: /boot/home/lbj/hammerToe.jpeg
> Exists? Oui
You can't lock an entry, but you can lock the entry's node (through BNode's Lock() function). Initializing a BEntry to point to a locked node is permitted, but the entry's directory must not be locked. If the directory is locked, the BEntry constructor and SetTo() function fail and set InitCheck() to B_BUSY.Furthermore, the destination directories in BEntry's Rename() and MoveTo() must be unlocked for the functions to succeed. And all directories in the path to the entry must be unlocked for GetPath() to succeed.
If you get a B_BUSY error, you may want to try again—it's strongly advised that locks be held as briefly as possible.
BEntry() |
BEntry(const BDirectory *dir, const char *path, bool traverse = false)
BEntry(const entry_ref *ref, bool traverse = false)
BEntry(const char *path, bool traverse = false)
BEntry(void)
BEntry(const BEntry &entry)Creates a new BEntry object that represents the entry described 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 new object to the entry that's represented by the argument. The two objects themselves maintain separate representation of the entry; in other words, they each contain their own a) file descriptor and b) string to identify the entry's a) directory and b) name.
To see if the initialization was successful, call InitCheck().
~BEntry |
virtual ~BEntry() Closes the BEntry's file descriptor and destroys the BEntry object.
Exists() |
bool Exists(void) const Returns true if the entry exists; false otherwise.
GetName() , GetPath() |
status_t GetName(char *buffer) const status_t GetPath(BPath *path) const These functions return the leaf name and full pathname of the BEntry's entry. The arguments must be allocated before they're passed in.
GetName() copies the leaf name into buffer. The buffer must be large enough to accommodate the name; B_FILE_NAME_LENGTH is a 100% safe bet:
char name[B_FILE_NAME_LENGTH];
entry.GetName(name);
If GetName() fails, *buffer is pointed at NULL.
GetPath() takes the entry's full pathname and initializes the BPath argument with it. To retrieve the path from the BPath object, call BPath::Path():
BPath path;
entry.GetPath(&path);
printf(">Entry pathname: %sn", path.Path());
If GetPath() fails, the argument is Unset().
RETURN CODES
GetParent() |
status_t GetParent(BEntry *entry) const
status_t GetParent(BDirectory *dir) constGets the directory, as a BEntry or BDirectory object, in which the object's entry lives. The argument must be allocated before it's passed in.
If the function is unsuccessful, the argument is Unset(). Because of this, you should be particularly careful if you're using the BEntry-argument version to destructively get a BEntry's parent:
if (entry.GetParent(&entry) != B_OK) {
/* you just lost 'entry' */
}
This example is legal; for example, you can use destructive iteration to loop your way up to the root directory. When you reach the root ("/"), GetParent() returns B_ENTRY_NOT_FOUND:
BEntry entry("/boot/home/fido");
status_t err;
char name[B_FILE_NAME_LENGTH];
/* Spit out the path components backwards, one at a time. */
do {
entry.GetName(name);
printf("> %sn", name);
} while ((err=entry.GetParent(&entry)) == B_OK);
/* Complain for reasons other than reaching the top. */
if (err != B_ENTRY_NOT_FOUND)
printf(">> Error: %sn", strerror(err));
This produces:
> fido
> home
> boot
> /
RETURN CODES
- B_OK. The information was successfully retrieved.
- B_NO_INIT. This BEntry isn't initialized.
- B_ENTRY_NOT_FOUND. Attempt to get the parent of the root directory.
- B_NO_MORE_FDS. Couldn't get another file descriptor.
GetPath() see GetName() |
GetRef() |
status_t GetRef(entry_ref *ref) const Gets the entry_ref for the object's entry; ref must be allocated before it's passed in. As with BEntry objects, entry_ref structures can be abstract—getting a valid entry_ref does not guarantee that the entry actually exists.
If the function isn't successful, ref is unset.
RETURN CODES
- B_OK. The entry_ref was successfully retrieved.
- B_NO_INIT. This object isn't initialized.
- B_NO_MEMORY. Storage for the entry_ref's name couldn't be allocated.
GetStat() |
virtual status_t GetStat(struct stat *st) const GetStat() returns the stat structure for the entry. The structure is copied into the st argument, which must be allocated. The BStatable object does not cache the stat structure; every time you call GetStat(), fresh stat information is retrieved.
RETURN CODES
- B_OK. Success.
- B_NO_MEMORY. Couldn't get the necessary resources to complete the transaction.
- B_BAD_VALUE. The entry doesn't exist (abstract entry).
InitCheck() |
status_t InitCheck(void) const Returns the status of the previous construction, assignment operation, or SetTo() call.
RETURN CODES
MoveTo() see Rename() |
Remove() |
status_t Remove(void) Remove() "unlinks" the entry from its directory. The entry's node isn't destroyed until all file descriptors that are open on the node are closed. This means that if you create BFile based on a BEntry, and then Remove() the BEntry, the BFile will still be able to read and write the file's data—the BFile has no way of knowing that the entry is gone. When the BFile is deleted, the node will be destroyed as well.
Remove() does not invalidate the BEntry. It simply makes it abstract (see "Abstract Entries").
RETURN CODES
Rename() , MoveTo() |
status_t Rename(const char *path, bool clobber = false) status_t MoveTo(BDirectory *dir, const char *path = NULL, bool clobber = false) These functions move the BEntry's entry and node to a new location. In both cases, the BEntry must not be abstract—you can't rename or move an abstract entry.
Rename() moves the entry to a new name, as given by path. path is usually a simple leaf name, but it can be a relative path. In the former case (simple leaf) the entry is renamed within its current directory. In the latter, the entry is moved into a subdirectory of its current directory, as given by the argument.
MoveTo() moves the entry to a different directory and optionally renames the leaf. Again, path can be a simple leaf or a relative path; in both cases, path is reckoned off of dir. If path is NULL, the entry is moved to dir, but retains its old leaf name.
If the entry's new location is already taken, the clobber argument decides whether the existing entry is removed to make way for yours. If it's true, the existing entry is removed; if it's false, the Rename() or MoveTo() function fails.
Upon success, this is updated to reflect the change to its entry. For example, when you invoke Rename() on a BEntry, the name of that specific BEntry object also changes. If the rename or move-to isn't successful, this isn't altered.
RETURN CODES
- B_OK. Success.
- B_NO_INIT. The BEntry is not initialized.
- B_ENTRY_NOT_FOUND. A directory to the new location doesn't exist, or this is an abstract entry.
- B_FILE_EXISTS. The new location is already taken (and you're not clobbering).
- B_BUSY. The directory that you're moving the entry into is locked.
SetTo() , Unset() |
status_t SetTo(const entry_ref *ref, bool traverse = false)
status_t SetTo(const const char *path, bool traverse = false)
status_t SetTo(const BDirectory *dir, const char *path, bool traverse = false)void Unset(void) Frees the BEntry's current entry reference, and initializes it to refer to the entry identified by the argument(s):
- In the ref version, the BEntry is initialized to refer to the given entry_ref.
- 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.
The traverse argument is used to resolve (or not) entries that are symlinks:
- If traverse is true, the link is resolved.
- If traverse is false, the BEntry refers to the link itself.
See " "Initializing and Traversing" on page40" for more information.
When you initialize a BEntry, you're describing a leaf name within a directory. The directory must exist, but the leaf doesn't have to. This allows you to create a BEntry to a file that doesn't exist (yet). See " "Abstract Entries" on page42" for more information.
Remember—successfully initializing a BEntry consumes a file descriptor. When you re-initialize, the old file descriptor is closed.
Unset() removes the object's association with its current entry, and sets InitCheck() to B_NO_INIT.
RETURN CODES
- B_OK. The BEntry was successfully initialized.
- B_BAD_VALUE. Bad argument value; uninitialized ref or dir.
- B_ENTRY_NOT_FOUND. A directory in the path to the entry doesn't exist.
- B_BUSY. The entry's directory is locked.
Unset() see SetTo() |
= (assignment) |
BEntry& operator=(const BEntry &entry) In the expression
BEntry a = b;
BEntry a is initialized to refer to the same entry as b. To gauge the success of the assignment, you should call InitCheck() immediately afterwards. Assigning a BEntry to itself is safe.
Assigning from an uninitialized BEntry is "successful": The assigned-to BEntry will also be uninitialized (B_NO_INIT).
== , != (comparison) |
bool operator==(const BEntry &entry) const bool operator!=(const BEntry &entry) const Two BEntry objects are said to be equal if they refer to the same entry (even if the entry is abstract), or if they're both uninitialized.
get_ref_for_path() |
status_t get_ref_for_path(const char *path, entry_ref *ref) Returns in ref an entry_ref for the file specified by the path argument.
RETURN CODES
- B_OK. The ref was returned successfully.
- B_ENTRY_NOT_FOUND. The file wasn't found, or the pathname string is empty.
- B_NO_MEMORY. Not enough memory.
- Other file errors.
|
Copyright © 2000 Be, Inc. All rights reserved..