symport/f32/sfsrv/cl_cli.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_cli.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <f32file.h>
       
    19 #include <e32debug.h>
       
    20 
       
    21 #include "cl_std.h"
       
    22 
       
    23 #ifdef _WIN32
       
    24 #include <cstdio>
       
    25 #include <io.h>
       
    26 #include <sys/stat.h>
       
    27 #include <string>
       
    28 #else
       
    29 #include <time.h>
       
    30 #include <sys/stat.h>
       
    31 #include <unistd.h>
       
    32 #include <errno.h>
       
    33 #include <stdio.h>
       
    34 
       
    35 #include <stdlib.h>
       
    36 #endif
       
    37 
       
    38 // ***
       
    39 // Map a Posix error to a Symbian error code
       
    40 //
       
    41 TInt mapErrSwitch(TInt aErr)
       
    42 	{
       
    43 	switch (aErr)
       
    44 		{
       
    45 	case ENOENT:
       
    46 		return KErrNotFound;
       
    47 	case EACCES:
       
    48 	case EPIPE:
       
    49 	case EROFS:
       
    50 		return KErrAccessDenied;
       
    51 	case EINVAL:
       
    52 	case EISDIR:
       
    53 	case ENOTDIR:
       
    54 		return KErrArgument;
       
    55 	case ENOTEMPTY:
       
    56 	case EBUSY:
       
    57 		return KErrInUse;
       
    58 	case EEXIST:
       
    59 		return KErrAlreadyExists;
       
    60 	case EBADF:
       
    61 		return KErrBadHandle;
       
    62 	case ENOMEM:
       
    63 		return KErrNoMemory;
       
    64 	case EFBIG:
       
    65 		return KErrTooBig;
       
    66 	default:
       
    67 		return -aErr;
       
    68 		}
       
    69 	return aErr;
       
    70 	}
       
    71 
       
    72 // ***
       
    73 // Map a Posix error to a Symbian error code
       
    74 //
       
    75 TInt mapErr(TInt aErr)
       
    76 	{
       
    77 	TInt symErr = mapErrSwitch(aErr);
       
    78 
       
    79 #ifdef _DEBUG_LOGGING
       
    80 	if (aErr != KErrNone)
       
    81 		RDebug::Print(_L("DEBUG: mapErr> %d => %d\n"), aErr, symErr);
       
    82 #endif
       
    83 	return symErr;
       
    84 	}
       
    85 
       
    86 #ifdef _WIN32
       
    87 const char KNativeSlashChar = '\\';
       
    88 #else
       
    89 const char KNativeSlashChar = '/';
       
    90 #endif
       
    91 
       
    92 // ***
       
    93 // Is the character a Symbian path separator?
       
    94 //
       
    95 TBool IsPathSep(TChar aChar)
       
    96 	{
       
    97 	return aChar == TChar('\\');
       
    98 	}
       
    99 
       
   100 // ***
       
   101 // Perform posix filename conversions
       
   102 //
       
   103 const char* PosixFilename(const TDesC &aIn, TDes8& aOut)
       
   104 	{
       
   105 	aOut.Zero();
       
   106 	for(TInt pos = 0; pos < aIn.Length(); pos++)
       
   107 		{
       
   108 		TChar c(aIn[pos]);
       
   109 
       
   110 		// Magic for using epocroot
       
   111 		if (pos == 0 && aIn.Length() >= 7 && IsPathSep(aIn[0]) && aIn.Mid(1, 6).CompareF(_L("epoc32")) == 0)
       
   112 			{
       
   113 			char* epocroot = getenv("EPOCROOT");
       
   114 			if (epocroot)
       
   115 				{
       
   116 				aOut.Append(TPtrC8(reinterpret_cast<const TUint8*>(epocroot), strlen(epocroot)));
       
   117 
       
   118 				// If the last character of EPOCROOT is not a slash then we have to add one
       
   119 				if (aOut[aOut.Length() - 1] != KNativeSlashChar)
       
   120 					aOut.Append(KNativeSlashChar);
       
   121 
       
   122 				continue;
       
   123 				}
       
   124 			}
       
   125 
       
   126 #ifndef _WIN32
       
   127 		// Drive letters ignored - go back home!
       
   128 		if (pos == 0 && aIn[1] == ':' && IsPathSep(aIn[2]))
       
   129 			{
       
   130 			char* home = getenv("HOME");
       
   131 			if (home)
       
   132 				aOut.Append(TPtrC8(reinterpret_cast<const TUint8*>(home), strlen(home)));
       
   133 			pos++;
       
   134 			continue;
       
   135 			}
       
   136 
       
   137 		// Convert backslashes to forward slashes
       
   138 		if (c == '\\')
       
   139 			{
       
   140 			aOut.Append('/');
       
   141 			continue;
       
   142 			}
       
   143 
       
   144 		// Lower case everything
       
   145 		c = c.GetLowerCase();
       
   146 #endif
       
   147 		aOut.Append(c);
       
   148 		}
       
   149 
       
   150 	const char* ret = reinterpret_cast<const char*>(aOut.PtrZ());
       
   151 #ifdef _DEBUG_LOGGING
       
   152     RDebug::Printf("DEBUG: PosixFilename> %s\n", ret);
       
   153 #endif
       
   154 	return ret;
       
   155 	}
       
   156 TBuf8<0x200> gFilenameBuf;
       
   157 const char* PosixFilename(const TDesC &aIn)
       
   158 	{
       
   159 	// Return the result
       
   160 	return PosixFilename(aIn, gFilenameBuf);
       
   161 	}
       
   162 
       
   163 EXPORT_C TBool RFs::IsValidDrive(TInt aDrive)
       
   164 /**
       
   165 Tests whether the specified drive number is valid.
       
   166 
       
   167 A valid drive number is any number between 0 and (KMaxDrives-1) inclusive,
       
   168 or the specific value KDefaultDrive (implying the session default drive).
       
   169 
       
   170 @param aDrive The drive number.
       
   171 			
       
   172 @return True if the drive is valid; false if not.				
       
   173 
       
   174 @see TDriveNumber 				
       
   175 */
       
   176 	{
       
   177 	return((aDrive>=0 && aDrive<KMaxDrives) || aDrive==KDefaultDrive);
       
   178 	}
       
   179 
       
   180 EXPORT_C TInt RFs::CharToDrive(TChar aChar,TInt& aDrive)
       
   181 /**
       
   182 Maps a drive character to a drive number.
       
   183 
       
   184 The drive character must be in the range A to Z or a to z. For example, drive A (or a)
       
   185 corresponds to zero, drive B (or b) corresponds to 1 etc. For the drive number
       
   186 enumeration, see TDriveNumber.
       
   187 
       
   188 @param aChar  The drive character.
       
   189 @param aDrive On return, contains the drive number.
       
   190 
       
   191 @return KErrNone, if successful;
       
   192         KErrArgument, if the drive character is not in the range A to Z or a to z.
       
   193         
       
   194 @see TDriveNumber        
       
   195 */
       
   196 	{
       
   197 
       
   198 	aChar.UpperCase();
       
   199 	if (aChar>='A' && aChar<='Z')
       
   200 		{
       
   201 		aDrive=(TInt)aChar-'A';
       
   202 		return(KErrNone);
       
   203 		}
       
   204 	return(KErrArgument);
       
   205 	}
       
   206 
       
   207 EXPORT_C TInt RFs::DriveToChar(TInt aDrive,TChar& aChar)
       
   208 /**
       
   209 Maps a drive number to the corresponding character.
       
   210 
       
   211 The drive number must be in the range 0 to (KMaxDrives-1). For example, drive
       
   212 number zero (EDriveA) corresponds to drive A, one (EDriveB)
       
   213 corresponds to drive B. For the drive number enumeration, see TDriveNumber.
       
   214 
       
   215 The drive number can also be KDefaultDrive, implying the default drive. In this
       
   216 case the current drive is taken and converted.
       
   217 
       
   218 @param aDrive The drive number.
       
   219 @param aChar  On return, contains the drive character.
       
   220 
       
   221 @return KErrNone, if successful;
       
   222         KErrArgument, if the drive number is invalid;
       
   223         otherwise one of the other system-wide error codes.
       
   224 */
       
   225 	{
       
   226 
       
   227 	if (aDrive==KDefaultDrive)
       
   228 		{
       
   229 
       
   230 #ifdef _WIN32
       
   231 		RFs fs;
       
   232 		TFileName path;
       
   233 		TInt r=fs.Connect();
       
   234 		if (r!=KErrNone)
       
   235 			return(r);
       
   236 		r=fs.SessionPath(path);
       
   237 		fs.Close();
       
   238 		if (r!=KErrNone)
       
   239 			return(r);
       
   240 
       
   241 		aChar=path[0];
       
   242 		return(KErrNone);
       
   243 
       
   244 #else
       
   245 
       
   246 		aChar='C';
       
   247 
       
   248 		return KErrNone;
       
   249 
       
   250 #endif
       
   251 		}
       
   252 	if (!IsValidDrive(aDrive))
       
   253 		return(KErrArgument);
       
   254 	aChar=aDrive+'A';
       
   255 	return(KErrNone);
       
   256 	}
       
   257 
       
   258 /** 
       
   259 Obtain the system drive number.
       
   260  
       
   261 The System Drive is a defined drive on the device which is:
       
   262  - Read/Writeable
       
   263  - Internal: Always available and not removable from the device
       
   264  - Non-Volatile (e.g. Flash memory, battery-backed RAM)
       
   265  - Only Accessible via Rfs (e.g. not available via USB mass storage)
       
   266      
       
   267 The System drive is utilised as:
       
   268  - Storage for Persistent settings from system and application software
       
   269  - Storage for Localisation resources
       
   270  - A Default Drive for user data
       
   271  - A Target Drive for Software installations
       
   272 
       
   273 It the system drive is not set previously (see RFs::SetSystemDrive) EDriveC is returned by default.
       
   274  
       
   275 @see RFs::GetSystemDriveChar
       
   276 @see RFs::SetSystemDrive   
       
   277 @see TDriveNumber
       
   278 @return TDriveNumber contains the drive number of the system drive.
       
   279  */
       
   280 EXPORT_C TDriveNumber RFs::GetSystemDrive()
       
   281 	{
       
   282 	return EDriveC;
       
   283 	}
       
   284 
       
   285 /**
       
   286 This is a wrapper around GetSystemDrive() function. It returns the character corresponding to the system drive.
       
   287 
       
   288 @parameter aDriveChar On return, contains the system drive character
       
   289 @return KErrNone if successful, otherwise one of the other system-wide error codes
       
   290 @see RFs::GetSystemDrive
       
   291 */
       
   292 EXPORT_C TChar RFs::GetSystemDriveChar()
       
   293 	{
       
   294 	return 'A' + GetSystemDrive();
       
   295 	}
       
   296 
       
   297 EXPORT_C TInt RFs::Connect(TInt)
       
   298 /**
       
   299 Connects a client to the file server.
       
   300 
       
   301 To end the file server session, use Close().
       
   302 
       
   303 @param aMessageSlots The number of message slots required. The default value of
       
   304 				     KFileServerDefaultMessageSlots indicates that message
       
   305 				     slots will be acquired dynamically from the system
       
   306 				     wide pool. Override this value with a fixed number, if
       
   307 				     a fixed number of slots are to be allocated to the session.
       
   308 				     If overriding, note that the number of message slots
       
   309 				     represents the number of operations, such as reads
       
   310 				     and writes, that can be outstanding at once;
       
   311 				     always remember to provide a spare slot for
       
   312 				     the cancel operation.
       
   313 
       
   314 @return KErrNone, if successful, otherwise one of the other system-wide
       
   315         error codes.
       
   316 */
       
   317 	{
       
   318 	return KErrNone;
       
   319 	}
       
   320 
       
   321 EXPORT_C TInt RFs::Drive(TDriveInfo& anInfo, TInt aDrive) const
       
   322 /**
       
   323 Gets information about a drive and the medium mounted on it.
       
   324 
       
   325 Note that Volume() can also be used to give information about the drive and
       
   326 the volume mounted on it. These two functions are separate because, while
       
   327 the characteristics of a drive cannot change, those of a
       
   328 volume can, by mounting different media, reformatting etc.
       
   329 			 
       
   330 @param anInfo On return, contains information describing the drive
       
   331 			  and the medium mounted on it. The value of TDriveInfo::iType
       
   332 			  shows whether the drive contains media.
       
   333 @param aDrive The drive for which information is requested.
       
   334               Specify KDefaultDrive for the session default drive.
       
   335 			  Specify a drive in the range EDriveA to EDriveZ for drives
       
   336 			  A to Z respectively.
       
   337 
       
   338 @return       KErrNone, if successful, otherwise one of the other
       
   339               system-wide error codes.
       
   340 			 
       
   341 @see RFs::Volume
       
   342 */
       
   343 	{
       
   344 	if (aDrive != EDriveC && aDrive != KDefaultDrive)
       
   345 		return KErrBadName;
       
   346 	
       
   347 	anInfo.iType = EMediaHardDisk;
       
   348 	anInfo.iBattery = EBatNotSupported;
       
   349 	anInfo.iDriveAtt = KDriveAttLocal|KDriveAttInternal;
       
   350 	anInfo.iMediaAtt = 0;
       
   351 	
       
   352 	return KErrNone;
       
   353 	}
       
   354 
       
   355 EXPORT_C TInt RFs::SessionPath(TDes& aPath) const
       
   356 /**
       
   357 Gets the session path.
       
   358 
       
   359 When a client connects to the file server, its session path is initialised to
       
   360 the system default path. The session path of an existing client can only be
       
   361 changed by this function.
       
   362 
       
   363 @param aPath On return, contains the session path, including a trailing
       
   364              backslash.
       
   365 
       
   366 @return KErrNone if successful, otherwise one of the other
       
   367         system-wide error codes.
       
   368 */
       
   369 	{
       
   370 
       
   371 #ifdef _DEBUG_LOGGING
       
   372 
       
   373     RDebug::Print(_L("DEBUG: SessionPath\n"), &aPath);
       
   374 
       
   375 #endif
       
   376 
       
   377 
       
   378 	TBuf8<KMaxFileName + 1> copy;
       
   379 	copy.Copy(aPath.Left(KMaxFileName));
       
   380 
       
   381 	// As the system for the current work directory
       
   382 	const char* path = reinterpret_cast<const char*>(copy.PtrZ());
       
   383 	if (getcwd(const_cast<char*>(path), copy.MaxLength() - 1) == NULL)
       
   384 		return mapErr(errno);
       
   385 	
       
   386 	// Get the length of the data
       
   387 	TInt len = strlen(path);	
       
   388 	copy.SetLength(len);
       
   389 
       
   390 	// We need one extra character of space for the backslash on the end
       
   391 	if (len == KMaxFileName)
       
   392 		return KErrOverflow;
       
   393 
       
   394 	// Make sure we use backslash rather than forward 
       
   395 	while(len--)
       
   396 		{
       
   397 		if (copy[len] == '/')
       
   398 			copy[len] = '\\';
       
   399 		}
       
   400 	
       
   401 	// Copy the data and append a back slash, as Symbian expects it
       
   402 	aPath.Copy(copy);
       
   403 	aPath.Append(TChar('\\'));
       
   404 	
       
   405 	return KErrNone;
       
   406 	}
       
   407 
       
   408 EXPORT_C TInt RFs::SetSessionPath(const TDesC& aPath)
       
   409 /**
       
   410 Sets the session path for the current file server client.
       
   411 
       
   412 When the client first connects to the file server, its session path
       
   413 is initialised to the system default path.
       
   414 
       
   415 Note that the session path is text-only. It does not cause any locking.
       
   416 Thus, although the path must be syntactically correct, its components
       
   417 do not need to be valid at the time the path is set, and any component may be
       
   418 deleted, removed or unmounted while the path is set.
       
   419 
       
   420 On TOOLS2 this function modifies the session path for ALL RFs sessions.
       
   421 
       
   422 @param aPath The new session path. Consists of a drive and path. Normally, a
       
   423              drive should be specified, but if not, the drive specified in
       
   424              the existing session path is preserved. If a file is specified,
       
   425              then the function fails and returns an error code. Therefore,
       
   426              the final component in the path must have a trailing backslash
       
   427              to indicate that it is a directory. All components of the
       
   428              path must be syntactically correct, for example, wildcard
       
   429              characters and double backslashes are not allowed in any
       
   430              part of it.
       
   431 
       
   432 @return KErrNone if successful, otherwise one of the other
       
   433         system-wide error codes.
       
   434 
       
   435 @capability Dependent If aPath is /Sys then AllFiles capability is required.
       
   436 @capability Dependent If aPath begins with /Private and does not match this process' SID
       
   437 					  then AllFiles capability is required.
       
   438 
       
   439 */
       
   440 	{
       
   441 
       
   442 #ifdef _DEBUG_LOGGING
       
   443 
       
   444     RDebug::Print(_L("DEBUG: SetSessionPath> path=%S\n"), &aPath);
       
   445 
       
   446 #endif
       
   447 
       
   448 
       
   449 	const char* name = PosixFilename(aPath);
       
   450 	if (chdir(name) != 0)
       
   451 		return mapErr(errno);
       
   452 	return KErrNone;
       
   453 	}
       
   454 
       
   455 /**
       
   456 Makes a directory.
       
   457 
       
   458 It should be a sub-directory of an existing	directory and its name should be
       
   459 unique within its parent directory, otherwise the function returns error code KErrAlreadyExists.
       
   460 				
       
   461 Note that if a filename is specified in the argument, it is	ignored.
       
   462 Therefore, there should be a trailing backslash after the final
       
   463 directory name in the argument to indicate that it is a directory, not a filename. 
       
   464 
       
   465 For example, following code will create directory "C:\\DIR1\\"
       
   466    
       
   467 @code
       
   468 fs.MkDir(_L("C:\\DIR1\\"));
       
   469 @endcode
       
   470 
       
   471 The last line in the following example will result in KErrAlreadyExists because "DIR2" doesn't have a trailing backslash, 
       
   472 therefore is considered as a file name and discarded. Directory "C:\\DIR1\\" has already been created.
       
   473 
       
   474 @code
       
   475 fs.MkDir(_L("C:\\DIR1\\"));     // shall create DIR1 in the root directory
       
   476 fs.MkDir(_L("C:\\DIR1\\DIR2")); // No trailing backslash, fails with KErrAlreadyExists
       
   477 @endcode
       
   478 
       
   479 This example will always fail because "DIR1" doesn't have a trailing backslash and discarded while the root
       
   480 directory always exists. 
       
   481 
       
   482 @code
       
   483 fs.MkDir(_L("C:\\DIR1"));  // No trailing backslash, will always fail with KErrAlreadyExists
       
   484 @endcode
       
   485 
       
   486 Note, the following case
       
   487 
       
   488 @code
       
   489 fs.MkDir(_L("C:\\example.txt\\"));	// would normally create a directory "c:\\example.txt\\" with KErrNone
       
   490 @endcode
       
   491  
       
   492 But if there is a file named "example.txt", which exists at the same location, KErrAccessDenied is returned.    
       
   493 
       
   494 Note also that because this method can return an error code (eg. because
       
   495 the disk is full) before checking whether the path already exists, it
       
   496 is not appropriate to use it just to work out whether a path exists or not.
       
   497 
       
   498 See MkDirAll(), which may also create intermediate directories.
       
   499 
       
   500 @param aPath The name of the new directory. Any path components which are
       
   501              not specified here will be taken from the session path.
       
   502 
       
   503 @return KErrNone if successful, otherwise one of the other
       
   504         system-wide error codes. Even if another error code is returned,
       
   505 		(for example, if the disk is full) it is still possible that the 
       
   506 		path may already exist.
       
   507 
       
   508 @capability Dependent If aPath is /Sys then Tcb capability is required.
       
   509 @capability Dependent If aPath begins with /Private and does not match this process' SID
       
   510 					  then AllFiles capability is required.
       
   511 @capability Dependent If aPath is /Resource then Tcb capability is required.
       
   512         
       
   513 @see RFs::MkDirAll       
       
   514 */
       
   515 EXPORT_C TInt RFs::MkDir(const TDesC& aPath)
       
   516 	{
       
   517 #ifdef _DEBUG_LOGGING
       
   518 
       
   519     RDebug::Print(_L("DEBUG: MkDir> path=%S\n"), &aPath);
       
   520 
       
   521 #endif
       
   522 
       
   523 
       
   524 
       
   525 	// Skip the file on the end
       
   526 	TInt len = aPath.Length();
       
   527 	while(len > 0 && !IsPathSep(aPath[len-1]))
       
   528 		len--;
       
   529 	TPtrC path(aPath.Left(len));
       
   530 
       
   531 	// Check if it exists already
       
   532 	TUint att;
       
   533 	if (RFs::Att(path, att) == KErrNone)
       
   534 		{
       
   535 		if (att&KEntryAttDir)
       
   536 			return KErrAlreadyExists;
       
   537 		else
       
   538 			// A file exists with the same name
       
   539 			return KErrAccessDenied;
       
   540 		}
       
   541 	const char* name = PosixFilename(path);
       
   542 
       
   543 #ifdef _WIN32
       
   544 	if (mkdir(name) != 0)
       
   545 #else
       
   546 	if (mkdir(name, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
       
   547 #endif
       
   548 		return mapErr(errno);
       
   549 	return KErrNone;
       
   550 	}
       
   551 
       
   552 /**
       
   553 Makes one or more directories.
       
   554 
       
   555 Any valid path component specified in aPath which does not already exist is
       
   556 created as a directory.
       
   557  
       
   558 Note that if a filename is specified in the argument, it is	ignored.
       
   559 Therefore, there should be a trailing backslash after the final
       
   560 directory name in the argument to indicate that it is a directory, not a
       
   561 filename.
       
   562 
       
   563 See also notes on RFs::MkDir() about trailing backslashes in directory names.
       
   564 
       
   565 Note also that because this method can return an error code (eg. because
       
   566 the disk is full) before checking whether the path already exists, it
       
   567 is not appropriate to use it just to work out whether a path exists or not.
       
   568 		
       
   569 See MkDir(), which creates only a single new directory.
       
   570 
       
   571 @param aPath The path name specifiying the directory or directories to
       
   572              create. If the function completes successfully, this path
       
   573              identifies a valid	directory. Any path components which are not
       
   574              specified here are taken from the session path.
       
   575 
       
   576 @return KErrNone if successful, otherwise one of the other
       
   577         system-wide error codes. Even if another error code is returned,
       
   578 		(for example, if the disk is full) it is still possible that the 
       
   579 		path may already exist. 
       
   580 
       
   581 
       
   582 @capability Dependent If aPath is /Sys then Tcb capability is required.
       
   583 @capability Dependent If aPath begins with /Private and does not match this process' SID
       
   584 					  then AllFiles capability is required.
       
   585 @capability Dependent If aPath is /Resource then Tcb capability is required.
       
   586 
       
   587 @see RFs::MkDir
       
   588 */
       
   589 EXPORT_C TInt RFs::MkDirAll(const TDesC& aPath)
       
   590 	{
       
   591 #ifdef _DEBUG_LOGGING
       
   592 	RDebug::Print(_L("DEBUG: MkDirAll> path=%S\n"), &aPath);
       
   593 #endif
       
   594 	
       
   595 	// Skip the file on the end
       
   596 	TInt len = aPath.Length();
       
   597 	while(len > 0 && !IsPathSep(aPath[len-1]))
       
   598 		len--;
       
   599 	TPtrC path(aPath.Left(len));
       
   600 
       
   601 	// Check if it exists already
       
   602 	TUint att;
       
   603 	if (RFs::Att(path, att) == KErrNone)
       
   604 		{
       
   605 		if (att&KEntryAttDir)
       
   606 			return KErrAlreadyExists;
       
   607 		else
       
   608 			// A file exists with the same name
       
   609 			return KErrAccessDenied;
       
   610 		}
       
   611 
       
   612 	// Skip drive letter
       
   613 	TInt start = 1;
       
   614 	if (len >= 3 && path[1] == TChar(':') && IsPathSep(path[2]))
       
   615 		{
       
   616 		start = 3;
       
   617 		}
       
   618 
       
   619 	for (TInt pos = start; pos < len; pos++)
       
   620 		{
       
   621 		if (IsPathSep(path[pos]))
       
   622 			{
       
   623 			TPtrC parent(path.Ptr(), pos + 1);
       
   624 			
       
   625 			TUint att;
       
   626 			TInt err = RFs::Att(parent, att);
       
   627 			if (err == KErrNotFound)
       
   628 				{
       
   629 				TInt err = RFs::MkDir(parent);
       
   630 #ifdef _DEBUG_LOGGING
       
   631 				RDebug::Print(_L("DEBUG: MkDirAll> parent=%S err=%d\n"), &parent, err);
       
   632 #endif
       
   633 				if (err != KErrNone)
       
   634 					return err;
       
   635 				}
       
   636 			else if (!(att & KEntryAttDir))
       
   637 				{
       
   638 				// Path element is not a directory
       
   639 				return KErrAccessDenied;
       
   640 				}
       
   641 			}
       
   642 		}
       
   643 	return KErrNone;
       
   644 	}
       
   645 
       
   646 EXPORT_C TInt RFs::RmDir(const TDesC& aPath)
       
   647 /**
       
   648 Removes a directory.
       
   649 
       
   650 The directory must be empty and cannot be the root directory. 
       
   651 
       
   652 Note that if a filename is specified in the argument, it is
       
   653 ignored. 
       
   654 
       
   655 For example, following code will result in directory "C:\\SRC\\" being removed as long as 
       
   656 it is empty, the existance of "ENTRY" will not be checked:
       
   657 
       
   658 @code
       
   659 fs.RmDir(_L("C:\\SRC\\ENTRY"));
       
   660 @endcode
       
   661 
       
   662 Similarly, following code will try to remove "C:\\SRC\\" instead of "C:\\SRC\DIR\\":
       
   663 @code
       
   664 fs.RmDir(_L("C:\\SRC\\DIR"));
       
   665 @endcode
       
   666 
       
   667 Therefore, there should be a trailing backslash after the final
       
   668 directory name in the argument to indicate that it is a directory, not a
       
   669 filename.
       
   670 
       
   671 See class CFileMan for information on deleting a
       
   672 non-empty directory and all of its contents.
       
   673 				
       
   674 @param aPath The path name of the directory to be removed. Any path	components
       
   675              which are not specified here are taken from the session path. Only
       
   676              the lowest-level directory identified is removed.
       
   677 
       
   678 @return KErrNone, if successful;
       
   679         KErrInUse, if trying to remove a non-empty directory or root directory;
       
   680         otherwise, one of the other system-wide error codes.
       
   681               
       
   682 @capability Dependent If aPath is /Sys then Tcb capability is required.
       
   683 @capability Dependent If aPath begins with /Private and does not match this process' SID
       
   684 					  then AllFiles capability is required.
       
   685 @capability Dependent If aPath is /Resource then Tcb capability is required.
       
   686 
       
   687 @see CFileMan
       
   688 */
       
   689 	{
       
   690 
       
   691 #ifdef _DEBUG_LOGGING
       
   692 
       
   693     RDebug::Print(_L("DEBUG: RmDir> path=%S\n"), &aPath);
       
   694 
       
   695 #endif
       
   696 
       
   697 
       
   698 	// Skip the file on the end
       
   699 	TInt len = aPath.Length();
       
   700 	while(len > 0 && !IsPathSep(aPath[len-1]))
       
   701 		len--;
       
   702 	TPtrC path(aPath.Left(len));
       
   703 
       
   704 	// Return error on an attempt to delete root!
       
   705 	if (len == 0 || (len <= 2 && IsPathSep(path[0])) || (len >= 3 && len < 5 && path[1] == TChar(':') && IsPathSep(path[2])))
       
   706 		return KErrInUse;
       
   707 
       
   708 	// Return an error if the directory doesn't exist or isn't a directory
       
   709 	TUint att;
       
   710 	if (RFs::Att(path, att) != KErrNone || !(att&KEntryAttDir))
       
   711 		return KErrNotFound;
       
   712 
       
   713 	const char* name = PosixFilename(path);
       
   714 	if (rmdir(name) != 0)
       
   715 		return mapErr(errno);
       
   716 	return KErrNone;
       
   717 	}
       
   718 
       
   719 EXPORT_C TInt RFs::Parse(const TDesC& aName, TParse& aParse) const
       
   720 /**
       
   721 Parses a filename specification.
       
   722 
       
   723 Parsing is done with wildcard resolution, using the session path as
       
   724 the default. You can then use TParse's getter functions to extract individual
       
   725 components of the resulting name. All the path components that are included
       
   726 in aName are put into the resulting	filename. Any components that are still
       
   727 missing are taken from the session path.
       
   728 
       
   729 Specifying:
       
   730 
       
   731 @code
       
   732 TParse fp;
       
   733 @endcode
       
   734 @code
       
   735 fs.Parse(name,fp);
       
   736 @endcode
       
   737 
       
   738 is equivalent to 
       
   739 
       
   740 @code
       
   741 TParse fp;
       
   742 @endcode
       
   743 @code
       
   744 fp.Set(name,NULL,&fs.SessionPath());
       
   745 @endcode
       
   746 
       
   747 Note that the function does not check for illegal characters, or for
       
   748 illegal path components in either of the paths specified.
       
   749 
       
   750 @param aName  The file name to be parsed, using the session path to provide
       
   751               the missing components.
       
   752 @param aParse A TParse objct that provides functions for
       
   753               extracting individual components of the resulting file name.
       
   754 
       
   755 @return KErrNone if successful, otherwise one of the other
       
   756         system-wide error codes.
       
   757 */
       
   758 	{
       
   759 	TFileName session_path;
       
   760 	TInt r = SessionPath(session_path);
       
   761 	if (r==KErrNone)
       
   762 		r = aParse.Set(aName, NULL, &session_path);
       
   763 	return r;
       
   764 	}
       
   765 
       
   766 EXPORT_C TInt RFs::Parse(const TDesC& aName,const TDesC& aRelated,TParse& aParse) const
       
   767 /**
       
   768 Parses a filename specification, specifying related file path components.
       
   769 
       
   770 Parsing is done with wildcard resolution, using the session path as
       
   771 the default. You can then use TParse's getter functions to extract individual
       
   772 components of the resulting name. All the path components that are included
       
   773 in aName are put into the resulting	filename. Any missing components are taken
       
   774 from the optional aRelated argument, which has the next order of precedence.
       
   775 Finally, any components that are still missing are taken from the session path.
       
   776 
       
   777 Specifying:
       
   778 
       
   779 @code
       
   780 TParse fp;
       
   781 @endcode
       
   782 @code
       
   783 fs.Parse(name,related,fp);
       
   784 @endcode
       
   785 
       
   786 is equivalent to 
       
   787 
       
   788 @code
       
   789 TParse fp;
       
   790 @endcode
       
   791 @code
       
   792 fp.Set(name,related,&fs.SessionPath());
       
   793 @endcode
       
   794 
       
   795 Note that the function does not check for illegal characters, or for
       
   796 illegal path components in any of the paths specified.
       
   797 
       
   798 @param aName    The file name to be parsed, using the session path and the
       
   799                 related path to provide the missing components.
       
   800 @param aRelated The related file specification.
       
   801 @param aParse   A TParse objct that provides functions for
       
   802                 extracting individual components of the resulting file name.
       
   803 
       
   804 @return KErrNone if successful, otherwise one of the other
       
   805         system-wide error codes.
       
   806 */
       
   807 	{
       
   808 	TFileName session_path;
       
   809 	TInt r = SessionPath(session_path);
       
   810 	if (r==KErrNone)
       
   811 		r = aParse.Set(aName, &aRelated, &session_path);
       
   812 	return r;
       
   813 	}
       
   814 
       
   815 EXPORT_C TInt RFs::Delete(const TDesC& aName)
       
   816 /**
       
   817 Deletes a single file.
       
   818 
       
   819 Wildcards are not allowed in either the	file name or the extension,
       
   820 otherwise an error is returned.
       
   821 
       
   822 Note that the file must be closed and must not be read-only.
       
   823 Hidden files can be deleted but system files cannot.
       
   824 
       
   825 See class CFileMan for information on deleting multiple files.
       
   826 		  
       
   827 @param aName The name of the file to be deleted. Any path components which
       
   828              are not specified here will be taken from the session path.
       
   829 
       
   830 @return KErrNone if successful, otherwise one of the other
       
   831         system-wide error codes.
       
   832 
       
   833 @capability Dependent If aName is /Sys then Tcb capability is required.
       
   834 @capability Dependent If aName begins with /Private and does not match this process' SID
       
   835 					  then AllFiles capability is required.
       
   836 @capability Dependent If aName is /Resource then Tcb capability is required.
       
   837         
       
   838 @see CFileMan        
       
   839 */
       
   840 	{
       
   841 
       
   842 #ifdef _DEBUG_LOGGING
       
   843 
       
   844     RDebug::Print(_L("DEBUG: Delete> name=%S\n"), &aName);
       
   845 
       
   846 #endif
       
   847 
       
   848 
       
   849 
       
   850 	TUint att;
       
   851 
       
   852 	TInt err = Att(aName, att);
       
   853 
       
   854 	if (err != KErrNone)
       
   855 
       
   856 		return err;
       
   857 
       
   858 
       
   859 
       
   860 	// Don't allow deletion of directories
       
   861 
       
   862 	if (att & KEntryAttDir)
       
   863 
       
   864 		return KErrAccessDenied;
       
   865 
       
   866 
       
   867 	const char* name = PosixFilename(aName);
       
   868 	if (remove(name) != 0)
       
   869 		return mapErr(errno);
       
   870 	return KErrNone;
       
   871 	}
       
   872 
       
   873 EXPORT_C TInt RFs::Rename(const TDesC& anOldName, const TDesC& aNewName)
       
   874 /**
       
   875 Renames a single file or directory.
       
   876 
       
   877 It can also be used to move a file or directory by specifying different
       
   878 destination and source directories.	If so, the destination and source
       
   879 directories must be on the same drive. If a	directory is moved, then
       
   880 the directory structure beneath it is also	moved.
       
   881 
       
   882 If a directory specified by aNewName is different from one specified
       
   883 by anOldName, then the file or directory is	moved to the new directory.
       
   884 The file or directory cannot be moved to another device by this means,
       
   885 either explicitly (by another drive	specified in the name) or implicitly
       
   886 (because the directory has been mapped to another device with SetSubst().
       
   887 
       
   888 The function fails and returns an error code in the following
       
   889 circumstances:
       
   890 
       
   891 1. If either the old or new name includes wildcards.
       
   892 
       
   893 2. If a file or directory with the new name already exists in
       
   894    the target directory. Overwriting is not permitted.
       
   895 
       
   896 3. If file anOldName does not exist, or is open.
       
   897 
       
   898 Read-only, system and hidden files may be renamed. The renamed
       
   899 file's attributes are preserved.
       
   900 
       
   901 Note that when this function is operating on directories, a	trailing backslash
       
   902 is not required after the final directory name in either anOldName or aNewName.
       
   903 
       
   904 See class CFileMan for information on renaming multiple files.
       
   905 		  				
       
   906 @param anOldName File or directory to be renamed. Any path components which are
       
   907                  not specified here will be taken from the session path.
       
   908 @param aNewName  Path specifying the new name for the file or directory and/or
       
   909 				 its new parent directory. All directories specified in this path
       
   910 				 must exist.
       
   911 				 Any path components which are not specified here will be taken
       
   912 				 from the session path.
       
   913 
       
   914 @return KErrNone if successful, otherwise one of the other
       
   915         system-wide error codes.
       
   916 
       
   917 @capability Dependent If either anOldName or aNewName is /Sys then Tcb capability is required.
       
   918 @capability Dependent If either anOldName or aNewName begins with /Private and does not match
       
   919 					  this process' SID then AllFiles capability is required.
       
   920 @capability Dependent If either anOldName or aNewName is /Resource then Tcb capability is required.
       
   921         
       
   922 @see CFileMan        
       
   923 */
       
   924 	{
       
   925 #ifdef _DEBUG_LOGGING
       
   926 
       
   927     RDebug::Print(_L("DEBUG: Rename> old=%S new=%S\n"), &anOldName, &aNewName);
       
   928 
       
   929 #endif
       
   930 
       
   931 
       
   932 
       
   933 	// Lose path separator on the end
       
   934 	TInt len = anOldName.Length();
       
   935 	while(len > 0 && IsPathSep(anOldName[len-1]))
       
   936 		len--;
       
   937 
       
   938 	TBuf8<KMaxFileName + 1> copyold;
       
   939 	const char* oldname = PosixFilename(anOldName, copyold);
       
   940 
       
   941 
       
   942 	// If new file exists already - return an error
       
   943 
       
   944 	TUint newAtt;
       
   945 
       
   946 	if (Att(aNewName, newAtt)== KErrNone)
       
   947 
       
   948 		return KErrAlreadyExists;
       
   949 
       
   950 
       
   951 	// Lose path separator on the end
       
   952 	len = aNewName.Length();
       
   953 	while(len > 0 && IsPathSep(aNewName[len-1]))
       
   954 		len--;
       
   955 
       
   956 	TBuf8<KMaxFileName + 1> copynew;
       
   957 	const char* newname = PosixFilename(aNewName, copynew);
       
   958 
       
   959 	if (rename(oldname, newname) != 0)
       
   960 		return mapErr(errno);
       
   961 	return KErrNone;
       
   962 	}
       
   963 
       
   964 EXPORT_C TInt RFs::Replace(const TDesC& anOldName, const TDesC& aNewName)
       
   965 /**
       
   966 Replaces a single file with another.
       
   967 
       
   968 This function does not support the use of wildcards. Unlike Rename(), it only
       
   969 applies to files.
       
   970 
       
   971 This function operates as follows:
       
   972 
       
   973 1. if the aNewName file does not exist, it is created.
       
   974 
       
   975 2. anOldName's contents, attributes and the date and time of its last
       
   976    modification are copied to file aNewName, overwriting any existing contents
       
   977    and attribute details.
       
   978 
       
   979 3. anOldName is deleted.
       
   980 				 
       
   981 anOldName may be hidden, read-only or a system file. However,
       
   982 neither anOldName, nor, if it exists, aNewName, can be open;
       
   983 aNewName must not be read-only.
       
   984 Both files must be on the same drive.
       
   985 
       
   986 @param anOldName The file to be replaced. Must exist and must be closed. It is
       
   987                  deleted by this function.
       
   988 @param aNewName  The file to replace anOldName. Does not need to exist, but if
       
   989                  it does exist, it must be closed. If it exists, its name
       
   990                  remains unchanged but its contents, attributes and the date
       
   991                  and time of its last modification are replaced by those
       
   992                  of anOldName.
       
   993                  If it does not exist, it will be created and is assigned
       
   994                  the contents and attributes of anOldName. Must not be followed
       
   995                  by a trailing backslash.
       
   996 
       
   997 @return KErrNone, if successful;
       
   998         KErrAccessDenied, if an attempt is made to replace a directory;
       
   999         otherwise one of the other system-wide error codes. 
       
  1000 
       
  1001 @capability Dependent If either anOldName or aNewName is /Sys then Tcb capability is required.
       
  1002 @capability Dependent If either anOldName or aNewName begins with /Private and does not match
       
  1003 					  this process' SID then AllFiles capability is required.
       
  1004 @capability Dependent If either anOldName or aNewName is /Resource then Tcb capability is required.
       
  1005 
       
  1006 */
       
  1007 	{
       
  1008 #ifdef _DEBUG_LOGGING
       
  1009 
       
  1010     RDebug::Print(_L("DEBUG: Replace> old=%S new=%S\n"), &anOldName, &aNewName);
       
  1011 
       
  1012 #endif
       
  1013 
       
  1014 
       
  1015 
       
  1016 	TInt err = RFs::Delete(aNewName);
       
  1017 	if (err<KErrNone && err!=KErrNotFound)
       
  1018 		return err;
       
  1019 	return RFs::Rename(anOldName, aNewName);
       
  1020 	}
       
  1021 
       
  1022 EXPORT_C TInt RFs::Att(const TDesC& aName, TUint& aAttValue) const
       
  1023 /**
       
  1024 Gets a file's attributes.
       
  1025 
       
  1026 @param aName The filename. Any path components which are not specified here
       
  1027              will be taken from the session path.
       
  1028 @param aVal  On return, the individual bits within the byte indicate which
       
  1029              attributes have been set. For more information see KEntryAttNormal
       
  1030 	         and the other file/directory attributes.
       
  1031 
       
  1032 @return KErrNone if successful, otherwise one of the other
       
  1033         system-wide error codes.
       
  1034 
       
  1035 @capability Dependent If aName contains /sys/ then AllFiles capability is required.
       
  1036 @capability Dependent If aName contains /Private/ and does not match
       
  1037 					  this process' SID then AllFiles capability is required.
       
  1038         
       
  1039 @see KEntryAttNormal
       
  1040 */
       
  1041 	{
       
  1042 #ifdef _DEBUG_LOGGING
       
  1043 	RDebug::Print(_L("DEBUG: Att> aName=%S\n"), &aName);
       
  1044 #endif
       
  1045 	
       
  1046 	TBuf<KMaxFileName + 1> copy;
       
  1047 	copy.Copy(aName.Left(KMaxFileName));
       
  1048 
       
  1049 	// Get rid of trailing backslash or forward slash
       
  1050 	if (copy.Length() > 0 && IsPathSep(copy[copy.Length() - 1]))
       
  1051 		copy.SetLength(copy.Length() - 1);
       
  1052 	
       
  1053 	// It seems you can't retrieve the attributes of root
       
  1054 	if (copy.Length() == 0 || (copy.Length() == 2 && copy[1] == ':'))
       
  1055 		return KErrBadName;
       
  1056 
       
  1057 	const char* name = PosixFilename(copy);
       
  1058 	
       
  1059 	struct stat sb;
       
  1060 	if(stat(name, &sb) != 0)
       
  1061 		return mapErr(errno);
       
  1062 	
       
  1063 	aAttValue = 0;
       
  1064     if (S_ISREG(sb.st_mode))
       
  1065     	aAttValue = KEntryAttNormal;
       
  1066     else if(S_ISDIR(sb.st_mode))
       
  1067     	aAttValue |= KEntryAttDir;
       
  1068 
       
  1069 	// Bit Value Specifier File          Directory
       
  1070 	// 0   1     x         executable    can search directory
       
  1071 	// 1   2     w         write access  can modify (delete/add files)
       
  1072 	// 2   4     r         read access   read access
       
  1073 
       
  1074 	// Test readonly flag - no write access
       
  1075     if (!(sb.st_mode & 0222))
       
  1076     	aAttValue |= KEntryAttReadOnly;
       
  1077     
       
  1078     return KErrNone;
       
  1079 	}
       
  1080 
       
  1081 EXPORT_C TInt RFs::SetAtt(const TDesC& aName, TUint aSetAttMask, TUint aClearAttMask)
       
  1082 /**
       
  1083 Sets or clears the attributes of a single file or directory.
       
  1084 
       
  1085 The function uses two bitmasks. The first bitmask specifies the	attributes
       
  1086 to be set; the second specifies the attributes to be cleared.
       
  1087 
       
  1088 An attempt to set or clear the KEntryAttDir, KEntryAttVolume or KEntryAttRemote
       
  1089 attributes have no effect.
       
  1090 
       
  1091 @param aName          File or directory name. Any path components which are not
       
  1092                       specified here will be taken from the session path. Must
       
  1093                       not include wildcard characters. The file must be closed.
       
  1094 @param aSetAttMask    Bitmask indicating the attributes to be set.
       
  1095 @param aClearAttMask  Bitmask indicating the attributes to be cleared. For more
       
  1096 				      information, see KEntryAttNormal and the other file or
       
  1097 				      directory attributes.
       
  1098 
       
  1099 @return KErrNone if successful, otherwise one of the other
       
  1100         system-wide error codes.
       
  1101 
       
  1102 @panic FSCLIENT 21 if any attribute appears in both bitmasks.
       
  1103 
       
  1104 
       
  1105 @capability Dependent If aName is /Sys then Tcb capability is required.
       
  1106 @capability Dependent If aName begins with /Private and does not match
       
  1107 					  this process' SID then AllFiles capability is required.
       
  1108 @capability Dependent If aName is /Resource then Tcb capability is required.
       
  1109 	
       
  1110 @see RFs::SetEntry
       
  1111 
       
  1112 */
       
  1113 	{
       
  1114 
       
  1115 #ifdef _DEBUG_LOGGING
       
  1116 
       
  1117 	RDebug::Print(_L("DEBUG: SetAtt> aName=%S set=%x clear=%x\n"), &aName, aSetAttMask, aClearAttMask);
       
  1118 
       
  1119 #endif
       
  1120 
       
  1121 
       
  1122 	const char* name = PosixFilename(aName);
       
  1123 	struct stat sb;
       
  1124 	if(stat(name, &sb) != 0)
       
  1125 		return mapErr(errno);
       
  1126 	
       
  1127 	// Clear readonly flag - write access
       
  1128     if (aClearAttMask&KEntryAttReadOnly)
       
  1129 	    sb.st_mode |= 0222;
       
  1130 
       
  1131     // Set readonly flag - no write access
       
  1132     if (aSetAttMask&KEntryAttReadOnly)
       
  1133     	sb.st_mode &= ~0222;
       
  1134     
       
  1135 	return mapErr(chmod(name, sb.st_mode));
       
  1136 	}
       
  1137 
       
  1138 EXPORT_C TInt RFs::Modified(const TDesC& aName,TTime& aTime) const
       
  1139 /**
       
  1140 Gets the last modification date and time of a file or a directory,
       
  1141 in UTC.
       
  1142 
       
  1143 If there has been no modification, the function gets the date and
       
  1144 time of the file or directory's creation.
       
  1145 
       
  1146 @param aName File or directory name.
       
  1147 @param aTime On return, contains the date and time of the file or
       
  1148              directory's last modification in universal time.
       
  1149 
       
  1150 @return KErrNone if successful, otherwise one of the other
       
  1151         system-wide error codes.
       
  1152 
       
  1153 @capability Dependent If aName contains /sys/ then AllFiles capability is required.
       
  1154 @capability Dependent If aName contains /Private/ and does not match
       
  1155 					  this process' SID then AllFiles capability is required.
       
  1156 
       
  1157 */
       
  1158 	{
       
  1159 
       
  1160 	TEntry e;
       
  1161 	TInt r=Entry(aName,e);
       
  1162 	if (r==KErrNone)
       
  1163 		aTime=e.iModified;
       
  1164 	return(r);
       
  1165 	}
       
  1166 
       
  1167 TInt ReadUid(const char* aName,TEntry& anEntry)
       
  1168 //
       
  1169 // Read the entry uid if present
       
  1170 //
       
  1171 	{
       
  1172     FILE* hFile = fopen(aName, "rb");
       
  1173     if (!hFile)
       
  1174     	return KErrGeneral;
       
  1175     
       
  1176 	//  First check to see if the first sixteen bytes form a valid UID
       
  1177 	TBuf8<sizeof(TCheckedUid)> checkedUidBuf;
       
  1178 	checkedUidBuf.SetLength(sizeof(TCheckedUid));
       
  1179 	TInt ret = fread(&checkedUidBuf[0], sizeof(TCheckedUid), 1, hFile);
       
  1180 	fclose(hFile);
       
  1181 	if (ret != 1)
       
  1182 		return KErrCorrupt;
       
  1183 	
       
  1184 	TCheckedUid checkedUid(checkedUidBuf);
       
  1185 	if(checkedUid.UidType()!=TUidType(TUid::Null(),TUid::Null(),TUid::Null()))
       
  1186 		anEntry.iType=checkedUid.UidType();
       
  1187 
       
  1188 	return KErrNone;
       
  1189 	}
       
  1190 
       
  1191 EXPORT_C TInt RFs::Entry(const TDesC& aName, TEntry& anEntry) const
       
  1192 /**
       
  1193 Gets the entry details for a file or directory.
       
  1194 
       
  1195 This information includes UID information.
       
  1196 
       
  1197 @param aName   Name of file or directory.
       
  1198 @param anEntry On return, contains the entry details for the file or directory. TEntry::iModified contains UTC date and time.
       
  1199 
       
  1200 @return KErrNone if successful, otherwise one of the other
       
  1201         system-wide error codes.
       
  1202 
       
  1203 @capability Dependent If aName contains "\\Sys\\" and includes an additional file or directory then AllFiles capability 
       
  1204 					  is required. For example, the paths "c:\\sys" and "c:\\sys\\" will always be readable, whereas
       
  1205 					  the path "c:\\sys\\abc\\" will only be readable with AllFiles capability.
       
  1206 
       
  1207 @capability Dependent If aName contains \\Private\\ and includes an additional file, or a directory which does not match
       
  1208 					  this process' SID, then AllFiles capability is required. For example, the paths "c:\\private" and 
       
  1209 					  "c:\\private\\" will always be readable, whereas the path "c:\\private\\<n>\\" will only be 
       
  1210 					  readable with AllFiles capability or if <n> matches the process' SID.
       
  1211 */
       
  1212 	{
       
  1213 
       
  1214 #ifdef _DEBUG_LOGGING
       
  1215 
       
  1216 	RDebug::Print(_L("DEBUG: Entry> aName=%S\n"), &aName);
       
  1217 
       
  1218 #endif
       
  1219 
       
  1220 
       
  1221 	TInt err = RFs::Att(aName, anEntry.iAtt);
       
  1222 	if (err < KErrNone)
       
  1223 		return err;
       
  1224 
       
  1225 	struct stat sb;
       
  1226 	TBuf<KMaxFileName + 1> copy;
       
  1227 	copy.Copy(aName.Left(KMaxFileName));
       
  1228 
       
  1229 	// Get rid of trailing backslash 
       
  1230 	if (copy.Length() > 0 && IsPathSep(copy[copy.Length() - 1]))
       
  1231 		copy.SetLength(copy.Length() - 1);
       
  1232 
       
  1233 	const char* name = PosixFilename(copy);
       
  1234 	if(stat(name, &sb) < 0)
       
  1235 		return KErrNotFound;
       
  1236 	
       
  1237 
       
  1238 	// On Symbian directories have zero size
       
  1239 	anEntry.iSize = (anEntry.iAtt&KEntryAttDir) ? 0 : sb.st_size;
       
  1240 
       
  1241     anEntry.iType = TUidType(TUid::Null(), TUid::Null(), TUid::Null());
       
  1242     ReadUid(name, anEntry);
       
  1243     
       
  1244 	struct tm *tm = gmtime(&sb.st_mtime);
       
  1245 	anEntry.iModified = TDateTime(1900 + tm->tm_year, TMonth(tm->tm_mon), tm->tm_mday - 1, tm->tm_hour, tm->tm_min, tm->tm_sec, 0);
       
  1246 
       
  1247 	// Just return the name
       
  1248 	TInt start = aName.LocateReverse('\\');
       
  1249 	if (start > 0)
       
  1250 		{
       
  1251 		if (anEntry.iAtt&KEntryAttDir)
       
  1252 			{
       
  1253 			anEntry.iName = aName.Left(start);
       
  1254 			start = anEntry.iName.LocateReverse('\\');
       
  1255 			if (start > 0)
       
  1256 				anEntry.iName = anEntry.iName.Mid(start + 1);
       
  1257 			}
       
  1258 		else
       
  1259 			anEntry.iName = aName.Mid(start + 1);
       
  1260 		}
       
  1261 	else
       
  1262 		anEntry.iName = aName;
       
  1263 	
       
  1264     return KErrNone;
       
  1265 	}
       
  1266 
       
  1267 EXPORT_C TInt RFs::SetEntry(const TDesC& aName,const TTime& aTime,TUint aSetAttMask,TUint aClearAttMask)
       
  1268 /**
       
  1269 Sets both the attributes and the last modified date and time for a file or directory.
       
  1270 
       
  1271 The function uses two bitmasks. The first bitmask determines
       
  1272 which attributes should be set. The second bitmask determines which should be cleared.
       
  1273 
       
  1274 An attempt to set or clear the KEntryAttDir, KEntryAttVolume or KEntryAttRemote
       
  1275 attributes have no effect.
       
  1276 			 
       
  1277 @param aName          File or directory name.
       
  1278 @param aTime	      New date and time. UTC date and time should be used.
       
  1279 @param aSetAttMask    Bitmask indicating which attributes are to be set.
       
  1280 @param aClearAttMask  Bitmask indicating which attributes are cleared. For more
       
  1281                       information, see KEntryAttNormal, and the other file
       
  1282                       or directory attributes.
       
  1283 
       
  1284 @return KErrNone, if successful;
       
  1285         KErrInUse, if the file is open;
       
  1286         otherwise one of the other system-wide error codes.
       
  1287 
       
  1288 @panic FSCLIENT 21 if any attribute appears in both bitmasks.        
       
  1289 
       
  1290 @capability Dependent If aName is /Sys then Tcb capability is required.
       
  1291 @capability Dependent If aName begins with /Private and does not match
       
  1292 					  this process' SID then AllFiles capability is required.
       
  1293 @capability Dependent If aName is /Resource then Tcb capability is required.
       
  1294 
       
  1295 @see KEntryAttNormal
       
  1296 @see KEntryAttDir
       
  1297 @see KEntryAttVolume
       
  1298 */
       
  1299 	{
       
  1300 	// No way to set modified date
       
  1301 	return SetAtt(aName, aSetAttMask, aClearAttMask);
       
  1302 	}
       
  1303 
       
  1304 TInt gBlockSize = 4096;
       
  1305 TInt gClusterSize = 4096;
       
  1306 EXPORT_C TInt RFs::VolumeIOParam(TInt aDriveNo, TVolumeIOParamInfo& aParamInfo) const
       
  1307 /**
       
  1308 This function queries a set of I/O parameters on the specified volume, this includes the block size of underlying media,
       
  1309 cluster size of the mounted file system and the recommended read/write buffer sizes. 
       
  1310 
       
  1311 The volume information is retuned through aParamInfo. Even if VolumeIOParam() returns successful, errors 
       
  1312 can effect the return value of each field within aParamInfo.
       
  1313 
       
  1314 @param aDrive A drive number, specifies which volume to query.
       
  1315 @param aParamInfo A TVolumeIOParamInfo containing the volume parameters.
       
  1316 
       
  1317 @return KErrNone if successful; otherwise, another system wide error code is returned.
       
  1318 */
       
  1319 	{
       
  1320 	aParamInfo.iBlockSize = gBlockSize;
       
  1321 	aParamInfo.iClusterSize = gClusterSize;
       
  1322 	aParamInfo.iRecReadBufSize = 4096;
       
  1323 	aParamInfo.iRecWriteBufSize = 4096;
       
  1324 	return KErrNone;
       
  1325 	}
       
  1326 
       
  1327 EXPORT_C TInt RFs::SetErrorCondition(TInt anError, TInt aCount)
       
  1328 	{
       
  1329 	return KErrNotSupported;
       
  1330 	}
       
  1331 
       
  1332 void Panic(TClientPanic aPanic)
       
  1333 //
       
  1334 // Panic the current client with a file server client side panic.
       
  1335 //
       
  1336 	{
       
  1337 
       
  1338 	User::Panic(_L("FSCLIENT panic"),aPanic);
       
  1339 	}