Pismo File Mount Development Kit build 154

Pismo Technic Inc., Copyright 2005-2009 Joe Lowe
2009.10.14

Preface

This document is targeted towards software developers wishing to integrate Pismo File Mount with their applications, or writing extensions for the Pismo File Mount Audit Package.

Portions of the document are also useful to users of the Pismo File Mount Audit Package.

Contents

Pismo File Mount

Description

Pismo File Mount is a Windows operating system extension that enables access and modification to user and program data through the file system interface of the operating system. By exposing data through the file system, problems can elegantly and efficiently be solved that otherwise require less flexible and more resource intensive solutions.

Pismo File Mount works by enabling user mode file systems to present file data through a virtual mount point on an existing local, remote, or removable drive. The virtual mount point is created in place on top of an existing file. Typically the mount point file is an archive or data file whose data is being exposed by the user mode file system, but purely virtual file systems are also possible. While mounted, the mount point file appears as a folder whose contents are served by the user mode file system.

Architecture

Kernel Mode File System Driver

The core of the Pismo File Mount system extension is a kernel mode device driver called pfmfs*.sys . This driver interfaces with the various core Windows system interfaces including the file system, virtual memory, and caching. Additionally this driver interacts with the built in and 3rd party file systems such as NTFS, CDFS, and FAT.

The drivers main purpose is to redirect file system requests to a user mode file system, or formatter.

PFM Protocol

The communication between the driver and formatter (user mode file system) is done over a bi-directional pipe using the PFM Protocol. This protocol is defined in pfmprotocol.h and pfmenum.h .

Formatters

Support for each virtual file system or container file format is implemented as a formatter. Each formatter exists as a DLL that exposes the PfmFormatter interface. This interface is used by the PFM mount logic to locate the correct formatter to mount a given file, and to connect the formatter to the driver.

Once a formatter has been connected to the driver, the driver redirects file system requests to the formatter using the PFM Protocol. Most formatters utilize the PfmMarshaller implementation provided in the PFM API DLL to convert the protocol into the more easily implemented PfmReadOnlyFormatterOps or PfmFormatterOps interface.

It is also possible for applications to contain embedded formatters in the application executable. These applications would bypass the normal mount logic, and directly create mounts through the PFM API.

Application Programming Interface DLL

Communication between client applications and the driver are routed through the API DLL, pfmapi*.dll. This DLL acts as a marshaller for functionality exposed by the driver through I/O control functions. Generally there is no need for applications or formatters to directly communicate with the driver using I/O control functions.

Applications interact with and control PFM using the PfmApi interface and the associated interfaces PfmMount, PfmIterator, PfmMonitor. These interfaces are defined in pfmapi.h and pfmenum.h .

The API DLL also contains an implementation of the PfmMarshaller interface. This interface abstracts formatters from the PFM Protocol, simplifying formatter implementation.

The driver I/O control functions, the user mode API, the protocol, and the protocol marshaller, are all versioned. This allows management of forward and backward compatibility with formatters and client applications. This versioning is transparent to client applications and formatters.

Command Line Interface

The command line executable pfm.exe is the reference user interface of Pismo File Mount. Using pfm.exe it is possible to:

Like all the command line executables in PFM, pfm.exe contains about information and command line help. Examples:

>pfm -h
>pfm mount -h
>pfm mount myphotos.zip
>pfm unmount myphotos.zip

Alerts

Like most file systems, PFM provides read and write data caching to increase file system performance. Since write caching delays the write of application data, it is not always possible to inform applications when writes fail. The accepted solution to this problem is to directly notify the user in the event of delayed write failures. Windows contains a built-in notification mechanism that notifies the user when delayed writes fail with the built-in file systems.

PFM includes an alerter component, which provides delayed write failure notifications for its own file systems. The alerter is implemented as an executable called pfmstat.exe. Pfmstat.exe is started by pfm.exe anytime a file is mounted, and automatically exits shortly after the last file is unmounted. While running, pfmstat.exe adds a notification icon to the explorer system tray.

When necessary, delayed write notifications are presented to the user as notification balloons. In the event explorer is not executing, a message box is displayed.

Installer

The PFM Audit Package and 3rd party applications that incorporate PFM install the core PFM files using the provided installer, pfminst.exe. Example:

The PFM installer has been designed to reduce points of failure during install/upgrade/uninstall, to simplify integration with 3rd party applications, and to reduce support costs.

Pismo File Mount Audit Package

Description

The Pismo File Mount Audit Package (PFMAP) is a utility application that utilizes the PFM system extension to allow users to mount the contents of files to the file system as read-write or read-only folders. PFMAP is built using the same PFM interfaces available to 3rd party application developers.

In addition to being a useful stand-alone application, PFMAP can be used with the PFM Developer Kit. This allows developers to create extension formatters for PFMAP, or to integrate PFM with their own applications.

Explorer shell extension

PFMAP includes an explorer shell extension, pfmshx*.dll. This shell extension allows convenient control of PFMAP directly from explorer.

Mount Control

The Mount Control application, pfmcontrol.exe, is the graphical user interface to PFMAP. All functionality in PFMAP can be accessed through this application, independent of explorer or the PFM command line interface. Mount Control is particularly useful to view all currently mounted files.

CD/DVD image file reader

Pfmisofs.dll is a read-only DVD and CD image file formatter. It supports all or part of the following formats and extensions:

Zip reader

Pfmzipfs.dll is a read-only ZIP archive file formatter. It supports the following formats and compression modes:

The implementation is missing the following potentially useful features:

Temporary file system

Pfmtempfs.dll implements a read-write temporary virtual file system. This formatter is primarily useful as an example formatter. The source code is provided with the development kit in tempfs.cpp .

The temp file system stores all file data in system memory. This limits the maximum amount of stored file data based on available physical memory and swap file space. On 32 bit systems the amount of stored file data cannot exceed 2GB due to limited process address space.

Private Folder file system

Pfmpfolderfs.dll implements a read, write, encrypted, compressed container file formatter. It allows storing sensitive files in a secure container file, accessible only with the correct password.

The user supplied password is converted to an encryption key using the PKCS5V2 algorithm. Data is encrypted using the AES encryption algorithm in XTS chaining mode.

Data compression uses the Zlib implementation of the deflate compression format. This is the same compression used in PNG images and ZIP archives.

The Private Folder data format documentation is not yet ready for public release. Pre-release information will be provided to interested parties upon request. For more information contact Pismo Technic Inc. support.

Development Kit

Description

The PFM Development Kit allows developers to build formatters for PFMAP, to enable new virtual file systems and to add support for new file formats. The kit also can be used to integrate PFM into 3rd party applications, either to allow third party applications to control the mounting and unmounting of files, or to allow applications to create virtual file systems for internal or external use.

Programming Languages

The development kit supports development in C and C++, and in the various CLR/.NET languages including C# and Visual Basic.

The documentation in this kit uses the C++ syntax when describing functions and interfaces. C developers should refer to the various header files, and to the differences between the various C and C++ samples. CLR/.NET developers should refer to the interfaces in the provided API shim assembly pfmclrapi.dll, the C++/CLI shim source code in pfmclrapi.cxx, and to the various C# and Visual Basic samples.

