--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/symport/f32/sfsrv/cl_file.cpp Thu Jun 25 15:59:54 2009 +0100
@@ -0,0 +1,1114 @@
+// Copyright (c) 1995-2009 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 "Symbian Foundation License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32\sfsrv\cl_file.cpp
+//
+//
+
+#include <f32file.h>
+#include <e32math.h>
+
+#include <cstdio>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+class TFileInfo
+ {
+public:
+ FILE* iHandle;
+ TFileName iName;
+ TUint iMode;
+ };
+
+#define GETFILEHANDLE(A,B) TFileInfo* A; memcpy(&A, B, 4);
+#define FILEHANDLE(A) GETFILEHANDLE(A,this);
+
+extern TInt mapErr(TInt);
+extern const char* PosixFilename(const TDesC &aIn);
+extern const char* PosixFilename(const TDesC &aIn, TDes8& aOut);
+
+/**
+Make a duplicate of the passed file handle in the same thread.
+
+By default, any thread in the process can use the duplicated handle to access the
+file. However, specifying EOwnerThread as the second parameter to this function,
+means that only the creating thread can use the handle.
+
+@param aFile The file handle to duplicate
+@param aType An enumeration whose enumerators define the ownership of this
+ handle. If not explicitly specified, EOwnerProcess is taken
+ as default.
+
+@return one of the other system-wide error codes.
+*/
+EXPORT_C TInt RFile::Duplicate(const RFile& aFile, TOwnerType aType)
+ {
+ GETFILEHANDLE(h,&aFile);
+ TFileName name(h->iName);
+ RFs fs; // This doesn't actually get used in the Open function
+ TUint mode = h->iMode;
+
+ // Get the file position
+ TInt pos = ftell(h->iHandle);
+ if (pos < 0)
+ return mapErr(errno);
+
+ // Open the file
+ TInt err = Open(fs, name, mode);
+ if (err != KErrNone)
+ return err;
+
+ // Set the file position
+ return Seek(ESeekStart, pos);
+ }
+
+EXPORT_C TInt RFile::Name(TDes &aName) const
+/**
+Gets the final part of a filename
+
+This is used to retrieve the name and extension of a file that has been
+passed from one process to another using the RFile::AdoptXXX() methods.
+
+@param aName On return, contains the name of the file, including the name and
+ extension but excluding the drive letter and path.
+
+@return KErrNone if successful, otherwise one of the other
+ system-wide error codes.
+
+*/
+ {
+ FILEHANDLE(h);
+ TParsePtrC ptr(h->iName);
+ aName = ptr.NameAndExt();
+ return KErrNone;
+ }
+
+
+EXPORT_C TInt RFile::FullName(TDes& aName) const
+/**
+Gets the full filename
+
+This is used to retrieve the full filename, including drive and path,
+of a file that has been passed from one process to another using the
+RFile::AdoptXXX() methods.
+
+@param aName On return, contains the full name of the file, including drive and path.
+
+@return KErrNone if successful, otherwise one of the other
+ system-wide error codes.
+
+*/
+ {
+ FILEHANDLE(h);
+ aName = h->iName;
+ return KErrNone;
+ }
+
+
+
+/*
+"r" Open a text file for reading
+"r+" Open a text file for read/write
+
+"rb" Open a binary file for reading
+"rb+" Open a binary file for read/write
+
+"w" Create a text file for writing
+"w+" Create a text file for read/write
+
+"wb" Create a binary file for writing
+"wb+" Create a binary file for read/write
+
+"a" Append to a text file
+"ab" Append to a binary file
+*/
+void GetFileMode(TDes8& aBuf, TUint aFileMode, TBool aOpen)
+ {
+ if (aOpen)
+ {
+ if (aFileMode & EFileWrite)
+ // Open a binary file for read/write
+ aBuf = _L8("rb+");
+ else
+ // Open a binary file for reading
+ aBuf = _L8("rb");
+ }
+ else
+ // Create a binary file for read/write
+ aBuf = _L8("wb+");
+ }
+
+TInt DoOpen(RFile* aFile, const TDesC &aName, TUint aFileMode, TBool aOpen)
+ {
+ const char* name = PosixFilename(aName);
+
+ TFileInfo* info = new TFileInfo;
+ if (!info)
+ return KErrNoMemory;
+
+ TBuf8<4> mode;
+ GetFileMode(mode, aFileMode, aOpen);
+ info->iHandle = fopen(name, reinterpret_cast<const char*>(mode.PtrZ()));
+
+#ifdef _DEBUG_LOGGING
+ RDebug::Print(_L("DEBUG: DoOpen> file=%S id=%x\n"), &aName, info->iHandle);
+#endif
+
+ if (!info->iHandle)
+ {
+ delete info;
+ return mapErr(errno);
+ }
+
+ // Symbian expects file pos at the begining
+ if (aOpen && aFileMode|EFileWrite)
+ {
+ if (fseek(info->iHandle, 0, SEEK_SET) != 0)
+ {
+ fclose(info->iHandle);
+ delete info;
+ return mapErr(errno);
+ }
+ }
+
+ info->iName = aName;
+ info->iMode = aFileMode;
+ memcpy(aFile, &info, 4);
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Open(RFs& aFs, const TDesC& aName, TUint aFileMode)
+/**
+Opens an existing file for reading or writing.
+
+If the file does not already exist, an error is returned.
+
+Notes:
+
+1. To close the file, use Close()
+
+2. Attempting to open a file with the read-only attribute using the EFileWrite
+ access mode results in an error.
+
+3. Attempting to open a file which is greater than or equal to 2GByte (2,147,483,648 bytes)
+ will fail with KErrTooBig
+
+4. After a file has been opened, the current write position is set to the start
+ of the file.
+ If necessary, use RFile::Seek() to move to a different position within
+ the file.
+
+@param aFs The file server session.
+@param aName The name of the file. Any path components (i.e. drive letter
+ or directory), which are not specified, are taken from
+ the session path.
+@param aMode The mode in which the file is opened. See TFileMode.
+
+@return KErrNone if successful, otherwise one of the other system-wide
+ error codes.
+
+@see TFileMode
+
+@capability Dependent If the path for aName is /Sys and aMode is neither
+ EFileShareReadersOnly nor EFileRead then Tcb capability is required.
+@capability Dependent If the path for aName is /Sys and aMode is either
+ EFileShareReadersOnly or EFileRead then Allfiles capability is required.
+@capability Dependent If the path for aName begins with /Private and does not match this process'
+ SID then AllFiles capability is required.
+@capability Dependent If the path for aName begins with /Resource and aMode is neither
+ EFileShareReadersOrWriters|EFileRead nor EFileShareReadersOnly
+ nor EFileRead then Tcb capability is required.
+
+*/
+ {
+#ifdef _DEBUG_LOGGING
+ RDebug::Print(_L("DEBUG: RFile::Open> name=%S mode=%x\n"), &aName, aFileMode);
+#endif
+
+ return DoOpen(this, aName, aFileMode, ETrue);
+ }
+
+EXPORT_C void RFile::Close()
+/**
+Closes the file.
+
+Any open files are closed when the file server session is closed.
+
+Close() is guaranteed to return, and provides no indication whether
+it completed successfully or not. When closing a file you have written to,
+you should ensure that data is committed to the file by invoking RFile::Flush()
+before closing. If Flush() completes successfully, Close() is essentially a
+no-operation.
+*/
+ {
+ FILEHANDLE(h);
+ if (h)
+ {
+ fflush(h->iHandle);
+ fclose(h->iHandle);
+ delete h;
+
+ // Make sure the handle is null
+ memset(this, 0, 4);
+ }
+ }
+
+EXPORT_C TInt RFile::Create(RFs& aFs, const TDesC& aName, TUint aFileMode)
+/**
+Creates and opens a new file for writing.
+
+If the file already exists, an error is returned.
+
+If the resulting path does not exist, then the operation cannot proceed and
+the function returns an error code.
+
+Notes:
+
+1. To close the file, use Close()
+
+2. It automatically sets the file's archive attribute.
+
+@param aFs The file server session.
+@param aName The name of the file. Any path components (i.e. drive letter
+ or directory), which are not specified, are taken from
+ the session path.
+@param aMode The mode in which the file is opened. The access mode is
+ automatically set to EFileWrite. See TFileMode.
+
+@return KErrNone if successful, otherwise one of the other system-wide
+ error codes.
+
+@see TFileMode
+
+@capability Dependent If the path in aName starts with /Sys then capability Tcb is required
+@capability Dependent If the path in aName starts with /Resource then capability Tcb is required
+@capability Dependent If the path in aName starts with /Private and does not match this process'
+ SID then AllFiles capability is required.
+
+*/
+ {
+#ifdef _DEBUG_LOGGING
+ RDebug::Print(_L("DEBUG: RFile::Create> name=%S mode=%x\n"), &aName, aFileMode);
+#endif
+
+ TUint att;
+ if (aFs.Att(aName, att) == KErrNone)
+ return KErrAlreadyExists;
+ return DoOpen(this, aName, aFileMode|EFileWrite, EFalse);
+ }
+
+EXPORT_C TInt RFile::Replace(RFs& aFs, const TDesC& aName, TUint aFileMode)
+/**
+Opens a file for writing, replacing the content of any existing file of the
+same name if it exists, or creating a new file if it does not exist.
+
+If the resulting path exists, then:
+
+- the length of an existing file with the same filename is re-set to zero
+
+- a new file is created, if no existing file with the same filename can be found.
+
+If the resulting path does not exist, then the operation cannot proceed and
+the function returns an error code.
+
+Notes:
+
+- To close the file, use Close(), defined in the base class RFsBase.
+
+- It automatically sets the file's archive attribute.
+
+@param aFs The file server session.
+@param aName The name of the file. Any path components (i.e. drive letter
+ or directory), which are not specified, are taken from
+ the session path.
+@param aMode The mode in which the file is opened. The access mode is
+ automatically set to EFileWrite. See TFileMode.
+
+@return KErrNone if successful, otherwise one of the other system-wide
+ error codes.
+
+@see TFileMode
+
+@capability Dependent If the path in aName starts with /Sys then capability Tcb is required
+@capability Dependent If the path in aName starts with /Resource then capability Tcb is required
+@capability Dependent If the path in aName starts with /Private and does not match this process'
+ SID then AllFiles capability is required.
+
+*/
+ {
+#ifdef _DEBUG_LOGGING
+ RDebug::Print(_L("DEBUG: RFile::Replace> name=%S mode=%x\n"), &aName, aFileMode);
+#endif
+
+ return DoOpen(this, aName, aFileMode|EFileWrite, EFalse);
+ }
+
+EXPORT_C TInt RFile::Temp(RFs& aFs, const TDesC& aPath, TFileName& aName, TUint aFileMode)
+/**
+Creates and opens a temporary file with a unique name for writing and reading.
+
+Notes:
+
+1. To close the file, use Close()
+
+@param aFs The file server session.
+@param aPath The directory in which the file is created.
+@param aName On return, contains the full path and file name of the file.
+ The filename is guaranteed to be unique within the directory
+ specified by aPath.
+@param aMode The mode in which the file is opened. The access mode is
+ automatically set to EFileWrite. See TFileMode.
+
+@return KErrNone if successful, otherwise one of the other system-wide
+ error codes.
+
+@see TFileMode
+
+@capability Dependent If aPath starts with /Sys then capability Tcb is required
+@capability Dependent If aPath starts with /Resource then capability Tcb is required
+@capability Dependent If aPath starts with /Private and does not match this process'
+ SID then AllFiles capability is required.
+*/
+ {
+ // Check for a valid path
+ if (aPath.Length() > 0 && aPath[aPath.Length() - 1] != '\\')
+ return KErrBadName;
+
+ // Create a temporary file name
+ TFileName name;
+ while(1)
+ {
+ name.Format(_L("%Ssymport%d.tmp"), &aPath, Math::Random());
+
+ TUint att;
+ TInt err = aFs.Att(name, att);
+ if (err == KErrNotFound)
+ break;
+ else if (err != KErrNone)
+ return err;
+ }
+
+ TInt err = Create(aFs, name, aFileMode);
+ if (err == KErrNone)
+ {
+ aName = name;
+ return KErrNone;
+ }
+ // The path couldn't be found
+ else if (err == KErrNotFound)
+ return KErrBadName;
+
+ return err;
+ }
+
+EXPORT_C TInt RFile::Read(TDes8& aDes) const
+/**
+Reads from the file at the current position.
+
+This is a synchronous function.
+
+Note that when an attempt is made to read beyond the end of the file,
+no error is returned.
+The descriptor's length is set to the number of bytes read into
+it. Therefore, when reading through a file,the end of file has been reached
+when the descriptor length, as returned by TDesC8::Length(), is zero.
+
+@param aDes Descriptor into which binary data is read. Any existing contents
+ are overwritten. On return, its length is set to the number of
+ bytes read.
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+
+@see TDesC8::Length
+*/
+ {
+ return Read(aDes, aDes.MaxLength());
+ }
+
+EXPORT_C TInt RFile::Read(TDes8& aDes, TInt aLength) const
+/**
+Reads the specified number of bytes of binary data from the file at the current position.
+
+This is a synchronous function.
+
+Note that when an attempt is made to read beyond the end of the file,
+no error is returned.
+The descriptor's length is set to the number of bytes read into
+it. Therefore, when reading through a file,the end of file has been reached
+when the descriptor length, as returned by TDesC8::Length(), is zero.
+Assuming aLength is less than the maximum length of the descriptor, the only circumstances
+in which Read() can return fewer bytes than requested, is when the end of
+file is reached or if an error occurs.
+
+@param aDes Descriptor into which binary data is read. Any existing
+ contents are overwritten. On return, its length is set to
+ the number of bytes read.
+
+@param aLength The number of bytes to be read from the file into the descriptor.
+ If an attempt is made to read more bytes than the descriptor's
+ maximum length, the function returns KErrOverflow.
+ This value must not be negative, otherwise the function
+ returns KErrArgument.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+
+#ifdef _DEBUG_LOGGING
+
+ RDebug::Print(_L("DEBUG: Read1> length=%d\n"), aLength);
+
+#endif
+
+
+ FILEHANDLE(h);
+ if (aLength > aDes.MaxLength())
+ return KErrOverflow;
+
+ // If the file has been written then you have set the position for a read to succeed
+ fseek(h->iHandle, 0, SEEK_CUR);
+
+ size_t len = fread(const_cast<TUint8*>(aDes.Ptr()), 1, aLength, h->iHandle);
+ TInt err = ferror(h->iHandle);
+ if (err != 0)
+ return mapErr(err);
+ aDes.SetLength(len);
+
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Read(TInt aPos, TDes8& aDes) const
+/**
+Reads from the file at the specified offset within the file
+
+This is a synchronous function.
+
+Note that when an attempt is made to read beyond the end of the file,
+no error is returned.
+The descriptor's length is set to the number of bytes read into it.
+Therefore, when reading through a file, the end of file has been reached
+when the descriptor length, as returned by TDesC8::Length(), is zero.
+
+@param aPos Position of first byte to be read. This is an offset from
+ the start of the file. If no position is specified, reading
+ begins at the current file position.
+ If aPos is beyond the end of the file, the function returns
+ a zero length descriptor.
+
+@param aDes The descriptor into which binary data is read. Any existing content
+ is overwritten. On return, its length is set to the number of
+ bytes read.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+
+@panic FSCLIENT 19 if aPos is negative.
+*/
+ {
+ return Read(aPos, aDes, aDes.MaxLength());
+ }
+
+EXPORT_C TInt RFile::Read(TInt aPos, TDes8& aDes, TInt aLength) const
+/**
+Reads the specified number of bytes of binary data from the file at a specified
+offset within the file.
+
+This is a synchronous function.
+
+Note that when an attempt is made to read beyond the end of the file,
+no error is returned.
+The descriptor's length is set to the number of bytes read into it.
+Therefore, when reading through a file, the end of file has been reached
+when the descriptor length, as returned by TDesC8::Length(), is zero.
+Assuming aLength is less than the maximum length of the descriptor, the only
+circumstances in which Read() can return fewer bytes than requested is when
+the end of file is reached or if an error has occurred.
+
+@param aPos Position of first byte to be read. This is an offset from
+ the start of the file. If no position is specified,
+ reading begins at the current file position.
+ If aPos is beyond the end of the file, the function returns
+ a zero length descriptor.
+
+@param aDes The descriptor into which binary data is read. Any existing
+ contents are overwritten. On return, its length is set to
+ the number of bytes read.
+@param aLength The number of bytes to read from the file into the descriptor.
+ If an attempt is made to read more bytes than the descriptor's
+ maximum length, then the function updates aStatus parameter with KErrOverflow.
+ It must not be negative otherwise the function updates aStatus with KErrArgument.
+
+@return KErrNone if successful, otherwise one of the other system-wide
+ error codes.
+
+@panic FSCLIENT 19 if aPos is negative.
+*/
+ {
+#ifdef _DEBUG_LOGGING
+
+ RDebug::Print(_L("DEBUG: Read2> length=%d\n"), aLength);
+
+#endif
+
+
+
+ FILEHANDLE(h);
+ if (aLength > aDes.MaxLength())
+ return KErrOverflow;
+
+ // Check pos doesn't go past the end of the file
+ TInt size;
+ TInt err = Size(size);
+ if (err != KErrNone)
+ return err;
+ aPos = Min(size, aPos);
+
+ if (fseek(h->iHandle, aPos, SEEK_SET) == 0)
+ {
+ size_t len = fread(const_cast<TUint8*>(aDes.Ptr()), 1, aLength, h->iHandle);
+ if (len == 0 && ferror(h->iHandle) != 0)
+ return mapErr(ferror(h->iHandle));
+ aDes.SetLength(len);
+ return KErrNone;
+ }
+ return mapErr(errno);
+ }
+
+EXPORT_C TInt RFile::Write(const TDesC8& aDes)
+/**
+Writes to the file at the current offset within the file.
+
+This is a synchronous function.
+
+NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
+
+@param aDes The descriptor from which binary data is written.
+ The function writes the entire contents of aDes to the file.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+ return Write(aDes, aDes.Length());
+ }
+
+EXPORT_C TInt RFile::Write(const TDesC8& aDes, TInt aLength)
+/**
+Writes a portion of a descriptor to the file at the current offset within
+the file.
+
+This is a synchronous function.
+
+NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
+
+@param aDes The descriptor from which binary data is written.
+@param aLength The number of bytes to be written from the descriptor.
+ This must not be greater than the length of the descriptor.
+ It must not be negative.
+
+@return KErrNone if successful; KErrArgument if aLength is negative;
+ otherwise one of the other system-wide error codes.
+
+@panic FSCLIENT 27 in debug mode, if aLength is greater than the length
+ of the descriptor aDes.
+*/
+ {
+#ifdef _DEBUG_LOGGING
+
+ RDebug::Print(_L("DEBUG: Write1> length=%d\n"), aLength);
+
+#endif
+
+
+
+ FILEHANDLE(h);
+ if (aLength < 0)
+ return KErrArgument;
+
+
+ // Trying to write to a file that hasn't been opened for write?
+
+ if (!(h->iMode&EFileWrite))
+
+ return KErrAccessDenied;
+
+
+ // If the file has been read then you have set the position for a write to succeed
+ fseek(h->iHandle, 0, SEEK_CUR);
+
+ size_t sz = fwrite(aDes.Ptr(), 1, aLength, h->iHandle);
+ if (sz != (TUint)aLength)
+ return mapErr(ferror(h->iHandle));
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Write(TInt aPos, const TDesC8& aDes)
+/**
+Writes to the file at the specified offset within the file
+
+This is a synchronous function.
+
+NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
+
+@param aPos The offset from the start of the file at which the first
+ byte is written.
+ If a position beyond the end of the file is specified, then
+ the write operation begins at the end of the file.
+ If the position has been locked, then the write fails.
+
+@param aDes The descriptor from which binary data is written. The function writes
+ the entire contents of aDes to the file.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+
+@panic FSCLIENT 19 if aPos is negative.
+*/
+ {
+ return Write(aPos, aDes, aDes.Length());
+ }
+
+EXPORT_C TInt RFile::Write(TInt aPos, const TDesC8& aDes, TInt aLength)
+/**
+Writes the specified number of bytes to the file at the specified offset within the file.
+
+This is a synchronous function.
+
+NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
+
+@param aPos The offset from the start of the file at which the first
+ byte is written.
+ If a position beyond the end of the file is specified, then
+ the write operation begins at the end of the file.
+ If the position has been locked, then the write fails.
+
+@param aDes The descriptor from which binary data is written.
+@param aLength The number of bytes to be written from aDes .
+ It must not be negative.
+
+@return KErrNone if successful; KErrArgument if aLength is negative;
+ otherwise one of the other system-wide error codes.
+
+@panic FSCLIENT 19 if aPos is negative.
+*/
+ {
+#ifdef _DEBUG_LOGGING
+
+ RDebug::Print(_L("DEBUG: Write2> length=%d\n"), aLength);
+
+#endif
+
+
+
+ FILEHANDLE(h);
+ if (aLength < 0)
+ return KErrArgument;
+
+
+ // Trying to write to a file that hasn't been opened for write?
+
+ if (!(h->iMode&EFileWrite))
+
+ return KErrAccessDenied;
+
+
+ // Check pos doesn't go past the end of the file
+ TInt size;
+ TInt err = Size(size);
+ if (err != KErrNone)
+ return err;
+ aPos = Min(size, aPos);
+
+ if (fseek(h->iHandle, aPos, SEEK_SET) == 0)
+ {
+ size_t sz = fwrite(aDes.Ptr(), 1, aLength, h->iHandle);
+ if (sz != (TUint)aDes.Length())
+ return mapErr(ferror(h->iHandle));
+ return KErrNone;
+ }
+ return mapErr(errno);
+ }
+
+EXPORT_C TInt RFile::Seek(TSeek aMode, TInt& aPos) const
+/**
+Sets the the current file position.
+
+The function can also be used to get the current file
+position without changing it. The file position is the position at which
+reading and writing takes place. The start of the file is position zero.
+
+To retrieve the current file position without changing it, specify ESeekCurrent
+for the seek mode, and zero for the offset.
+
+If the seek mode is ESeekStart, then:
+
+1. the function does not modify the aPos argument,
+
+2. the function returns an error if the offset specified is negative.
+
+If the seek mode is ESeekAddress, an error is returned if:
+
+1. the file is not in ROM,
+
+2. the offset specified is greater than the size of the file.
+
+@param aMode Seek mode. Controls the destination of the seek operation.
+@param aPos Offset from location specified in aMode. Can be negative.
+ On return contains the new file position.
+ If the seek mode is either ESeekCurrent or ESeekEnd and the offset
+ specifies a position before the start of the file
+ or beyond the end of the file, then on return, aPos is set to
+ the new file position (either the start or the end of the file).
+ If the seek mode is ESeekAddress, aPos returns the address of
+ the byte at the specified offset within the file.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+ FILEHANDLE(h);
+
+ // Get file size
+ TInt size;
+ TInt ret = Size(size);
+ if (ret != KErrNone)
+ return ret;
+
+ switch(aMode)
+ {
+ case ESeekStart:
+ {
+ // Make sure you don't seek past the end
+ ret = fseek(h->iHandle, Min(aPos, size), SEEK_SET);
+ break;
+ }
+ case ESeekCurrent:
+ {
+ // Get file position
+ if ((ret = ftell(h->iHandle)) >= 0)
+ {
+ TInt current = ret;
+ ret = 0;
+
+ // Try and move the file position
+ // fseek will move past the end of the file but RFile doesn't allow this
+ // fseek thinks it's invalid to move before the start, RFile allows this and sets file pos to zero
+ TInt request = Max(0, Min(current + aPos, size));
+ if ((ret = fseek(h->iHandle, request, SEEK_SET)) == 0)
+ aPos = request;
+ }
+ break;
+ }
+ case ESeekEnd:
+ {
+ // Try and move the file position
+ // fseek will move past the end of the file but RFile doesn't allow this
+ TInt request = Max(0, Min(size + aPos, size));
+ if ((ret = fseek(h->iHandle, request, SEEK_SET)) == 0)
+ aPos = request;
+ break;
+ }
+ default: // Applies to ESeekAddress
+ return KErrNotSupported;
+ }
+ if (ret)
+ return mapErr(errno);
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Flush()
+/**
+Commits data to the storage device and flushes internal buffers without closing
+the file.
+
+Although RFile::Close() also flushes internal buffers, it is often useful
+to call Flush() before a file is closed. This is because Close() returns no
+error information, so there is no way of telling whether the final data was
+written to the file successfully or not. Once data has been flushed, Close()
+is effectively a no-operation.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+ FILEHANDLE(h);
+
+ // Flush messes with the file pointer!
+ TInt oldpos = ftell(h->iHandle);
+ if (oldpos < 0)
+ return mapErr(errno);
+ if (fflush(h->iHandle) != 0)
+ return mapErr(errno);
+ if (fseek(h->iHandle, oldpos, SEEK_SET) != 0)
+ return mapErr(errno);
+
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Size(TInt& aSize) const
+/**
+Gets the current file size.
+
+@param aSize On return, the size of the file in bytes.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+ FILEHANDLE(h);
+
+ // Have to flush data before changing size - flush messes with the file pointer!
+ TInt oldpos = ftell(h->iHandle);
+ if (oldpos < 0)
+ return mapErr(errno);
+ if (fflush(h->iHandle) != 0)
+ return mapErr(errno);
+ if (fseek(h->iHandle, oldpos, SEEK_SET) != 0)
+ return mapErr(errno);
+
+ struct stat sb;
+ if (fstat(fileno(h->iHandle), &sb) == 0)
+ {
+ aSize = sb.st_size;
+ return KErrNone;
+ }
+
+ return mapErr(errno);
+ }
+
+EXPORT_C TInt RFile::SetSize(TInt aSize)
+/**
+Sets the file size.
+
+If the size of the file is reduced, data may be lost from
+the end of the file.
+
+Note:
+
+1. The current file position remains unchanged unless SetSize() reduces the size
+ of the file in such a way that the current file position is now beyond
+ the end of the file. In this case, the current file position is set to
+ the end of file.
+
+2. If the file was not opened for writing, an error is returned.
+
+@param aSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+
+@panic FSCLIENT 20 If aSize is negative.
+
+*/
+ {
+ FILEHANDLE(h);
+
+
+ // Trying to set size on a file that hasn't been opened for write?
+
+ if (!(h->iMode&EFileWrite))
+
+ return KErrAccessDenied;
+
+
+ // fflush messes with the file position!
+ TInt oldpos = ftell(h->iHandle);
+ if (oldpos < 0)
+ return mapErr(errno);
+ if (fflush(h->iHandle) != 0)
+ return mapErr(errno);
+ if (fseek(h->iHandle, oldpos, SEEK_SET) != 0)
+ return mapErr(errno);
+
+ // Now change the file size
+ if (ftruncate(fileno(h->iHandle), aSize) != 0)
+ return mapErr(errno);
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Att(TUint& aVal) const
+/**
+Gets the file's attributes.
+
+@param aVal A bitmask which, on return, contains the file’s attributes.
+ For more information, see KEntryAttNormal and the other
+ file/directory attributes.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+
+@see KEntryAttNormal
+*/
+ {
+ FILEHANDLE(h);
+ RFs fs;
+ return fs.Att(h->iName, aVal);
+ }
+
+EXPORT_C TInt RFile::SetAtt(TUint aSetAttMask,TUint aClearAttMask)
+/**
+Sets or clears file attributes using two bitmasks.
+
+The first mask controls which attributes are set.
+The second controls which attributes are cleared.
+
+Notes:
+
+1. The file must have been opened for writing, or an error is returned.
+
+2. A panic is raised if any attribute is specified in both bitmasks.
+
+3. An attempt to set or clear the KEntryAttDir, KEntryAttVolume or KEntryAttRemote
+ attributes have no effect.
+
+4. The new attribute values take effect when the file is flushed or closed (which
+ implies a flush).
+
+@param aSetAttMask A bitmask indicating the file attributes to be set
+@param aClearAttMask A bitmask indicating the attributes to be cleared. For
+ more information see KEntryAttNormal, and the other
+ file/directory attributes.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+
+@panic FSCLIENT 21 if the same attribute bit is set in both bitmasks.
+*/
+ {
+ FILEHANDLE(h);
+ RFs fs;
+ return fs.SetAtt(h->iName, aSetAttMask, aClearAttMask);
+ }
+
+EXPORT_C TInt RFile::Modified(TTime& aTime) const
+/**
+Gets local date and time the file was last modified, in universal time.
+
+@param aTime On return, contains the date and time the file was last modified in UTC.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+ FILEHANDLE(h);
+ RFs fs;
+ TEntry entry;
+ TInt err = fs.Entry(h->iName, entry);
+ if (err < KErrNone)
+ return err;
+ aTime = entry.iModified;
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::ChangeMode(TFileMode aNewMode)
+/**
+Switches an open file's access mode between EFileShareExclusive and EFileShareReadersOnly.
+
+This allows or disallows read-only access without having to close and re-open the file.
+
+@param aNewMode The new access mode.
+
+@return KErrNone, if successful;
+ KErrArgument, if aNewMode has any value other than the two specified;
+ KErrAccessDenied, if:
+ a) the function is called when the current file share
+ mode is EFileShareAny;
+ b) the file has multiple readers, and an attempt is made
+ to change the share mode to EFileShareExclusive;
+ c) the file has been opened for writing in EFileShareExclusive mode, and an
+ attempt is made to change the access mode to EFileShareReadersOnly.
+
+@capability Dependent If the path starts with /Resource then capability DiskAdmin is required
+
+*/
+ {
+ // Pretend it worked!
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Drive(TInt &aDriveNumber, TDriveInfo &aDriveInfo) const
+/**
+Gets information about the drive on which this file resides.
+
+@param aDriveNumber On return, the drive number.
+
+@param aDriveInfo On return, contains information describing the drive
+ and the medium mounted on it. The value of TDriveInfo::iType
+ shows whether the drive contains media.
+
+@return KErrNone, if successful, otherwise one of the other
+ system-wide error codes
+
+@see RFs::Drive
+*/
+ {
+ aDriveNumber = EDriveC;
+ aDriveInfo.iType = EMediaHardDisk;
+ aDriveInfo.iBattery = EBatNotSupported;
+ aDriveInfo.iDriveAtt = KDriveAttLocal|KDriveAttInternal;
+ aDriveInfo.iMediaAtt = 0;
+ return KErrNone;
+ }
+
+EXPORT_C TInt RFile::Rename(const TDesC& aNewName)
+/**
+Renames a file.
+
+If aNewName specifies a different directory to the one in which
+the file is currently located, then the file is moved.
+
+@param aNewName The new file name and/or directory path. No part may contain
+ wildcard characters or an error is returned.
+
+@return KErrNone if successful, otherwise one of the other system-wide error
+ codes.
+*/
+ {
+ FILEHANDLE(h);
+ TFileName name(h->iName);
+
+ // Need the file to be opened for write
+ if (!(h->iMode & EFileWrite))
+ return KErrAccessDenied;
+
+ TBuf8<KMaxFileName + 1> copyOld;
+ const char* oldName = PosixFilename(name, copyOld);
+
+ TBuf8<KMaxFileName + 1> copyNew;
+ const char* newName = PosixFilename(aNewName, copyNew);
+
+ // Remember the file position
+ TInt pos = 0;
+ TInt err = Seek(ESeekCurrent, pos);
+ if (err != KErrNone)
+ return err;
+
+ // Close the file
+ Close();
+
+ // Rename the file
+ if (rename(oldName, newName) != 0)
+ return mapErr(errno);
+
+ // Open the file again
+ RFs fs;
+ err = Open(fs, aNewName, EFileWrite);
+ if (err != KErrNone)
+ return err;
+
+ // Reposition the file pointer
+ return Seek(ESeekStart, pos);
+ }
+