Pismo File Mount Development Kit build 165

Pismo Technic Inc., Copyright 2005-2012 Joe Lowe
2012.05.16

Preface

This document is targeted towards software developers wishing to integrate Pismo File Mount into their applications.

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 portable operating system extension that enables the development of file systems and file system extensions using common user mode application development tools.

Applications can utilize Pismo File Mount to expose data through the file system as mounted volumes. Volumes are exposed through drive letters, UNC paths, through a mount point overlaying an exsting file on a system volume, or through a mount point overlaying an empty folder on a system volume.

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 socket 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

Applications interact with and control PFM using the PfmApi interface and the associated interfaces PfmMount, PfmFileMount , and PfmMarshaller. These interfaces are defined in pfmapi.h and pfmmarshaller.h.

Command Line Interface

Pismo File Mount includes a command line interface. This is implemented as the "pfm" command, usable from a command or terminal prompt. Using pfm it is possible to:

The command line interface includes basic help information. 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. Operating systems typically contain a notification mechanism that notifies the user when delayed writes fail with the built-in file systems. PFM includes a dedicated delayed write failure notification mechanism, the alerter.

The alerter is implemented as an executable called pfmstat. Pfmstat is started anytime a PFM volume is mounted, and automatically exits shortly after the last PFM volume is unmounted. On Windows pfmstat adds a notification icon to the system tray (Windows only).

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 by software developers.

Explorer shell extension

PFMAP includes an Explorer shell extension. 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 file systems. The kit also can be used to integrate existing PFM file systems into 3rd party applications.

Programming Languages

The development kit supports development in C, C++, and C#.

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. C# developers should refer to the interfaces in the provided C# API shim clrapi, and to the various 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

The C, C++, and C# applications developed in Microsoft Developer Studio can easily utilize or implement the PFM API and other interfaces.

Other Tools

For Mac and Linux development, GCC is recommended, but any other compilers capable of building native applications should also work.

For Windows development, developers are encouraged to use the C/C++ compiler included with the free Windows SDK (2007 and later) or DevStudio Express editions, in preference to GCC based compilers.

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, PfmFileMount, PfmFileMountUi, 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.

pfmmarshaller.h

Pfmmarshaller.h contains the definition of the PfmMarshaller interface implemented in the PFM API DLL for use by file systems.

Samples

Hello World file system application in C, C++, and C#

hellofs.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.

Windows:

>cl -I../include hellofs.c advapi32.lib
>echo any data > anyfile
>start hellofs anyfile
>type anyfile\readme.txt

Mac/Linux

>gcc -I../include hellofs.c -o hellofs
>echo any data > anyfile
>./hellofs anyfile

hellofs.cpp contains source code to the C++ equivalent of the above sample.

>cl -I../include hellofs.cpp advapi32.lib
>echo any data > anyfile
>start hellofs anyfile
>type anyfile\readme.txt
hellofs.cs contains source code to the C# equivalent of the above sample. This sample can be compiled with the included project file using Visual Studio 2010 or Visual C# 2010 Express Edition. This sample requires that you first compile the clrapi sample.

Temp file system application 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.

tempfs.cs and contain source code to an equivalent temporary file system written in C#.

Mounter application in C++ and C#

The mounter samples will mount files via the registered PFMAP formatters. mounter.cs in C#, and mounter.cpp in C++. These samples can be compiled with the included project files using Visual Studio 2010 or from the command line using the Platform SDK on Windows or GCC on Mac/Linux.

C# PFM API shim in C++/CLI

Applications written in C# (or other Microsoft CLR languages) cannot directly use the PFMAPI. The sample API shim pfmclrapi.cxx can be used from C# applications. This shim can be compiled and freely bundled with C# applications, and can be customized as necessary for each application.

The sample API shim can be compiled with the included project files using Visual Studio 2010 or Visual C# Express Edition.

Application Development

Getting Started

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

Applications written in C# can integrate with PFM using a shim such as the sample shim provided with the development kit.

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

Concepts

Errors

The PFM API interfaces return system error codes such as ERROR_ACCESS_DENIED on Windows or EACCESS on Mac and Linux.

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 until after the system is restarted.

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.

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.

PfmApi::Alerter

int/*error*/ PfmApi::Alerter (
   const wchar_t* reserved1 ,
   PfmAlerter** alerter )