Tools

Windows SDK C/C++ Compiler

Developers using PFMAP have the option of downloading the free Windows SDK and Debugging Tools for Windows from Microsoft and using them to compile and work with the samples.

Microsoft Developer Studio

To build formatters using Microsoft Developer Studio, create a project/solution for a DLL or Class Library and use the .def file supplied with the samples.

Other Tools

Many development tools capable of building standard Windows DLLs from C/C++ source files can be used with this development kit.

Developers are encouraged to use the C/C++ compiler included with the free Windows SDK (2007 and later) in preference to the Cygwin/Mingw GNU compiler. If the Cygwin/Mingw GNU compiler is used, you must build native Windows DLLs, not shared libraries that run with the Cygwin unix emulator.

C/C++ Header Files

Though parts of the following header files currently lack documentation, all of the interfaces and definitions are public and supported. Any questions regarding undocumented interfaces should be directed to Pismo Technic Inc. support.

pfmapi.h

Pfmapi.h contains the definitions of the PFM API, including the interfaces PfmApi, PfmMount, PfmIterator, PfmMonitor, and PfmAlerter.

pfmenum.h

Pfmenum.h contains definitions of constants and flags that are used in both the PFM API and the PFM Protocol.

pfmprotocol.h

Pfmprotocol.h contains the definitions that make up the PFM Protocol.

It is not necessary for most applications or formatters to use these definitions.

pfmformatter.h

Pfmformatter.h contains the definition of the PfmFormatter interface that is implemented by formatters.

It is possible for applications to implement virtual file systems by directly using the PFM API. These applications would not implement the formatter interface.

pfmmarshaller.h

Pfmmarshaller.h contains the definition of the PfmMarshaller interface implemented in the PFM API DLL for use by formatters. It also contains the definitions of the PfmReadOnlyFormatterOps and PfmFormatterOps interfaces implemented by formatters.

Samples

Hellofs Application in C and C#

Hellofsapp.c contains source code to a very simple C language virtual file system application. When run, this application presents a virtual file system containing a single read-only file, named readme.txt, containing the text "hello world".

The following commands can be executed in a Windows SDK CMD shell to build and test the application. A Windows SDK CMD shell can be created by executing the "Start Menu - Programs - Microsoft Windows SDK - CMD Shell" menu shortcut created when a 2007 or later version of the Windows SDK is installed.

>cl hellofsapp.c advapi32.lib
>echo any data > anyfile
>start hellofsapp anyfile
>type anyfile\readme.txt

Hellofsapp.cs contains source code to an equivalent very simple C# language virtual file system application. This sample can be compiled with the included project file using Visual Studio 2008 or Visual C# 2008 Express Edition.

Hellofs Formatter in C

Hellofs.cpp contains source code to a very simple C++ language formatter. When mounted, this formatter presents a single read-only file, named readme.txt, containing the text "hello world".

The following commands can be executed in a Windows SDK CMD shell to build and test this formatter. A Windows SDK CMD shell can be created by executing the "Start Menu - Programs - Microsoft Windows SDK - CMD Shell" menu shortcut created when a 2007 or later version of the Windows SDK is installed.

>cl hellofs.c /Fehellofs.dll /link /dll /def:pfmformatter.def advapi32.lib
>pfm register hellofs.dll
   (This modifies the HKCR\PismoFileMount registry key.)
>echo #!hellofs >hello.mnt
>pfm mount hello.mnt
>type hello.mnt\readme.txt
>pfm unmount hello.mnt
>pfm unregister hellofs.dll
>pfm mount hello.mnt
   (This should fail since the formatter is unregistered.)

Tempfs Formatter in C++ and C#

Tempfs.cpp contains source code to a read-write temporary virtual file system written in C++. When mounted it creates an empty folder. While mounted files and folders can be created. When unmounted all contained data is discarded.

The C++ tempfs formatter is included in PFMAP as pfmtempfs.dll .

Additionally, tempfs2.cs and fsshim.cxx contain source code to an equivalent temporary file system written in C# with a C++/CLI shim. Information on compiling and testing this sample formatter is included in readme.txt .

Unmount Utility in C# and Visual Basic

Two versions of a sample application that will list and unmount mounted files is provided, unmount.cs in C#, and unmount.vb in Visual Basic. These samples can be compiled with the included project files using Visual Studio 2008 or Visual C#/Basic 2008 Express Edition.

Application Development

Getting Started

The PFM API allows direct integration of PFM with applications written in C and C++.

Applications written in CLR/.NET languages can integrate with PFM using pfmclrapi.dll provided with the development kit. CLR/.NET applications must distribute a private copy of pfmclrapi.dll as it is not a part of PFM or PFMAP. Developers are free to customise pfmclrapi.dll using the provided C++/CLI source in pfmclrapi.cxx .

Integration with PFM allows applications to perform a number of useful functions.

Concepts

Errors

The PFM API interfaces return system Win32 error codes such as ERROR_ACCESS_DENIED.

MountId

Each time a new mount is created it is assigned a unique identifier. This identifier is used in the various interfaces to identify the mount. MountIds are not reused.

ChangeInstance

PFM maintains a change instance count for the mount list and for each individual mount. Each time mount status changes the mounts change instance is incremented. Each time a mount is created or destroyed the mount list change instance is incremented. These change instances are used with PfmApi::Iterate and PfmMonitor::Wait to allow applications to efficiently monitor for changes.

Mounting Files

The supported interface by which applications can mount files is the command line utility pfm.exe , or the non command line equivalent pfmhost.exe . Both of these programs support the same functionality for mounting files. Pfmhost.exe avoids creating a user visible console window when it is run.

The command line syntax and available options are documented as command line help in pfm.exe .

>pfm mount -h
syntax: pfm mount [<switch> ...] <file>
switches:
  -a  Allow everyone read access.
  -b  Open new mount in shell.
  -c  Authenticate through console.
  -d  Single process mount for diagnostics.
  -e  Display mount options dialog.
  -f <formatter name>  Name of formatter with which to mount file.
  -i  Mount visible only to owner. Default for non admins.
  -l  Prompt for credentials if needed for system visibility.
  -m <drive letter>  Map drive letter to mount.
  -o <user sid>  Alternate owner.
  -p <pid>  Limit mount visibility to specified process and children.
  -r  Mount read only.
  -s  Mount visible to all users and system. Default for admins.
  -u  Accessible only through UNC.
  -v  Verbose output.
  -w  Allow everyone read and write access.

Unmounting Files

Applications can unmount files using the PFM API.

#include "pfmenum.h"
#include "pfmapi.h"
   ...
   PfmApi* pfm = 0;
   PfmMount* mount = 0;
   int error = PfmApiFactory(&pfm);
   if(!error)
   {
      error = pfm->Open(L"c:\\somemountedfile.iso",&mount);
   }
   if(!error)
   {
      error = mount->Unmount(0|*pfmUnmountFlags*|);
   }
   if(mount)
   {
      mount->Release();
   }
   if(pfm)
   {
      pfm->Release();
   }

