A C++ Framework for QNX Virtual Filesystems


Code

The latest source for the virtual filesystems can be downloaded from my home page, here. You'll also need socket++ to compile the pop3 filesystem, also available from my home page.

This code is distributed under the GNU General Public Licence. I was going to distribute it under the library licence, but I can't find a copy on my machine. If the GPL's a problem for anybody, contact me, I could put it under the library licence.


Comments

In the process of writing QNX4 resource managers it becomes clear that a substantial amount of the code, especially for virtual filesystems, is very generic and reusable. This has been recognized by QSSL, and their newest version of QNX4, Neutrino, has incorporated a common framework to handle this generic functionality. This is supposed to substantially reduce the cut-and-paste coding in writing a resource manager, as well as contribute to Neutrinos small memory footprint.

However, I'm not using Neutrino.

Since the effort involved in implementing a virtual filesystem is considerable, I think it has remained a moderately arcane area. It was also getting in the way of me moving past the QNX mechanics and getting to what I really wanted to do: write an ftp or html filesystem. So, as a first step, I wrote a prototype of a virtual filesystem framework in C++, and implemented a RAM filesystem in the process since it seemed a good test case.

I've only recently discovered that QSSL has published a much better example of writing a virtual filesystem than they used to have, and that the example comes in the form of a framework, see iomanager2. My framework is surprisingly similar, but does some things theirs doesn't. I've read theirs and merged some of the useful ideas into mine.

As a next step I decided to tackle a Tar filesystem, a resource manager that would give a (read-only) filesystem-like interface to a tar file, one that you can cd into, then view a file with less or vi, etc. This is now done, and I've also implemented support for compressed tar files, and integration into the mount command (so you can do a 'mount -t tgz hello-1.2.tgz /src/hello').

My next goal was going to be an ftp filesystem, based on the ftp support that already exists in the socket++ library. However, that requires changes to the ftp support in socket++ to make it more useable, so I implemented a pop3 filesystem instead. It presents a pop3 e-mail account as a virtual filesystem, allowing you to read your pop3 mail with your favorite text editor.


Caveats

This is my code, I wrote it for free, I did it because I thought it was pretty interesting, and you can use it freely (under the terms of the GPL). It is not, however, production code. It works well enough to play with, and if you find it useful I'd be very pleased. If anybody has any comments, questions, encounters any problems, etc., please feel free to contact me, I'd like to help.

Here's some of the problems that I'm aware of:


Background

For the last few years I've worked primarily with QNX4. One of the most interesting things about QNX is the ability to write a resource manager capable of taking over a prefix in the pathname space (such as /dev) and responding to the file oriented Unix system calls, such as open(), read(), write(), readdir(), stat(), chdir(), etc. In QNX, all API's that operate on a path, or on the file descriptor returned by opening a path, are implemented using resource managers. Mostly these resource managers are used to implement mountable file systems, or fairly generic Unix block and character-oriented device drivers in /dev/. Exceptions are the message queue server, which offers the POSIX.4 ``mq_*'' API as well as a filesystem interface, and the QNX print spoolers, which offer a filesystem interface under the (virtual) /dev/spool directory as well as the more traditional ``lp*'' commands.

An interesting possibility is to write resource managers that allow an interface to other, less traditional, functionality.

One example of this is a resource manager that behaves as a single file, but where the contents are different each time the file is read, dynamically chosen from an index file. An implementation of this for QNX is available from Astra, binary only. Its a handy way of having a .signature that changes each time it is read.

Another, less playful, example is the networking API in the RoadRunner operating system. In this OS, opening a tcp connection is accomplished by doing an open on a path such as /net/tcp/192.168.3.9/80, which would open a connection to port 80 on the specified server. I can't link directly to the pertinent page, so follow Documentation>>html>>Tcp File System.

The power of this is in the simplification of APIs, and the unification of diverse interfaces, already a strength of the Unix I/O architecture in which as many system resources as possible are presented as ``files''. When an open() can be called on any resource, you don't have to code your application to deal specifically with those kinds of resources. For instance, you could write a framegrabber driver where every time you read it you read the current bitmap. Then you could write another manager that every time it was read it read the current bitmap, and converted it to a gif on the fly. Instant image capture on your web page, if you have an inline link to that pseudo file.

The point isn't so much that open() and read() are intrinsically easier to use than a custom API, such as frame_read(), frame_to_gif(), etc., as that applications don't have to know about your cutom API to use the resource; what's the chance that Apache will have that frame grabber API built in? Or that vmail will, when you try to send the current image as an attached gif?

Another interesting OS is the FSF's HURD, which is advertised to use the underlying Mach OS's message passing to implement resource managers for things such as a virtual filesystem for easy access to ftp servers. I'm still waiting for the promised Debian GNU/HURD to see how well it works, but I'm getting impatient...