This function starts an instance of the pfmstat user mode helper application and returns a alerter object that holds a reference to the pfmstat application to prevent it from exiting.

PfmFileMount interface

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

This interface allows applications to mount a container file system via a PFM Audit Package formatter. This interface is returned from the PfmApi::FileMountCreate function.

PfmFileMount::Release

void PfmFileMount::Release ( )

Free the interface instance and any associated resources. If the file mount has completed and was not detached, an unmount will be performed on the resulting mount.

PfmFileMount::Cancel

void PfmFileMount::Cancel ( )

Asynchronously cancel the ongoing file mount operation and close any related user interface dialogs.

PfmFileMount::Start

int /*error*/ PfmFileMount::Start (
   const PfmFileMountCreateParams* params )

Start a file mount operation. This will result in user interface dialogs being displayed as necessary.

PfmFileMount::Send

void PfmFileMount::Send (
   const wchar_t* data,
   int/*bool*/    newLine);

This function can be used to send data back to the formatter during authentication. This may be needed for user interface that is mounting formatters with authentication that require more than simple password queries.

PfmFileMount::Status

void PfmFileMount::Status (
   const wchar_t* data,
   int/*bool*/    newLine )

This function is used to print mount status messages to the file mount user interface. It generally results in a matching call to PfmFileMountUi::Status . Any status prefixed with the string "ERROR: " may be used as the message in the final error dialog that is displayed if the mount fails.

PfmFileMount::WaitReady

int /*error*/ PfmFileMount::WaitReady ( )

This function will block until the mount operation completes successfully or fails due to an error or is cancelled.

PfmFileMount::GetMount

PfmMount* PfmFileMount::GetMount ( )

This function returns an unreferenced ptr to the PfmMount object associated with a successful file mount operation. The caller is responsible to add a reference to the object if it will be using it beyond the lifetime of the PfmFileMount object. If called before the file mount is ready, or on a file mount that has failed, it will return null.

PfmFileMount::Detach

void PfmFileMount::Detach ( )

This function detaches a successful out-of-process file mount from the current process. This allows the mount to survive after the file mount object is releases and after the current process exits.

If this function is called on an in-process file mount then it will block until an unmount occurs.

PfmFileMountUi

The PfmFileMountUi interface is defined in pfmapi.h .

This interface is implemented by applications that are performing file mount operations, to allow the display of a custom user interface.

PfmFileMountUi::Start

void PfmFileMountUi::Start ( )

PfmFileMountUi::Complete

void PfmFileMountUi::Complete (
   const wchar_t* errorMessage )

PfmFileMountUi::Status

void PfmFileMountUi::Status (
   const wchar_t* data ,
   int/*bool*/    newLine )

PfmFileMountUi::QueryPassword

const wchar_t* PfmFileMountUi::QueryPassword (
   int count )

PfmFileMountUi::ClearPassword

void PfmFileMountUi::ClearPassword ( )

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, PfmApi::MountOpenId, and PfmFileMount::GetMount 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 .

PfmAlerter interface

The PfmAlerter interface is defined in pfmapi.h .

This interface is returned from the PfmApi::Alerter function. It holds an instance of a user mode helper application that will display critical file system user messages, and that performs verious other utility tasks for the file system.

PfmAlerter::Release

void PfmAlerter::Release(void)

Free the interface instance and any associated resources.

File System 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

When debugging applications that are exposing PFM file system volumes, it is important that the debugger never access the PFM volume. If the debugger does access the PFM volume then it will deadlock. If a deadlock occurs, you can perform an unmount of the volume from another command prompt to get things moving again, but you will probably need to restart your debugging session. You also can kill the process to resolve a deadlock.

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 on Windows 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.

On Mac and Linux you can view traces using the tracecmd command line tools.

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.

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::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;
   PfmMarshallerServeParams_Init(&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 ,
   int/*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.

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

fileMountFlags

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 ;
}

PfmFileMountCreateParams

struct PfmFileMountCreateParams
{
   size_t         paramsSize ;
   const wchar_t* mountFileName ;
   int            mountFlags ;
   int            fileMountFlags ;
   wchar_t        driveLetter ;
   const wchar_t* password;
   PfmFileMountUi* ui;
}

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 ;
}