Alternatively applications can use the unmount command of pfm.exe or pfmhost.exe .

>pfm unmount -h
syntax: pfm unmount <file>

Virtual File Systems

Applications can use PFM to allow creation of virtual file systems, exposing data generated directly by the application. Much of the code required is the same as required to implement a formatter, except for the initial mount logic.

A simple sample virtual file system application is the Hellofs Application sample.

PfmApi interface

The PfmApi interface is defined in pfmapi.h . Some constants and flags are defined in pfmenum.h .

This interface allows applications to interact with and control PFM.

PfmApiFactory

int /*error*/ PfmApiFactory (
   PfmApi** api )

This function loads the API DLL and retrieves an instance of the PfmApi interface.

PfmApi::Release

void PfmApi::Release ( )

Free the interface instance and any associated resources.

PfmApi::MountCreate

int /*error*/ PfmApi::MountCreate (
   const PfmMountCreateParams* params,
   PfmMount**                  mount )

Create a new file mount whose data will be served using the PFM Protocol through the mountCreateParams.toFormatterWrite and mountCreateParams.fromFormatterRead pipes or socket.

The params structure should be initialized as follows:

   PfmMountCreateParams params;
   memset(&params,0,sizeof(params));
   params.paramsSize = sizeof(params);
   params.mountFileName = ...;
   params.mountFlags = ...;
   params.toFormatterWrite = ...;
   params.fromFormatterRead = ...;

Applications that only want to initiate mounts, but not create their own virtual file systems, do not use this function. Instead they would use the command line interface of pfm.exe or pfmhost.exe to mount files.

Developers who wish to use this function should contact Pismo Technic Inc. support for additional information and sample code.

PfmApi::MountOpen

int /*error*/ PfmApi::MountOpen (
   const wchar_t* mountFileName ,
   PfmMount**     mount )

Opens the file mount using the name of the mounted file. The mount must be visible to the calling process. If the mount is not visible to the calling process then it must be opened by mountId using the PfmApi::MountOpenId function.

PfmApi::MountOpenId

int /*error*/ PfmApi::MountOpenId (
   int        mountId ,
   PfmMount** mount )

Open the file mount identified by the mountId parameter. The mountId parameter is typically retrieved from the PfmIterator::Next function.

PfmApi::Iterate

int /*error*/ PfmApi::Iterate (
   int64_t       startChangeInstance ,
   int64_t*      nextChangeInstance ,
   PfmIterator** iterator )

This function creates and returns an instance of the PfmIterator interface, which allows applications to query a complete or partial list of file mounts.

To iterate all mounts, zero should be passed for the startChangeInstance parameter.

The nextChangeInstance parameter is the location to store the current change instance of the mount list that will be returned by the iterator. This change instance can be used as the startChangeInstance parameter in future calls to iterate only mounts that have changed.

PfmApi::Monitor

int /*error*/ PfmApi::Monitor (
   PfmMonitor** monitor )

This function creates and returns an instance of the PfmMonitor interface, which allows applications to efficiently maintain an updated list of all file mounts and mount states.

PfmMount interface

The PfmMount interface is defined in pfmapi.h . Some constants and flags are defined in pfmenum.h .

This interface allows applications to query information about, and control, an existing file mount. This interface is returned from the PfmApi::MountCreate, PfmApi::MountOpen, and PfmApi::MountOpenId functions.

PfmMount::Release

void PfmMount::Release ( )

Free the interface instance and any associated resources.

Once this function is called, any previous data returned from this interface should no longer be used. In particular, any pointers to strings are no longer valid.

PfmMount::Refresh

int /*error*/ PfmMount::Refresh ( )

Update to match any changes to the state of the mount.

Once this function is called, any previous data returned from this interface should no longer be used. In particular, any pointers to strings will no longer be valid.

PfmMount::Unmount

int /*error*/ PfmMount::Unmount (
   int unmountFlags )

End an existing file mount. The mount will remain visible through the PfmApi::Iterate function until all PfmMount instances referring to the mount are released.

PfmMount::GetMountId

int /*mountId*/ PfmMount::GetMountId ( )

PfmMount::GetMountFlags

int /*mountFlags*/ PfmMount::GetMountFlags ( )

PfmMount::GetStatusFlags

int /*statusFlags*/ PfmMount::GetStatusFlags ( )

PfmMount::GetVolumeFlags

int /*volumeFlags*/ PfmMount::GetVolumeFlags ( )

PfmMount::GetChangeInstance

int64_t /*changeInstance*/ PfmMount::GetChangeInstance ( )

PfmMount::GetVisibleSessionId

int PfmMount::GetVisibleSessionId ( )

PfmMount::GetVisibleProcessId

int PfmMount::GetVisibleProcessId ( )

PfmMount::GetFileName

const wchar_t* PfmMount::GetFileName ( )

The returned pointer to a string is only valid until the next call to the PfmMount::Refresh function or until the PfmMount instance is released.

PfmMount::GetUncName

const wchar_t* PfmMount::GetUncName ( )

The returned pointer to a string is only valid until the next call to the PfmMount::Refresh function or until the PfmMount instance is released.

PfmMount::GetDriveLetter

wchar_t PfmMount::GetDriveLetter ( )

PfmMount::GetOwnerSid

const wchar_t* PfmMount::GetOwnerSid ( )

The returned pointer to a string is only valid until the next call to the PfmMount::Refresh function or until the PfmMount instance is released.

PfmMount::GetOwnerName

const wchar_t* PfmMount::GetOwnerName ( )

The returned pointer to a string is only valid until the next call to the PfmMount::Refresh function or until the PfmMount instance is released.

PfmMount::GetFormatterName

const wchar_t* PfmMount::GetFormatterName ( )

The returned pointer to a string is only valid until the next call to the PfmMount::Refresh function or until the PfmMount instance is released.

PfmMount::Flush

int /*error*/ PfmMount::Flush ( )

PfmMount::Hide

int /*error*/ PfmMount::Hide ( )

PfmMount::Control

int /*error*/ PfmMount::Control (
   int         controlCode ,
   const void* input ,
   size_t      inputSize ,
   void*       output ,
   size_t      maxOutputSize ,
   size_t*     outputSize )

Send a formatter specific control code through to the formatter. Formatters using PfmMarshaller will see a the control code via a call to PfmReadOnlyFormatterOps::Control or PfmFormatterOps::Control.

Since control codes are formatter specific, applications must identify the formatter before sending control codes. This can be done using PfmMount::GetFormatterName function.

Formatters should number their control codes starting at zero or one and not leave gaps. The range of available control codes is limited and is not guaranteed to remain constant.

PfmMount::WaitReady

int /*error*/ PfmMount::WaitReady (
   int timeoutMsecs )

Wait for the mount to become ready.

PfmIterator interface

The PfmIterator interface is defined in pfmapi.h .

This interface is returned from the PfmApi::Iterate function. It allows applications to retrieve the mountId and current changeInstance of all file mounts.

PfmIterator::Release

void PfmIterator::Release ( )

Free the interface instance and any associated resources.

PfmIterator::Next

