DummyFS : A FileSystem step by step

This article was done with the IFS Kit provided by Microsoft through the MSDN partnership. All ressources below are packaged in this zip file.


DummyFS : A FileSystem step by step

Rémi Peyronnet – Février 2002

Introduction
Setting up a handy environnement
Your very first driver
Your first File System Driver
Conclusion
Références

Introduction

This is a complet idiot guide to build a filesystem driver. The goal of this guide is to learn you the basics of a simple file system driver, and to help you to set up a good development environment.

I. Setting up a handy environnement

Requirements
Installing the DDK
Usefull tools and resources
Integrate with Visual Studio

I. 1. Requirements

Before considering developping a file system driver, you must have the IFS DDK (Installable File System Driver Development Kit). For information about ordering this kit : http://www.microsoft.com/ddk/IFSkit/

I recently discovered a free ntifs.h, maintained by Bo Branten. This could be usefull if you consider developping a free project. But as there is not an official header, without documentation and warranty on this code, I strongly disencourage you to use it.

You also really should consider buying a book about kernel mode programming and NT file systems. There are some good references in the resources below. As I am a poor student, I do not bought one, but doing so, I do not know the ‘best practices’ of kernel mode development, so be carefull…

I. 2. Installing the DDK

Well, there is not much to say about that. The procedure is very simple. Once the setup.exe launched, select the items to be installed, and process. I recommend you to install the filesystem examples, and the OSR documentation. You should also consider installing other driver examples, as it would provide you extra kernel mode source code example.

You should also be aware of two details :

  • You will probably often use the command line. So you should provide a short and easy path name, as the default C:\WINDDK.
  • Building examples take a large amount of space. If you intend to do so, check there is an additionnal 200 Mo space on the drive you selected.

You have now all the tools installed. To compile an example, select the correct Build Environnement in the Start menu (IFS-DDK Kit 2600\Build Environments\Win XP Free Build Environment), go in the directory of the driver you want built, and type build. This build utility is great, as you will see. Do not use nmake /f, it does not work properly.

I. 3. Usefull tools and resources

OSR (Open Systems Resources) and SysInternals provide very usefull tools and materials. To be efficient in your driver’s development, these tools would be an invaluable help :

  • dbgMon or DebugView : DebugView is an application that lets you monitor debug output on your local system, or any computer on the network that you can reach via TCP/IP.
  • WinObj : WinObj displays information about the Object Manager’name space. You will be able tosee here (or not) your driver. This tool is the graphical equivalent of the Microsoft’s DDK utility objdir.
  • OSR Driver Loader : This GUI-based tool will make all the appropriate registry entries for your driver, and even allow you to start your driver without rebooting.
  • WinDbg : WinDbg is a free GUI kernel debugging tool for windows. You can perform powerfull tasks as remote kernel debugging, kernel mode connection and moreover, you can use the microsoft symbol server to retrieve the symbols you need, without any efforts. WinDbg has a graphical interface, but rely on command line tools, so you should consider read carefully the documentation and microsoft.public.windbg to know how to use the command line. A must have.

Also, the documentation is mandatory. Here are some resources :

  • Obviously the main resource is the IFS DDK Help.
  • The IFS DDK include some very interesting documentation from OSR. You will find this documentation in src/filesystem/OSR_docs.
  • NTFSD : NT-FSD is the mailing list of File System Development. You can access it via email, via web-based interface, or via news

I. 4. Integrate with Visual Studio

The DDKBuild utility
Have Intellisense

Visual Studio provides a very handy development environment. It helps you to develop faster and better. But surprisingly, Microsoft did not integrate the DDK with Visual Studio. The good point is that the build utility is really good, but the bad point is that there is no handy IDE. We will see here how to integrte the DDK in Visual Studio.

I. 4. a. The DDKBuild utility

The DDK introduce a new utility that replaces the makefile : build. That is very easy to use, very straight-forward and efficient. All the build information is stored in the sources and is highly configurable. But as it is not a standard makefile, it is a bit more difficult to use in Visual Studio.

