symport/f32/sfsrv/cl_file.cpp
changeset 1 0a7b44b10206
child 2 806186ab5e14
equal deleted inserted replaced
0:c55016431358 1:0a7b44b10206
       
     1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Symbian Foundation License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32\sfsrv\cl_file.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <f32file.h>
       
    19 #include <e32math.h>
       
    20 
       
    21 #include <cstdio>
       
    22 #include <errno.h>
       
    23 #include <sys/stat.h>
       
    24 #include <unistd.h>
       
    25 
       
    26 class TFileInfo
       
    27 	{
       
    28 public:
       
    29 	FILE* iHandle;
       
    30 	TFileName iName;
       
    31 	TUint iMode;
       
    32 	};
       
    33 
       
    34 #define GETFILEHANDLE(A,B) TFileInfo* A; memcpy(&A, B, 4);
       
    35 #define FILEHANDLE(A) GETFILEHANDLE(A,this);
       
    36 	
       
    37 extern TInt mapErr(TInt);
       
    38 extern const char* PosixFilename(const TDesC &aIn);
       
    39 extern const char* PosixFilename(const TDesC &aIn, TDes8& aOut);
       
    40 
       
    41 /**
       
    42 Make a duplicate of the passed file handle in the same thread.
       
    43 
       
    44 By default, any thread in the process can use the duplicated handle to access the 
       
    45 file. However, specifying EOwnerThread as the second parameter to this function, 
       
    46 means that only the creating thread can use the handle.
       
    47 
       
    48 @param	aFile	The file handle to duplicate
       
    49 @param	aType	An enumeration whose enumerators define the ownership of this 
       
    50 				handle. If not explicitly specified, EOwnerProcess is taken
       
    51 				as default.
       
    52 
       
    53 @return	one of the other system-wide error codes.
       
    54 */
       
    55 EXPORT_C TInt RFile::Duplicate(const RFile& aFile, TOwnerType aType)
       
    56 	{
       
    57 	GETFILEHANDLE(h,&aFile);
       
    58 	TFileName name(h->iName);
       
    59 	RFs fs;  // This doesn't actually get used in the Open function
       
    60 	TUint mode = h->iMode;
       
    61 
       
    62 	// Get the file position
       
    63 	TInt pos = ftell(h->iHandle);
       
    64 	if (pos < 0)
       
    65 		return mapErr(errno);
       
    66 
       
    67 	// Open the file
       
    68 	TInt err = Open(fs, name, mode);
       
    69 	if (err != KErrNone)
       
    70 		return err;
       
    71 
       
    72 	// Set the file position
       
    73 	return Seek(ESeekStart, pos); 
       
    74 	}
       
    75 
       
    76 EXPORT_C TInt RFile::Name(TDes &aName) const
       
    77 /**
       
    78 Gets the final part of a filename
       
    79 
       
    80 This is used to retrieve the name and extension of a file that has been 
       
    81 passed from one process to another using the RFile::AdoptXXX() methods.
       
    82 
       
    83 @param	aName	On return, contains the name of the file, including the name and 
       
    84 				extension but excluding the drive letter and path.
       
    85 
       
    86 @return KErrNone if successful, otherwise one of the other
       
    87         system-wide error codes.
       
    88 
       
    89 */
       
    90 	{
       
    91     FILEHANDLE(h);
       
    92     TParsePtrC ptr(h->iName);
       
    93     aName = ptr.NameAndExt();
       
    94     return KErrNone;
       
    95 	}
       
    96 
       
    97 
       
    98 EXPORT_C TInt RFile::FullName(TDes& aName) const
       
    99 /**
       
   100 Gets the full filename
       
   101 
       
   102 This is used to retrieve the full filename, including drive and path,
       
   103 of a file that has been passed from one process to another using the 
       
   104 RFile::AdoptXXX() methods.
       
   105 
       
   106 @param	aName	On return, contains the full name of the file, including drive and path.
       
   107 
       
   108 @return KErrNone if successful, otherwise one of the other
       
   109         system-wide error codes.
       
   110 
       
   111 */
       
   112 	{
       
   113     FILEHANDLE(h);
       
   114     aName = h->iName;
       
   115     return KErrNone;
       
   116 	}
       
   117 
       
   118 
       
   119 
       
   120 /*
       
   121 "r" 	Open a text file for reading
       
   122 "r+" 	Open a text file for read/write
       
   123 
       
   124 "rb" 	Open a binary file for reading
       
   125 "rb+" 	Open a binary file for read/write
       
   126 
       
   127 "w" 	Create a text file for writing
       
   128 "w+" 	Create a text file for read/write
       
   129 
       
   130 "wb" 	Create a binary file for writing
       
   131 "wb+" 	Create a binary file for read/write
       
   132 
       
   133 "a" 	Append to a text file
       
   134 "ab" 	Append to a binary file
       
   135 */
       
   136 void GetFileMode(TDes8& aBuf, TUint aFileMode, TBool aOpen)
       
   137 	{
       
   138 	if (aOpen)
       
   139 		{
       
   140 		if (aFileMode & EFileWrite)
       
   141 			// Open a binary file for read/write
       
   142 			aBuf = _L8("rb+");
       
   143 		else
       
   144 			// Open a binary file for reading
       
   145 			aBuf = _L8("rb");
       
   146 		}
       
   147 	else
       
   148 		// Create a binary file for read/write 
       
   149 		aBuf = _L8("wb+");
       
   150 	}
       
   151 
       
   152 TInt DoOpen(RFile* aFile, const TDesC &aName, TUint aFileMode, TBool aOpen)
       
   153     {
       
   154 	const char* name = PosixFilename(aName);
       
   155    
       
   156 	TFileInfo* info = new TFileInfo;
       
   157 	if (!info)
       
   158 		return KErrNoMemory;
       
   159 	
       
   160 	TBuf8<4> mode;
       
   161 	GetFileMode(mode, aFileMode, aOpen);
       
   162 	info->iHandle = fopen(name, reinterpret_cast<const char*>(mode.PtrZ()));
       
   163     
       
   164 #ifdef _DEBUG_LOGGING
       
   165     RDebug::Print(_L("DEBUG: DoOpen> file=%S id=%x\n"), &aName, info->iHandle);
       
   166 #endif
       
   167     
       
   168     if (!info->iHandle)
       
   169     	{
       
   170     	delete info;
       
   171     	return mapErr(errno);
       
   172     	}
       
   173 
       
   174 	// Symbian expects file pos at the begining
       
   175 	if (aOpen && aFileMode|EFileWrite)
       
   176 		{
       
   177 		if (fseek(info->iHandle, 0, SEEK_SET) != 0)
       
   178 			{
       
   179 			fclose(info->iHandle);
       
   180 			delete info;
       
   181 	    	return mapErr(errno);
       
   182 			}
       
   183 		}
       
   184 
       
   185     info->iName = aName;
       
   186     info->iMode = aFileMode;
       
   187     memcpy(aFile, &info, 4);
       
   188     return KErrNone;
       
   189     }
       
   190 
       
   191 EXPORT_C TInt RFile::Open(RFs& aFs, const TDesC& aName, TUint aFileMode)
       
   192 /**
       
   193 Opens an existing file for reading or writing.
       
   194 
       
   195 If the file does not already exist, an error is returned.
       
   196 
       
   197 Notes:
       
   198 
       
   199 1. To close the file, use Close()
       
   200 
       
   201 2. Attempting to open a file with the read-only attribute using the EFileWrite
       
   202    access mode results in an error.
       
   203 
       
   204 3. Attempting to open a file which is greater than or equal to 2GByte (2,147,483,648 bytes)
       
   205    will fail with KErrTooBig
       
   206 
       
   207 4. After a file has been opened, the current write position is set to the start
       
   208    of the file.
       
   209    If necessary, use RFile::Seek() to move to a different position within
       
   210    the file.
       
   211 
       
   212 @param aFs   The file server session.
       
   213 @param aName The name of the file. Any path components (i.e. drive letter
       
   214              or directory), which are not specified, are taken from
       
   215              the session path.
       
   216 @param aMode The mode in which the file is opened. See TFileMode.
       
   217 
       
   218 @return KErrNone if successful, otherwise one of the other system-wide
       
   219         error codes.
       
   220         
       
   221 @see TFileMode
       
   222 
       
   223 @capability Dependent If the path for aName is /Sys and aMode is neither
       
   224 					  EFileShareReadersOnly nor EFileRead then Tcb capability is required.
       
   225 @capability Dependent If the path for aName is /Sys and aMode is either
       
   226 					  EFileShareReadersOnly or EFileRead then Allfiles capability is required.
       
   227 @capability Dependent If the path for aName begins with /Private and does not match this process'
       
   228 					  SID then AllFiles capability is required.
       
   229 @capability Dependent If the path for aName begins with /Resource and aMode is neither
       
   230  					  EFileShareReadersOrWriters|EFileRead nor EFileShareReadersOnly 
       
   231  					  nor EFileRead then Tcb capability is required.
       
   232 
       
   233 */
       
   234     {
       
   235 #ifdef _DEBUG_LOGGING
       
   236 	RDebug::Print(_L("DEBUG: RFile::Open> name=%S mode=%x\n"), &aName, aFileMode);
       
   237 #endif
       
   238 	
       
   239     return DoOpen(this, aName, aFileMode, ETrue);
       
   240     }
       
   241 
       
   242 EXPORT_C void RFile::Close()
       
   243 /**
       
   244 Closes the file.
       
   245 
       
   246 Any open files are closed when the file server session is closed.
       
   247 
       
   248 Close() is guaranteed to return, and provides no indication whether
       
   249 it completed successfully or not. When closing a file you have written to,
       
   250 you should ensure that data is committed to the file by invoking RFile::Flush()
       
   251 before closing. If Flush() completes successfully, Close() is essentially a
       
   252 no-operation.
       
   253 */
       
   254     {
       
   255     FILEHANDLE(h);
       
   256     if (h)
       
   257     	{
       
   258     	fflush(h->iHandle);
       
   259     	fclose(h->iHandle);
       
   260     	delete h;
       
   261 
       
   262 		// Make sure the handle is null
       
   263         memset(this, 0, 4);
       
   264     	}
       
   265     }
       
   266 
       
   267 EXPORT_C TInt RFile::Create(RFs& aFs, const TDesC& aName, TUint aFileMode)
       
   268 /**
       
   269 Creates and opens a new file for writing.
       
   270 
       
   271 If the file already exists, an error is returned.
       
   272 
       
   273 If the resulting path does not exist, then the operation cannot proceed and
       
   274 the function returns an error code.
       
   275 
       
   276 Notes:
       
   277 
       
   278 1. To close the file, use Close()
       
   279 
       
   280 2. It automatically sets the file's archive attribute.
       
   281 
       
   282 @param aFs   The file server session.
       
   283 @param aName The name of the file. Any path components (i.e. drive letter
       
   284              or directory), which are not specified, are taken from
       
   285              the session path.
       
   286 @param aMode The mode in which the file is opened. The access mode is
       
   287              automatically set to EFileWrite. See TFileMode.
       
   288 
       
   289 @return KErrNone if successful, otherwise one of the other system-wide
       
   290         error codes.
       
   291         
       
   292 @see TFileMode
       
   293 
       
   294 @capability Dependent If the path in aName starts with /Sys then capability Tcb is required
       
   295 @capability Dependent If the path in aName starts with /Resource then capability Tcb is required
       
   296 @capability Dependent If the path in aName starts with /Private and does not match this process'
       
   297 					  SID then AllFiles capability is required.
       
   298 
       
   299 */
       
   300     {
       
   301 #ifdef _DEBUG_LOGGING
       
   302     RDebug::Print(_L("DEBUG: RFile::Create> name=%S mode=%x\n"), &aName, aFileMode);
       
   303 #endif
       
   304     
       
   305     TUint att;
       
   306     if (aFs.Att(aName, att) == KErrNone)
       
   307     	return KErrAlreadyExists;
       
   308     return DoOpen(this, aName, aFileMode|EFileWrite, EFalse);
       
   309     }
       
   310 
       
   311 EXPORT_C TInt RFile::Replace(RFs& aFs, const TDesC& aName, TUint aFileMode)
       
   312 /**
       
   313 Opens a file for writing, replacing the content of any existing file of the
       
   314 same name if it exists, or creating a new file if it does not exist.
       
   315 
       
   316 If the resulting path exists, then:
       
   317 
       
   318 - the length of an existing file with the same filename is re-set to zero 
       
   319 
       
   320 - a new file is created, if no existing file with the same filename can be found.
       
   321 
       
   322 If the resulting path does not exist, then the operation cannot proceed and
       
   323 the function returns an error code.
       
   324 
       
   325 Notes:
       
   326 
       
   327 - To close the file, use Close(), defined in the base class RFsBase.
       
   328 
       
   329 - It automatically sets the file's archive attribute.
       
   330 
       
   331 @param aFs   The file server session.
       
   332 @param aName The name of the file. Any path components (i.e. drive letter
       
   333              or directory), which are not specified, are taken from
       
   334              the session path.
       
   335 @param aMode The mode in which the file is opened. The access mode is
       
   336              automatically set to EFileWrite. See TFileMode.
       
   337 
       
   338 @return KErrNone if successful, otherwise one of the other system-wide
       
   339         error codes.
       
   340         
       
   341 @see TFileMode
       
   342 
       
   343 @capability Dependent If the path in aName starts with /Sys then capability Tcb is required
       
   344 @capability Dependent If the path in aName starts with /Resource then capability Tcb is required
       
   345 @capability Dependent If the path in aName starts with /Private and does not match this process'
       
   346 					  SID then AllFiles capability is required.
       
   347 
       
   348 */
       
   349     {
       
   350 #ifdef _DEBUG_LOGGING
       
   351     RDebug::Print(_L("DEBUG: RFile::Replace> name=%S mode=%x\n"), &aName, aFileMode);
       
   352 #endif
       
   353     
       
   354     return DoOpen(this, aName, aFileMode|EFileWrite, EFalse);
       
   355     }
       
   356 
       
   357 EXPORT_C TInt RFile::Temp(RFs& aFs, const TDesC& aPath, TFileName& aName, TUint aFileMode)
       
   358 /**
       
   359 Creates and opens a temporary file with a unique name for writing and reading.
       
   360 
       
   361 Notes:
       
   362 
       
   363 1. To close the file, use Close()
       
   364 
       
   365 @param aFs   The file server session.
       
   366 @param aPath The directory in which the file is created.
       
   367 @param aName On return, contains the full path and file name of the file.
       
   368              The filename is guaranteed to be unique within the directory
       
   369              specified by aPath.
       
   370 @param aMode The mode in which the file is opened. The access mode is
       
   371              automatically set to EFileWrite. See TFileMode.
       
   372 
       
   373 @return KErrNone if successful, otherwise one of the other system-wide
       
   374         error codes.
       
   375         
       
   376 @see TFileMode
       
   377 
       
   378 @capability Dependent If aPath starts with /Sys then capability Tcb is required
       
   379 @capability Dependent If aPath starts with /Resource then capability Tcb is required
       
   380 @capability Dependent If aPath starts with /Private and does not match this process'
       
   381 					  SID then AllFiles capability is required.
       
   382 */
       
   383 	{
       
   384 	// Check for a valid path
       
   385 	if (aPath.Length() > 0 && aPath[aPath.Length() - 1] != '\\')
       
   386 		return KErrBadName;
       
   387 
       
   388 	// Create a temporary file name
       
   389 	TFileName name;
       
   390 	while(1)
       
   391 		{
       
   392 		name.Format(_L("%Ssymport%d.tmp"), &aPath, Math::Random());	
       
   393 
       
   394 		TUint att;
       
   395 		TInt err = aFs.Att(name, att);
       
   396 		if (err == KErrNotFound)
       
   397 			break;
       
   398 		else if (err != KErrNone)
       
   399 			return err;
       
   400 		}
       
   401 		
       
   402 	TInt err = Create(aFs, name, aFileMode);
       
   403 	if (err == KErrNone)
       
   404 		{
       
   405 		aName = name;
       
   406 		return KErrNone;
       
   407 		}
       
   408 	// The path couldn't be found
       
   409 	else if (err == KErrNotFound)
       
   410 		return KErrBadName;
       
   411 
       
   412 	return err;
       
   413 	}
       
   414 
       
   415 EXPORT_C TInt RFile::Read(TDes8& aDes) const
       
   416 /**
       
   417 Reads from the file at the current position.
       
   418 
       
   419 This is a synchronous function.
       
   420 
       
   421 Note that when an attempt is made to read beyond the end of the file,
       
   422 no error is returned. 
       
   423 The descriptor's length is set to the number of bytes read into 
       
   424 it. Therefore, when reading through a file,the end of file has been reached 
       
   425 when the descriptor length, as returned by TDesC8::Length(), is zero.
       
   426 
       
   427 @param aDes Descriptor into which binary data is read. Any existing contents 
       
   428             are overwritten. On return, its length is set to the number of
       
   429             bytes read.
       
   430 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   431         codes.
       
   432 
       
   433 @see TDesC8::Length
       
   434 */
       
   435 	{
       
   436 	return Read(aDes, aDes.MaxLength());
       
   437 	}
       
   438 
       
   439 EXPORT_C TInt RFile::Read(TDes8& aDes, TInt aLength) const
       
   440 /**
       
   441 Reads the specified number of bytes of binary data from the file at the current position.
       
   442 
       
   443 This is a synchronous function.
       
   444 
       
   445 Note that when an attempt is made to read beyond the end of the file,
       
   446 no error is returned. 
       
   447 The descriptor's length is set to the number of bytes read into 
       
   448 it. Therefore, when reading through a file,the end of file has been reached 
       
   449 when the descriptor length, as returned by TDesC8::Length(), is zero.
       
   450 Assuming aLength is less than the maximum length of the descriptor, the only circumstances 
       
   451 in which Read() can return fewer bytes than requested, is when the end of 
       
   452 file is reached or if an error occurs.
       
   453 
       
   454 @param aDes    Descriptor into which binary data is read. Any existing
       
   455                contents are overwritten. On return, its length is set to
       
   456                the number of bytes read.
       
   457             
       
   458 @param aLength The number of bytes to be read from the file into the descriptor. 
       
   459                If an attempt is made to read more bytes than the descriptor's 
       
   460                maximum length, the function returns KErrOverflow.
       
   461                This value must not be negative, otherwise the function
       
   462                returns KErrArgument.
       
   463                
       
   464 @return KErrNone if successful, otherwise one of the other system-wide error
       
   465         codes.
       
   466 */
       
   467 	{
       
   468 
       
   469 #ifdef _DEBUG_LOGGING
       
   470 
       
   471     RDebug::Print(_L("DEBUG: Read1> length=%d\n"), aLength);
       
   472 
       
   473 #endif
       
   474 
       
   475 
       
   476     FILEHANDLE(h);
       
   477     if (aLength > aDes.MaxLength())
       
   478     	return KErrOverflow;
       
   479 
       
   480 	// If the file has been written then you have set the position for a read to succeed
       
   481 	fseek(h->iHandle, 0, SEEK_CUR);
       
   482 
       
   483     size_t len = fread(const_cast<TUint8*>(aDes.Ptr()), 1, aLength, h->iHandle);
       
   484 	TInt err = ferror(h->iHandle);
       
   485 	if (err != 0)
       
   486 		return mapErr(err);
       
   487 	aDes.SetLength(len);
       
   488 		
       
   489     return KErrNone;
       
   490 	}
       
   491 
       
   492 EXPORT_C TInt RFile::Read(TInt aPos, TDes8& aDes) const
       
   493 /**
       
   494 Reads from the file at the specified offset within the file
       
   495 
       
   496 This is a synchronous function.
       
   497 
       
   498 Note that when an attempt is made to read beyond the end of the file,
       
   499 no error is returned. 
       
   500 The descriptor's length is set to the number of bytes read into it.
       
   501 Therefore, when reading through a file, the end of file has been reached 
       
   502 when the descriptor length, as returned by TDesC8::Length(), is zero.
       
   503 
       
   504 @param aPos Position of first byte to be read.  This is an offset from
       
   505             the start of the file. If no position is specified, reading
       
   506             begins at the current file position. 
       
   507             If aPos is beyond the end of the file, the function returns
       
   508             a zero length descriptor.
       
   509             
       
   510 @param aDes The descriptor into which binary data is read. Any existing content
       
   511             is overwritten. On return, its length is set to the number of
       
   512             bytes read.
       
   513             
       
   514 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   515         codes.
       
   516 
       
   517 @panic FSCLIENT 19 if aPos is negative.        
       
   518 */
       
   519 	{
       
   520     return Read(aPos, aDes, aDes.MaxLength());
       
   521 	}
       
   522 
       
   523 EXPORT_C TInt RFile::Read(TInt aPos, TDes8& aDes, TInt aLength) const
       
   524 /**
       
   525 Reads the specified number of bytes of binary data from the file at a specified 
       
   526 offset within the file.
       
   527 
       
   528 This is a synchronous function.
       
   529 
       
   530 Note that when an attempt is made to read beyond the end of the file,
       
   531 no error is returned. 
       
   532 The descriptor's length is set to the number of bytes read into it.
       
   533 Therefore, when reading through a file, the end of file has been reached 
       
   534 when the descriptor length, as returned by TDesC8::Length(), is zero.
       
   535 Assuming aLength is less than the maximum length of the descriptor, the only
       
   536 circumstances in which Read() can return fewer bytes than requested is when
       
   537 the end of file is reached or if an error has occurred.
       
   538 
       
   539 @param aPos    Position of first byte to be read. This is an offset from
       
   540                the start of the file. If no position is specified, 
       
   541                reading begins at the current file position.
       
   542                If aPos is beyond the end of the file, the function returns
       
   543                a zero length descriptor.
       
   544                
       
   545 @param aDes    The descriptor into which binary data is read. Any existing
       
   546                contents are overwritten. On return, its length is set to
       
   547                the number of bytes read.
       
   548 @param aLength The number of bytes to read from the file into the descriptor. 
       
   549                If an attempt is made to read more bytes than the descriptor's
       
   550                maximum length, then the function updates aStatus parameter with KErrOverflow.
       
   551                It must not be negative otherwise the function updates aStatus with KErrArgument.
       
   552                
       
   553 @return KErrNone if successful, otherwise one of the other system-wide
       
   554         error codes.
       
   555 
       
   556 @panic FSCLIENT 19 if aPos is negative.        
       
   557 */
       
   558 	{
       
   559 #ifdef _DEBUG_LOGGING
       
   560 
       
   561     RDebug::Print(_L("DEBUG: Read2> length=%d\n"), aLength);
       
   562 
       
   563 #endif
       
   564 
       
   565 
       
   566 
       
   567 	FILEHANDLE(h);
       
   568     if (aLength > aDes.MaxLength())
       
   569     	return KErrOverflow;
       
   570 
       
   571 	// Check pos doesn't go past the end of the file
       
   572 	TInt size;
       
   573 	TInt err = Size(size);
       
   574 	if (err != KErrNone)
       
   575 		return err;
       
   576 	aPos = Min(size, aPos);
       
   577 
       
   578     if (fseek(h->iHandle, aPos, SEEK_SET) == 0)
       
   579     	{
       
   580     	size_t len = fread(const_cast<TUint8*>(aDes.Ptr()), 1, aLength, h->iHandle);
       
   581     	if (len == 0 && ferror(h->iHandle) != 0)
       
   582     		return mapErr(ferror(h->iHandle));
       
   583         aDes.SetLength(len);
       
   584         return KErrNone;
       
   585     	}
       
   586     return mapErr(errno);
       
   587 	}
       
   588 
       
   589 EXPORT_C TInt RFile::Write(const TDesC8& aDes)
       
   590 /**
       
   591 Writes to the file at the current offset within the file.
       
   592 
       
   593 This is a synchronous function.
       
   594 
       
   595 NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
       
   596 
       
   597 @param aDes The descriptor from which binary data is written.
       
   598             The function writes the entire contents of aDes to the file.
       
   599 
       
   600 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   601         codes.
       
   602 */
       
   603 	{
       
   604     return Write(aDes, aDes.Length());
       
   605 	}
       
   606 
       
   607 EXPORT_C TInt RFile::Write(const TDesC8& aDes, TInt aLength)
       
   608 /**
       
   609 Writes a portion of a descriptor to the file at the current offset within
       
   610 the file.
       
   611 
       
   612 This is a synchronous function.
       
   613 
       
   614 NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
       
   615 
       
   616 @param aDes    The descriptor from which binary data is written.
       
   617 @param aLength The number of bytes to be written from the descriptor.
       
   618                This must not be greater than the length of the descriptor.
       
   619                It must not be negative.
       
   620 
       
   621 @return KErrNone if successful; KErrArgument if aLength is negative;
       
   622 		otherwise one of the other system-wide error codes.
       
   623         
       
   624 @panic FSCLIENT 27 in debug mode, if aLength is greater than the length
       
   625        of the descriptor aDes.  
       
   626 */
       
   627     {
       
   628 #ifdef _DEBUG_LOGGING
       
   629 
       
   630     RDebug::Print(_L("DEBUG: Write1> length=%d\n"), aLength);
       
   631 
       
   632 #endif
       
   633 
       
   634 
       
   635 
       
   636     FILEHANDLE(h);
       
   637     if (aLength < 0)
       
   638     	return KErrArgument;
       
   639 
       
   640 
       
   641 	// Trying to write to a file that hasn't been opened for write?
       
   642 
       
   643 	if (!(h->iMode&EFileWrite))
       
   644 
       
   645 		return KErrAccessDenied;
       
   646 
       
   647 
       
   648 	// If the file has been read then you have set the position for a write to succeed
       
   649 	fseek(h->iHandle, 0, SEEK_CUR);
       
   650 
       
   651     size_t sz = fwrite(aDes.Ptr(), 1, aLength, h->iHandle);
       
   652 	if (sz != (TUint)aLength)
       
   653 		return mapErr(ferror(h->iHandle));
       
   654     return KErrNone;
       
   655     }
       
   656 
       
   657 EXPORT_C TInt RFile::Write(TInt aPos, const TDesC8& aDes)
       
   658 /**
       
   659 Writes to the file at the specified offset within the file
       
   660 
       
   661 This is a synchronous function.
       
   662 
       
   663 NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
       
   664 
       
   665 @param aPos The offset from the start of the file at which the first
       
   666             byte is written. 
       
   667             If a position beyond the end of the file is specified, then
       
   668             the write operation begins at the end of the file.
       
   669             If the position has been locked, then the write fails.
       
   670             
       
   671 @param aDes The descriptor from which binary data is written. The function writes 
       
   672             the entire contents of aDes to the file.
       
   673             
       
   674 @return KErrNone if successful, otherwise one of the other system-wide error
       
   675         codes.
       
   676 
       
   677 @panic FSCLIENT 19 if aPos is negative.                       
       
   678 */
       
   679 	{
       
   680     return Write(aPos, aDes, aDes.Length());
       
   681 	}
       
   682 
       
   683 EXPORT_C TInt RFile::Write(TInt aPos, const TDesC8& aDes, TInt aLength)
       
   684 /**
       
   685 Writes the specified number of bytes to the file at the specified offset within the file.
       
   686 
       
   687 This is a synchronous function.
       
   688 
       
   689 NB Attempting to extend the file to 2 GByte or greater will fail with KErrTooBig
       
   690 
       
   691 @param aPos    The offset from the start of the file at which the first
       
   692                byte is written. 
       
   693                If a position beyond the end of the file is specified, then
       
   694                the write operation begins at the end of the file.
       
   695                If the position has been locked, then the write fails.
       
   696                              
       
   697 @param aDes    The descriptor from which binary data is written.
       
   698 @param aLength The number of bytes to be written from aDes .
       
   699 			   It must not be negative.
       
   700 
       
   701 @return KErrNone if successful; KErrArgument if aLength is negative;
       
   702 		otherwise one of the other system-wide error codes.
       
   703         
       
   704 @panic FSCLIENT 19 if aPos is negative.                       
       
   705 */
       
   706     {
       
   707 #ifdef _DEBUG_LOGGING
       
   708 
       
   709     RDebug::Print(_L("DEBUG: Write2> length=%d\n"), aLength);
       
   710 
       
   711 #endif
       
   712 
       
   713 
       
   714 
       
   715     FILEHANDLE(h);
       
   716     if (aLength < 0)
       
   717     	return KErrArgument;
       
   718 
       
   719 
       
   720 	// Trying to write to a file that hasn't been opened for write?
       
   721 
       
   722 	if (!(h->iMode&EFileWrite))
       
   723 
       
   724 		return KErrAccessDenied;
       
   725 
       
   726 
       
   727 	// Check pos doesn't go past the end of the file
       
   728 	TInt size;
       
   729 	TInt err = Size(size);
       
   730 	if (err != KErrNone)
       
   731 		return err;
       
   732 	aPos = Min(size, aPos);
       
   733 
       
   734     if (fseek(h->iHandle, aPos, SEEK_SET) == 0)
       
   735     	{
       
   736     	size_t sz = fwrite(aDes.Ptr(), 1, aLength, h->iHandle);
       
   737     	if (sz != (TUint)aDes.Length())
       
   738     		return mapErr(ferror(h->iHandle));
       
   739     	return KErrNone;
       
   740     	}
       
   741     return mapErr(errno);
       
   742 	}
       
   743 
       
   744 EXPORT_C TInt RFile::Seek(TSeek aMode, TInt& aPos) const
       
   745 /**
       
   746 Sets the the current file position.
       
   747 
       
   748 The function can also be used to get the current file 
       
   749 position without changing it. The file position is the position at which
       
   750 reading and writing takes place. The start of the file is position zero.
       
   751 
       
   752 To retrieve the current file position without changing it, specify ESeekCurrent 
       
   753 for the seek mode, and zero for the offset.
       
   754 
       
   755 If the seek mode is ESeekStart, then:
       
   756 
       
   757 1. the function does not modify the aPos argument,
       
   758 
       
   759 2. the function returns an error if the offset specified is negative.
       
   760 
       
   761 If the seek mode is ESeekAddress, an error is returned if:
       
   762 
       
   763 1. the file is not in ROM, 
       
   764 
       
   765 2. the offset specified is greater than the size of the file.
       
   766 
       
   767 @param aMode Seek mode. Controls the destination of the seek operation.
       
   768 @param aPos  Offset from location specified in aMode. Can be negative.
       
   769              On return contains the new file position.
       
   770              If the seek mode is either ESeekCurrent or ESeekEnd and the offset
       
   771              specifies a position before the start of the file 
       
   772              or beyond the end of the file, then on return, aPos is set to
       
   773              the new file position (either the start or the end of the file).
       
   774              If the seek mode is ESeekAddress, aPos returns the address of
       
   775              the byte at the specified offset within the file.
       
   776 
       
   777 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   778         codes.
       
   779 */
       
   780 	{
       
   781 	FILEHANDLE(h);
       
   782 	
       
   783 	// Get file size
       
   784 	TInt size;
       
   785 	TInt ret = Size(size);
       
   786 	if (ret != KErrNone)
       
   787 		return ret;
       
   788 
       
   789 	switch(aMode)
       
   790 		{
       
   791 		case ESeekStart:
       
   792 			{			
       
   793 			// Make sure you don't seek past the end
       
   794 			ret = fseek(h->iHandle, Min(aPos, size), SEEK_SET);
       
   795 			break;
       
   796 			}
       
   797 		case ESeekCurrent:
       
   798 			{
       
   799 			// Get file position
       
   800 			if ((ret = ftell(h->iHandle)) >= 0)
       
   801 				{
       
   802 				TInt current = ret;
       
   803 				ret = 0;
       
   804 
       
   805 				// Try and move the file position
       
   806 				// fseek will move past the end of the file but RFile doesn't allow this
       
   807 				// fseek thinks it's invalid to move before the start, RFile allows this and sets file pos to zero
       
   808 				TInt request = Max(0, Min(current + aPos, size));
       
   809 				if ((ret = fseek(h->iHandle, request, SEEK_SET)) == 0)
       
   810 					aPos = request;
       
   811 				}
       
   812 			break;
       
   813 			}
       
   814 		case ESeekEnd:
       
   815 			{
       
   816 			// Try and move the file position
       
   817 			// fseek will move past the end of the file but RFile doesn't allow this
       
   818 			TInt request = Max(0, Min(size + aPos, size));
       
   819 			if ((ret = fseek(h->iHandle, request, SEEK_SET)) == 0)
       
   820 				aPos = request;
       
   821 			break;
       
   822 			}
       
   823 		default: // Applies to ESeekAddress
       
   824 			return KErrNotSupported;
       
   825 		}
       
   826 	if (ret)
       
   827 		return mapErr(errno);
       
   828 	return KErrNone;
       
   829 	}
       
   830 
       
   831 EXPORT_C TInt RFile::Flush()
       
   832 /**
       
   833 Commits data to the storage device and flushes internal buffers without closing 
       
   834 the file.
       
   835 
       
   836 Although RFile::Close() also flushes internal buffers, it is often useful 
       
   837 to call Flush() before a file is closed. This is because Close() returns no 
       
   838 error information, so there is no way of telling whether the final data was 
       
   839 written to the file successfully or not. Once data has been flushed, Close() 
       
   840 is effectively a no-operation.
       
   841 
       
   842 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   843         codes.
       
   844 */
       
   845     {
       
   846     FILEHANDLE(h);
       
   847 
       
   848 	// Flush messes with the file pointer!
       
   849     TInt oldpos = ftell(h->iHandle);
       
   850 	if (oldpos < 0)
       
   851 		return mapErr(errno);
       
   852     if (fflush(h->iHandle) != 0)
       
   853     	return mapErr(errno);
       
   854     if (fseek(h->iHandle, oldpos, SEEK_SET) != 0)
       
   855 		return mapErr(errno);
       
   856 
       
   857 	return KErrNone;
       
   858     }
       
   859 
       
   860 EXPORT_C TInt RFile::Size(TInt& aSize) const
       
   861 /**
       
   862 Gets the current file size.
       
   863 
       
   864 @param aSize On return, the size of the file in bytes.
       
   865 
       
   866 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   867         codes.
       
   868 */
       
   869 	{
       
   870     FILEHANDLE(h);
       
   871     
       
   872 	// Have to flush data before changing size - flush messes with the file pointer!
       
   873     TInt oldpos = ftell(h->iHandle);
       
   874 	if (oldpos < 0)
       
   875 		return mapErr(errno);
       
   876     if (fflush(h->iHandle) != 0)
       
   877     	return mapErr(errno);
       
   878     if (fseek(h->iHandle, oldpos, SEEK_SET) != 0)
       
   879     	return mapErr(errno);
       
   880 	
       
   881     struct stat sb;
       
   882     if (fstat(fileno(h->iHandle), &sb) == 0)
       
   883     	{
       
   884     	aSize = sb.st_size;
       
   885     	return KErrNone;
       
   886     	}
       
   887 
       
   888     return mapErr(errno);
       
   889 	}
       
   890 
       
   891 EXPORT_C TInt RFile::SetSize(TInt aSize)
       
   892 /**
       
   893 Sets the file size.
       
   894 
       
   895 If the size of the file is reduced, data may be lost from 
       
   896 the end of the file.
       
   897 
       
   898 Note:
       
   899 
       
   900 1. The current file position remains unchanged unless SetSize() reduces the size 
       
   901    of the file in such a way that the current file position is now beyond
       
   902    the end of the file. In this case, the current file position is set to
       
   903    the end of file. 
       
   904 
       
   905 2. If the file was not opened for writing, an error is returned.
       
   906 
       
   907 @param aSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
       
   908 
       
   909 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   910         codes.
       
   911 
       
   912 @panic FSCLIENT 20 If aSize is negative.
       
   913 
       
   914 */
       
   915 	{
       
   916 	FILEHANDLE(h);
       
   917 
       
   918 
       
   919 	// Trying to set size on a file that hasn't been opened for write?
       
   920 
       
   921 	if (!(h->iMode&EFileWrite))
       
   922 
       
   923 		return KErrAccessDenied;
       
   924 
       
   925 
       
   926     // fflush messes with the file position!
       
   927     TInt oldpos = ftell(h->iHandle);
       
   928 	if (oldpos < 0)
       
   929 		return mapErr(errno);
       
   930     if (fflush(h->iHandle) != 0)
       
   931     	return mapErr(errno);
       
   932     if (fseek(h->iHandle, oldpos, SEEK_SET) != 0)
       
   933     	return mapErr(errno);
       
   934     
       
   935 	// Now change the file size
       
   936 	if (ftruncate(fileno(h->iHandle), aSize) != 0)
       
   937 		return mapErr(errno);
       
   938 	return KErrNone;
       
   939 	}
       
   940 
       
   941 EXPORT_C TInt RFile::Att(TUint& aVal) const
       
   942 /**
       
   943 Gets the file's attributes.
       
   944 
       
   945 @param aVal A bitmask which, on return, contains the file’s attributes.
       
   946             For more information, see KEntryAttNormal and the other
       
   947             file/directory attributes.    
       
   948 
       
   949 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   950         codes.
       
   951         
       
   952 @see KEntryAttNormal        
       
   953 */
       
   954 	{
       
   955 	FILEHANDLE(h);
       
   956 	RFs fs;
       
   957 	return fs.Att(h->iName, aVal);
       
   958 	}
       
   959 
       
   960 EXPORT_C TInt RFile::SetAtt(TUint aSetAttMask,TUint aClearAttMask)
       
   961 /**
       
   962 Sets or clears file attributes using two bitmasks.
       
   963 
       
   964 The first mask controls which attributes are set.
       
   965 The second controls which attributes are cleared.
       
   966 
       
   967 Notes:
       
   968 
       
   969 1. The file must have been opened for writing, or an error is returned.
       
   970 
       
   971 2. A panic is raised if any attribute is specified in both bitmasks.
       
   972 
       
   973 3. An attempt to set or clear the KEntryAttDir, KEntryAttVolume or KEntryAttRemote
       
   974    attributes have no effect.
       
   975 
       
   976 4. The new attribute values take effect when the file is flushed or closed (which 
       
   977    implies a flush).
       
   978 
       
   979 @param aSetAttMask   A bitmask indicating the file attributes to be set
       
   980 @param aClearAttMask A bitmask indicating the attributes to be cleared. For 
       
   981                      more information see KEntryAttNormal, and the other
       
   982                      file/directory attributes.
       
   983                      
       
   984 @return KErrNone if successful, otherwise one of the other system-wide error 
       
   985         codes.
       
   986         
       
   987 @panic FSCLIENT 21 if the same attribute bit is set in both bitmasks.
       
   988 */
       
   989 	{
       
   990 	FILEHANDLE(h);
       
   991 	RFs fs;
       
   992 	return fs.SetAtt(h->iName, aSetAttMask, aClearAttMask);
       
   993 	}
       
   994 
       
   995 EXPORT_C TInt RFile::Modified(TTime& aTime) const
       
   996 /**
       
   997 Gets local date and time the file was last modified, in universal time.
       
   998 
       
   999 @param aTime On return, contains the date and time the file was last modified in UTC.
       
  1000 
       
  1001 @return KErrNone if successful, otherwise one of the other system-wide error 
       
  1002         codes.
       
  1003 */
       
  1004 	{
       
  1005 	FILEHANDLE(h);
       
  1006 	RFs fs;
       
  1007 	TEntry entry;
       
  1008 	TInt err = fs.Entry(h->iName, entry);
       
  1009 	if (err < KErrNone)
       
  1010 		return err;
       
  1011 	aTime = entry.iModified;
       
  1012 	return KErrNone;
       
  1013 	}
       
  1014 
       
  1015 EXPORT_C TInt RFile::ChangeMode(TFileMode aNewMode)
       
  1016 /**
       
  1017 Switches an open file's access mode between EFileShareExclusive and EFileShareReadersOnly.
       
  1018 
       
  1019 This allows or disallows read-only access without having to close and re-open the file.
       
  1020 
       
  1021 @param aNewMode The new access mode.
       
  1022 
       
  1023 @return KErrNone, if successful;
       
  1024         KErrArgument, if aNewMode has any value other than the two specified;
       
  1025         KErrAccessDenied, if:
       
  1026         a) the function is called when the current file share
       
  1027         mode is EFileShareAny;
       
  1028         b) the file has multiple readers, and an attempt is made
       
  1029         to change the share mode to EFileShareExclusive; 
       
  1030         c) the file has been opened for writing in EFileShareExclusive mode, and an 
       
  1031         attempt is made to change the access mode to EFileShareReadersOnly.
       
  1032 
       
  1033 @capability Dependent If the path starts with /Resource then capability DiskAdmin is required
       
  1034 
       
  1035 */
       
  1036 	{
       
  1037 	// Pretend it worked!
       
  1038 	return KErrNone;
       
  1039 	}
       
  1040 
       
  1041 EXPORT_C TInt RFile::Drive(TInt &aDriveNumber, TDriveInfo &aDriveInfo) const
       
  1042 /**
       
  1043 Gets information about the drive on which this file resides.
       
  1044  
       
  1045 @param aDriveNumber On return, the drive number.
       
  1046 
       
  1047 @param aDriveInfo   On return, contains information describing the drive
       
  1048                     and the medium mounted on it. The value of TDriveInfo::iType
       
  1049                     shows whether the drive contains media.
       
  1050 
       
  1051 @return       KErrNone, if successful, otherwise one of the other
       
  1052               system-wide error codes
       
  1053               
       
  1054 @see RFs::Drive
       
  1055 */
       
  1056 	{
       
  1057 	aDriveNumber = EDriveC;
       
  1058 	aDriveInfo.iType = EMediaHardDisk;
       
  1059 	aDriveInfo.iBattery = EBatNotSupported;
       
  1060 	aDriveInfo.iDriveAtt = KDriveAttLocal|KDriveAttInternal;
       
  1061 	aDriveInfo.iMediaAtt = 0;
       
  1062 	return KErrNone;
       
  1063 	}
       
  1064 
       
  1065 EXPORT_C TInt RFile::Rename(const TDesC& aNewName)
       
  1066 /**
       
  1067 Renames a file.
       
  1068 
       
  1069 If aNewName specifies a different directory to the one in which 
       
  1070 the file is currently located, then the file is moved.
       
  1071 
       
  1072 @param aNewName The new file name and/or directory path. No part may contain 
       
  1073                 wildcard characters or an error is returned.
       
  1074                 
       
  1075 @return KErrNone if successful, otherwise one of the other system-wide error 
       
  1076         codes.
       
  1077 */
       
  1078 	{
       
  1079 	FILEHANDLE(h);
       
  1080 	TFileName name(h->iName);
       
  1081 	
       
  1082 	// Need the file to be opened for write
       
  1083 	if (!(h->iMode & EFileWrite))
       
  1084 		return KErrAccessDenied;
       
  1085 
       
  1086 	TBuf8<KMaxFileName + 1> copyOld;
       
  1087 	const char* oldName = PosixFilename(name, copyOld);
       
  1088 	
       
  1089 	TBuf8<KMaxFileName + 1> copyNew;
       
  1090 	const char* newName = PosixFilename(aNewName, copyNew);
       
  1091 	
       
  1092 	// Remember the file position
       
  1093 	TInt pos = 0;
       
  1094 	TInt err = Seek(ESeekCurrent, pos);
       
  1095 	if (err != KErrNone)
       
  1096 		return err;
       
  1097 
       
  1098 	// Close the file
       
  1099 	Close();
       
  1100 	
       
  1101 	// Rename the file
       
  1102 	if (rename(oldName, newName) != 0)
       
  1103 		return mapErr(errno);
       
  1104 	
       
  1105 	// Open the file again
       
  1106 	RFs fs;
       
  1107 	err = Open(fs, aNewName, EFileWrite);
       
  1108 	if (err != KErrNone)
       
  1109 		return err;
       
  1110 
       
  1111 	// Reposition the file pointer
       
  1112 	return Seek(ESeekStart, pos);
       
  1113 	}
       
  1114