int /*mountId*/ PfmIterator::Next (
   int64_t* changeInstance )

PfmMonitor interface

The PfmMonitor interface is defined in pfmapi.h .

This interface is returned from the PfmApi::Monitor function. It allows applications to monitor for the creation and deletion of file mounts.

PfmMonitor::Release

void PfmMonitor::Release(void)

Free the interface instance and any associated resources.

PfmMonitor::Wait

int /*error*/ PfmMonitor::Wait (
   int64_t nextChangeInstance ,
   int     timeoutMsecs )

Wait for the change instance of the mount list to be different from the nextChangeInstance parameter, or until another thread calls the PfmMonitor::Cancel function.

PfmMonitor::Cancel

void PfmMonitor::Cancel ( )

Return early from any calls to PfmMonitor::Wait .

Formatter Development

Getting Started

New formatter developers should first compile and test one of the sample formatters using their chosen compiler. The steps outlined for Hellofs are a good start with the SDK compiler.

Testing

Debugging formatters can be done by loading the formatter via the command line interface. Using the mount command -d switch will cause pfm.exe to load the formatter directly in process, which simplifies debugging. To debug a formatter named myformatter.dll, that recognizes the contents of the file somefile.bin, using windbg, you could enter the following command at the command prompt:

>pfm register myformatter.dll
>windbg pfm mount -d -f myformatter somefile.bin

The PfmMarshaller interface provides some built in tracing functionality that is useful during development. To see these traces you will need to download and install Pismo Trace Monitor, available on the Pismo Technic Inc. website, http://www.pismotechnic.com/ .

You start the trace monitor using the "Start Menu - Programs - Pismo Trace Monitor" menu link, or by running tracemon.exe .

New trace channels are hidden by default. You will need to use the unhide command from the trace monitor window menu to make channels visible. Do this after you have mounted a file.

Concepts

Errors

The PFM Protocol and the PfmReadOnlyFormatterOps and PfmFormatterOps interfaces return error codes as defined in pfmenum.h , such as pfmErrorAccessDenied. The other interfaces return Win32 error codes such as ERROR_ACCESS_DENIED. The protocol is remotable and portable, so the use of system error codes is not appropriate.

Folders are Files

The term file is regularly used in this document to mean file or folder. Unless stated otherwise, all PFM Protocol requests and related marshalled functions work the same for files and folders.

File Names

The PFM Protocol represents all file names in UTF8. The marshaller converts UTF8 file names to and from wchar_t file names for use by the formatters.

The protocol and the driver support multiple named files, or hard links. Formatters that support hard links make use of the driver maintained parentFileId and endName in order to identify which name for a file is being manipulated.

The protocol allows the formatter to return a case corrected spelling for the last element of the name of opened files. This case corrected name is used by the driver when emulating short name aliases (DOS 8.3 file names). Short names are still used by many applications, including portions of Windows itself. Formatters that do not provide the case corrected end name will have reduced application compatibility.

OpenId and OpenSequence

OpenId and openSequence are integral parts of the PFM protocol. The openId is the mechanism used to identify open files and folders. OpenSequence is maintained by the driver and used by the formatter to identify when the last reference to an open file or folder has closed.

OpenIds are not file IDs. In particular the openId values for new files is assigned by the driver, where file IDs are assigned by the formatter.

The use of openIds and openSequence allows PFM to provide atomicity guarantees during file system name space changes and share mode checks. Without this mechanism the driver would have to make assumptions about the formatters name space, and hold locks while waiting for the formatter to process many requests.

Deleted Files

The PFM Protocol handles file deletion using a unix model, where deletion applies to file names as opposed to underlying file data. After a file has been deleted, the file data must remain accessible until the file is finally closed.

The unix file deletion model requires extra code for some formatters. For other formatters it is trivially supported. Regardless, it is a requirement for formatters and is utilized by the driver.

Formatter developers should understand that the NT file system model is more complex than is apparent to casual users of the Win32 API. Using a unix model for file delete allows the driver to achieve a high level of application compatibility in a more portable and supportable way than if the native NT delete model were directly supported by the protocol.

Concurrency

The Windows kernel is massively multi-threaded. The PFM driver runs in the kernel, and therefore must also be multi-threaded. Likewise, the PFM Protocol used by the driver to communicate with formatters supports requests being processed in parallel and in any order, so formatters can also be implemented multi-threaded.

Formatters are not required to be multi-threaded. Both the driver and the protocol have been carefully designed to support multi-threaded formatters and formatters that serially process requests. All formatters that implement PfmFormatterOps or PfmReadOnlyFormatterOps are inherently single-threaded.

Formatters that require concurrency or multi-threaded operation must either directly process the PFM protocol, or must implement the PfmFormatterDispatch interface. Developers who wish to implement multi-threaded formatters should contact Pismo Technic Inc. support for additional information and sample code.

PfmFormatter interface

The PfmFormatter interface is defined in pfmformatter.h . Some constants and flags are defined in pfmenum.h .

This interface is implemented by formatters. It is used by the PFM mount logic to identify which formatter understands the format of the file the user has selected to mount, and then it is used to connect the formatter with the bi-directional pipe to communicate with the driver.

PfmFormatterFactory1

int /*error*/ PfmFormatterFactory1 (
   PfmFormatter** formatter )

This function is exported by all formatter DLLs. It returns an instance of the formatter interface.

PfmFormatter::Release

void PfmFormatter::Release ( )

PFM calls this function when it has finished using the formatter interface.

PfmFormatter::Identify

int /*error*/ PfmFormatter::Identify (
   HANDLE         statusWrite ,
   const wchar_t* mountFileName ,
   HANDLE         mountFileHandle ,
   const void*    mountFileData ,
   size_t         mountFileDataSize )

During the mount process, PFM calls each formatters identify function, passing it data about the file being mounted. The first formatter that returns no error (0) will be used to mount the file.

For performance reasons, formatters should avoid opening the file during identify, or unnecessarily reading additional file data. Formatters should use the supplied file data if it is large enough. More file data should be read using the supplied handle if necessary.

The statusWrite parameter is the write handle of a pipe to which status text can be sent during the identify process. Text sent to the statusWrite handle will appear on the verbose mount status dialog (pfm mount -v ...). This handle can be passed to the PfmMarshaller::SetStatus function to allow the PfmMarshaller print functions to be used.

PfmFormatter::Serve

int /*error*/ PfmFormatter::Serve (
   const wchar_t* mountFileName ,
   int            mountFlags ,
   HANDLE         toFormatterRead ,
   HANDLE         fromFormatterWrite )

When PFM has identified the correct formatter, and established the mount with the driver, it calls the formatter serve function. The read and write handles passed to the formatter can be used to read PFM Protocol requests from the driver and write results. These handles can be provided to a PfmMarshaller instance to handle the marshalling of the protocol to the more easily implemented PfmReadOnlyFormatterOps and PfmFormatterOps interfaces.

The read and write handles remain connected to the mount status dialog until the driver sees the protocol ready string. This allows the formatter to continue to display status text and perform user prompting while initializing. The PfmMarshaller::ServeReadOnly and PfmMarshaller::ServeReadWrite functions send the ready string to the driver.