In fact, it was. Today, the ddkbuild.bat utility makes this operation very easy :

  1. Create a new project, of type ‘Makefile’.
  2. As the command line, enter ‘ddkbuild.bat -XP free .’ and ‘/a’ for the rebuild all switch.
  3. Copy the ddkbuild.bat utility in the project folder. The ddkbuild utility uses the environnement variables to get the correct paths. Please check that the correct paths are provided. The ddkbuild can also provide support for multiple DDK versions (2K, XP,…), and both of the Free (debug) and Checked (release) builds.
  4. To complete the integration with VS, you can also generate the browsing information (the bsc file). To do that, simply add in your sources file the two lines : BROWSER_INFO=1 and BROWSERFILE=DummyFS.bsc. Then changes you project settings in Visual Studio (general tab, Browse info file name field)

I. 4. b. Have Intellisense

Intellisense is what completes your word when you type Ctrl-Space, what suggests you the members of a class when you type ‘.’ or ‘->’ and what shows you the parameter of a function when you type ‘(‘. This is very handy! All these information are created when editing the project’s files, and stored in the .ncb file. For instance, you will find three ncb : win32.ncb, crt.ncb and mfcatl.ncb in you devstudio/bin directory. But surprisingly, Microsoft does not seem to have added support to third party ncb, nor to the DDK. We will have to use of a small trick to add this support.

The contents of the NCB file are created when editing a file. For instance, when you add a method, Visual Studio parse the method and update its NCB. Also, when you add a .c or a .h in the project, the file is parsed and all the functions and classes are added. I observed the following behaviour :

  • A struct is added when its definition is found (ie in the .h file).
  • A standalone function is added only when its implementation is found. That means that the simple definition in the .h file is not enough : the .c file is needed. To fake this behaviour, you can replace all the ‘);’ string by ‘){}’ in the .h file you have. It transforms the declarations in an empty implementation, and so the function is added in the NCB. Of course, this modified .h won’t be anymore useable for your project, so make a copy.
  • The classes members and methods are handled properly, with or without implementation. So, there is nothing to do.

Also, I remarks that when you add a file, the contents is parsed and added to the NCB file. And it also add these entities to the ClassView tree. That is now very handy, because our real classes and functions are flooded in all these stuff. But what is great is when you remove the file you added, the classview information disappears, but not the intellisense information ! That is exactlyt what we want !

To summerize what you have to do with your project :

  1. Start with an empty project.
  2. Add all the .h files containing the intellisense information you want.
  3. Perform the replacement of ‘);’ by ‘){}’ to have intellisense information on standalone functions. Do not save !
  4. Remove all the h files to clean the classview tree.
  5. Close the project, and save the NCB file.

You should save your NCB file because sometimes it gets corrupt. If this is the case, you will just have to replace the corrupted NCB file with the saved one, without the need of doing again all this .h stuff.

Visual Studio does not provide support for third party NCB files ( I have not found any file where to add a specific NCB). But it loads three files win32.ncb, crt.ncb, mfcatl.ncb, located in the Microsoft Visual Studio\Common\MSDev98\Bin directory. But as it is not very frequent to use MFC when developping a kernel driver, I suggest you to replace temporarly the mfcatl.ncb file with your ncb file : this ncb will automatically be open for all your projects, and you will not need to do the .h stuff for each project. In addition, when your project’s NCB file is corrupt, you can safely delete it without any loss.

With a little more work you can get this compile, and generate a bsc file. But I do not know in what that can help you…

This method has been successfully tested on Visual Studio 6. As it is very dependant on the way Visual Studio behaves, this may not work on Visual Studio .Net.

II. Your very first driver

A little explanation
Your first run
Source File

II. 1. A little explanation

Well, now everything is ready to begin the real stuff in good conditions. We will see in this section the base structure of a device driver. Note that there is nothing specific to a file system driver. This is only the very smallest device driver.

The structure is very simple : a device driver must export the DriverEntry entry point. The Device Manager will call this function when the driver is being loaded. This function will basically create a device object for the driver, and will register our driver. Additionnal initialization could be done.

