Brad,
First, let me point out that filter drivers are often not easier than
file systems to implement. The lower edge of a file system is (usually)
a block or network interface, while the lower edge of a filter driver is
typically a file system. The latter interface is more complicated.
A “filter driver” attempts to modify the behavior of an existing file
system. It seems from your description that you are trying to create
the appearance of a separate volume where the actual implementation of
storage is not tied to that appearance. To me that suggests a virtual
file system (essentially one that redirects the actual storage to the
real location.)
But the range of options isn’t exactly black and white. You could, for
example, create an NTFS volume and have it store your logical
presentation, with the redirection information encoded as reparse
points. In that case you’d be implementing a filter driver that catches
the reparse operations and interprets it so the request can be sent to
the original location. This would in fact be a filter driver and you’d
be exploiting this extra NTFS volume as your storage of the naming
information.
Or you might choose instead to implement this as a logical file system,
where you store the name space structure in some proprietary format
(hey, store it in SQL if you want, it really doesn’t matter.) Then when
someone queries a directory you construct the format of the directory
and ship it to them. When someone opens a file or stream you use the
name information to figure out where the REAL object is located and send
the request to that alternate location. You might do this via the
STATUS_REPARSE mechanism (“get out of the way”) or you might do this via
a mapping mechanism (“don’t bypass me”) depending upon your specific
requirements (one “issue” with the get out of the way approach is the
relative open, which can complicate things.)
Based upon what you’ve described thus far, my personal inclination would
be to create a logical structure via private data representation,
retrieve the information dynamically as I needed it and redirect the
requests to the “real target” wherever it might be located (I keep
thinking it might be worthwhile trying to use the “open by ID”
optimization, but that might just be unduly complicated.) As long as
you control directories, the only relative opens would be on the
file/stream (so someone could open another stream of the same file) and
that might be sufficient. But if you are sensitive to renames, for
example, then the “get out of the way” approach probably doesn’t work as
well for you, and you may want to watch for the renames on those files.
Then you either go to the double mapping technique (first file object
points to you, second file object points to the NTFS instance of the
file) or you use a hybrid technique (so you have a filter to watch for
meta-data operations, and a namespace driver to present the logical
format.)
The beauty of this space is that there are so many different ways of
achieving the specific functionality. None of them are perfect and each
of them has a range of trade-offs involved (and the BEST part is they
are short-term/long-term trade-offs that you seldom understand until you
are done with the project and realize you’ve chosen a less-than-optimal
solution.)
Job security in this business is very good. 
Regards,
Tony
Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com