PfmMarshaller interface

The PfmMarshaller interface is defined in pfmmarshaller.h . Some constants and flags are defined in pfmenum.h .

This interface is implemented in the PFM API DLL. It is used to convert the PFM Protocol into the PfmReadOnlyFormatterOps and PfmFormatterOps interfaces that are implemented by formatters.

PfmMarshallerFactory

int /*error*/ PfmMarshallerFactory (
   PfmMarshaller** marshaller )

This function creates an instance of the PfmMarshaller interface.

PfmMarshaller::Release

void PfmMarshaller::Release ( )

Formatters should call this function when they are finished using an instance of the PfmMarshaller interface.

PfmMarshaller::SetTrace

void PfmMarshaller::SetTrace (
   const wchar_t* traceChannelName )

Formaters can optionally call this function to initialize a diagnostic trace channel to help with testing and field troubleshooting.

The Pismo Trace Monitor application must be installed to view the traces that are generated when this function is used. This applications is available on the Pismo Technic Inc. website, http://www.pismotechnic.com/ .

PfmMarshaller::SetStatus

void PfmMarshaller::SetStatus (
   HANDLE write )

Formatters can call this function to set a write handle to a pipe to send status text that is written using the status functions (Print, Vprintf, Printf, Line). This is primarily useful in the implementation of PfmFormatter::Identify.

The marshaller does not duplicate or reference the supplied handle. Formatters must make a second call to this function, specifying INVALID_HANDLE_VALUE to prevent the marshaller from later using the handle.

PfmMarshaller::ConvertSystemError

int /*pfmError*/ PfmMarshaller::ConvertSystemError (
   int error )

This function can optionally be used by formatters to convert system (win32) error codes to the equivalent PFM error codes needed with the PfmReadOnlyFormatterOps and PfmFormatterOps interfaces.

PfmMarshaller::Identify

int /*error*/ PfmMarshaller::Identify (
   const char* mountFileData ,
   size_t      mountFileDataLen ,
   const char* formatterName )

This function can optionally be used by formatters to identify mount files that are using a unix style shell specification as a file type identifier. This is primarily useful for virtual file systems, where the mount file is only a marker file. The PFM sample formatters use this.

For example, passing a value of "sampleformatter" for formatterName would match a file containing the following text in the first line of the file:

#!sampleformatter

PfmMarshaller::GetPassword

int /*error*/ PfmMarshaller::GetPassword (
   HANDLE          read ,
   const wchar_t*  prompt ,
   const wchar_t** password )

Formatters that require passwords can use this function to query the user to enter a password. The prompt value is the text to display with the prompt, typically "user name:" or "password:". The returned password is valid until the next call to either PfmMarshaller::GetPassword or PfmMarshaller::ClearPassword.

PfmMarshaller::ClearPassword

void PfmMarshaller::ClearPassword ( )

This function should be called after PfmMarshaller::GetPassword, when the returned password is no longer needed. This clears the password from system memory, reducing the chance that it will persist in the page file or appear in subsequent uninitialized memory allocations.

PfmMarshaller::ServeReadWrite

int /*error*/ PfmMarshaller::ServeReadWrite (
   PfmFormatterOps* formatter ,
   int              volumeFlags ,
   const char*      formatterName ,
   HANDLE           toFormatterRead ,
   HANDLE           fromFormatterWrite )

This function is called by read-write formatters when they are ready to begin processing requests from the driver. The serve function sends the PFM Protocol ready string to the driver, which results in the mount status dialog closing. It then goes into a loop, reading protocol requests from the driver, calling the associated functions in the PfmFormatterOps interface, and sending results back to the driver.

The serve function will return when the driver disconnects from the formatter by closing its end of the pipe, or by sending a disconnect request.

The volumeFlags and formatterName parameters are provided to the driver, which uses the information to satisfy volume information queries made by applications.

PfmMarshaller::ServeReadOnly

int /*error*/ PfmMarshaller::ServeReadOnly (
   PfmReadOnlyFormatterOps* formatter ,
   int                      volumeFlags ,
   const char*              formatterName ,
   HANDLE                   toFormatterRead ,
   HANDLE                   fromFormatterWrite )

This function is equivalent to PfmMarshaller::ServeReadWrite , except that it is used by read-only formatters.

PfmMarshaller::ServeDispatch

int /*error*/ PfmMarshaller::ServeDispatch (
   PfmMarshallerServeParams* params )

This function is used instead of PfmMarshaller::ServeReadWrite , by formatters that require concurrent or multi-threaded operation.

The params structure should be initialized as follows:

   PfmMarshallerServeParams params;
   memset(&params,0,sizeof(params));
   params.paramsSize = sizeof(params);
   params.dispatch = ...;
   params.volumeFlags = ...;
   params.formatterName = ...;
   params.toFormatterRead = ...;
   params.fromFormatterWrite = ...;

Developers who wish to use this function should contact Pismo Technic Inc. support for additional information and sample code.

PfmMarshaller::Print

void PfmMarshaller::Print (
   const wchar_t* data )

This function can be used by formatters during identify and mount initialization, to send status data to the mount status dialog through the handle specified in an earlier call to PfmMarshaller::SetStatus.

This function can be used during processing of requests from the driver to send traces to the trace channel specified in an earlier call to PfmMarshaller::SetTrace.

PfmMarshaller::Vprintf

void PfmMarshaller::Vprintf (
   const wchar_t* format ,
   va_list        args )

This function can be used by formatters during identify and mount initialization, to send status data to the mount status dialog through the handle specified in an earlier call to PfmMarshaller::SetStatus.

This function can be used during processing of requests from the driver to send traces to the trace channel specified in an earlier call to PfmMarshaller::SetTrace.

PfmMarshaller::Printf

void PfmMarshaller::Printf (
   const wchar_t* format ,
   ... )

This function can be used by formatters during identify and mount initialization, to send status data to the mount status dialog through the handle specified in an earlier call to PfmMarshaller::SetStatus.

This function can be used during processing of requests from the driver to send traces to the trace channel specified in an earlier call to PfmMarshaller::SetTrace.

PfmMarshaller::Line

void PfmMarshaller::Line (
   const wchar_t* data ,
   bool           newLine )

This function can be used by formatters during identify and mount initialization, to send status data to the mount status dialog through the handle specified in an earlier call to PfmMarshaller::SetStatus.

This function can be used during processing of requests from the driver to send traces to the trace channel specified in an earlier call to PfmMarshaller::SetTrace.

PfmMarshallerListResult interface

The PfmMarshallerListResult interface is defined in pfmmarshaller.h .

This interface is implemented in the PFM API DLL. It is used by formatters to return the variable number of results for the PfmReadOnlyFormatterOps::List and PfmFormatterOps::List functions.

PfmMarshallerListResult::Add

bool /*added*/ PfmMarshallerListResult::Add (
   const PfmAttribs* attribs ,
   const wchar_t*    endName ,
   bool*             needMore )

While processing a call to the PfmReadOnlyFormatterOps::List or PfmFormatterOps::List functions, a formatter will make repeated calls to this function to add files to the results to be returned to the driver.