We have to intialize our DriverObject with the correct values. A very important thing is the array MajorFunction. Here you indicate the callbacks function to use for a specific request. Here we will indicate the same dispatch function for all the request, and select a wide range of request to handle. This is only for testing purpose, to see when a specific function is called. As our driver does nothing, we do not actually see anything :-). We provide also a callback function called when the driver is being unloaded. This callback has a very special behaviour, especially with File System driver, and we will discuss this matter later. Then we create the device, with a specific name.

The DFSControl dispatch function does not do much. It simply retrieves the request, and print the request in the DebugMonitor. Note that you retrieve the information with IoGetCurrentIrpStackLocation and that you have to finish the request with filling the Irp struct correctly and with IoCompeteRequest and with returning STATUS_NOT_IMPLEMENTED (in our case).

A handy command is DbgPrint. This allows you to print debug information that you will see with the DebugMon utility.

The sources file used to build the project is also very simple. We indicate the name and the type of our driver, some compiler option, the source file(SOURCES=), and the precompiled header(PRECOMPILED_*=). Note that the names in TARGETNAME, in FSD_SERVICE_PATH and in FSD_DRIVER_NAME are very important. You will see them in the WinObj tree.

II. 2. Your first run

This part is very important the first time. You must really understand what you are doing, else you will reboot a bunch of time. While developping a device driver, you should really consider the use of two computers : one for developping, one for testing and debugging. This will allow you to use the sophisticated remote kernel debugging mode, with stepping capabilities. Also, you will be able to search your error while the debuggee computer will be rebooting :-).

The OSR Driver Loader tool makes this step easy.

  1. Launch the utility, select your device driver, and click on register.
  2. Launch then the DebugMon utility, to see the output of your driver. Apply a filter if other drivers are outputting some verbose data.
  3. Click on the Start Driver button. You should see the Driver Entry debug message.
  4. Then click on the Stop Driver button. You should now see the Driver Unload message.

That is it ! You’ve done your first driver. You can play a dozen time with loadin/unloading it…

II. 3. Source File

 

III. Your first File System Driver

Explanation
Source File

III. 1. Explanation

In the Step 0, we have seen the basic structure of a Device Driver. In this step, we will see how to register our file system, and how to resolve the unload problems.

Register a filesystem is quite easy. This is done by IoRegisterFileSystem. Doing this, we increment the number of references to our Device Object. But the device manager will unload our driver only if there is zero reference and zero device objects attached to our driver.

To remove all these references and device objects, we will define and implement a user-defined IOCTL (IO Control). This IOCTL will be sent by another program we will develop (unloader). The processing of this IOCTL will be very simple :

  • IoUnregisterFileSystem : to unregister our filesystem
  • IoDeleteDevice : to be unloaded, a filesystem must have all the device deleted. It is a small difference compared to our device driver in the step 0. That is why if the only change you make in the step 0 is a IoRegisterFileSystem directly followed by a IoUnregisterFileSystem, the driver won’t be unloaded.

To be able to call the driver, a symbolic link has been developped. This will allow us to do a CreateFile(“\\.\NameOfTheSymbolicLink”) and to send our IOCTL with DeviceIOControl. Another method is to use the function IoGetDriverObjectPointer but I did not succeed in using it (error during the initialization of the DLL…) This symbolic link will be created in DriverEntry, and deleted in the Unload function. To finish with, the name of our driver must not be the same as our service. Also, you must add a CREATE and CLOSE major function. Here these functions will be really simple : the main goal is not creating file, but obtaining a handle on our driver. So these functions do nothing else but return STATUS_SUCCESS

Here you are, you have now a file system device driver that is capable of unloading. Be carefull in your development, because any error will be fatal, and you will be obliged to reboot…

III. 2. Source File

DummyFS.c
Unloader

III. 2. a. DummyFS.c

 

III. 2. b. Unloader

 

Conclusion

I hope this has been usefull to you, and that like me you will have pleasure to develop a file system driver. That is a hard work, but as it is very technical, it is fascinating. Also, it unleashes your possibilities with your computer.

Références

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Close Menu