Getting Started with the CBFS component


Introduction

The CBFS component consists of two parts: a kernel mode system driver, and a user mode API known as the CBFS component. The driver works on the system level behind the scenes; you don't interact with it directly. Instead, you integrate the CBFS component into your application, then use it to create, delete, and manipulate a virtual drive. The CBFS component also provides events that your application must implement to actually handle various filesystem operations related to your virtual drive.

Contents

Install and Uninstall the Drivers

The CBFS system driver must be installed on a machine before the CBFS component can be used to create and manage virtual drives. This is done using the Install method, which is present in the CBFS component API, as well as in a standalone Installer DLL included with the toolkit. The CBFS API method is useful when your application is responsible for installing the driver; while the Installer DLL is designed to be used from installation scripts.

It may be necessary to reboot the system after calling Install in order to complete the driver installation process; the Install method will return a value that indicates whether this is necessary. Once the driver installation is complete, you'll be able to use the CBFS component to create and manage virtual drives.

The driver needs to be installed only once. There is no need to install it each time you start your application. If the driver is not installed correctly, you will receive error code 2 ("file not found") when trying to use the CBFS component, which means that the driver could not be found or loaded.

To uninstall the system driver, call the Uninstall method; available in both the CBFS component API and the Installer DLL. Note that this is not necessary if you are only upgrading to a new minor version of the driver.

Create and Delete a Virtual Drive

Before doing anything else with the CBFS component, you must call its Initialize method. Once this is done, you'll be able to create a virtual drive, which consists of both the "drive" itself, an "virtual media" (think of it almost like a CD drive, and the actual CD itself).

To create the virtual drive, call the CreateStorage method. Next, assign a mounting point to the drive using the AddMountingPoint method. You can create a visible drive by assigning a drive letter, or you can create an "invisible" drive by assigning a UNC path. Invisible drives are not shown in File Explorer or other file managers, but can still be accessed by users and applications that know the correct UNC path to use. Alternatively, the virtual filesystem can be mounted as a folder on an existing NTFS drive.

Finally, insert the "virtual media" into the virtual drive by calling the MountMedia method. At this point the virtual filesystem will be available for users and other applications to use. In order for it to function correctly, your application must implement the CBFS component's various events, and handle the various filesystem operations. More information about how to do this is discussed in the sections below, as well as in the product's documentation.

When you're finished with the virtual drive, call the UnmountMedia method to remove the "virtual media" from the drive, and then delete the drive using the DeleteStorage method.

Handle the Events

The CBFS component's event handlers are where your application actually implements the functionality of the virtual filesystem. CBFS hides most of the complexities involved; the following sections discuss the primary considerations to take into account. The events can generally be grouped into categories based on functionality; some are optional while others are required. Refer to the documentation for more specific information about each individual event.

Provide Information about the Filesystem

To provide information about the virtual filesystem's label (i.e., the name of the volume) and size, your application needs to handle the GetVolumeId, GetVolumeLabel, and GetVolumeSize events. Since the OS can change the volume label, it also needs to handle the SetVolumeLabel event.

Provide Information about the Filesystem's Contents

An important operation for any filesystem is to provide information about its contents to the OS. When the OS needs to read the contents of some directory (starting from the root directory), it sends requests that are translated into the EnumerateDirectory and CloseEnumeration events.

The EnumerateDirectory event is fired while the OS enumerates the contents of some directory. Each time your application handles the EnumerateDirectory event, it must return information about a different file or subdirectory contained in the directory that is being enumerated (assuming that there are still files and/or subdirectories to report). Unlike the Win32 interface, which has the FindFirstFile and FindNextFile functions, the EnumerateDirectory event in CBFS Connect is fired for both the first and subsequent entries in the directory; and will continue to fire until your application returns False in the EnumerateDirectory event's FileFound parameter.

To store information about which file or directory was last reported (in order to know, e.g., which file or directory to report next), the application can use the EnumerationContext parameter. For example, the following strategy could be employed: if EnumerationContext is not allocated, the application knows that this is the first request for enumeration of the given directory. The application can retrieve (or prepare to retrieve) the information about that directory's entries, then store it in the context, and also pass back information about the first entry. Subsequent firings of the EnumerateDirectory event will use the same EnumerationContext, allowing the application to use the information it stored within that context to handle the events.

Once the application reports that there are no more files or directories left to enumerate, the CloseEnumeration event will fire. At this point the application would need to clean up any data stored in the EnumerationContext, and free any other resources it allocated to handle the enumeration.