Formatters should continue to call this function until either the needMore variable is set to false by the add function, or there are no more files to add to the results.

In the event the function returns false, the file was not added to the result. The formatter must add this same file on the next call to the list function with the same openId and listId.

PfmMarshallerListResult::Add8

bool /*added*/ PfmMarshallerListResult::Add8 (
   const PfmAttribs* attribs ,
   const char*       endName ,
   bool*             needMore )

This function is equivalent to PfmMarshallerListResult::Add except that it takes a UTF8 file name.

PfmMarshallerListResult::NoMore

void PfmMarshallerListResult::NoMore ( )

While processing a call to the PfmReadOnlyFormatterOps::List or PfmFormatterOps::List functions, a formatter should call this function when all files have been added to the result. This lets the driver know there is no need to issue an additional list request.

PfmReadOnlyFormatterOps

The PfmReadOnlyFormatterOps interface is defined in pfmmarshaller.h .

This interface is implemented by read-only formatters, to process file system requests from the driver that are marshalled through PfmMarshaller.

PfmReadOnlyFormatterOps::ReleaseName

void PfmReadOnlyFormatterOps::ReleaseName (
   wchar_t* name )

The marshaller calls this function to allow the formatter to free memory that was used to return case corrected file name information from the PfmReadOnlyFormatterOps::Open function, or to return the media label from the PfmReadOnlyFormatterOps::MediaInfo function.

PfmReadOnlyFormatterOps::Open

int /*pfmError*/ PfmReadOnlyFormatterOps::Open (
   const PfmNamePart* nameParts ,
   size_t             namePartCount ,
   int8_t             accessLevel ,
   int64_t            newOpenId ,
   PfmOpenAttribs*    openAttribs ,
   wchar_t**          endName )

This function is called by the marshaller to process file open requests from the driver. Correct use of newOpenId parameter, the openAttribs->openId result, and the openAttribs->openSequence result, are critical to proper functioning of the atomicity guarantees provided by the driver.

If the formatter returns no error (0) then it must return the information about the newly opened file/folder through the openAttribs parameter, and optionally through the endName parameter. All of the openAttribs->attribs fields must be filled. The four time fields in openAttribs->attribs should be filled with valid times, or with constant pfmTimeInvalid.

The name of the file being opened is indicated by the nameParts and namePartCount parameters.

If the formatter determines that the indicated file has not already been opened then it must associate the driver specified newOpenId with the file, and return this same value in openAttribs->openId . The openAttribs->openSequence value must be initialized to a non zero positive value, and the value must be associated with the open file for use during subsequent close processing.

If the formatter determines that the indicated file is already open then it must return in openAttribs->openId the openId that is already associated with the open file. The openAttribs->openSequence value must be initialized to a positive value that is greater than the openSequence returned by any previous open of the same file. The new openSequence value must be associated with the open file for use during subsequent close processing.

If the formatter is opening a file with different spelling for the last name component than was specified by the driver then it must return the correct spelling through the endName parameter. If the endName is returned then the marshaller will call the PfmReadOnlyFormatterOps::ReleaseName function to allow the formatter to free any related memory.

The openAttribs->accessLevel field should be filled with the highest access level currently available for the file. For most read-only formatters this field can always be initialized with pfmAccessReadData. For redirectors, the accessLevel parameter can be used to avoid opening source files with higher access levels than are needed for the current request.

PfmReadOnlyFormatterOps::Close

int /*pfmError*/ PfmReadOnlyFormatterOps::Close (
   int64_t openId ,
   int64_t openSequence )

There is not a one to one correspondence between open and close requests. The driver generates a close request when it believes what may be the last reference to an open file has been released. The formatter decides if the last reference is actually gone by comparing the openSequence parameter against the openSequence associated with the file on the most recent successful open.

If the openSequence parameter is less than the openSequence of the file then the file is still open. The formatter should perform no action.

If the openSequence parameter is greater than or equal to the openSequence of the file then the driver no longer has any references to the file. The formatter can free resources associated with the open file.

After all references to an file are gone, the formatter has the choice of forgetting the openId that was associated with the file, or saving the openId for use if the file is re-opened. Saving the openId allows the driver to associate cache data with the file.

Errors from this function are ignored by the driver.

PfmReadOnlyFormatterOps::List

int /*pfmError*/ PfmReadOnlyFormatterOps::List (
   int64_t                  openId ,
   int64_t                  listId ,
   PfmMarshallerListResult* listResult )

This function is called by the marshaller to generate list results for the contents of folders.

The behavior of this function for non-folder files is undefined. Formatters are free to handle this in whatever way is convenient.

The formatter must create and maintain state information for each unique listId parameter that is used to list contents of a folder. The formatter should create this state when it sees a new listId. The formatter frees this state when it receives a call to PfmReadOnlyFormatterOps::ListEnd with a matching openId/listId, or when it frees resources associated with an open folder wile processing a call to PfmReadOnlyFormatterOps::Close for the same openId.

Folder contents are added to the results by repeatedly calling the PfmMarshallerListResult::Add or PfmMarshallerListResult::Add8 functions of the listResult parameter, followed by a final call to the PfmMarshallerListResult::NoMore.

PfmReadOnlyFormatterOps::ListEnd

int /*pfmError*/ PfmReadOnlyFormatterOps::ListEnd (
   int64_t openId ,
   int64_t listId )

See PfmReadOnlyFormatterOps::List.

PfmReadOnlyFormatterOps::Read

int /*pfmError*/ PfmReadOnlyFormatterOps::Read (
   int64_t  openId ,
   uint64_t fileOffset ,
   void*    data ,
   size_t   requestedSize ,
   size_t*  outActualSize )

The behavior of this function for folders is undefined. Formatters are free to handle this in whatever way is desired.

PfmReadOnlyFormatterOps::Capacity

int /*pfmError*/ PfmReadOnlyFormatterOps::Capacity (
   uint64_t* totalCapacity )

PfmReadOnlyFormatterOps::FlushMedia

int /*pfmError*/ PfmReadOnlyFormatterOps::FlushMedia (
   bool* mediaClean)

The driver will generate a flush media request shortly after a preiod of inactivity (~1 second). The formatter can use this request to perform whatever updates are applicable based on the file system characteristics.

If an error is returned from this function, a cache write failure notification will be displayed to the user.

The driver will continue to generate media flush requests every few seconds unless the formatter set the mediaClean parameter to true.

PfmReadOnlyFormatterOps::Control

int /*pfmError*/ PfmReadOnlyFormatterOps::Control (
   int64_t     openId ,
   int8_t      accessLevel ,
   int         controlCode ,
   const void* input ,
   size_t      inputSize ,
   void*       output ,
   size_t      maxOutputSize ,
   size_t*     outputSize )

PfmReadOnlyFormatterOps::MediaInfo

int /*pfmError*/ PfmReadOnlyFormatterOps::MediaInfo (
   int64_t       openId ,
   PfmMediaInfo* mediaInfo ,
   wchar_t**     mediaLabel )

