--- a/Symbian3/PDK/Source/GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita Tue Mar 30 11:42:04 2010 +0100
+++ b/Symbian3/PDK/Source/GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita Tue Mar 30 11:56:28 2010 +0100
@@ -1,270 +1,270 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
-<!-- This component and the accompanying materials are made available under the terms of the License
-"Eclipse Public License v1.0" which accompanies this distribution,
-and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
-<!-- Initial Contributors:
- Nokia Corporation - initial contribution.
-Contributors:
--->
-<!DOCTYPE concept
- PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
-<concept id="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81" xml:lang="en"><title>File
-Server Extensions Tutorial</title><prolog><metadata><keywords/></metadata></prolog><conbody>
-<p>Describes how to develop and use a file server extension. </p>
-<p>See <xref href="GUID-983F0ABD-470C-51C3-B6AE-1B1AA55AB4A2.dita">File Server
-Extensions</xref> for more information about the file server extension architecture. </p>
-<section id="GUID-4FEA7E17-8ACE-58E2-B90A-FB2F9BB33766"><title>Developing
-an extension</title><p>This section describes how to use the APIs defined
-by the file server to implement a new extension. It contains the following
-sections: <ul>
-<li><p><xref href="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita#GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81/GUID-4CFC2D17-60B9-512F-8896-54AA0F8221CE">Project
-file and build</xref> describes the requirements for an extension's project
-file. </p></li>
-<li><p><xref href="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita#GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81/GUID-7744238A-BFE2-53BD-9B57-D38ED08811EB">Implementing
-the factory class</xref> describes the factory class that each extension DLL
-must implement to create proxy driver objects. </p></li>
-<li><p><xref href="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita#GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81/GUID-6B7F5F60-D50F-5BB0-AB3D-8D065FE5865A">Implementing
-the proxy drive extension class</xref> describes the proxy drive class that
-each extension DLL must implement to provide its extension functionality. </p></li>
-</ul></p><p>The examples quoted are taken from the <codeph>t_logext</codeph> test
-extension, which is available in the Symbian platform source code at <filepath>os/kernelhwsrv/kerneltest/f32test/ext/t_logext.cpp</filepath>.
-That test code simply logs when the extension functions are called. </p> <p id="GUID-4CFC2D17-60B9-512F-8896-54AA0F8221CE"><b>Project file and build</b> </p><p>A
-file server extension is implemented as a polymorphic DLL. Its project file
-must be written as follows: </p><ul>
-<li id="GUID-8D625BD6-E5D5-53B1-B9D2-634C59DC213F"><p> <codeph>TARGETTYPE</codeph> should
-be set to <codeph>fsy</codeph>. This means that the project does not require
-a <filepath>.def</filepath> file to specify its frozen exports: the build
-tools will assume the correct frozen exports for the type. </p> </li>
-<li id="GUID-66234A27-AB5D-5534-9267-25B65F4821D9"><p>The DLL name is conventionally
-given the extension <filepath>.fxt</filepath>. </p> </li>
-<li id="GUID-D0718103-1D7B-5926-822E-1CB4B24C68B8"><p>The second UID should
-be <codeph>0x100039df</codeph>. </p> </li>
-<li id="GUID-910E63DC-9A65-5124-950B-A7F2BF2929CC"><p>The DLL is loaded by
-the file server, and therefore must have the same platform security capabilities
-as that process: <codeph>TCB ProtServ DiskAdmin AllFiles PowerMgmt CommDD</codeph>. </p></li>
-</ul><p>The following shows an example project file: </p><codeblock id="GUID-0DAA1B8E-2A55-5942-A166-B09666258967" xml:space="preserve">TARGET t_logext.fxt
-TARGETTYPE fsy
-
-SOURCEPATH ../ext
-SOURCE t_logext.cpp
-
-SYSTEMINCLUDE /epoc32/include
-
-LIBRARY euser.lib efile.lib
-
-UID 0x100039df 0x10000CEE
-VENDORID 0x70000001
-
-#include "../../f32/group/f32caps.mmh" // Include capabilities of File Server process</codeblock> <p id="GUID-7744238A-BFE2-53BD-9B57-D38ED08811EB"><b>Implementing the factory
-class</b> </p><p>Each extension DLL must implement a factory class that is
-responsible for creating proxy driver objects. This is done by implementing
-a class derived from <xref href="GUID-57D0E9E3-D1B9-36A1-9038-96336F58EA08.dita"><apiname>CProxyDriveFactory</apiname></xref>. A pointer to an
-object of this class must be returned by the first function exported from
-the extension DLL. </p><codeblock id="GUID-ABBFEF73-38FE-5689-B89A-FA8207DD2F81" xml:space="preserve">class CLoggerProxyDriveFactory : public CProxyDriveFactory
- {
-public:
- CLoggerProxyDriveFactory();
- virtual TInt Install();
- virtual CProxyDrive* NewProxyDriveL(CProxyDrive* aProxy,CMountCB* aMount);
- };
-
-...
-
-// Create a new factory
-EXPORT_C CProxyDriveFactory* CreateFileSystem()
- {
- return(new CLoggerProxyDriveFactory());
- }
-</codeblock> <p><b>Factory
-initialisation </b> </p> <p> <codeph>CProxyDriveFactory</codeph> defines a
-pure virtual function <codeph>Install()</codeph> that is called once by the
-file server before any other factory object function. You must implement this
-to do any required setup. <codeph>CProxyDriveFactory</codeph> is derived from <xref href="GUID-578CD638-601C-353D-B1C4-557C72A00DF1.dita"><apiname>CFsObject</apiname></xref>,
-which means that the file server maintains a reference count of its use, and
-allows clients to refer to the object through a name (a string). The <codeph>Install()</codeph> function's
-implementation should set the extension's name: </p><codeblock id="GUID-ACF692BF-8C52-5430-80C6-9702EFD0FB7D" xml:space="preserve">TInt CLoggerProxyDriveFactory::Install()
- {
- _LIT(KLoggerName,"Logger");
- return(SetName(&KLoggerName));
- }
-</codeblock> <p>Clients can get the name of an extension using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-F00D3D91-212A-3192-8A2E-989912AAA9DD"><apiname>RFs::ExtensionName()</apiname></xref>,
-and then use it to specify the extension in functions such as <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-5003658C-C5A0-39F0-A518-65B20CD41567"><apiname>RFs::MountExtension()</apiname></xref>. </p><p><codeph>CProxyDriveFactory</codeph> also defines a virtual function <codeph>Remove()</codeph>, which is called
-just before when the factory object is destroyed. You can override this to
-do any required cleanup. </p> <p><b>Proxy drive factory </b> </p><p><codeph>CProxyDriveFactory</codeph> defines
-a pure virtual function <codeph>NewProxyDriveL()</codeph> that is called by
-the file server to obtain a new proxy drive extension object. You must implement
-this to create the proxy drive extension. </p><codeblock id="GUID-77B7A963-83D7-5D80-9374-53D296E2248B" xml:space="preserve">CProxyDrive* CLoggerProxyDriveFactory::NewProxyDriveL(CProxyDrive* aProxy,CMountCB* aMount)
- {
- return(CLoggerExtProxyDrive::NewL(aProxy,aMount));
- }</codeblock><p>The <codeph>aProxy</codeph> argument represents the last
-extension to be mounted. The new extension will be mounted on top of it. <codeph>aProxy</codeph> could
-be an object from another extension library, or a file server <codeph>CLocalProxyDrive</codeph> object
-that calls the media sub-system. </p><p><codeph>aMount</codeph> represents
-the mounted drive to which the extension is being added. </p><p><codeph>aProxy</codeph> and <codeph>aMount</codeph> are
-required by the proxy drive extension base class (<codeph>CBaseExtProxyDrive</codeph>)
-constructor: </p><codeblock id="GUID-EF379FC2-F2A5-5F47-8BA6-2C286DF746FA" xml:space="preserve">CLoggerExtProxyDrive::CLoggerExtProxyDrive(CProxyDrive* aProxyDrive, CMountCB* aMount)
- :CBaseExtProxyDrive(aProxyDrive,aMount)
- {
- ...
- }</codeblock><p>The arguments are used to initialise private data in <codeph>CBaseExtProxyDrive</codeph>. </p> <p><b>DLL's first exported function</b></p><p>The DLL's first exported function
-should create a new instance of the factory class: </p><codeblock id="GUID-9173B82F-90BA-5FBD-9EC9-FA7EB08E3794" xml:space="preserve">EXPORT_C CProxyDriveFactory* CreateFileSystem()
-//
-// Create a new file system
-//
- {
- return(new CLoggerProxyDriveFactory());
- }</codeblock> <p id="GUID-6B7F5F60-D50F-5BB0-AB3D-8D065FE5865A"><b>Implementing the proxy drive
-extension class</b> </p><p>An extension DLL must contain a proxy drive class
-that implements the extension. This is done by implementing a class derived
-from <xref href="GUID-FAFF712B-2295-3907-B839-D77F052160DA.dita"><apiname>CBaseExtProxyDrive</apiname></xref>. <codeph>CBaseExtProxyDrive</codeph> defines
-virtual functions that are called by the file system to handle requests such
-as reading and writing data from the drive. The functions have default implementations
-that simply pass on the request to the media driver, or possibly, to another
-extension if one is installed. Your derived class implementation can override
-these functions to modify this default functionality. Such a function implementation
-typically performs its particular functionality, then calls the corresponding
-base class function to pass on the request to the media driver. </p><p>The
-sequence of calls made to the extension, and the format of the data passed
-in those calls, vary according to the file system type. Therefore, to implement
-a file system extension you need a good understanding of the particular file
-system for which the extension is targeted. </p> <p><b>Initialisation</b> </p><p>The file server calls the proxy drive class <xref href="GUID-E735AB4A-E9D5-33C7-ACEC-815013C0777A.dita"><apiname>Initialise()</apiname></xref> function
-after construction. You can override this function to do any set up you require.
-Your implementation should end by calling the base class function <xref href="GUID-FAFF712B-2295-3907-B839-D77F052160DA.dita#GUID-FAFF712B-2295-3907-B839-D77F052160DA/GUID-0B9ABB2C-6B33-389C-9FF9-04A4799682D9"><apiname>CBaseExtProxyDrive::Initialise()</apiname></xref> to
-pass on the request. </p><codeblock id="GUID-B52DB6C7-1A2E-516F-A6EB-14A71B2E7BF3" xml:space="preserve">TInt CLoggerExtProxyDrive::Initialise()
- {
- // extension specific initialisation
- // ...
- return(CBaseExtProxyDrive::Initialise());
- }</codeblock><p>The file system may at initialisation and at later times
-request capability information from the drive using the <codeph>Caps()</codeph> function: </p><codeblock id="GUID-9436817E-396D-57D8-A7D7-BE6060DA0C32" xml:space="preserve">TInt Caps(TDes8 &anInfo);</codeblock><p>On
-return, <codeph>anInfo</codeph> is a packaged capability structure, as defined
-in <filepath>d32locd.h</filepath>. <codeph>CBaseExtProxyDrive</codeph> implements <codeph>Caps()</codeph> to
-get the capabilities from the drive. </p><p><b> Cleanup</b> </p><p>If the drive is dismounted, the extension is notified by a call to
-its <codeph>Dismounted()</codeph> function, and the proxy drive object is
-deleted. </p><p><b>Reading
-data from the drive</b> </p><p>A file system requests to read data from the
-drive by calling the proxy drive's virtual <codeph>Read()</codeph> functions,
-of which there are three overloads. A proxy drive extension can override these
-functions to modify the read functionality. The implementation should as usual
-pass on the request to the drive using the base class's functions. </p><codeblock id="GUID-45E9CADA-5278-59D2-91B4-C6C687730642" xml:space="preserve">TInt CLoggerExtProxyDrive::Read(TInt64 aPos,TInt aLength,TDes8& aTrg)
- {
- // do extension specific operations
- // ...
- return(CBaseExtProxyDrive::Read(aPos,aLength,aTrg));
- }
-</codeblock><p><b>Writing
-data to the drive</b> </p><p>A file system requests to write data to the drive
-by calling the proxy drive's virtual <codeph>Write()</codeph> functions, of
-which there are three overloads. A proxy drive extension can override these
-functions to modify the write functionality. The implementation should as
-usual pass on the request to the drive using the base class function. </p><codeblock id="GUID-BA726003-1033-5609-84CE-61747F6EA287" xml:space="preserve">TInt CLoggerExtProxyDrive::Write(TInt64 aPos,const TDesC8& aSrc)
- {
- // do extension specific operations
- // ...
- return(CBaseExtProxyDrive::Write(aPos,aSrc));
- }
-</codeblock><p>It is possible for some media, such as a RAM disk type drive,
-to be dynamically resized to fit the data being written to it. The proxy drive
-interface's <codeph>Enlarge()</codeph> and <codeph>ReduceSize()</codeph> functions
-handle such resizing requests. An extension can override these functions if
-required. </p><p><b>Formatting
-a drive</b> </p><p>A file system requests to format a drive by calling the
-proxy drive's virtual <xref href="GUID-A13BA97D-AB50-30C9-B0A6-51EFCD1A93D6.dita"><apiname>Format()</apiname></xref> functions, of which there
-are two overloads. A proxy drive extension can override these functions to
-modify the drive format functionality. The implementations should as usual
-pass on the request to the drive using the base class functions. </p><p><b>Password and drive locking</b> </p><p>Some drive types can be locked using
-a password, using functions such as <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-1FFBA354-A069-36D4-BEFF-0BD5CCF125E1"><apiname>RFs::LockDrive()</apiname></xref>. The
-proxy drive class defines a number of functions, <xref href="GUID-5BCEAABF-D060-3F29-A8AE-0C14A8DFC1D2.dita"><apiname>Clear()</apiname></xref>, <xref href="GUID-216F09C2-60A8-3E42-B466-5D47233E125B.dita"><apiname>ErasePassword()</apiname></xref>, <xref href="GUID-55300467-B647-3CAC-899E-AF7D2A6C1792.dita"><apiname>Lock()</apiname></xref>,
-and <xref href="GUID-17D8CCBA-9880-3E8D-B58F-7869218AF986.dita"><apiname>Unlock()</apiname></xref>, to handle such requests. Extensions can override
-these functions and should pass on the request to the drive using the base
-class functions. </p><p><b>Error
-information</b> </p><p>File systems can in some circumstances request information
-from the media driver about the last error that occurred. The proxy drive
-class defines the function <xref href="GUID-46546BBB-46C0-3AA7-A6F5-CD68A24EF5E9.dita"><apiname>GetLastErrorInfo()</apiname></xref> to handle
-such requests. Extensions can override this function or use the default implementation
-provided by the base class. The error information is a packaged <codeph>TErrorInfo</codeph> structure. </p><p><b>Extension functions</b> </p><p>The proxy drive class implements the common
-Symbian platform pattern that allows new functionality to be added to an existing
-class without altering the interface, which could cause a compatibility break.
-The <codeph>GetInterface()</codeph> function takes an ID argument indicating
-the functionality being requested, and generic input and output arguments.
-An extension can override this if required. </p><codeblock id="GUID-3C50ABD5-D485-5BC5-8D34-0FA40E78BF6A" xml:space="preserve">TInt CLoggerExtProxyDrive::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput)
- {
- switch(aInterfaceId)
- {
- // file caching supported, so pass query on to next extension
- case ELocalBufferSupport:
- return CBaseExtProxyDrive::LocalBufferSupport();
-
- default:
- return CBaseExtProxyDrive::GetInterface(aInterfaceId, aInterface, aInput);
- }
- }</codeblock> <p><b>Test
-operations</b> </p><p>The file server offers an interface, <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-DEB7A7A9-7E75-3F6A-9C20-2E5FC8FB6128"><apiname>RFs::ControlIo()</apiname></xref>,
-that allows a message to be sent to a media driver in debug builds, in order
-to simplify writing test programs. </p><p>The proxy drive class defines the
-function <xref href="GUID-446113DA-8032-375C-9000-16C8E6704E67.dita"><apiname>ControlIO()</apiname></xref> to handle such requests. Extensions
-can override this function or use the default implementation provided by the
-base class. </p></section>
-<section id="GUID-9E7099C2-9A97-503A-B8D7-ADD8A66C8D59"><title>Deploying and
-using an extension</title><p>An extension library is only called after a client
-has requested the file server to load the extension library and to mount it
-on a particular drive. This section first describes how to do this at the
-same time as mounting the target file system, and then how to add an extension
-to an already mounted file system. </p> <p><b>Mounting
-extensions in the Base Starter</b> </p><p>To mount a primary extension, modify
-the <xref href="GUID-80698E62-E310-59CA-A524-5CF44C437BE4.dita">Base Starter</xref> to
-use the <xref href="GUID-EDED466A-BBD8-30E7-A50D-3A0631B73AE9.dita"><apiname>RFs:AddExtension()</apiname></xref> and <xref href="GUID-9CE6C690-F1C4-329C-B9AF-84A8FAB3E1F0.dita"><apiname>RFs:MountFileSystem()</apiname></xref> functions
-as shown below. </p><codeblock id="GUID-F3802A21-365A-5291-A57F-856B11FCEC81" xml:space="preserve">// If an extension is required, assume its name is set in iExtName
-if (iExtName)
- {
- TPtrC extname(iExtName);
- r=iFs.AddExtension(extname);
- if (r==KErrNone || r==KErrAlreadyExists)
- r=iFs.MountFileSystem(fileSysName,extname,drive);
- }
-else
- r=iFs.MountFileSystem(fileSysName,drive);</codeblock> <p><xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-0754C075-92B6-37B3-8959-61D8D65DB491"><apiname>RFs::MountFileSystem()</apiname></xref> can
-be passed a flag to specify whether the drive is mounted as synchronous or
-asynchronous. An asynchronous drive has its own processing thread, i.e. operations
-on it do not block the file server and other drives. A synchronous drive's
-requests are processed by the main file server thread and it is possible to
-block it with operations on other drives. A drive should be mounted as synchronous
-if it is very fast, such an internal RAM or ROFS drive.</p><p> <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-7546C0FA-4FD4-3C3D-B9E5-92F371759A4B"><apiname>RFs::DismountFileSystem()</apiname></xref> is
-used to dismount a file system and any primary and secondary extensions mounted
-on the drive. </p><p>No resources can be open on the drive while an extension
-is mounted as this operation involves a dismount/remount. If the remount fails,
-then the extension is dismounted from the drive. </p> <p><b>Mounting by client-side request</b> </p><p>The functions in the file server
-client API allow extensions to be managed by file server clients. </p><p>Most
-of these functions require the name of the extension. Use <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-F00D3D91-212A-3192-8A2E-989912AAA9DD"><apiname>RFs::ExtensionName()</apiname></xref> to
-get the name of an extension on the specified drive at position <codeph>aPos</codeph>.
-The position is the location in the extension chain, the first extension added
-is equal to zero. If an extension is not found at <codeph>aPos</codeph> then <codeph>KErrNotFound</codeph> is
-returned. </p><codeblock id="GUID-C435F3B8-635D-56EB-BCEE-E4EE4CF390DC" xml:space="preserve">const TInt KMaxFileSystemExtNameLength = 100; // Arbitrary length
-TBuf<KMaxFileSystemExtNameLength> fsExtName;
-r = TheFs.ExtensionName(fsExtName, driveNo, 0);</codeblock><p>To mount a secondary
-extension it must first be added to the file server using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-D45FD363-EEF9-3F77-8FA1-49270D8E89A0"><apiname>RFs::AddExtension()</apiname></xref>.
-This loads the specified extension and adds it to the extension container
-in the file server. The extension can then be mounted onto the specified drive
-using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-5003658C-C5A0-39F0-A518-65B20CD41567"><apiname>RFs::MountExtension()</apiname></xref>. </p><p>To dismount an extension
-from a specified drive, use <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-D8D25E61-6480-30A0-9A3E-BE7A28FD896C"><apiname>RFs::DismountExtension()</apiname></xref>. This
-can only dismount extensions that were mounted using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-5003658C-C5A0-39F0-A518-65B20CD41567"><apiname>RFs::MountExtension()</apiname></xref>.
-No resources can be open on the drive when an extension is dismounted. This
-operation involves a dismount/remount if there is a current <xref href="GUID-FADDE053-CC1C-39BC-A52D-27093041BE20.dita"><apiname>CMountCB</apiname></xref> object
-mounted on the drive. An extension can be removed from the file server using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-7B8DB8F9-DE75-3FF3-8AE6-1467C3CD4ACF"><apiname>RFs::RemoveExtension()</apiname></xref>. </p> </section>
-<section id="GUID-789DB94B-0650-4FE5-A8B6-312A8A9B499F"><title>Possible issues with file server extensions</title><p>Loading
-other libraries (such as device drivers and DLLs) from an extension uses the
-kernel's loader, which in turn uses the file server. This raises the possibility
-of deadlock. Even if your file system extension is for a different file system
-than from the one where your driver lives, the loader may still scan other
-drives. </p><p>Note that <xref href="GUID-57D0E9E3-D1B9-36A1-9038-96336F58EA08.dita#GUID-57D0E9E3-D1B9-36A1-9038-96336F58EA08/GUID-F3CA0484-A983-31A1-A44C-A067E711E528"><apiname>CProxyDriveFactory::Install()</apiname></xref> is
-called from the file server's main thread, so using the file server from there
-is guaranteed to deadlock. The simplest solution to this is to have the client
-that calls <codeph>RFs::AddExtension()</codeph> load the required library
-beforehand. </p><p>An alternative approach would be to create
-a new thread from the <codeph>Install()</codeph> function and, in order to
-load a driver, call <codeph>User::LoadLogicalDevice()</codeph> in that thread.
-Your code would need to solve the synchronisation problem of ensuring that
-the <codeph>User::LoadLogicalDevice()</codeph> call has completed before attempting
-to mount the extension on a drive. </p> </section>
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
+<!-- This component and the accompanying materials are made available under the terms of the License
+"Eclipse Public License v1.0" which accompanies this distribution,
+and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
+<!-- Initial Contributors:
+ Nokia Corporation - initial contribution.
+Contributors:
+-->
+<!DOCTYPE concept
+ PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
+<concept id="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81" xml:lang="en"><title>File
+Server Extensions Tutorial</title><prolog><metadata><keywords/></metadata></prolog><conbody>
+<p>Describes how to develop and use a file server extension. </p>
+<p>See <xref href="GUID-983F0ABD-470C-51C3-B6AE-1B1AA55AB4A2.dita">File Server
+Extensions</xref> for more information about the file server extension architecture. </p>
+<section id="GUID-4FEA7E17-8ACE-58E2-B90A-FB2F9BB33766"><title>Developing
+an extension</title><p>This section describes how to use the APIs defined
+by the file server to implement a new extension. It contains the following
+sections: <ul>
+<li><p><xref href="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita#GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81/GUID-4CFC2D17-60B9-512F-8896-54AA0F8221CE">Project
+file and build</xref> describes the requirements for an extension's project
+file. </p></li>
+<li><p><xref href="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita#GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81/GUID-7744238A-BFE2-53BD-9B57-D38ED08811EB">Implementing
+the factory class</xref> describes the factory class that each extension DLL
+must implement to create proxy driver objects. </p></li>
+<li><p><xref href="GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81.dita#GUID-E10F01A3-6451-52AF-BB35-D93D8D27DD81/GUID-6B7F5F60-D50F-5BB0-AB3D-8D065FE5865A">Implementing
+the proxy drive extension class</xref> describes the proxy drive class that
+each extension DLL must implement to provide its extension functionality. </p></li>
+</ul></p><p>The examples quoted are taken from the <codeph>t_logext</codeph> test
+extension, which is available in the Symbian platform source code at <filepath>os/kernelhwsrv/kerneltest/f32test/ext/t_logext.cpp</filepath>.
+That test code simply logs when the extension functions are called. </p> <p id="GUID-4CFC2D17-60B9-512F-8896-54AA0F8221CE"><b>Project file and build</b> </p><p>A
+file server extension is implemented as a polymorphic DLL. Its project file
+must be written as follows: </p><ul>
+<li id="GUID-8D625BD6-E5D5-53B1-B9D2-634C59DC213F"><p> <codeph>TARGETTYPE</codeph> should
+be set to <codeph>fsy</codeph>. This means that the project does not require
+a <filepath>.def</filepath> file to specify its frozen exports: the build
+tools will assume the correct frozen exports for the type. </p> </li>
+<li id="GUID-66234A27-AB5D-5534-9267-25B65F4821D9"><p>The DLL name is conventionally
+given the extension <filepath>.fxt</filepath>. </p> </li>
+<li id="GUID-D0718103-1D7B-5926-822E-1CB4B24C68B8"><p>The second UID should
+be <codeph>0x100039df</codeph>. </p> </li>
+<li id="GUID-910E63DC-9A65-5124-950B-A7F2BF2929CC"><p>The DLL is loaded by
+the file server, and therefore must have the same platform security capabilities
+as that process: <codeph>TCB ProtServ DiskAdmin AllFiles PowerMgmt CommDD</codeph>. </p></li>
+</ul><p>The following shows an example project file: </p><codeblock id="GUID-0DAA1B8E-2A55-5942-A166-B09666258967" xml:space="preserve">TARGET t_logext.fxt
+TARGETTYPE fsy
+
+SOURCEPATH ../ext
+SOURCE t_logext.cpp
+
+SYSTEMINCLUDE /epoc32/include
+
+LIBRARY euser.lib efile.lib
+
+UID 0x100039df 0x10000CEE
+VENDORID 0x70000001
+
+#include "../../f32/group/f32caps.mmh" // Include capabilities of File Server process</codeblock> <p id="GUID-7744238A-BFE2-53BD-9B57-D38ED08811EB"><b>Implementing the factory
+class</b> </p><p>Each extension DLL must implement a factory class that is
+responsible for creating proxy driver objects. This is done by implementing
+a class derived from <xref href="GUID-57D0E9E3-D1B9-36A1-9038-96336F58EA08.dita"><apiname>CProxyDriveFactory</apiname></xref>. A pointer to an
+object of this class must be returned by the first function exported from
+the extension DLL. </p><codeblock id="GUID-ABBFEF73-38FE-5689-B89A-FA8207DD2F81" xml:space="preserve">class CLoggerProxyDriveFactory : public CProxyDriveFactory
+ {
+public:
+ CLoggerProxyDriveFactory();
+ virtual TInt Install();
+ virtual CProxyDrive* NewProxyDriveL(CProxyDrive* aProxy,CMountCB* aMount);
+ };
+
+...
+
+// Create a new factory
+EXPORT_C CProxyDriveFactory* CreateFileSystem()
+ {
+ return(new CLoggerProxyDriveFactory());
+ }
+</codeblock> <p><b>Factory
+initialisation </b> </p> <p> <codeph>CProxyDriveFactory</codeph> defines a
+pure virtual function <codeph>Install()</codeph> that is called once by the
+file server before any other factory object function. You must implement this
+to do any required setup. <codeph>CProxyDriveFactory</codeph> is derived from <xref href="GUID-578CD638-601C-353D-B1C4-557C72A00DF1.dita"><apiname>CFsObject</apiname></xref>,
+which means that the file server maintains a reference count of its use, and
+allows clients to refer to the object through a name (a string). The <codeph>Install()</codeph> function's
+implementation should set the extension's name: </p><codeblock id="GUID-ACF692BF-8C52-5430-80C6-9702EFD0FB7D" xml:space="preserve">TInt CLoggerProxyDriveFactory::Install()
+ {
+ _LIT(KLoggerName,"Logger");
+ return(SetName(&KLoggerName));
+ }
+</codeblock> <p>Clients can get the name of an extension using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-F00D3D91-212A-3192-8A2E-989912AAA9DD"><apiname>RFs::ExtensionName()</apiname></xref>,
+and then use it to specify the extension in functions such as <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-5003658C-C5A0-39F0-A518-65B20CD41567"><apiname>RFs::MountExtension()</apiname></xref>. </p><p><codeph>CProxyDriveFactory</codeph> also defines a virtual function <codeph>Remove()</codeph>, which is called
+just before when the factory object is destroyed. You can override this to
+do any required cleanup. </p> <p><b>Proxy drive factory </b> </p><p><codeph>CProxyDriveFactory</codeph> defines
+a pure virtual function <codeph>NewProxyDriveL()</codeph> that is called by
+the file server to obtain a new proxy drive extension object. You must implement
+this to create the proxy drive extension. </p><codeblock id="GUID-77B7A963-83D7-5D80-9374-53D296E2248B" xml:space="preserve">CProxyDrive* CLoggerProxyDriveFactory::NewProxyDriveL(CProxyDrive* aProxy,CMountCB* aMount)
+ {
+ return(CLoggerExtProxyDrive::NewL(aProxy,aMount));
+ }</codeblock><p>The <codeph>aProxy</codeph> argument represents the last
+extension to be mounted. The new extension will be mounted on top of it. <codeph>aProxy</codeph> could
+be an object from another extension library, or a file server <codeph>CLocalProxyDrive</codeph> object
+that calls the media sub-system. </p><p><codeph>aMount</codeph> represents
+the mounted drive to which the extension is being added. </p><p><codeph>aProxy</codeph> and <codeph>aMount</codeph> are
+required by the proxy drive extension base class (<codeph>CBaseExtProxyDrive</codeph>)
+constructor: </p><codeblock id="GUID-EF379FC2-F2A5-5F47-8BA6-2C286DF746FA" xml:space="preserve">CLoggerExtProxyDrive::CLoggerExtProxyDrive(CProxyDrive* aProxyDrive, CMountCB* aMount)
+ :CBaseExtProxyDrive(aProxyDrive,aMount)
+ {
+ ...
+ }</codeblock><p>The arguments are used to initialise private data in <codeph>CBaseExtProxyDrive</codeph>. </p> <p><b>DLL's first exported function</b></p><p>The DLL's first exported function
+should create a new instance of the factory class: </p><codeblock id="GUID-9173B82F-90BA-5FBD-9EC9-FA7EB08E3794" xml:space="preserve">EXPORT_C CProxyDriveFactory* CreateFileSystem()
+//
+// Create a new file system
+//
+ {
+ return(new CLoggerProxyDriveFactory());
+ }</codeblock> <p id="GUID-6B7F5F60-D50F-5BB0-AB3D-8D065FE5865A"><b>Implementing the proxy drive
+extension class</b> </p><p>An extension DLL must contain a proxy drive class
+that implements the extension. This is done by implementing a class derived
+from <xref href="GUID-FAFF712B-2295-3907-B839-D77F052160DA.dita"><apiname>CBaseExtProxyDrive</apiname></xref>. <codeph>CBaseExtProxyDrive</codeph> defines
+virtual functions that are called by the file system to handle requests such
+as reading and writing data from the drive. The functions have default implementations
+that simply pass on the request to the media driver, or possibly, to another
+extension if one is installed. Your derived class implementation can override
+these functions to modify this default functionality. Such a function implementation
+typically performs its particular functionality, then calls the corresponding
+base class function to pass on the request to the media driver. </p><p>The
+sequence of calls made to the extension, and the format of the data passed
+in those calls, vary according to the file system type. Therefore, to implement
+a file system extension you need a good understanding of the particular file
+system for which the extension is targeted. </p> <p><b>Initialisation</b> </p><p>The file server calls the proxy drive class <xref href="GUID-E735AB4A-E9D5-33C7-ACEC-815013C0777A.dita"><apiname>Initialise()</apiname></xref> function
+after construction. You can override this function to do any set up you require.
+Your implementation should end by calling the base class function <xref href="GUID-FAFF712B-2295-3907-B839-D77F052160DA.dita#GUID-FAFF712B-2295-3907-B839-D77F052160DA/GUID-0B9ABB2C-6B33-389C-9FF9-04A4799682D9"><apiname>CBaseExtProxyDrive::Initialise()</apiname></xref> to
+pass on the request. </p><codeblock id="GUID-B52DB6C7-1A2E-516F-A6EB-14A71B2E7BF3" xml:space="preserve">TInt CLoggerExtProxyDrive::Initialise()
+ {
+ // extension specific initialisation
+ // ...
+ return(CBaseExtProxyDrive::Initialise());
+ }</codeblock><p>The file system may at initialisation and at later times
+request capability information from the drive using the <codeph>Caps()</codeph> function: </p><codeblock id="GUID-9436817E-396D-57D8-A7D7-BE6060DA0C32" xml:space="preserve">TInt Caps(TDes8 &anInfo);</codeblock><p>On
+return, <codeph>anInfo</codeph> is a packaged capability structure, as defined
+in <filepath>d32locd.h</filepath>. <codeph>CBaseExtProxyDrive</codeph> implements <codeph>Caps()</codeph> to
+get the capabilities from the drive. </p><p><b> Cleanup</b> </p><p>If the drive is dismounted, the extension is notified by a call to
+its <codeph>Dismounted()</codeph> function, and the proxy drive object is
+deleted. </p><p><b>Reading
+data from the drive</b> </p><p>A file system requests to read data from the
+drive by calling the proxy drive's virtual <codeph>Read()</codeph> functions,
+of which there are three overloads. A proxy drive extension can override these
+functions to modify the read functionality. The implementation should as usual
+pass on the request to the drive using the base class's functions. </p><codeblock id="GUID-45E9CADA-5278-59D2-91B4-C6C687730642" xml:space="preserve">TInt CLoggerExtProxyDrive::Read(TInt64 aPos,TInt aLength,TDes8& aTrg)
+ {
+ // do extension specific operations
+ // ...
+ return(CBaseExtProxyDrive::Read(aPos,aLength,aTrg));
+ }
+</codeblock><p><b>Writing
+data to the drive</b> </p><p>A file system requests to write data to the drive
+by calling the proxy drive's virtual <codeph>Write()</codeph> functions, of
+which there are three overloads. A proxy drive extension can override these
+functions to modify the write functionality. The implementation should as
+usual pass on the request to the drive using the base class function. </p><codeblock id="GUID-BA726003-1033-5609-84CE-61747F6EA287" xml:space="preserve">TInt CLoggerExtProxyDrive::Write(TInt64 aPos,const TDesC8& aSrc)
+ {
+ // do extension specific operations
+ // ...
+ return(CBaseExtProxyDrive::Write(aPos,aSrc));
+ }
+</codeblock><p>It is possible for some media, such as a RAM disk type drive,
+to be dynamically resized to fit the data being written to it. The proxy drive
+interface's <codeph>Enlarge()</codeph> and <codeph>ReduceSize()</codeph> functions
+handle such resizing requests. An extension can override these functions if
+required. </p><p><b>Formatting
+a drive</b> </p><p>A file system requests to format a drive by calling the
+proxy drive's virtual <xref href="GUID-A13BA97D-AB50-30C9-B0A6-51EFCD1A93D6.dita"><apiname>Format()</apiname></xref> functions, of which there
+are two overloads. A proxy drive extension can override these functions to
+modify the drive format functionality. The implementations should as usual
+pass on the request to the drive using the base class functions. </p><p><b>Password and drive locking</b> </p><p>Some drive types can be locked using
+a password, using functions such as <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-1FFBA354-A069-36D4-BEFF-0BD5CCF125E1"><apiname>RFs::LockDrive()</apiname></xref>. The
+proxy drive class defines a number of functions, <xref href="GUID-5BCEAABF-D060-3F29-A8AE-0C14A8DFC1D2.dita"><apiname>Clear()</apiname></xref>, <xref href="GUID-216F09C2-60A8-3E42-B466-5D47233E125B.dita"><apiname>ErasePassword()</apiname></xref>, <xref href="GUID-55300467-B647-3CAC-899E-AF7D2A6C1792.dita"><apiname>Lock()</apiname></xref>,
+and <xref href="GUID-17D8CCBA-9880-3E8D-B58F-7869218AF986.dita"><apiname>Unlock()</apiname></xref>, to handle such requests. Extensions can override
+these functions and should pass on the request to the drive using the base
+class functions. </p><p><b>Error
+information</b> </p><p>File systems can in some circumstances request information
+from the media driver about the last error that occurred. The proxy drive
+class defines the function <xref href="GUID-46546BBB-46C0-3AA7-A6F5-CD68A24EF5E9.dita"><apiname>GetLastErrorInfo()</apiname></xref> to handle
+such requests. Extensions can override this function or use the default implementation
+provided by the base class. The error information is a packaged <codeph>TErrorInfo</codeph> structure. </p><p><b>Extension functions</b> </p><p>The proxy drive class implements the common
+Symbian platform pattern that allows new functionality to be added to an existing
+class without altering the interface, which could cause a compatibility break.
+The <codeph>GetInterface()</codeph> function takes an ID argument indicating
+the functionality being requested, and generic input and output arguments.
+An extension can override this if required. </p><codeblock id="GUID-3C50ABD5-D485-5BC5-8D34-0FA40E78BF6A" xml:space="preserve">TInt CLoggerExtProxyDrive::GetInterface(TInt aInterfaceId,TAny*& aInterface,TAny* aInput)
+ {
+ switch(aInterfaceId)
+ {
+ // file caching supported, so pass query on to next extension
+ case ELocalBufferSupport:
+ return CBaseExtProxyDrive::LocalBufferSupport();
+
+ default:
+ return CBaseExtProxyDrive::GetInterface(aInterfaceId, aInterface, aInput);
+ }
+ }</codeblock> <p><b>Test
+operations</b> </p><p>The file server offers an interface, <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-DEB7A7A9-7E75-3F6A-9C20-2E5FC8FB6128"><apiname>RFs::ControlIo()</apiname></xref>,
+that allows a message to be sent to a media driver in debug builds, in order
+to simplify writing test programs. </p><p>The proxy drive class defines the
+function <xref href="GUID-446113DA-8032-375C-9000-16C8E6704E67.dita"><apiname>ControlIO()</apiname></xref> to handle such requests. Extensions
+can override this function or use the default implementation provided by the
+base class. </p></section>
+<section id="GUID-9E7099C2-9A97-503A-B8D7-ADD8A66C8D59"><title>Deploying and
+using an extension</title><p>An extension library is only called after a client
+has requested the file server to load the extension library and to mount it
+on a particular drive. This section first describes how to do this at the
+same time as mounting the target file system, and then how to add an extension
+to an already mounted file system. </p> <p><b>Mounting
+extensions in the Base Starter</b> </p><p>To mount a primary extension, modify
+the <xref href="GUID-80698E62-E310-59CA-A524-5CF44C437BE4.dita">Base Starter</xref> to
+use the <xref href="GUID-EDED466A-BBD8-30E7-A50D-3A0631B73AE9.dita"><apiname>RFs:AddExtension()</apiname></xref> and <xref href="GUID-9CE6C690-F1C4-329C-B9AF-84A8FAB3E1F0.dita"><apiname>RFs:MountFileSystem()</apiname></xref> functions
+as shown below. </p><codeblock id="GUID-F3802A21-365A-5291-A57F-856B11FCEC81" xml:space="preserve">// If an extension is required, assume its name is set in iExtName
+if (iExtName)
+ {
+ TPtrC extname(iExtName);
+ r=iFs.AddExtension(extname);
+ if (r==KErrNone || r==KErrAlreadyExists)
+ r=iFs.MountFileSystem(fileSysName,extname,drive);
+ }
+else
+ r=iFs.MountFileSystem(fileSysName,drive);</codeblock> <p><xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-0754C075-92B6-37B3-8959-61D8D65DB491"><apiname>RFs::MountFileSystem()</apiname></xref> can
+be passed a flag to specify whether the drive is mounted as synchronous or
+asynchronous. An asynchronous drive has its own processing thread, i.e. operations
+on it do not block the file server and other drives. A synchronous drive's
+requests are processed by the main file server thread and it is possible to
+block it with operations on other drives. A drive should be mounted as synchronous
+if it is very fast, such an internal RAM or ROFS drive.</p><p> <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-7546C0FA-4FD4-3C3D-B9E5-92F371759A4B"><apiname>RFs::DismountFileSystem()</apiname></xref> is
+used to dismount a file system and any primary and secondary extensions mounted
+on the drive. </p><p>No resources can be open on the drive while an extension
+is mounted as this operation involves a dismount/remount. If the remount fails,
+then the extension is dismounted from the drive. </p> <p><b>Mounting by client-side request</b> </p><p>The functions in the file server
+client API allow extensions to be managed by file server clients. </p><p>Most
+of these functions require the name of the extension. Use <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-F00D3D91-212A-3192-8A2E-989912AAA9DD"><apiname>RFs::ExtensionName()</apiname></xref> to
+get the name of an extension on the specified drive at position <codeph>aPos</codeph>.
+The position is the location in the extension chain, the first extension added
+is equal to zero. If an extension is not found at <codeph>aPos</codeph> then <codeph>KErrNotFound</codeph> is
+returned. </p><codeblock id="GUID-C435F3B8-635D-56EB-BCEE-E4EE4CF390DC" xml:space="preserve">const TInt KMaxFileSystemExtNameLength = 100; // Arbitrary length
+TBuf<KMaxFileSystemExtNameLength> fsExtName;
+r = TheFs.ExtensionName(fsExtName, driveNo, 0);</codeblock><p>To mount a secondary
+extension it must first be added to the file server using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-D45FD363-EEF9-3F77-8FA1-49270D8E89A0"><apiname>RFs::AddExtension()</apiname></xref>.
+This loads the specified extension and adds it to the extension container
+in the file server. The extension can then be mounted onto the specified drive
+using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-5003658C-C5A0-39F0-A518-65B20CD41567"><apiname>RFs::MountExtension()</apiname></xref>. </p><p>To dismount an extension
+from a specified drive, use <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-D8D25E61-6480-30A0-9A3E-BE7A28FD896C"><apiname>RFs::DismountExtension()</apiname></xref>. This
+can only dismount extensions that were mounted using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-5003658C-C5A0-39F0-A518-65B20CD41567"><apiname>RFs::MountExtension()</apiname></xref>.
+No resources can be open on the drive when an extension is dismounted. This
+operation involves a dismount/remount if there is a current <xref href="GUID-FADDE053-CC1C-39BC-A52D-27093041BE20.dita"><apiname>CMountCB</apiname></xref> object
+mounted on the drive. An extension can be removed from the file server using <xref href="GUID-E263C747-946F-35AA-9F1D-41833BD350FC.dita#GUID-E263C747-946F-35AA-9F1D-41833BD350FC/GUID-7B8DB8F9-DE75-3FF3-8AE6-1467C3CD4ACF"><apiname>RFs::RemoveExtension()</apiname></xref>. </p> </section>
+<section id="GUID-789DB94B-0650-4FE5-A8B6-312A8A9B499F"><title>Possible issues with file server extensions</title><p>Loading
+other libraries (such as device drivers and DLLs) from an extension uses the
+kernel's loader, which in turn uses the file server. This raises the possibility
+of deadlock. Even if your file system extension is for a different file system
+than from the one where your driver lives, the loader may still scan other
+drives. </p><p>Note that <xref href="GUID-57D0E9E3-D1B9-36A1-9038-96336F58EA08.dita#GUID-57D0E9E3-D1B9-36A1-9038-96336F58EA08/GUID-F3CA0484-A983-31A1-A44C-A067E711E528"><apiname>CProxyDriveFactory::Install()</apiname></xref> is
+called from the file server's main thread, so using the file server from there
+is guaranteed to deadlock. The simplest solution to this is to have the client
+that calls <codeph>RFs::AddExtension()</codeph> load the required library
+beforehand. </p><p>An alternative approach would be to create
+a new thread from the <codeph>Install()</codeph> function and, in order to
+load a driver, call <codeph>User::LoadLogicalDevice()</codeph> in that thread.
+Your code would need to solve the synchronisation problem of ensuring that
+the <codeph>User::LoadLogicalDevice()</codeph> call has completed before attempting
+to mount the extension on a drive. </p> </section>
</conbody></concept>
\ No newline at end of file