In addition to the aforementioned events, directory enumeration also causes the OpenFile and CloseFile to fire for the directory that is being enumerated.(Windows doesn't distinguish between files and directories when it sends certain requests to the filesystem).

Directory enumeration is used to get a list of entries in the directory, but it's sometimes necessary for the OS to obtain information about a particular file or directory. Such requests are passed to your application via the GetFileInfo event. This event is very similar to EnumerateDirectory and requests the same information, however it also gives you the name of the file or directory of interest.

Create and Open Files

The CBFS component exposes two events related to creating and opening files: CreateFile and OpenFile. As the names suggest, these events are fired when the OS needs to create a new file or open an existing file.

When your application handles these events, it usually obtains access to some resource (be it a file, a remote resource, a reference to a memory block, etc.). It is necessary to keep a handle to that resource stored somewhere so that it can be used to handle events that fire for subsequent file operations. To assist with this, CBFS provides FileContext and HandleContext parameters that the application can use to store data related to a particular file/directory, or a particular instance of a handle to said file/directory. These contexts are passed to any other events that fire for the file or directory in question (read, write, resize, rename, etc.), allowing your application to handle them more efficiently.

To optimize multiple file-open operations that occur in parallel (for example, when you open two instances of some application that opens supplementary files or DLLs), CBFS Connect can fire the OpenFile event just the first time the file is opened. If the file is opened successfully, the opened file is then used for the next file open operations, which happen while the original file handle is opened. Note that if the file is opened with a different access mode, such a scheme is not suitable. To enable or disable the described behavior and have the OpenFile event be fired every time or only once, use the FireAllOpenCloseEvents property.

As mentioned above, CreateFile and OpenFile are fired for files and also for directories. The directories are created via the CreateFile event and they are opened for enumeration using the OpenFile event.

Close Files

After a file is read from or written to, it is closed by the OS. Closing doesn't necessarily happen as soon as the application that used the file calls the Win32 CloseFile function. In some cases, the OS (or rather, its cache manager) keeps the handle to the file open for some time.

The CloseFile event includes the file and handle contexts as parameters, and these contexts must be disposed of by your application.

If CBFS fired the OpenFile event only the first time the file was opened, CloseFile will also be called only when the last handle to the file is closed by the OS (see the description of this behavior above).

When the directory contents enumeration is performed by the OS, CloseFile is called for the directory being enumerated when the enumeration is completed.

File Read/Write Operations

When the OS sends file read and write requests to the filesystem, the CBFS component's ReadFile and WriteFile events will fire. Both events include parameters that describe the offset into the file at which your application must begin reading/writing data, the data itself, etc.

The ReadFile and WriteFile events also include the FileContext and HandleContext parameters, described above. However, the latter may be empty if the read/write operation is performed by the OS's cache manager or memory manage, since such requests can occur without any specific handle being present.

File Resize Requests

Prior to writing file data, the OS will notify the filesystem that a certain amount of space must be allocated for the file. Such notifications are exposed via the SetAllocationSize event, allowing your application to pre-allocate storage space to ensure that the subsequent write operations complete successfully.

Note that this allocation size is not to be confused with the file size, which is the actual size of a file. The allocation size is always greater than or equal to the file size (except for in very specific situations; refer to the documentation for more information). When the OS wants to change the actual file's size, the SetFileSize event will fire.

Both of the aforementioned events include the FileContext and HandleContext parameters. However, the latter may be empty if the write operation is performed by the OS's cache manager or memory manage, since such requests can occur without any specific handle being present.

Renaming and Deletion

File and directory renaming, moving, and deletion are all atomic operations that must be handled via the RenameOrMoveFile and DeleteFile events.

Advanced Operations

CBFS supports a number of advanced filesystem operations, including: manipulation of named streams (also known as alternate data streams), security operations (getting/setting security attributes for a file or directory), reparse points, and hard link operations.

Working with Named Streams

Named streams (otherwise known as alternate data streams) are additional data chunks stored in a file that are not part of the file's "main" contents. Each such stream has its own name within the file. Support for named streams is optional, and is controlled using the UseAlternateDataStreams property.

Working with named streams is very similar to working with regular files. Named streams are opened via the OpenFile event and are read/written/closed in the same way that files are. When a named stream is opened, the file name contains a colon (:) that delimits the file name and the stream name.

A file's named streams are enumerated using the EnumerateNamedStreams and CloseNamedStreamsEnumeration events in a manner similar to directory enumeration.

Handling Security Operations

Security operations include setting and retrieving the ACLs (access control lists) for files and directories using the GetFileSecurity and SetFileSecurity events. Support for these events (and thus security attributes) is optional, and is controlled using the UseWindowsSecurity property.

Handling Reparse Point Operations

Reparse points are an advanced concept unique to the NTFS filesystem; they can be thought of as extra blocks of data that "overlay" main file or directory information. Windows uses reparse points to implement symbolic links, directory junctions, and more; and third-party applications can also use them for their own purposes.

Reparse point operations are exposed via the SetReparsePoint, GetReparsePoint, and DeleteReparsePoint events. Support for these events (and thus reparse points) is optional, and is controlled using the UseReparsePoints property.

Hard links are alternate names for the same file data. A given file always has at least one hard link (the main file name), and may have more. Working with hard links is therefore the same as working with any file name—in fact, it's exactly the same, since you're just using some name to access a file, as usual. The one exception is that applications that support hard links must ensure that they don't delete a file's actual contents until the last hard link to it has been deleted.

New hard links are created via the CreateHardLink event, and a file's hard links are enumerated using the EnumerateHardLinks and CloseHardLinksEnumeration events in a manner similar to directory enumeration. Support for these events (and thus hard links) is optional, and is controlled using the UseHardLinks property.

We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@callback.com.