The driver sends a media info request to retrieve media identification information such as media label and media id. Formatters are free to fail this request, or to return only partial information. The returned information can be accessed by client applications using the Win32 GetVolumeInformation() system call.

The supplied open ID may be zero, or may be the id of an open file or folder. The formatter is free to ignore the open id or to return different information based on what file or folder the open id refers to.

If a media label is returned then the marshaller will call the PfmReadOnlyFormatterOps::ReleaseName function to allow the formatter to free any related memory.

PfmFormatterOps

The PfmFormatterOps interface is defined in pfmmarshaller.h .

This interface is implemented by read-write formatters, to process file system requests from the driver that are marshalled through PfmMarshaller .

PfmFormatterOps::ReleaseName

void PfmFormatterOps::ReleaseName (
   wchar_t* name )

The marshaller calls this function to allow the formatter to free memory that was used to return case corrected file name information from the PfmFormatterOps::Open and PfmFormatterOps::Move functions, or to return the media label from the PfmFormatterOps::MediaInfo function.

PfmFormatterOps::Open

int /*pfmError*/ PfmFormatterOps::Open (
   const           PfmNamePart* nameParts ,
   size_t          namePartCount ,
   int8_t          createFileType ,
   uint8_t         createFileFlags ,
   int64_t         writeTime ,
   int64_t         newCreateOpenId ,
   int8_t          existingAccessLevel ,
   int64_t         newExistingOpenId ,
   bool*           existed ,
   PfmOpenAttribs* openAttribs ,
   int64_t*        parentFileId ,
   wchar_t**       endName )

This function is called by the marshaller to process file open and create requests from the driver. Correct use of newCreateOpenId parameter, the newExistingOpenId parameter, the existed result, the openAttribs->openId result, and the openAttribs->openSequence result, are critical to proper functioning of the atomicity guarantees provided by the driver.

If the formatter returns no error (0) then it must return the information about the newly opened/created file through the openAttribs parameter, the existed parameter, and optionally through the parentFileId parameter the endName parameter. All of the openAttribs->attribs fields must be filled. The four time fields in openAttribs->attribs should be filled with valid times, or with constant pfmTimeInvalid.

The name of the file being opened is indicated by the nameParts and namePartCount parameters.

If the formatter determines that the indicated file exists but has not already been opened then it must associate the driver specified newExistingOpenId with the file, and return this same value in openAttribs->openId. The openAttribs->openSequence value must be initialized to a non zero positive value, and the value must be associated with the open file for use during subsequent close processing. The variable referenced by the existed parameter must be set to true.

If the formatter determines that the indicated file is already open then it must return in openAttribs->openId the same openId that is already associated with the open file. The openAttribs->openSequence value must be initialized to a positive value that is greater than the openSequence returned by any previous open of the same file. The new openSequence value must be associated with the open file for use during subsequent close processing. The variable referenced by the existed parameter must be set to true.

If the parent folder of the indicated file does not exist then the formatter should return pfmErrorParentNotFound.

If the indicated file does not exist and the newCreateOpenId parameter is zero then the formatter should return pfmErrorNotFound.

If the indicated file does not exist and the newCreateOpenId parameter is non-zero then the formatter should create the file. The createFileType, createFileFlags, and writeTime parameters should be used to to initialize the new file. The formatter must associate the driver specified newCreateOpenId with the file, and return this same value in openAttribs->openId. The openAttribs->openSequence value must be initialized to a non zero positive value, and the value must be associated with the open file for use during subsequent close processing. The variable referenced by the existed parameter must be set to false.

If the formatter is opening a file with different spelling for the last name component than was specified by the driver then it must return the correct spelling through the endName parameter. If the endName is returned then the marshaller will call the PfmFormatterOps::ReleaseName function to allow the formatter to free any related memory.

The openAttribs->accessLevel field should be filled with the highest access level currently available for the file. For most formatters this field can always be initialized with pfmAccessWriteData. For redirectors, when opening existing files, the existingAccessLevel parameters can be used to avoid opening files with higher access levels than are needed for the current request.

PfmFormatterOps::Replace

int /*pfmError*/ PfmFormatterOps::Replace (
   int64_t            targetOpenId ,
   int64_t            targetParentFileId ,
   const PfmNamePart* targetEndName ,
   Uuint8_t           createFileFlags ,
   int64_t            writeTime ,
   int64_t            newCreateOpenId ,
   PfmOpenAttribs*    openAttribs )

The marshaller calls this function when processing a replace request from the driver. This request is made when an existing file is being replaced by a new file with the same name. The replaced file name becomes deleted.

The file being replaced has already been opened and is identified with the targetOpenId parameter.

If the target file type is a folder and the formatter does not support replace for folders then the formatter should return pfmErrorInvalid. Formatters must support replace for files.

If the target file type is a folder and the folder is not empty then the formatter should return pfmErrorNotEmpty.

Formatters that support multiple names for a single file (hard links) should use the targetParentFileId and targetEndName parameters to identify which name is being replaced.

The createFileFlags and writeTime parameters should be used to initialize the new file. The file type is always the same as the target.

The newCreateOpenId and openAttribs parameters should be treated the same as is described for the PfmFormatterOps::Open function when a new file is created.

PfmFormatterOps::Move

int /*pfmError*/ PfmFormatterOps::Move (
   int64_t            sourceOpenId ,
   int64_t            sourceParentFileId ,
   const PfmNamePart* sourceEndName ,
   const PfmNamePart* targetNameParts ,
   size_t             targetNamePartCount ,
   bool               deleteSource ,
   int64_t            writeTime ,
   int64_t            newExistingOpenId ,
   bool*              existed ,
   PfmOpenAttribs*    openAttribs ,
   int64_t*           parentFileId ,
   wchar_t**          endName )

This function is called by the marshaller to process move requests from the driver. This request is made when a file is being renamed. Proper handling of the newExistingOpenId parameter, exists result, openAttribs->openId result, and openAttribs->openSequence result, are critical to proper functioning of the atomicity guarantees provided by the driver.

The sourceOpenId parameter specifies the previously opened file that is being renamed. The sourceParentFileId and sourceEndName parameters can be used by formatters that support hard links to determine which name for the file is being renamed.

The targetNameParts and targetNamePartCount parameters specified the new file name (target) for the file.

If the parent folder of the target file name does not exist then the formatter should return pfmErrorParentNotFound.

If a file already exists with the target file name, then the existing target file should be opened. In this case the source file is left unmodified and no rename or move operation is performed. The variable pointed to by the existed parameter must be set to true. The newExistingOpenId, openAttribs, parentFileId, and endName parameters should be used in the same manner as is described for the PfmFormatterOps::Open function when an existing file is opened.

If the source file name has been deleted then the move request is the equivalent of an undelete. Formatters must support this for files, but can return pfmErrorInvalid for folders.

If the deleteSource parameter is false, and the formatter does not determine that the source file name is deleted, then the move request is creating an additional name for the file (hard link). Formatters that do not support hard links should fail the request with pfmErrorInvalid.

