Derived from: public BObject
Declared in: <storage/Store.h>
BStore is an abstract class that defines common functionality for its two subclasses, BFile and BDirectory. You never construct direct instances of BStore, nor does the Storage Kit "deliver" such BStore instances to your application. The BStore objects that you work with will always be instances of BFile or BDirectory (or from a class derived from these).
Furthermore, you shouldn't derive your own classes directly from BStore. If you want to create your own file class, you should derive your class from BFile (or, possibly, BResourceFile). Y
Note: Throughout this class description, the terms "file" and "item" are used generically to mean an actual item in a file system. The characteristics ascribed to files (in the following) apply to directories as well.
Every file in the file system has a database record associated with it. The record contains information about the file, such as its name, when it was created, the directory it lives in, and so on. All file system activities are performed on the basis of these "file records." For example, if you want to locate a file, you have to locate the file's record; passing the record (albeit indirectly, as described below) to a BStore causes the object to "refer to" the file on disk. Until the object is referred to a file, it's abstract and useless.
A BStore's record is established through a record ref. A record ref (or, simply, ref) is a structure of type record_ref that uniquely identifies a record across all databases by listing the record's ID as well as the ID of its database:
struct record_ref { record_id record; database_id database; }
The nicety of the ref is that it bundles up all the database information that a BStore needs, allowing your application to ignore the details of database organization.
Note: Record refs aren't used only to identify records that describe files. A record ref is simply a means for a identifying a record, regardless of what that record signifies.
BStore's SetRef() function sets the calling object's ref directly. This function is often used in an implementation of BApplication's RefsReceived() hook function. RefsReceived() is invoked automatically when a ref is sent to your application in a BMessage. For example, when the user drops a file icon on your application, your application receives the ref of the file through a RefsReceived() notification.
In a typical implementation of RefsReceived(), you would ask the ref if it represents a file or directory, allocate a BFile or BDirectory accordingly, and then pass the ref to the object in an invocation of SetRef(). An example of this is given in the description of the does_ref_conform() function, in the section "Global Functions, Constants, and Defined Types."
SetRef() isn't the only way to refer an object to a file. The most important of the other functions that perform this feat are listed below:
Using these functions, you can traverse an entire file system: Given a BVolume object, you can descend the file system by calling GetRootDirectory(), and then iteratively and recursively calling GetFile() and GetDirectory(). Given a BFile or BDirectory, you can ascend the hierarchy through recursive calls to GetParent() .
An example of file system browsing, and a discussion of the file system hierarchy is given in the description of the BDirectory class.
Continuing the list of ref-setting functions, the following group of Storage Kit functions set refs as side-effects of altering the structure of the file system:
A file's ref acts as a system-wide identifier for the file. If you want to "send" a file to some other application, or to another thread in your own application--in other words, if you want more than one process to operate asynchronously on the same file--you should communicate the identity of the file by sending its ref. The thread that receives the ref would construct its own BStore object and call SetRef() , in the manner of the RefsReceived() function, described earlier.
You can't retrieve a BStore's ref directly from the object. Instead, you retrieve the object's record (through the Record() function) and then retrieve the ref from the record (through BRecord's Ref() function). The example below demonstrates this as it prepares a BMessage to hold a ref that's sent another application:
/* 'zapp' is the signature of the app that we want to send the * ref to. */ BMessenger *msngr = new BMessenger('zapp'); /* By declaring the BMessage to be a B_REFS_RECEIVED command, * the message will automatically show up (when sent) in the * other app's RefsReceived() function. */ BMessage *msg = new BMessage(B_REFS_RECEIVED); /* Retrieve the ref from aFile (which is assumed to be * an extant BFile object). */ record_ref fileRef = aFile->Record()->Ref(); /* Add the ref to the BMessage and send it. */ msg->AddRef("refs", fileRef); msngr->SendMessage(msg);
It's possible to "customize" your files by, providing them with "custom" records. To do this you need to understand a little bit about the database side of the Storage Kit. Before continuing here, you should be familiar with the BRecord and BTable classes.
When you create a new file, a record that represents the file is automatically created and added to the database. The table to which this record conforms depends on whether the file is, literally, a file (as opposed to a directory): If it's a file, the record conforms to the "File" table; if it's a directory, it conforms to "Folder." (Resource files, as described in the BResourceFile class, also conform to "File".)
The Create() function, defined by BDirectory, lets you declare (by name) a table of your own design as the table to which the new file's record will conform. The only restriction on the table is that it should inherit (in the table-inheritance sense) from either "File" or "Folder" as the item that you're creating is a file or a directory.
By creating and using your own "file tables," you can augment the amount and type of information that's kept in a file's record. In the example shown below, a "Image File" table is defined and used to create a new file:
/* The BDatabase object aDB is assumed to exist. */ BTable *ImageTable = aDB->CreateTable("Image Table", "File"); SoundTable->AddLongField("Height"); SoundTable->AddLongField("Width"); SoundTable->AddStringField("Description"); /* Create a new "image file." The BDirectory object aDir * is assumed to exist. */ BFile myImageFile; aDir->Create("Bug.image", &myImageFile, "Image Table");
Tables, remember, are defined for specific databases; the ImageTable definition shown here is defined for the aDB database. Similarly, a directory is part of a specific file system. If you designate a table when creating a new file, the table's database and the directory's file system must belong to the same volume. Put programmatically, the database and directory objects used above must be related thus:
aDB->Volume() == aDir->Volume()
To add data to a file's record, you get the record through BStore's Record() function, and then call BRecord's data-adding functions. For example:
BRecord *myImageRec = myIageFile->Record(); myImageRec->SetLong("Height", 256); myImageRec->SetLong("Width", 512); myImageRec->SetString("Description", "Bug squish"); myImageRec->Commit();
The Commit() call at the end of the example is essential: If you change a file's record directly, you must commit the changes yourself (but see The File Creation Hook for an exception to this rule).
If you create and use your own file records, heed the following:
In some cases, you may want to change a new file's record before the file becomes "public." Normally, when you call BDirectory's Create() function, the system creates a record for the file, fills in the fields that it knows about (in other words, it fills in the fields that belong to the "File" or "Folder" table), commits the record, and then returns the new BFile (or BDirectory) to you. (This would be the natural order of things in the example shown above.)
The important point here is that the record is committed before you get a chance to touch the fields that you're interested in. If some application has a live query running (as defined by the BQuery class), the incompletely filled-in record --which will be a candidate for the query from the time that it's committed by the system --may inappropriately pass the query.
To give you access to the record before it's committed, Create() lets you pass a store creation hook function as an optional (fourth) argument. Such a function assumes the following protocol:
long store_creation_hook_name(BStore *item , void *hookData)
Note that this is a global function; the store creation hook can't be declared as part of a class. Also, although store_creation_hook is declared (in Store.h ) as a typedef, the declaration is intended to be seen for its protocol only: You can't declare a function as a store_creation_hook type.
The store creation hook is called just after the file's record is created, but before it's committed. The first argument is a BStore object that represents the new file. The record changes shown in the previous example would be performed in a store creation hook thus:
/* Define a store creation hook function. */ long imageFileHook(BStore *item, void *hookData) { BRecord *myImageRec = item->Record(); myImageRec->SetLong("Height", 256); myImageRec->SetLong("Width", 512); myImageRec->SetString("Description", "Bug squish"); return B_NO_ERROR; }
Note that you don't commit record changes that you make in a store creation hook. They'll be committed for you after the function returns. If the hook function returns a value other than B_NO_ERROR, the store creation is aborted (by the Create() function).
The Create() call with this hook function would look like this:
aDir->Create("Bug.image", &myImageFile, "Image Table", imageFileHook);
All Storage Kit functions that create files provide a store creation hook mechanism. These are:
The details of the mechanism as demonstrated by the Create() examples shown here apply without modification to the other functions as well.
You can pass additional data to your hook function by supplying a buffer of void * data as the Create() function's final argument. This "hook data" is passed as the second argument to the hook function. Here, we redefine the hook function used above to accept an image description string as hook data:
/* Define a store creation hook function. */ bool imageFileHook(BStore *item, void *hookData) { BRecord *myImageRec = item->Record(); myImageRec->SetLong("Height", 256); myImageRec->SetLong("Width", 512); myImageRec->SetString("Description", (char *)hookData); return TRUE; }
And here we call Create(), passing it some hook data:
aDir->Create("Bug.image", &myImageFile, "Image Table", iamgeFileHook, (void *)"Bug squish");
The rules that govern the use and implementation of a store creation hook are similar to those you follow when, in general, you modify a BStore's record.
protected:
BStore(void)
The BStore constructor is protected to prevent you from creating direct instances of the class.
virtual ~BStore(void)
Although the BStore is public, you can't actually use it. Since you can't construct a BStore object, you'll never have the opportunity to destroy one.
long CreationTime(void) long ModificationTime(void) long SetModificationTime(const long time)
The first two functions return the time the referred-to item was created and last modified, measured in seconds since January 1, 1970. To convert the time value to a string, you can use standard-C function strftime() or ctime() (as declared in time.h). If the object doesn't refer to a file (or directory), the functions return B_ERROR.
SetModificationTime() lets you set the modification time for the item. The function returns B_ERROR if the object's ref isn't set, if the item lives in a read-only file system, or if the modification time couldn't otherwise be set.
And a very special note to all you BFile users: These three functions work regardless of the open state of the target object.
int Error(void)
Returns an error code that indicates the success of the previous BStore function call. The possible codes are:
The Error() function doesn't record the success of the BStore operators.
long GetName(char *name)
Copies the BStore's name into name. You must allocate the argument before you pass it in. File names are never longer than the constant B_FILE_NAME_LENGTH; to be safe, name should be at least that long. It's the caller's responsibility to free the name buffer.
If the BStore doesn't refer to a file, this returns NULL and sets the Error() code to B_ERROR.
See also: SetName()
long GetParent(BDirectory *parent)
Sets the argument's ref to the directory that contains this BStore. You must allocate the argument before you pass it to the function; it's the caller's responsibility to delete the argument object.
If this BStore represents a volume's root directory (for which there is no parent), or if the object is invalid, this function returns B_ERROR; otherwise, it returns B_NO_ERROR.
long GetPath(char *buffer, long bufferSize)
Constructs the full path name to this object and copies the name into buffer. You must allocate the buffer before you pass it in; you pass the size of the buffer (in bytes) through the bufferSize argument.
The path name is absolute and includes the volume name as its first element. You could, for example, cache the name and then use it later as the argument to the global get_ref_for_path() function. As long as the file system hasn't changed, the latter function would return the ref of the original item.
If the object doesn't refer to a file system item, or if the buffer isn't long enough to accommodate the name, B_ERROR is returned and nothing is copied into the buffer. Otherwise, B_NO_ERROR is returned.
See also: get_ref_for_path(), BDirectory::GetRefForPath()
long MoveTo(BDirectory *dir, const char *newName = NULL, store_creation_hook *hookFunc = NULL, void *hookData = NULL)
Removes the item from its present directory, and moves it to the directory represented by dir. You can, optionally, rename the item at the same time by providing a value for the newName argument.
The hookFunc and hookData arguments let you alter the file's record before it's committed. This is exhaustively explained in the section The File Creation Hook of the introduction to this class.
See also: SetName(), BFile::CopyTo(), BDirectory::Create()
BRecord *Record(void)
Returns a BRecord object that represents the record in the database that holds information for the file system item that this BStore refers to. You can examine the values in the BRecord (through functions defined by the BRecord class), but you should only set and modify those fields that you've defined yourself (if any).
Any changes that you make to the BRecord must be explicitly committed by calling BRecord's Commit() function. Furthermore, you must commit your changes before calling other BStore functions, even those that are seemingly innocuous.
More information on the use and meaning of a BStore's record is given in the section Custom Files of the introduction to this class.
long SetName(const char *name)
Sets the name of the item to name. If the item is the root directory for its volume, the name of the volume is set to the argument as well.
Every item within a directory must have a different name; if name conflicts with an existing item in the same directory, the function fails and returns B_NAME_IN_USE. Also, you can't change the name of a file that's currently open; SetName() will return B_ERROR in this case. B_ERROR is also returned if, for any other reason, the name couldn't be changed. Success is indicated by a return of B_NO_ERROR.
virtual long SetRef(record_ref ref) virtual long SetRef(BVolume *volume, record_id id)
Sets the object's record ref. By setting an BStore's ref, you cause the object to refer to a file in the file system.
The first version of the function sets the ref to the argument that you pass. This version of the function is typically called in response to a ref being received by your application.
The second version induces the ref from the BVolume (which implies a specific database) and record ID arguments. This version is useful if you're finding files through a database query.
More information on a BStore's ref is given in the section Files, Records, and BFSItems of the introduction to this class.
long VolumeID(void)
Returns the ID of the volume in which this item is stored. To turn the ID into a BVolume object, pass it to BVolume's SetID() function.
See also: BVolume::SetID()
inline BStore& operator=(const BStore&)
Sets the ref of the left operand object to be the same as that of the right operand object.
bool operator==(BStore) const
Compares the two objects based on their refs. If the refs are the same, the objects are judged to be the same.
bool operator!=(BStore) const
Compares the two objects based on their refs. If the refs are not the same, the objects are
judged to be not the same.
The Be Book, HTML Edition, for Developer Release 8 of the Be Operating System.
Copyright © 1996 Be, Inc. All rights reserved.
Be, the Be logo, BeBox, BeOS, BeWare, and GeekPort are trademarks of Be, Inc.
Last modified September 6, 1996.