If the formatter is able to create the new name for the file then updated information about the source file is returned through the openAttribs and parentFileId parameters, openAttribs->openId must contain sourceOpenId, openAttribs->openSequence must contain a value equal to or higher than the largest openSequence value returned in any previous open for the file. The variable pointed to by the existed parameter must be set to false.

PfmFormatterOps::MoveReplace

int /*pfmError*/ PfmFormatterOps::MoveReplace (
   int64_t            sourceOpenId ,
   int64_t            sourceParentFileId ,
   const PfmNamePart* sourceEndName ,
   int64_t            targetOpenId ,
   int64_t            targetParentFileId ,
   const PfmNamePart* targetEndName ,
   bool               deleteSource ,
   int64_t            writeTime )

The marshaller calls this function when processing a move-replace request from the driver. This request is made when a an opened source file is being renamed to the same name as an opened target file. The replaced target file name becomes deleted.

Some processing for this function is similar to PfmFormatterOps::Replace, except that the source file is guaranteed to exist since it is already open.

Some processing for this function is similar to PfmFormatterOps::Move, specifically with handling of deleted source files and the deleteSource parameter.

PfmFormatterOps::Delete

int /*pfmError*/ PfmFormatterOps::Delete (
   int64_t            openId ,
   int64_t            parentFileId ,
   const PfmNamePart* endName ,
   int64_t            writeTime )

The marshaller calls this function when processing a delete request from the driver. This request is made when a file name is being deleted.

Formatters that support multiple file names for a single file (hard links) can use the parentFileId and endName parameters to identify which file name is being deleted.

PfmFormatterOps::Close

int /*pfmError*/ PfmFormatterOps::Close (
   int64_t openId ,
   int64_t openSequence )

See PfmReadOnlyFormatterOps::Close.

PfmFormatterOps::FlushFile

int /*pfmError*/ PfmFormatterOps::FlushFile (
   int64_t openId ,
   uint8_t fileFlags ,
   int64_t createTime ,
   int64_t accessTime ,
   int64_t writeTime ,
   int64_t changeTime )

Updated attributes for modified files are supplied to the formatter in the flush file request.

If the fileFlags parameter is the value pfmFileFlagsInvalid then the formatter should skip updating the file flags.

If any of the time parameters are the value pfmTimeInvald then the formatter should skip updating the associated time value.

Errors from this function are ignored by the driver. If a formatter wants the user to be notified of a flush related error, it must return an error from a subsequent call to PfmFormatterOps::FlushMedia.

PfmFormatterOps::List

int /*pfmError*/ PfmFormatterOps::List (
   int64_t                  openId ,
   int64_t                  listId ,
   PfmMarshallerListResult* listResult )

See PfmReadOnlyFormatterOps::List.

PfmFormatterOps::ListEnd

int /*pfmError*/ PfmFormatterOps::ListEnd (
   int64_t openId ,
   int64_t listId )

See PfmReadOnlyFormatterOps::ListEnd.

PfmFormatterOps::Read

int /*pfmError*/ PfmFormatterOps::Read (
   int64_t  openId ,
   uint64_t fileOffset ,
   void*    data ,
   size_t   requestedSize ,
   size_t*  outActualSize )

The behavior of this function for folders is undefined. Formatters are free to handle this in whatever way is convenient.

PfmFormatterOps::Write

int /*pfmError*/ PfmFormatterOps::Write (
   int64_t     openId ,
   uint64_t    fileOffset ,
   const void* data ,
   size_t      requestedSize ,
   size_t*     outActualSize )

The behavior of this function for folders is undefined. Formatters are free to handle this in whatever way is convenient.

The behavior of zero length writes is undefined. Formatters are free to handle this in whatever way is convenient.

PfmFormatterOps::SetSize

int /*pfmError*/ PfmFormatterOps::SetSize (
   int64_t  openId ,
   uint64_t fileSize )

PfmFormatterOps::Capacity

int /*pfmError*/ PfmFormatterOps::Capacity (
   uint64_t* totalCapacity ,
   uint64_t* availableCapacity )

PfmFormatterOps::FlushMedia

int /*pfmError*/ PfmFormatterOps::FlushMedia (
   bool* mediaClean )

See PfmReadOnlyFormatterOps::FlushMedia .

PfmFormatterOps::Control

int /*pfmError*/ PfmFormatterOps::Control (
   int64_t     openId ,
   int8_t      accessLevel ,
   int         controlCode ,
   const void* input ,
   size_t      inputSize ,
   void*       output ,
   size_t      maxOutputSize ,
   size_t*     outputSize )

PfmFormatterOps::MediaInfo

int /*pfmError*/ PfmFormatterOps::MediaInfo (
   int64_t       openId ,
   PfmMediaInfo* mediaInfo ,
   wchar_t**     mediaLabel )

See PfmReadOnlyFormatterOps::MediaInfo.

PfmFormatterDispatch

The PfmFormatterDispatch interface is defined in pfmmarshaller.h .

This interface is implemented by multi-threaded formatters to process file system requests from the driver that are marshalled through PfmMarshaller.

Developers who wish to implement this interface should contact Pismo Technic Inc. support for additional information and sample code.

Data Types

mountFlags

unmountFlags

statusFlags

pfmError

fileType

fileFlags

time

All file times used in the PFM Protocol and with the PfmReadOnlyFormatterOps and PfmFormatterOps interfaces are in the Windows FILETIME format, 64 bit count of 100 nano second units since Jan 1 1601 UTC.

accessLevel

volumeFlags

PfmAttribs

struct PfmAttribs
{
   int8_t   fileType ;
   uint8_t  fileFlags ;
   int64_t  fileId ;
   uint64_t fileSize ;
   int64_t  createTime ;
   int64_t  accessTime ;
   int64_t  writeTime ;
   int64_t  changeTime ;
}

PfmOpenAttribs

struct PfmOpenAttribs
{
   int64_t    openId ;
   int64_t    openSequence ;
   int8_t     accessLevel ;
   PfmAttribs attribs ;
}

PfmNamePart

struct PfmNamePart
{
   const wchar_t* name ;
   size_t         len ;
   const char*    name8 ;
   size_t         len8 ;
}

The name8 field points to a UTF8 string, not to an ANSI or OEM codepage string.

The name and name8 fields point to the same string in two different encodings. Formatters should use the name that is most convenient. Both names are zero terminated with the length available in the respective len field.

PfmMediaInfo

struct PfmMediaInfo
{
   GUID     mediaUuid ;
   uint64_t mediaId64 ;
   uint32_t mediaId32 ;
   uint8_t  mediaFlags ;
   int64_t  createTime ;
}

PfmMountCreateParams

struct PfmMountCreateParams
{
   size_t         paramsSize ;
   const wchar_t* mountFileName ;
   int            mountFlags ;
   wchar_t        driveLetter ;
   HANDLE         toFormatterWrite ;
   HANDLE         fromFormatterRead ;
}

PfmMarshallerServeParams

struct PfmMarshallerServeParams
{
   size_t                paramsSize ;
   PfmFormatterDispatch* dispatch ;
   int                   volumeFlags ;
   const char*           formatterName;
   HANDLE                toFormatterRead ;
   HANDLE                fromFormatterWrite ;
}