os/kernelhwsrv/userlibandfileserver/fileserver/sfsrv/cl_fman.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include "cl_std.h"
sl@0
    17
sl@0
    18
#define RETURNIFERROR(a,b,t)  					\
sl@0
    19
	{											\
sl@0
    20
	if ((a=b)!=KErrNone)						\
sl@0
    21
		{										\
sl@0
    22
		if(iStatus)								\
sl@0
    23
			User::RequestComplete(iStatus,a);	\
sl@0
    24
		TInt _t = t;							\
sl@0
    25
		if (_t)	{TRACE1(UTF::EBorder, t, MODULEUID, a);}	\
sl@0
    26
		return(a);								\
sl@0
    27
		}										\
sl@0
    28
	}
sl@0
    29
sl@0
    30
#define RETURNIFERRORD(a,b,t)  		 			\
sl@0
    31
	TInt a; 									\
sl@0
    32
	RETURNIFERROR(a,b,t)
sl@0
    33
sl@0
    34
const TUint KRecurseFlag	=	0x40000000;
sl@0
    35
const TUint KScanDownFlag	=	0x20000000;
sl@0
    36
const TUint KFManBusyFlag	=	0x10000000;
sl@0
    37
const TUint KOverWriteFlag	=	0x08000000;
sl@0
    38
const TUint KMoveRenameFlag	=	0x04000000;
sl@0
    39
const TUint KCopyFromHandle	=	0x00000001;
sl@0
    40
sl@0
    41
const TInt KPathIncGran=32;
sl@0
    42
sl@0
    43
const TUint KMovingFilesMask = KEntryAttMatchExclude | KEntryAttDir;
sl@0
    44
sl@0
    45
TInt ShrinkNames(RFs& aFs, TFileName& aParent, TFileName& aItem, TBool aAppend);
sl@0
    46
sl@0
    47
LOCAL_C HBufC8* AllocateBuffer(TInt64 aLength)
sl@0
    48
	{
sl@0
    49
const TInt KBigBufSize = 512 * 1024;
sl@0
    50
const TInt KMediumBufSize = 32 * 1024;
sl@0
    51
const TInt KSmallBufSize = 4 * 1024;
sl@0
    52
	// Min result shall be of TInt size
sl@0
    53
	// Hence to suppress warning
sl@0
    54
	TInt big = (TInt)(Min(aLength,(TInt64)KBigBufSize));
sl@0
    55
	HBufC8* bufPtr=HBufC8::New(big);
sl@0
    56
	if (bufPtr==NULL)
sl@0
    57
		bufPtr=HBufC8::New(KMediumBufSize);
sl@0
    58
	if (bufPtr==NULL)
sl@0
    59
		bufPtr=HBufC8::New(KSmallBufSize);
sl@0
    60
	return(bufPtr);
sl@0
    61
	}
sl@0
    62
sl@0
    63
LOCAL_C TInt IncPathLength(TInt aLen)
sl@0
    64
	{
sl@0
    65
	return(((aLen+KPathIncGran-1)/KPathIncGran)*KPathIncGran);
sl@0
    66
	}
sl@0
    67
sl@0
    68
LOCAL_C TInt CreateTargetNameFromSource(TDes& aTrgName, const TDesC& aTrgMask, const TDesC& aSrcName)
sl@0
    69
// Replace the wildcards with letters from the matched file.
sl@0
    70
	{
sl@0
    71
	TFileName destName;
sl@0
    72
	TParsePtrC trg(aTrgMask);
sl@0
    73
	TParsePtrC src(aSrcName);
sl@0
    74
	TPtrC mask(trg.NameAndExt());
sl@0
    75
	TPtrC source(src.NameAndExt());
sl@0
    76
	TInt steps = 1;
sl@0
    77
	TBool starCharFound = EFalse;
sl@0
    78
	if(mask.LocateReverse('.')!=KErrNotFound || aTrgMask.Right(1)==_L("*"))
sl@0
    79
		{
sl@0
    80
		mask.Set(trg.Name());
sl@0
    81
		source.Set(src.Name());
sl@0
    82
		steps = 2;
sl@0
    83
		}
sl@0
    84
	for(TInt i = 0; i < steps;
sl@0
    85
	    i++, mask.Set(trg.ExtPresent() ? trg.Ext() : _L(".*")) , source.Set(src.Ext()))
sl@0
    86
		{
sl@0
    87
		TInt offset = 0;
sl@0
    88
		starCharFound = EFalse;
sl@0
    89
		while(offset < mask.Length())
sl@0
    90
			{
sl@0
    91
			TChar currentChar = mask[offset];
sl@0
    92
			switch(currentChar)
sl@0
    93
				{
sl@0
    94
				case KMatchAny:
sl@0
    95
					if(offset < source.Length() && !starCharFound)
sl@0
    96
						{
sl@0
    97
						destName.Append(source.Mid(offset));
sl@0
    98
						starCharFound = ETrue;
sl@0
    99
						}
sl@0
   100
					break;
sl@0
   101
				case KMatchOne:
sl@0
   102
					if(offset < source.Length())
sl@0
   103
				    {
sl@0
   104
				    destName.Append(source[offset]);
sl@0
   105
				    }
sl@0
   106
					break;
sl@0
   107
				default:
sl@0
   108
					destName.Append(currentChar);
sl@0
   109
					break;
sl@0
   110
				}
sl@0
   111
			offset++;
sl@0
   112
			}
sl@0
   113
		}
sl@0
   114
	if(destName.Right(1) == _L("."))
sl@0
   115
		{
sl@0
   116
		destName.SetLength(destName.Length()-1);
sl@0
   117
		}
sl@0
   118
	if(aTrgName.Length()+destName.Length() > KMaxFileName)
sl@0
   119
		{
sl@0
   120
		return KErrBadName;
sl@0
   121
		}
sl@0
   122
	aTrgName.Append(destName);
sl@0
   123
	return KErrNone;
sl@0
   124
	}
sl@0
   125
sl@0
   126
EXPORT_C MFileManObserver::TControl MFileManObserver::NotifyFileManStarted()
sl@0
   127
/**
sl@0
   128
Inform the observer that an operation is about to start.
sl@0
   129
sl@0
   130
This is done immediately before each entry is processed.
sl@0
   131
sl@0
   132
@return The implementation of this function should return:
sl@0
   133
        MFileManObserver::EContinue, to allow processing of the current file
sl@0
   134
        to proceed;
sl@0
   135
        MFileManObserver::ECancel, to skip processing the current file and move
sl@0
   136
        to the next file;
sl@0
   137
        MFileManObserver::EAbort to abort the entire operation.
sl@0
   138
        The default return value is MFileManObserver::EContinue.
sl@0
   139
*/
sl@0
   140
	{
sl@0
   141
sl@0
   142
	return(EContinue);
sl@0
   143
	}
sl@0
   144
sl@0
   145
sl@0
   146
sl@0
   147
sl@0
   148
EXPORT_C MFileManObserver::TControl MFileManObserver::NotifyFileManOperation()
sl@0
   149
/**
sl@0
   150
Informs the observer that an operation, i.e. a copy or a move, is proceeding.
sl@0
   151
sl@0
   152
Large files are copied and moved in stages.
sl@0
   153
After each portion of the source file has been copied to the target, this
sl@0
   154
function is called.
sl@0
   155
sl@0
   156
It may be useful to call CFileMan::BytesTransferredByCopyStep() from this
sl@0
   157
function to retrieve the current status of the operation.
sl@0
   158
sl@0
   159
@return The implementation of this function should return:
sl@0
   160
        MFileManObserver::ECancel, to cancel the current operation, closing the current source
sl@0
   161
        and target files, the current target file is deleted.
sl@0
   162
        If the operation is performed on several files, cancelling one will not abort whole batch.
sl@0
   163
sl@0
   164
        MFileManObserver::EContinue, to continue with the operation.
sl@0
   165
        The default return value is MFileManObserver::EContinue.
sl@0
   166
sl@0
   167
@see CFileMan
sl@0
   168
*/
sl@0
   169
	{
sl@0
   170
sl@0
   171
	return(EContinue);
sl@0
   172
	}
sl@0
   173
sl@0
   174
sl@0
   175
sl@0
   176
sl@0
   177
EXPORT_C MFileManObserver::TControl MFileManObserver::NotifyFileManEnded()
sl@0
   178
/**
sl@0
   179
Informs the observer that an operation is complete.
sl@0
   180
sl@0
   181
This is done immediately after a directory entry has been processed.
sl@0
   182
sl@0
   183
It may be useful to call CFileBase::GetLastError()
sl@0
   184
and CFileBase::GetMoreInfoAboutError() from this function to retrieve
sl@0
   185
information about how the operation ended.
sl@0
   186
sl@0
   187
@return The implementation of this function should return:
sl@0
   188
        MFileManObserver::EContinue or MFileManObserver::ECancel, to proceed
sl@0
   189
        with processing the next entry. MFileManObserver::ECancel will not
sl@0
   190
        cancel processing the current entry;
sl@0
   191
        MFileManObserver::ERetry, to re-attempt processing the previous file;
sl@0
   192
        MFileManObserver::EAbort, to abort the entire operation.
sl@0
   193
        The default return value is MFileManObserver::EContinue.
sl@0
   194
sl@0
   195
@see CFileBase
sl@0
   196
*/
sl@0
   197
	{
sl@0
   198
sl@0
   199
	return(EContinue);
sl@0
   200
	}
sl@0
   201
sl@0
   202
sl@0
   203
sl@0
   204
sl@0
   205
EXPORT_C CFileBase::CFileBase(RFs& aFs)
sl@0
   206
/**
sl@0
   207
Protected default constructor.
sl@0
   208
sl@0
   209
Note that the class is intended only as an abstract base for other classes.
sl@0
   210
sl@0
   211
@param aFs File server session.
sl@0
   212
*/
sl@0
   213
	: iFs(aFs)
sl@0
   214
	{
sl@0
   215
	}
sl@0
   216
sl@0
   217
sl@0
   218
sl@0
   219
sl@0
   220
EXPORT_C void CFileBase::ConstructL()
sl@0
   221
/**
sl@0
   222
Second phase constructor.
sl@0
   223
*/
sl@0
   224
	{
sl@0
   225
sl@0
   226
	iScanner=CDirScan::NewL(iFs);
sl@0
   227
	User::LeaveIfError(iSynchronizer.CreateLocal(0));
sl@0
   228
	}
sl@0
   229
sl@0
   230
sl@0
   231
sl@0
   232
sl@0
   233
EXPORT_C CFileBase::~CFileBase()
sl@0
   234
/**
sl@0
   235
Destructor.
sl@0
   236
sl@0
   237
Frees resources prior to destruction of the object.
sl@0
   238
*/
sl@0
   239
	{
sl@0
   240
sl@0
   241
	delete iScanner;
sl@0
   242
	delete iDirList;
sl@0
   243
	iSynchronizer.Close();
sl@0
   244
	User::Free(iSessionPath);
sl@0
   245
	}
sl@0
   246
sl@0
   247
sl@0
   248
sl@0
   249
sl@0
   250
GLDEF_C void DoFManBaseOperationL(TAny* aPtr)
sl@0
   251
//
sl@0
   252
// File manager asynchronous thread
sl@0
   253
//
sl@0
   254
	{
sl@0
   255
sl@0
   256
	CFileBase& fMan=*(CFileBase*)aPtr;
sl@0
   257
	User::LeaveIfError(fMan.iFs.Connect());
sl@0
   258
	User::LeaveIfError(fMan.iFs.SetSessionPath(*fMan.iSessionPath));
sl@0
   259
	fMan.iNumberOfFilesProcessed = 0;
sl@0
   260
	fMan.RunL();
sl@0
   261
	}
sl@0
   262
sl@0
   263
GLDEF_C TInt FManBaseThreadFunction(TAny* aPtr)
sl@0
   264
//
sl@0
   265
// Initialise New thread
sl@0
   266
//
sl@0
   267
	{
sl@0
   268
sl@0
   269
	CTrapCleanup* cleanup=CTrapCleanup::New();
sl@0
   270
	if (cleanup==NULL)
sl@0
   271
		return(KErrNoMemory);
sl@0
   272
	CFileBase& fMan=*(CFileBase*)aPtr;
sl@0
   273
	fMan.iSynchronizer.Wait();
sl@0
   274
	TRAPD(ret,DoFManBaseOperationL(aPtr));
sl@0
   275
	if (ret==KErrNone)
sl@0
   276
		ret=fMan.iLastError;
sl@0
   277
	delete cleanup;
sl@0
   278
	fMan.iSwitches=0;
sl@0
   279
	fMan.iFs=fMan.iFsOld;
sl@0
   280
	fMan.iStatus=NULL;
sl@0
   281
	fMan.iFManThread.Close();
sl@0
   282
	return(ret);
sl@0
   283
	}
sl@0
   284
sl@0
   285
sl@0
   286
sl@0
   287
sl@0
   288
EXPORT_C void CFileBase::RunInSeparateThreadL(TThreadFunction aThreadFunction)
sl@0
   289
/**
sl@0
   290
Creates a separate thread to run the command.
sl@0
   291
sl@0
   292
@param aThreadFunction The thread function.
sl@0
   293
*/
sl@0
   294
	{
sl@0
   295
	iSwitches|=KFManBusyFlag;
sl@0
   296
	User::LeaveIfError(iFManThread.Create(KNullDesC,aThreadFunction,KDefaultStackSize,NULL,this));
sl@0
   297
	iFManThread.SetPriority(EPriorityMuchLess);
sl@0
   298
	TFileName sessionPath;
sl@0
   299
	User::LeaveIfError(iFs.SessionPath(sessionPath));
sl@0
   300
	if (iSessionPath==NULL)
sl@0
   301
		iSessionPath=HBufC::NewL((sessionPath.Length()));
sl@0
   302
	else if (iSessionPath->Des().MaxLength()<sessionPath.Length())
sl@0
   303
		iSessionPath=iSessionPath->ReAllocL(IncPathLength(sessionPath.Length()));
sl@0
   304
	iSessionPath->Des()=sessionPath;
sl@0
   305
	iFsOld=iFs;
sl@0
   306
	iLastError=KErrNone;
sl@0
   307
	iFManThread.Logon(*iStatus);
sl@0
   308
	iFManThread.Resume();
sl@0
   309
	}
sl@0
   310
sl@0
   311
sl@0
   312
sl@0
   313
sl@0
   314
EXPORT_C void CFileBase::RunL()
sl@0
   315
/**
sl@0
   316
Executes a command.
sl@0
   317
sl@0
   318
@capability Dependent the capabilities required by this method, of the abstract class CFileBase,
sl@0
   319
					  will be dependent on and provided by the concrete-class implementation of
sl@0
   320
					  the DoOperationL method
sl@0
   321
sl@0
   322
*/
sl@0
   323
	{
sl@0
   324
	if (iStatus && (iSwitches&KFManBusyFlag)==EFalse)
sl@0
   325
		{
sl@0
   326
		RunInSeparateThreadL(FManBaseThreadFunction);
sl@0
   327
		return;
sl@0
   328
		}
sl@0
   329
sl@0
   330
	TBool copyFromHandle = (iSwitches & KCopyFromHandle)?(TBool)ETrue:(TBool)EFalse;
sl@0
   331
sl@0
   332
	CDirScan::TScanDirection scanDir=(iSwitches&KScanDownFlag) ? CDirScan::EScanDownTree : CDirScan::EScanUpTree;
sl@0
   333
sl@0
   334
	if (!copyFromHandle)
sl@0
   335
		{
sl@0
   336
		TRAP(iLastError,iScanner->SetScanDataL(iSrcFile.FullName(),iMatchEntry,ESortByName|EAscending,scanDir));
sl@0
   337
		if (iLastError==KErrNone)
sl@0
   338
			TRAP(iLastError,iScanner->NextL(iDirList));
sl@0
   339
sl@0
   340
		if (iLastError!=KErrNone)
sl@0
   341
			{
sl@0
   342
			iErrorInfo=EInitializationFailed;
sl@0
   343
			User::Leave(iLastError);
sl@0
   344
			}
sl@0
   345
		}
sl@0
   346
sl@0
   347
	FOREVER
sl@0
   348
		{
sl@0
   349
		if (copyFromHandle || iDirList->Count())
sl@0
   350
			{
sl@0
   351
			iLastError=KErrNone;
sl@0
   352
			iErrorInfo=ENoExtraInformation;
sl@0
   353
			TInt action=(iObserver) ? iObserver->NotifyFileManStarted() : MFileManObserver::EContinue;
sl@0
   354
			// Check if NotifyFileManStarted returned ECancel.
sl@0
   355
			if ( action == MFileManObserver::ECancel)
sl@0
   356
				iLastError=KErrCancel;
sl@0
   357
			if (action==MFileManObserver::EContinue)
sl@0
   358
				{
sl@0
   359
				iNumberOfFilesProcessed++;
sl@0
   360
				TRAP(iLastError,DoOperationL());
sl@0
   361
				action=(iObserver) ? iObserver->NotifyFileManEnded() : MFileManObserver::EContinue;
sl@0
   362
				}
sl@0
   363
			else if(action==MFileManObserver::ERetry)
sl@0
   364
			  {
sl@0
   365
			  Panic(EFManBadValueFromObserver);
sl@0
   366
			  }
sl@0
   367
sl@0
   368
sl@0
   369
			switch(action)
sl@0
   370
				{
sl@0
   371
			case MFileManObserver::EContinue:
sl@0
   372
			case MFileManObserver::ECancel:
sl@0
   373
				break;
sl@0
   374
			case MFileManObserver::ERetry:
sl@0
   375
				continue;
sl@0
   376
			case MFileManObserver::EAbort:
sl@0
   377
				delete iDirList;
sl@0
   378
				iDirList=NULL;
sl@0
   379
				iCurrentEntry = 0;
sl@0
   380
				User::Leave(KErrCancel);
sl@0
   381
			default:
sl@0
   382
				Panic(EFManBadValueFromObserver);
sl@0
   383
				}
sl@0
   384
			}
sl@0
   385
		iCurrentEntry++;
sl@0
   386
		if (copyFromHandle || iCurrentEntry>=iDirList->Count())
sl@0
   387
			{
sl@0
   388
			delete iDirList;
sl@0
   389
			iDirList=NULL;
sl@0
   390
			iCurrentEntry=0;
sl@0
   391
sl@0
   392
			if (iSwitches&KRecurseFlag)
sl@0
   393
				{
sl@0
   394
				TRAPD(ret,iScanner->NextL(iDirList));
sl@0
   395
				if (ret!=KErrNone && ret!=KErrPathNotFound)
sl@0
   396
					{
sl@0
   397
					iErrorInfo=EScanNextDirectoryFailed;
sl@0
   398
					iLastError = ret;
sl@0
   399
					User::Leave(iLastError);
sl@0
   400
					}
sl@0
   401
				}
sl@0
   402
			if (iDirList==NULL)
sl@0
   403
				{
sl@0
   404
				CompleteOperationL();
sl@0
   405
				return;
sl@0
   406
				}
sl@0
   407
			}
sl@0
   408
		}
sl@0
   409
	}
sl@0
   410
sl@0
   411
sl@0
   412
sl@0
   413
sl@0
   414
EXPORT_C void CFileBase::SetObserver(MFileManObserver* anObserver)
sl@0
   415
/**
sl@0
   416
Sets the observer.
sl@0
   417
sl@0
   418
Use this function to provide CFileMan with an MFileManObserver, or, if one
sl@0
   419
already exists, to change the observer.
sl@0
   420
sl@0
   421
@param anObserver File management observer.
sl@0
   422
sl@0
   423
@see CFileMan
sl@0
   424
@see MFileManObserver
sl@0
   425
*/
sl@0
   426
	{
sl@0
   427
sl@0
   428
	iObserver=anObserver;
sl@0
   429
	}
sl@0
   430
sl@0
   431
sl@0
   432
sl@0
   433
sl@0
   434
EXPORT_C const TEntry& CFileBase::CurrentEntry()
sl@0
   435
/**
sl@0
   436
Gets the entry currently being processed.
sl@0
   437
sl@0
   438
@return Contains the current entry.
sl@0
   439
*/
sl@0
   440
	{
sl@0
   441
sl@0
   442
	__ASSERT_ALWAYS(iDirList && iCurrentEntry>=0 && iCurrentEntry<iDirList->Count(),Panic(EFManCurrentEntryInvalid));
sl@0
   443
	return (*iDirList)[iCurrentEntry];
sl@0
   444
	}
sl@0
   445
sl@0
   446
sl@0
   447
sl@0
   448
sl@0
   449
EXPORT_C TPtrC CFileBase::AbbreviatedPath()
sl@0
   450
/**
sl@0
   451
Gets the abbreviated path of the file or directory currently being processed.
sl@0
   452
sl@0
   453
The abbreviated path is its path relative to the top level directory
sl@0
   454
specified in the operation.
sl@0
   455
sl@0
   456
@return The abbreviated path.
sl@0
   457
*/
sl@0
   458
	{
sl@0
   459
sl@0
   460
	return iScanner->AbbreviatedPath();
sl@0
   461
	}
sl@0
   462
sl@0
   463
sl@0
   464
sl@0
   465
sl@0
   466
EXPORT_C TPtrC CFileBase::FullPath()
sl@0
   467
/**
sl@0
   468
Gets the full path of the file or directory currently being processed.
sl@0
   469
sl@0
   470
The full path includes the drive letter, path and filename.
sl@0
   471
sl@0
   472
@return The full path.
sl@0
   473
*/
sl@0
   474
	{
sl@0
   475
sl@0
   476
	return iScanner->FullPath();
sl@0
   477
	}
sl@0
   478
sl@0
   479
sl@0
   480
sl@0
   481
sl@0
   482
EXPORT_C TInt CFileBase::GetLastError()
sl@0
   483
/**
sl@0
   484
Gets the latest error code returned during a CFileMan
sl@0
   485
operation.
sl@0
   486
sl@0
   487
This function may be called from MFileManObserver::NotifyFileManEnded().
sl@0
   488
sl@0
   489
@return KErrNone, or another error code that might have been
sl@0
   490
        returned by a CFileMan operation.
sl@0
   491
*/
sl@0
   492
	{
sl@0
   493
sl@0
   494
	return(iLastError);
sl@0
   495
	}
sl@0
   496
sl@0
   497
sl@0
   498
sl@0
   499
sl@0
   500
EXPORT_C TFileManError CFileBase::GetMoreInfoAboutError()
sl@0
   501
/**
sl@0
   502
Gets additional information about the latest error returned during
sl@0
   503
a CFileMan operation.
sl@0
   504
sl@0
   505
For example, if a rename fails, this function
sl@0
   506
can be used to report whether the source or target name caused the problem.
sl@0
   507
This information supplements that provided GetLastError().
sl@0
   508
sl@0
   509
@return The extra information about the last CFileMan error.
sl@0
   510
sl@0
   511
@see CFileMan
sl@0
   512
@see CFileBase::GetLastError()
sl@0
   513
*/
sl@0
   514
	{
sl@0
   515
sl@0
   516
	return(iErrorInfo);
sl@0
   517
	}
sl@0
   518
sl@0
   519
sl@0
   520
sl@0
   521
sl@0
   522
EXPORT_C CFileMan* CFileMan::NewL(RFs& aFs)
sl@0
   523
/**
sl@0
   524
Constructs and allocates memory for a new CFileMan object.
sl@0
   525
sl@0
   526
@param aFs File server session.
sl@0
   527
sl@0
   528
@return Newly created CFileMan object.
sl@0
   529
*/
sl@0
   530
	{
sl@0
   531
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManNewL1, MODULEUID, aFs.Handle());
sl@0
   532
sl@0
   533
	CFileMan* fileMan=new(ELeave) CFileMan(aFs);
sl@0
   534
	CleanupStack::PushL(fileMan);
sl@0
   535
	fileMan->CFileBase::ConstructL();
sl@0
   536
	CleanupStack::Pop();
sl@0
   537
sl@0
   538
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManNewL1Return, MODULEUID, fileMan);
sl@0
   539
	return fileMan;
sl@0
   540
	}
sl@0
   541
sl@0
   542
sl@0
   543
sl@0
   544
sl@0
   545
EXPORT_C CFileMan* CFileMan::NewL(RFs& aFs,MFileManObserver* anObserver)
sl@0
   546
/**
sl@0
   547
Constructs and allocates memory for a new CFileMan object with an observer.
sl@0
   548
sl@0
   549
@param aFs        File server session.
sl@0
   550
@param anObserver File management observer.
sl@0
   551
sl@0
   552
@return Newly created CFileMan object.
sl@0
   553
*/
sl@0
   554
	{
sl@0
   555
	TRACE2(UTF::EBorder, UTraceModuleEfsrv::ECFileManNewL2, MODULEUID, aFs.Handle(), anObserver);
sl@0
   556
sl@0
   557
	CFileMan* fileMan=new(ELeave) CFileMan(aFs);
sl@0
   558
	CleanupStack::PushL(fileMan);
sl@0
   559
	fileMan->CFileBase::ConstructL();
sl@0
   560
	CleanupStack::Pop();
sl@0
   561
	fileMan->SetObserver(anObserver);
sl@0
   562
sl@0
   563
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManNewL2Return, MODULEUID, fileMan);
sl@0
   564
	return fileMan;
sl@0
   565
	}
sl@0
   566
sl@0
   567
sl@0
   568
sl@0
   569
sl@0
   570
CFileMan::CFileMan(RFs& aFs)
sl@0
   571
//
sl@0
   572
// Constructor and destructor
sl@0
   573
//
sl@0
   574
	: CFileBase(aFs)
sl@0
   575
	{
sl@0
   576
	}
sl@0
   577
CFileMan::~CFileMan()
sl@0
   578
	{
sl@0
   579
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManDestructor, MODULEUID, this);
sl@0
   580
sl@0
   581
	TRACE0(UTF::EBorder, UTraceModuleEfsrv::ECFileManDestructorReturn, MODULEUID);
sl@0
   582
	}
sl@0
   583
sl@0
   584
sl@0
   585
EXPORT_C CFileMan::TAction CFileMan::CurrentAction()
sl@0
   586
/**
sl@0
   587
Gets the action which CFileMan is currently carrying out.
sl@0
   588
sl@0
   589
@return The action which CFileMan is carrying out.
sl@0
   590
*/
sl@0
   591
	{
sl@0
   592
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCurrentAction, MODULEUID, this);
sl@0
   593
sl@0
   594
	TAction action = ENone;
sl@0
   595
sl@0
   596
	// Mapping table between internal and external action indicators.
sl@0
   597
	switch(iAction)
sl@0
   598
		{
sl@0
   599
	case EInternalNone:
sl@0
   600
		action = ENone;
sl@0
   601
		break;
sl@0
   602
	case EInternalAttribs:
sl@0
   603
		action = EAttribs;
sl@0
   604
		break;
sl@0
   605
	case EInternalCopy:
sl@0
   606
		action = ECopy;
sl@0
   607
		break;
sl@0
   608
	case EInternalCopyForMove:
sl@0
   609
		action = EMove;
sl@0
   610
		break;
sl@0
   611
	case EInternalDelete:
sl@0
   612
		action = EDelete;
sl@0
   613
		break;
sl@0
   614
	case EInternalRenameInvalidEntry:
sl@0
   615
		action = ERenameInvalidEntry;
sl@0
   616
		break;
sl@0
   617
	case EInternalRenameForMove:
sl@0
   618
	case EInternalRename:
sl@0
   619
		action = ERename;
sl@0
   620
		break;
sl@0
   621
	case EInternalRmDir:
sl@0
   622
		action = ERmDir;
sl@0
   623
		break;
sl@0
   624
	case EInternalCopyFromHandle:
sl@0
   625
		action = ECopyFromHandle;
sl@0
   626
		break;
sl@0
   627
	default:
sl@0
   628
		Panic(EFManUnknownAction);
sl@0
   629
		}
sl@0
   630
sl@0
   631
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCurrentActionReturn, MODULEUID, action);
sl@0
   632
	return (action);
sl@0
   633
	}
sl@0
   634
sl@0
   635
sl@0
   636
sl@0
   637
sl@0
   638
EXPORT_C void CFileMan::GetCurrentTarget(TFileName& aTrgName)
sl@0
   639
/**
sl@0
   640
Gets the name of the target file for the CFileMan operation currently
sl@0
   641
being carried out.
sl@0
   642
sl@0
   643
This function is relevant when copying, moving or renaming files.
sl@0
   644
sl@0
   645
@param aTrgName The full path and filename of the target file for
sl@0
   646
                the current CFileMan operation
sl@0
   647
*/
sl@0
   648
	{
sl@0
   649
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManGetCurrentTarget, MODULEUID, this);
sl@0
   650
sl@0
   651
	GetSrcAndTrg(iTmpParse, aTrgName);
sl@0
   652
sl@0
   653
	TRACEMULT1(UTF::EBorder, UTraceModuleEfsrv::ECFileManGetCurrentTargetReturn, MODULEUID, aTrgName);
sl@0
   654
	}
sl@0
   655
sl@0
   656
sl@0
   657
sl@0
   658
sl@0
   659
EXPORT_C void CFileMan::GetCurrentSource(TFileName& aSrcName)
sl@0
   660
/**
sl@0
   661
Gets the name of the source file or directory for the CFileMan operation
sl@0
   662
currently being carried out.
sl@0
   663
sl@0
   664
The source is the file or directory which is being copied, moved or deleted.
sl@0
   665
sl@0
   666
@param aSrcName The full path and filename of the source file for the current
sl@0
   667
                CFileMan operation.
sl@0
   668
*/
sl@0
   669
	{
sl@0
   670
	TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManGetCurrentSource, MODULEUID, this);
sl@0
   671
sl@0
   672
    TPtrC fullPath(FullPath());
sl@0
   673
	iTmpParse.Set(CurrentEntry().iName, &fullPath, NULL);
sl@0
   674
	aSrcName = iTmpParse.FullName();
sl@0
   675
sl@0
   676
	TRACEMULT1(UTF::EBorder, UTraceModuleEfsrv::ECFileManGetCurrentSourceReturn, MODULEUID, aSrcName);
sl@0
   677
	}
sl@0
   678
sl@0
   679
void CFileMan::GetSrcAndTrg(TParse& aSrcName,TFileName& aTrgName)
sl@0
   680
//
sl@0
   681
// Get the current target for the operation
sl@0
   682
//
sl@0
   683
	{
sl@0
   684
	TFileName fullpath = FullPath();
sl@0
   685
	TInt ret = aSrcName.Set(CurrentEntry().iName, &fullpath, NULL);
sl@0
   686
	if(ret == KErrBadName)
sl@0
   687
		{
sl@0
   688
		// Try heap variables first
sl@0
   689
		TBool done = EFalse;
sl@0
   690
		TFileName* current = new TFileName;
sl@0
   691
		if (current != NULL)
sl@0
   692
			{
sl@0
   693
			current->Copy(CurrentEntry().iName);
sl@0
   694
sl@0
   695
			ret = ShrinkNames(iFs, fullpath, *current, EFalse);
sl@0
   696
			if(ret == KErrNone)
sl@0
   697
				{
sl@0
   698
				ret = aSrcName.Set(*current, &fullpath, NULL);
sl@0
   699
				done = ETrue;
sl@0
   700
				}
sl@0
   701
			delete current;
sl@0
   702
			}
sl@0
   703
sl@0
   704
		if (!done) //heap method failed
sl@0
   705
			{
sl@0
   706
			TFileName current = CurrentEntry().iName;
sl@0
   707
			ret = ShrinkNames(iFs, fullpath, current, EFalse);
sl@0
   708
			if(ret == KErrNone)
sl@0
   709
				{
sl@0
   710
				ret = aSrcName.Set(current, &fullpath, NULL);
sl@0
   711
				}
sl@0
   712
			}
sl@0
   713
		}
sl@0
   714
	__ASSERT_DEBUG(ret == KErrNone, Panic(EBadLength));
sl@0
   715
	aTrgName=iTrgFile.DriveAndPath();
sl@0
   716
	TPtrC relPath=iScanner->AbbreviatedPath();
sl@0
   717
	aTrgName.Append(relPath.Right(relPath.Length()-1));
sl@0
   718
	CreateTargetNameFromSource(aTrgName,iTrgFile.NameAndExt(),aSrcName.NameAndExt());
sl@0
   719
	}
sl@0
   720
sl@0
   721
sl@0
   722
sl@0
   723
sl@0
   724
EXPORT_C TInt CFileMan::BytesTransferredByCopyStep()
sl@0
   725
/**
sl@0
   726
Gets the number of bytes transferred during a copy or move operation.
sl@0
   727
sl@0
   728
Large files are copied and moved in stages. After each portion of
sl@0
   729
the source file has been copied to the target, the number of bytes
sl@0
   730
transferred is updated. This function may be called
sl@0
   731
from MFileManObserver::NotifyFileManOperation()
sl@0
   732
and may be used to support the increment of progress bars.
sl@0
   733
sl@0
   734
@return The number of bytes transferred.
sl@0
   735
*/
sl@0
   736
	{
sl@0
   737
	TRACE2(UTF::EBorder, UTraceModuleEfsrv::ECFileManBytesTransferredByCopyStep, MODULEUID, this, iBytesTransferred);
sl@0
   738
sl@0
   739
	return(iBytesTransferred);
sl@0
   740
	}
sl@0
   741
sl@0
   742
sl@0
   743
sl@0
   744
sl@0
   745
LOCAL_C void MakeParseWild(TParse& aParse, TFileName& aName)
sl@0
   746
//
sl@0
   747
// Append _L("\\*") or _L("*") to aParse
sl@0
   748
//
sl@0
   749
	{
sl@0
   750
	if(!aParse.IsWild())
sl@0
   751
		{
sl@0
   752
		aName = aParse.FullName();
sl@0
   753
		if (aParse.NamePresent() || aParse.ExtPresent())
sl@0
   754
			{
sl@0
   755
			if (aName.Length()<=254)
sl@0
   756
				aName.Append(_L("\\*"));
sl@0
   757
			}
sl@0
   758
		else
sl@0
   759
			{
sl@0
   760
			if (aName.Length()<=255)
sl@0
   761
				aName.Append(_L("*"));
sl@0
   762
			}
sl@0
   763
		aParse.Set(aName,NULL,NULL);
sl@0
   764
		}
sl@0
   765
	}
sl@0
   766
sl@0
   767
sl@0
   768
void CFileMan::CheckForDirectory()
sl@0
   769
//
sl@0
   770
// If iTrgFile is a directory set target to iTrgFile\\*
sl@0
   771
//
sl@0
   772
	{
sl@0
   773
	TInt trg = iFs.Entry(iTrgFile.FullName(), iTmpEntry);
sl@0
   774
	if (trg==KErrNone && iTmpEntry.iAtt&KEntryAttDir)
sl@0
   775
		MakeParseWild(iTrgFile, iTmpName1);
sl@0
   776
	TInt src = iFs.Entry(iSrcFile.FullName(), iTmpEntry);
sl@0
   777
	if (src==KErrNone && iTmpEntry.iAtt&KEntryAttDir)
sl@0
   778
		{
sl@0
   779
		MakeParseWild(iSrcFile, iTmpName1);
sl@0
   780
		if (trg==KErrNotFound && (iSwitches&KRecurseFlag))
sl@0
   781
			MakeParseWild(iTrgFile, iTmpName1);
sl@0
   782
		}
sl@0
   783
	}
sl@0
   784
sl@0
   785
void CFileMan::DoSynchronize(TInt aRetValue)
sl@0
   786
//
sl@0
   787
// Synchronise with fmanthread
sl@0
   788
//
sl@0
   789
	{
sl@0
   790
sl@0
   791
	if (iStatus && aRetValue==KErrNone)
sl@0
   792
		iSynchronizer.Signal(); // FManThread started
sl@0
   793
	if (iStatus && aRetValue!=KErrNone)
sl@0
   794
		iStatus=NULL; // FManThread failed to start
sl@0
   795
	}
sl@0
   796
sl@0
   797
LOCAL_C void NextInPath(const TDesC& aPath,TPtrC& anEntry,TInt& aPos)
sl@0
   798
//
sl@0
   799
// Returns the next entry in the path
sl@0
   800
//
sl@0
   801
	{
sl@0
   802
sl@0
   803
	anEntry.Set(NULL,0);
sl@0
   804
	if ((aPos+1)>=aPath.Length())
sl@0
   805
		return;
sl@0
   806
	TPtrC path(aPath.Mid(aPos+1)); // Skip delimiter
sl@0
   807
	TInt delimiterPos=path.Locate(KPathDelimiter);
sl@0
   808
	if (delimiterPos==KErrNotFound)
sl@0
   809
		delimiterPos=aPath.Length()-(aPos+1);
sl@0
   810
	if (delimiterPos<=0)
sl@0
   811
		return;
sl@0
   812
sl@0
   813
	if (path[delimiterPos-1]==KExtDelimiter) // return "F32." as "F32"
sl@0
   814
		anEntry.Set(aPath.Mid(aPos+1,delimiterPos-1));
sl@0
   815
	else
sl@0
   816
		anEntry.Set(aPath.Mid(aPos+1,delimiterPos));
sl@0
   817
	aPos+=delimiterPos+1;
sl@0
   818
	}
sl@0
   819
sl@0
   820
LOCAL_C TBool ComparePaths(const TDesC& aPath1,const TDesC& aPath2)
sl@0
   821
//
sl@0
   822
// Return ETrue if the paths are identical
sl@0
   823
// To catch case "\\F32.\\GROUP\\" == "\\F32\\GROUP\\"
sl@0
   824
//
sl@0
   825
	{
sl@0
   826
sl@0
   827
	TPtrC entry1(NULL,0);
sl@0
   828
	TPtrC entry2(NULL,0);
sl@0
   829
	TInt pos1=0;
sl@0
   830
	TInt pos2=0;
sl@0
   831
sl@0
   832
	do {
sl@0
   833
		NextInPath(aPath1,entry1,pos1);
sl@0
   834
		NextInPath(aPath2,entry2,pos2);
sl@0
   835
		if (entry1.MatchF(entry2)==KErrNotFound)
sl@0
   836
			return(EFalse);
sl@0
   837
		} while (entry1.Length() && entry2.Length());
sl@0
   838
sl@0
   839
	return(ETrue);
sl@0
   840
	}
sl@0
   841
sl@0
   842
EXPORT_C TBool FileNamesIdentical(const TDesC& aFileName1,const TDesC& aFileName2)
sl@0
   843
//
sl@0
   844
// Return ETrue if the filenames (and paths) are identical
sl@0
   845
// NB "Agenda" == "AGENda."
sl@0
   846
//
sl@0
   847
	{
sl@0
   848
sl@0
   849
	TParsePtrC file1(aFileName1);
sl@0
   850
	TParsePtrC file2(aFileName2);
sl@0
   851
	if (file1.Drive().MatchF(file2.Drive())==KErrNotFound)
sl@0
   852
		return(EFalse);
sl@0
   853
	if (file1.Name().MatchF(file2.Name())==KErrNotFound)
sl@0
   854
		return(EFalse);
sl@0
   855
	if (ComparePaths(file1.Path(),file2.Path())==EFalse)
sl@0
   856
		return(EFalse);
sl@0
   857
	if (file1.Ext().Length()==0 || file2.Ext().Length()==0)
sl@0
   858
		{ // Agenda == Agenda.
sl@0
   859
		if (file1.Ext().Length()==1 || file2.Ext().Length()==1)
sl@0
   860
			return(ETrue);
sl@0
   861
		}
sl@0
   862
	if (file1.Ext().MatchF(file2.Ext())==KErrNotFound &&
sl@0
   863
		file1.NameAndExt().MatchF(file2.NameAndExt())==KErrNotFound)
sl@0
   864
		return(EFalse);
sl@0
   865
	return(ETrue);
sl@0
   866
	}
sl@0
   867
sl@0
   868
sl@0
   869
sl@0
   870
sl@0
   871
EXPORT_C TInt CFileMan::Attribs(const TDesC& aName,TUint aSetMask,TUint aClearMask,const TTime& aTime,TUint aSwitches,TRequestStatus& aStatus)
sl@0
   872
/**
sl@0
   873
Sets or clears attributes for one or more files using two bitmasks.
sl@0
   874
sl@0
   875
This is an asynchronous function.
sl@0
   876
Its behaviour is the same as the synchronous overload.
sl@0
   877
sl@0
   878
@param aName      Path indicating the file(s) whose attributes are to be
sl@0
   879
                  changed. Any path components which are not specified
sl@0
   880
                  here will be taken from the session path.
sl@0
   881
                  Use wildcards to specify more than one file.
sl@0
   882
@param aSetMask   Bitmask indicating the attributes to be set.
sl@0
   883
@param aClearMask Bitmask indicating the attributes to be cleared.
sl@0
   884
                  For more information, see KEntryAttNormal and the other
sl@0
   885
                  file/directory attributes.
sl@0
   886
@param aTime      Contains the new modification date and time for the files, in UTC.
sl@0
   887
                  To preserve the file's timestamps, specify a TTime value of 0.
sl@0
   888
@param aSwitches  Specify zero for no recursion;
sl@0
   889
                  CFileMan::ERecurse for recursion.
sl@0
   890
                  By default, the synchronous variant of this function operates
sl@0
   891
                  non-recursively.
sl@0
   892
@param aStatus    The request status object. On request completion,
sl@0
   893
                  indicates how the request completed:
sl@0
   894
                  KErrNone, if successful, otherwise one of the other system-wide error
sl@0
   895
                  codes.
sl@0
   896
sl@0
   897
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
   898
					is still pending; otherwise one of the other system-wide error codes
sl@0
   899
sl@0
   900
@capability Dependent If aName is /Sys then Tcb capability is required.
sl@0
   901
@capability Dependent If aName begins with /Private and does not match
sl@0
   902
					  this process' SID then AllFiles capability is required.
sl@0
   903
@capability Dependent If aName is /Resource then Tcb capability is required.
sl@0
   904
sl@0
   905
*/
sl@0
   906
	{
sl@0
   907
	TRACEMULT8(UTF::EBorder, UTraceModuleEfsrv::ECFileManAttribs1, MODULEUID,
sl@0
   908
		(TUint) this, aName, aSetMask, aClearMask, I64LOW(aTime.Int64()), I64HIGH(aTime.Int64()), aSwitches, (TUint) &aStatus);
sl@0
   909
sl@0
   910
	TInt r;
sl@0
   911
	if (iSwitches&KFManBusyFlag)
sl@0
   912
		{
sl@0
   913
		r = KErrInUse;
sl@0
   914
		}
sl@0
   915
	else
sl@0
   916
		{
sl@0
   917
		iStatus=&aStatus;
sl@0
   918
		r = Attribs(aName,aSetMask,aClearMask,aTime,aSwitches);
sl@0
   919
		}
sl@0
   920
sl@0
   921
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManAttribs1Return, MODULEUID, r);
sl@0
   922
	return r;
sl@0
   923
	}
sl@0
   924
sl@0
   925
sl@0
   926
sl@0
   927
sl@0
   928
EXPORT_C TInt CFileMan::Attribs(const TDesC& aName,TUint aSetMask,TUint aClearMask,const TTime& aTime,TUint aSwitches)
sl@0
   929
/**
sl@0
   930
Sets or clears attributes for one or more files using two bitmasks
sl@0
   931
sl@0
   932
This is a synchronous function.
sl@0
   933
sl@0
   934
The first bitmask specifies the attributes to be set.
sl@0
   935
The second specifies the attributes to be cleared.
sl@0
   936
The date and time of the files' last modification can also be changed.
sl@0
   937
sl@0
   938
The function can operate recursively or non-recursively.
sl@0
   939
When operating non-recursively, only the matching files located in the directory
sl@0
   940
specified in aName are affected. When operating recursively, all matching files
sl@0
   941
in the directory hierarchy below the directory specified in aName will be affected.
sl@0
   942
sl@0
   943
Notes:
sl@0
   944
sl@0
   945
1. A panic is raised if any attribute is specified in both bitmasks.
sl@0
   946
sl@0
   947
2. Attempting to change the attributes for an open file results in an error
sl@0
   948
   for that file, as retrieved by CFileBase::GetLastError().
sl@0
   949
sl@0
   950
3. An attempt to set or clear the KEntryAttDir or KEntryAttVolume attribute
sl@0
   951
   for a file or directory will have no effect.
sl@0
   952
sl@0
   953
@param aName      Path indicating the file(s) whose attributes are to be
sl@0
   954
                  changed. Any path components which are not specified
sl@0
   955
                  here will be taken from the session path.
sl@0
   956
                  Use wildcards to specify more than one file.
sl@0
   957
@param aSetMask   Bitmask indicating the attributes to be set.
sl@0
   958
@param aClearMask Bitmask indicating the attributes to be cleared.
sl@0
   959
                  For more information, see KEntryAttNormal and the other
sl@0
   960
                  file/directory attributes.
sl@0
   961
@param aTime      Contains the new modification date and time for the files, in UTC.
sl@0
   962
                  To preserve the file's timestamps, specify a TTime value of 0.
sl@0
   963
@param aSwitches  Specify zero for no recursion;
sl@0
   964
                  CFileMan::ERecurse for recursion.
sl@0
   965
                  By default, the synchronous variant of this function operates
sl@0
   966
                  non-recursively.
sl@0
   967
sl@0
   968
@return KErrNone if successful, otherwise one of the other system-wide error codes.
sl@0
   969
sl@0
   970
@capability Dependent If aName is /Sys then Tcb capability is required.
sl@0
   971
@capability Dependent If aName begins with /Private and does not match
sl@0
   972
					  this process' SID then AllFiles capability is required.
sl@0
   973
@capability Dependent If aName is /Resource then Tcb capability is required.
sl@0
   974
sl@0
   975
*/
sl@0
   976
	{
sl@0
   977
	TRACEMULT7(UTF::EBorder, UTraceModuleEfsrv::ECFileManAttribs2, MODULEUID,
sl@0
   978
		(TUint) this, aName, aSetMask, aClearMask, I64LOW(aTime.Int64()), I64HIGH(aTime.Int64()), aSwitches);
sl@0
   979
sl@0
   980
	TInt ret;
sl@0
   981
	if (iSwitches&KFManBusyFlag)
sl@0
   982
		{
sl@0
   983
		ret = KErrInUse;
sl@0
   984
		}
sl@0
   985
	else
sl@0
   986
		{
sl@0
   987
		SetFlags(aSwitches&EOverWrite,aSwitches&ERecurse,ETrue,EFalse);
sl@0
   988
		RETURNIFERRORD(r,iFs.Parse(aName,iSrcFile),UTraceModuleEfsrv::ECFileManAttribs2Return);
sl@0
   989
		iSetMask=aSetMask;
sl@0
   990
		iClearMask=aClearMask;
sl@0
   991
		iTime=aTime;
sl@0
   992
		iAction = EInternalAttribs;
sl@0
   993
		iMatchEntry=KEntryAttMaskSupported; // all entries
sl@0
   994
		iNumberOfFilesProcessed = 0;
sl@0
   995
		TRAP(r,RunL());
sl@0
   996
		ret=(r==KErrNone) ? iLastError : r;
sl@0
   997
		DoSynchronize(r);
sl@0
   998
		}
sl@0
   999
sl@0
  1000
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManAttribs2Return, MODULEUID, ret);
sl@0
  1001
	return(ret);
sl@0
  1002
	}
sl@0
  1003
sl@0
  1004
sl@0
  1005
sl@0
  1006
sl@0
  1007
EXPORT_C TInt CFileMan::Copy(const TDesC& anOld,const TDesC& aNew,TUint aSwitches,TRequestStatus& aStatus)
sl@0
  1008
/**
sl@0
  1009
Copies one or more files.
sl@0
  1010
sl@0
  1011
This is an asynchronous function.
sl@0
  1012
Its behaviour is the same as the synchronous overload.
sl@0
  1013
sl@0
  1014
@param anOld     Path indicating the file(s) to be copied.
sl@0
  1015
                 Any path components which are not specified here will be
sl@0
  1016
                 taken from the session path.
sl@0
  1017
@param aNew      Path indicating the directory into which the file(s) are to be copied.
sl@0
  1018
				 Any path components which are not specified here will be
sl@0
  1019
                 taken from the session path
sl@0
  1020
@param aSwitches Specify zero for no overwriting and no recursion;
sl@0
  1021
                 CFileMan::EOverWrite to overwrite files with the same name;
sl@0
  1022
                 CFileMan::ERecurse for recursion.
sl@0
  1023
                 By default, the synchronous variant of this function operates
sl@0
  1024
                 non-recursively and with overwriting.
sl@0
  1025
@param aStatus   The request status object. On request completion,
sl@0
  1026
                 indicates how the request completed:
sl@0
  1027
                 KErrNone, if successful, otherwise one of the other system-wide error
sl@0
  1028
                 codes.
sl@0
  1029
sl@0
  1030
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
  1031
					is still pending; otherwise one of the other system-wide error codes
sl@0
  1032
sl@0
  1033
@capability AllFiles
sl@0
  1034
sl@0
  1035
@capability Dependent If the path for aNew begins with /Sys then Tcb capability is required.
sl@0
  1036
@capability Dependent If the path for aNew begins with /Resource then Tcb capability is required
sl@0
  1037
sl@0
  1038
*/
sl@0
  1039
	{
sl@0
  1040
	TRACEMULT5(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy1, MODULEUID,
sl@0
  1041
		(TUint) this, anOld, aNew, aSwitches, (TUint) &aStatus);
sl@0
  1042
sl@0
  1043
	TInt r;
sl@0
  1044
	if (iSwitches&KFManBusyFlag)
sl@0
  1045
		r = KErrInUse;
sl@0
  1046
	else
sl@0
  1047
		{
sl@0
  1048
		iStatus=&aStatus;
sl@0
  1049
		r = Copy(anOld,aNew,aSwitches);
sl@0
  1050
		}
sl@0
  1051
sl@0
  1052
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy1Return, MODULEUID, r);
sl@0
  1053
	return(r);
sl@0
  1054
	}
sl@0
  1055
sl@0
  1056
sl@0
  1057
sl@0
  1058
sl@0
  1059
EXPORT_C TInt CFileMan::Copy(const TDesC& anOld,const TDesC& aNew,TUint aSwitches)
sl@0
  1060
/**
sl@0
  1061
Copies one or more files.
sl@0
  1062
sl@0
  1063
This is a synchronous function.
sl@0
  1064
sl@0
  1065
NB the following applies to files greater than or equal to 2GBytes in size
sl@0
  1066
(2,147,483,648 bytes) :
sl@0
  1067
- Only files smaller than 2GBytes will be copied; any larger files will be skipped and
sl@0
  1068
processing will continue with the next file.
sl@0
  1069
- If at least one file is smaller than 2GBytes, then KErrNone will be returned.
sl@0
  1070
- If all files are greater than or equal to 2GBytes ,then KErrTooBig will be returned.
sl@0
  1071
sl@0
  1072
One way to detect the presence of any large file(s) is to use an observer: calling
sl@0
  1073
CFileBase::GetLastError() from MFileManObserver::NotifyFileManEnded() will return
sl@0
  1074
KErrToBig for any file >= 2GBytes in size.
sl@0
  1075
sl@0
  1076
Note: the copy operation behaves differently when MFileManObserver is used.
sl@0
  1077
MFileManObserver should be used with multiple files as it enables you to capture the results of all file copy operations.
sl@0
  1078
sl@0
  1079
If MFileManObserver is NOT used then only the result of the last
sl@0
  1080
file copy operation is returned because the results of previous file copy operations are overwritten.
sl@0
  1081
sl@0
  1082
Optionally, this function can be set to overwrite any files with the same name
sl@0
  1083
which exist in the target directory. If the flag is set for no overwriting,
sl@0
  1084
then any files with the same name will not be overwritten, and an error
sl@0
  1085
(KErrAlreadyExists) will be returned for that file. Error codes may be retrieved
sl@0
  1086
using CFileBase::GetLastError().
sl@0
  1087
sl@0
  1088
If recursive operation is set, all intermediate directories will be created,
sl@0
  1089
including any directories in the path specified by aNew which do not
sl@0
  1090
already exist.
sl@0
  1091
sl@0
  1092
If recursive operation is not set, only the matching files located in
sl@0
  1093
the single directory specified in anOld are copied.
sl@0
  1094
No intermediate directories will be created; if any directories in
sl@0
  1095
the destination path do not exist, no files will be copied, and this function
sl@0
  1096
will return KErrPathNotFound.
sl@0
  1097
sl@0
  1098
 Notes:
sl@0
  1099
 1.	This function operates on files only, therefore:
sl@0
  1100
 1.1	In contrast to the way CFileMan::Move() and CFileMan::Rename()
sl@0
  1101
 	behave, the behaviour of the copy operation does not depend on the presence
sl@0
  1102
 	or absence of a trailing backslash ("\") character. Therefore it is only
sl@0
  1103
 	possible to copy the content of the source path. It is NOT
sl@0
  1104
 	possible by use of a trailing backslash ("\") character to request that the
sl@0
  1105
 	last directory level plus its content be copied to the target path.
sl@0
  1106
sl@0
  1107
 	This means that the following two example copy operations will behave
sl@0
  1108
 	identically
sl@0
  1109
sl@0
  1110
 	@code
sl@0
  1111
 	CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1112
 	...
sl@0
  1113
 	fm->Copy(_L("C:\\SRC\\"), _L("C:\\TRG\\"), CFileMan::ERecurse);
sl@0
  1114
 	fm->Copy(_L("C:\\SRC"), _L("C:\\TRG\\"), CFileMan::ERecurse);
sl@0
  1115
 	@endcode
sl@0
  1116
sl@0
  1117
 	because they will be interpreted as follows:
sl@0
  1118
 	@code
sl@0
  1119
 	fm->Copy(_L("C:\\SRC\\*"),_L("C:\\TRG\\"), CFileMan::ERecurse);
sl@0
  1120
 	@endcode
sl@0
  1121
sl@0
  1122
 1.2	If there is no file to operate on i.e. if source directory is empty, the
sl@0
  1123
 	function will do nothing and return error code KErrNotFound.
sl@0
  1124
sl@0
  1125
 2. Files can be copied across drives.
sl@0
  1126
sl@0
  1127
 3. Open files can be copied if they have been opened using
sl@0
  1128
      the EFileShareReadersOnly file share mode.
sl@0
  1129
sl@0
  1130
 4. Read-only, hidden and system files can be copied and
sl@0
  1131
   the source file's attributes are preserved in the target file.
sl@0
  1132
sl@0
  1133
@param anOld     Path indicating the file(s) to be copied.
sl@0
  1134
                 Any path components which are not specified here will be
sl@0
  1135
                 taken from the session path.
sl@0
  1136
@param aNew      Path indicating the directory into which the file(s) are to be copied.
sl@0
  1137
				 Any path components which are not specified here will be
sl@0
  1138
                 taken from the session path
sl@0
  1139
@param aSwitches Specify zero for no overwriting and no recursion;
sl@0
  1140
                 CFileMan::EOverWrite to overwrite files with the same name;
sl@0
  1141
                 CFileMan::ERecurse for recursion.
sl@0
  1142
                 By default, the synchronous variant of this function operates
sl@0
  1143
                 non-recursively and with overwriting.
sl@0
  1144
sl@0
  1145
@return KErrNone if successful, KErrNotFound if source directory is empty, otherwise one of the other system-wide error codes.
sl@0
  1146
sl@0
  1147
@see CFileBase::GetLastError()
sl@0
  1148
sl@0
  1149
@capability AllFiles
sl@0
  1150
sl@0
  1151
@capability Dependent If the path for anOld begins with /Sys then Tcb capability is required.
sl@0
  1152
@capability Dependent If the path for anOld begins with /Resource then Tcb capability is required
sl@0
  1153
sl@0
  1154
*/
sl@0
  1155
	{
sl@0
  1156
	TRACEMULT4(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy2, MODULEUID, (TUint) this, anOld, aNew, aSwitches);
sl@0
  1157
sl@0
  1158
	if (iSwitches&KFManBusyFlag)
sl@0
  1159
		{
sl@0
  1160
		TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy2Return, MODULEUID, KErrInUse);
sl@0
  1161
		return(KErrInUse);
sl@0
  1162
		}
sl@0
  1163
	SetFlags(aSwitches&EOverWrite,aSwitches&ERecurse,ETrue,EFalse);
sl@0
  1164
	RETURNIFERRORD(r,iFs.Parse(anOld,iSrcFile),UTraceModuleEfsrv::ECFileManCopy2Return);
sl@0
  1165
	RETURNIFERROR(r,iFs.Parse(aNew,_L("*"),iTrgFile),UTraceModuleEfsrv::ECFileManCopy2Return);
sl@0
  1166
	CheckForDirectory();
sl@0
  1167
sl@0
  1168
	if((iSwitches&KRecurseFlag) && iTrgFile.DriveAndPath().MatchF(iSrcFile.FullName()) != KErrNotFound)
sl@0
  1169
		{
sl@0
  1170
		TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy2Return, MODULEUID, KErrArgument);
sl@0
  1171
		return(KErrArgument);
sl@0
  1172
		}
sl@0
  1173
sl@0
  1174
	iAction = EInternalCopy;
sl@0
  1175
	iMatchEntry=KEntryAttMaskSupported;
sl@0
  1176
	iNumberOfFilesProcessed = 0;
sl@0
  1177
	TRAP(r,RunL());
sl@0
  1178
	TInt ret=(r==KErrNone) ? iLastError : r;
sl@0
  1179
	DoSynchronize(r);
sl@0
  1180
sl@0
  1181
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy2Return, MODULEUID, ret);
sl@0
  1182
	return(ret);
sl@0
  1183
	}
sl@0
  1184
sl@0
  1185
sl@0
  1186
sl@0
  1187
sl@0
  1188
EXPORT_C TInt CFileMan::Delete(const TDesC& aName,TUint aSwitches,TRequestStatus& aStatus)
sl@0
  1189
/**
sl@0
  1190
Deletes one or more files.
sl@0
  1191
sl@0
  1192
This is an asynchronous function.
sl@0
  1193
Its behaviour is the same as the synchronous overload.
sl@0
  1194
sl@0
  1195
@param aName     Path indicating the file(s) to be deleted.
sl@0
  1196
                 May either be a full path, or relative to the session path.
sl@0
  1197
                 Use wildcards to specify more than one file.
sl@0
  1198
                 NOTE: if you pass KNullDesC, the empty (or null) descriptor,
sl@0
  1199
                 then the function interprets this to mean \\*.*
sl@0
  1200
@param aSwitches Specify:
sl@0
  1201
                 zero for no recursion;
sl@0
  1202
                 CFileMan::ERecurse for recursion.
sl@0
  1203
                 By default, the synchronous variant of this function
sl@0
  1204
                 operates non-recursively.
sl@0
  1205
@param aStatus   The request status object. On request completion,
sl@0
  1206
                 indicates how the request completed:
sl@0
  1207
                 KErrNone, if successful, otherwise one of the other system-wide error
sl@0
  1208
                 codes.
sl@0
  1209
sl@0
  1210
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
  1211
					is still pending; otherwise one of the other system-wide error codes
sl@0
  1212
sl@0
  1213
@capability Dependent If aName is /Sys then Tcb capability is required.
sl@0
  1214
@capability Dependent If aName begins with /Private and does not match this process' SID
sl@0
  1215
					  then AllFiles capability is required.
sl@0
  1216
@capability Dependent If aName is /Resource then Tcb capability is required.
sl@0
  1217
sl@0
  1218
@see KNullDesC
sl@0
  1219
*/
sl@0
  1220
	{
sl@0
  1221
	TRACEMULT4(UTF::EBorder, UTraceModuleEfsrv::ECFileManDelete1, MODULEUID, (TUint) this, aName, aSwitches, (TUint) &aStatus);
sl@0
  1222
sl@0
  1223
	TInt r;
sl@0
  1224
	if (iSwitches&KFManBusyFlag)
sl@0
  1225
		{
sl@0
  1226
		r = KErrInUse;
sl@0
  1227
		}
sl@0
  1228
	else
sl@0
  1229
		{
sl@0
  1230
		iStatus=&aStatus;
sl@0
  1231
		r = Delete(aName,aSwitches);
sl@0
  1232
		}
sl@0
  1233
sl@0
  1234
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManDelete1Return, MODULEUID, r);
sl@0
  1235
	return(r);
sl@0
  1236
	}
sl@0
  1237
sl@0
  1238
sl@0
  1239
sl@0
  1240
sl@0
  1241
EXPORT_C TInt CFileMan::Delete(const TDesC& aName,TUint aSwitches)
sl@0
  1242
/**
sl@0
  1243
Deletes one or more files.
sl@0
  1244
sl@0
  1245
This is a synchronous function.
sl@0
  1246
sl@0
  1247
This function can operate recursively or non-recursively.
sl@0
  1248
When operating non-recursively, only the matching files located in
sl@0
  1249
the directory specified in aName are affected.
sl@0
  1250
When operating recursively, all matching files in the directory hierarchy
sl@0
  1251
below the directory specified in aName will be deleted.
sl@0
  1252
sl@0
  1253
Note that read-only and open files may not be deleted.
sl@0
  1254
Attempting to do so will return an error for that file.
sl@0
  1255
Error codes may be retrieved using CFileBase::GetLastError().
sl@0
  1256
sl@0
  1257
@param aName     Path indicating the file(s) to be deleted.
sl@0
  1258
                 May either be a full path, or relative to the session path.
sl@0
  1259
                 Use wildcards to specify more than one file.
sl@0
  1260
                 NOTE: if you pass KNullDesC, the empty (or null) descriptor,
sl@0
  1261
                 then the function interprets this to mean \\*.*
sl@0
  1262
@param aSwitches Specify:
sl@0
  1263
                 zero for no recursion;
sl@0
  1264
                 CFileMan::ERecurse for recursion.
sl@0
  1265
                 By default, the synchronous variant of this function
sl@0
  1266
                 operates non-recursively.
sl@0
  1267
sl@0
  1268
@return KErrNone if successful, otherwise one of the other system-wide error
sl@0
  1269
        codes.
sl@0
  1270
sl@0
  1271
@see CFileBase::GetLastError()
sl@0
  1272
sl@0
  1273
@capability Dependent If aName is /Sys then Tcb capability is required.
sl@0
  1274
@capability Dependent If aName begins with /Private and does not match this process' SID
sl@0
  1275
					  then AllFiles capability is required.
sl@0
  1276
@capability Dependent If aName is /Resource then Tcb capability is required.
sl@0
  1277
sl@0
  1278
@see KNullDesC
sl@0
  1279
*/
sl@0
  1280
	{
sl@0
  1281
	TRACEMULT3(UTF::EBorder, UTraceModuleEfsrv::ECFileManDelete2, MODULEUID, (TUint) this, aName, aSwitches);
sl@0
  1282
sl@0
  1283
	TInt ret;
sl@0
  1284
	if (iSwitches&KFManBusyFlag)
sl@0
  1285
		{
sl@0
  1286
		ret = KErrInUse;
sl@0
  1287
		}
sl@0
  1288
	else
sl@0
  1289
		{
sl@0
  1290
		SetFlags(aSwitches&EOverWrite,aSwitches&ERecurse,ETrue,EFalse);
sl@0
  1291
		RETURNIFERRORD(r,iFs.Parse(aName,iSrcFile),UTraceModuleEfsrv::ECFileManDelete2Return);
sl@0
  1292
		iAction = EInternalDelete;
sl@0
  1293
		iMatchEntry=KEntryAttHidden|KEntryAttMatchExclude|KEntryAttDir;
sl@0
  1294
	//	Exclude directories and system files - include hidden files
sl@0
  1295
		iNumberOfFilesProcessed = 0;
sl@0
  1296
		TRAP(r,RunL());
sl@0
  1297
		ret=(r==KErrNone) ? iLastError : r;
sl@0
  1298
		DoSynchronize(r);
sl@0
  1299
		}
sl@0
  1300
sl@0
  1301
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManDelete2Return, MODULEUID, ret);
sl@0
  1302
	return(ret);
sl@0
  1303
	}
sl@0
  1304
sl@0
  1305
sl@0
  1306
sl@0
  1307
sl@0
  1308
EXPORT_C TInt CFileMan::Move(const TDesC& anOld,const TDesC& aNew,TUint aSwitches,TRequestStatus& aStatus)
sl@0
  1309
/**
sl@0
  1310
Moves one or more files.
sl@0
  1311
sl@0
  1312
This is an asynchronous function.
sl@0
  1313
Its behaviour is the same as the synchronous overload.
sl@0
  1314
sl@0
  1315
@param anOld     Path indicating the files to be moved. May be either
sl@0
  1316
                 a full path, or relative to the session path. Any path
sl@0
  1317
				 components which are not specified here will be taken
sl@0
  1318
				 from the session path.
sl@0
  1319
@param aNew      Path indicating the directory into which the file(s) are
sl@0
  1320
                 to be moved. Any path components which are not specified
sl@0
  1321
                 here will be taken from the session path.
sl@0
  1322
@param aSwitches Specify zero for no overwriting and no recursion;
sl@0
  1323
                 CFileMan::EOverWrite to overwrite files with the same name;
sl@0
  1324
                 CFileMan::ERecurse for recursion.
sl@0
  1325
                 By default, the synchronous variant of this function operates
sl@0
  1326
                 non-recursively and with overwriting.
sl@0
  1327
@param aStatus   The request status object. On request completion,
sl@0
  1328
                 indicates how the request completed:
sl@0
  1329
                 KErrNone, if successful, otherwise one of the other system-wide error
sl@0
  1330
                 codes.
sl@0
  1331
sl@0
  1332
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
  1333
					is still pending; otherwise one of the other system-wide error codes
sl@0
  1334
sl@0
  1335
@capability Dependent If the path in aNew starts with /Sys then capability Tcb is required
sl@0
  1336
@capability Dependent If the path in aNew starts with /Resource then capability Tcb is required
sl@0
  1337
sl@0
  1338
@capability AllFiles
sl@0
  1339
sl@0
  1340
@capability Dependent If the path in anOld starts with /Sys then Tcb capability is required.
sl@0
  1341
@capability Dependent If the path in anOld starts with /Resource then Tcb capability is required.
sl@0
  1342
sl@0
  1343
*/
sl@0
  1344
	{
sl@0
  1345
	TRACEMULT5(UTF::EBorder, UTraceModuleEfsrv::ECFileManMove1, MODULEUID,
sl@0
  1346
		(TUint) this, anOld, aNew, aSwitches, (TUint) &aStatus);
sl@0
  1347
sl@0
  1348
	TInt r;
sl@0
  1349
	if (iSwitches&KFManBusyFlag)
sl@0
  1350
		{
sl@0
  1351
		r = KErrInUse;
sl@0
  1352
		}
sl@0
  1353
	else
sl@0
  1354
		{
sl@0
  1355
		iStatus=&aStatus;
sl@0
  1356
		r = Move(anOld,aNew,aSwitches);
sl@0
  1357
		}
sl@0
  1358
sl@0
  1359
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManMove1Return, MODULEUID, r);
sl@0
  1360
	return r;
sl@0
  1361
	}
sl@0
  1362
sl@0
  1363
sl@0
  1364
sl@0
  1365
sl@0
  1366
EXPORT_C TInt CFileMan::Move(const TDesC& anOld,const TDesC& aNew,TUint aSwitches)
sl@0
  1367
/**
sl@0
  1368
Moves one or more files.
sl@0
  1369
sl@0
  1370
This is a synchronous function.
sl@0
  1371
sl@0
  1372
Optionally, this function can be set to overwrite any files with the same name
sl@0
  1373
which exist in the target directory. If the flag is set for no overwriting,
sl@0
  1374
then any files with the same name will not be overwritten, and
sl@0
  1375
an error (KErrAlreadyExists) will be returned for that file.
sl@0
  1376
Error codes may be retrieved using CFileBase::GetLastError().
sl@0
  1377
By default, when the function is operating synchronously, files are overwritten.
sl@0
  1378
sl@0
  1379
When this function is operating recursively, all intermediate directories will
sl@0
  1380
be created, including all directories in the destination path specified
sl@0
  1381
by aNew which do not already exist.
sl@0
  1382
sl@0
  1383
If recursive operation is not set, only the matching files located in
sl@0
  1384
the single directory specified in anOld are moved. No intermediate directories
sl@0
  1385
will be created; if any directories in the destination path do not exist,
sl@0
  1386
no files will be moved, and this function will return KErrPathNotFound.
sl@0
  1387
sl@0
  1388
The behaviour of the move operation is sensitive to the presence (or absence)
sl@0
  1389
of a trailing backslash ("\") character on the end of the source path:
sl@0
  1390
- if there is a trailing backslash ("\") character, then the operation moves
sl@0
  1391
  the content of the last directory level only.
sl@0
  1392
- if there is no trailing backslash ("\") character, then the operation behaves
sl@0
  1393
  recursively by default and moves both the last directory level and all of its content.
sl@0
  1394
  Notice that no trailing backslash ("\") implies moving files recursively automatically.
sl@0
  1395
sl@0
  1396
For example, if the directory level "b" contains the files F1,F2 and F3, then:
sl@0
  1397
@code
sl@0
  1398
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1399
...
sl@0
  1400
fm->Move(_L("C:\\a\\b\\"), _L("C:\\x\\y\\"), CFileMan::ERecurse);
sl@0
  1401
@endcode
sl@0
  1402
sl@0
  1403
results in files F1, F2 and F3 being moved from C:\\a\\b to C:\\x\\y, leaving the
sl@0
  1404
path C:\\a\\b unchanged, except that it no longer contains the files
sl@0
  1405
F1, F2 and F3.
sl@0
  1406
sl@0
  1407
If there is no trailing backslash character, for example:
sl@0
  1408
@code
sl@0
  1409
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1410
...
sl@0
  1411
fm->Move(_L("C:\\a\\b"), _L("C:\\x\\y\\"), CFileMan::ERecurse);
sl@0
  1412
@endcode
sl@0
  1413
sl@0
  1414
then both the directory level "b" and its contents are moved. This means that
sl@0
  1415
there is no longer a directory "b" under C:\\a. Instead there is a new
sl@0
  1416
directory structure C:\\x\\y\\b and the files F1, F2, and F3 now exist
sl@0
  1417
under C:\\x\\y\\b. Also if "b" contains subdirectories, then these are also
sl@0
  1418
moved along with "b".
sl@0
  1419
sl@0
  1420
If there is no trailing backslash character and the switch is not set, i.e.
sl@0
  1421
0 is passed as an argument, the operation behaves the same way as by passing
sl@0
  1422
CFileMan::ERecurse flag.
sl@0
  1423
sl@0
  1424
for example:
sl@0
  1425
@code
sl@0
  1426
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1427
...
sl@0
  1428
fm->Move(_L("C:\\a\\b"), _L("C:\\x\\y\\"), 0);
sl@0
  1429
@endcode
sl@0
  1430
sl@0
  1431
The example above produces the same output as:
sl@0
  1432
sl@0
  1433
@code
sl@0
  1434
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1435
...
sl@0
  1436
fm->Move(_L("C:\\a\\b"), _L("C:\\x\\y\\"), CFileMan::ERecurse);
sl@0
  1437
@endcode
sl@0
  1438
sl@0
  1439
Notes:
sl@0
  1440
sl@0
  1441
-# Read-only, hidden and system files can be moved and the source file's
sl@0
  1442
   attributes are preserved in the target file, but open files cannot
sl@0
  1443
   be moved. Attempting to move an open file will return an error for
sl@0
  1444
   that file, as retrieved by CFileBase::GetLastError().
sl@0
  1445
sl@0
  1446
@param anOld	 Path indicating the files to be moved. May be either a full path, or
sl@0
  1447
				 relative to the session path. Note that if you specify a directory level,
sl@0
  1448
				 then the behaviour of the move operation is sensitive to the presence
sl@0
  1449
				 (or absence) of a trailing backslash ("\") character. Any path components
sl@0
  1450
				 which are not specified here will be taken from the session path. See the
sl@0
  1451
				 main description for the detailed explanation.
sl@0
  1452
@param aNew      Path indicating the directory into which the file(s) are to be moved.
sl@0
  1453
				 Any path components which are not specified here will be taken from the session path.
sl@0
  1454
@param aSwitches CFileMan::EOverWrite to overwrite files with the same name;
sl@0
  1455
                 CFileMan::ERecurse for recursion.
sl@0
  1456
                 By default, the synchronous variant of this function operates non-recursively and
sl@0
  1457
				 with overwriting. And no trailing backslash ("\") character at the end of source path
sl@0
  1458
				 always means CFileMan::ERecurse.
sl@0
  1459
sl@0
  1460
@return KErrNone if successful, otherwise one of the other system-wide error
sl@0
  1461
        codes.
sl@0
  1462
sl@0
  1463
@capability Dependent If the path in aNew starts with /Sys then capability Tcb is required
sl@0
  1464
@capability Dependent If the path in aNew starts with /Resource then capability Tcb is required
sl@0
  1465
sl@0
  1466
@capability AllFiles
sl@0
  1467
sl@0
  1468
@capability Dependent If the path in anOld starts with /Sys then Tcb capability is required.
sl@0
  1469
@capability Dependent If the path in anOld starts with /Resource then Tcb capability is required.
sl@0
  1470
sl@0
  1471
@see CFileBase::GetLastError()
sl@0
  1472
*/
sl@0
  1473
	{
sl@0
  1474
	TRACEMULT4(UTF::EBorder, UTraceModuleEfsrv::ECFileManMove2, MODULEUID,
sl@0
  1475
		(TUint) this, anOld, aNew, aSwitches);
sl@0
  1476
sl@0
  1477
sl@0
  1478
	if (iSwitches&KFManBusyFlag)
sl@0
  1479
		{
sl@0
  1480
		TRACE1(UTF::EBorder, UTraceModuleEfsrv::ECFileManMove2Return, MODULEUID, KErrInUse);
sl@0
  1481
		return(KErrInUse);
sl@0
  1482
		}
sl@0
  1483
sl@0
  1484
	iNumberOfFilesProcessed = 0;
sl@0
  1485
sl@0
  1486
	RETURNIFERRORD(r,iFs.Parse(anOld,iSrcFile),UTraceModuleEfsrv::ECFileManMove2Return);
sl@0
  1487
	RETURNIFERROR(r,iFs.Parse(aNew,_L("*"),iTrgFile),UTraceModuleEfsrv::ECFileManMove2Return);
sl@0
  1488
sl@0
  1489
	TInt ret = KErrNone;
sl@0
  1490
	TBool aComplete = EFalse;
sl@0
  1491
	if(SrcTrgDrivesIdentical())
sl@0
  1492
		{
sl@0
  1493
		ret = SetupMoveOnSameDrive(aSwitches, aComplete);
sl@0
  1494
		}
sl@0
  1495
	else
sl@0
  1496
		{
sl@0
  1497
		ret = SetupMoveAcrossDrives(aSwitches);
sl@0
  1498
		}
sl@0
  1499
sl@0
  1500
	if(ret != KErrNone || aComplete)
sl@0
  1501
		{
sl@0
  1502
		if (iStatus)
sl@0
  1503
			{
sl@0
  1504
			User::RequestComplete(iStatus, ret);
sl@0
  1505
			}
sl@0
  1506
		TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManMove2Return, MODULEUID, ret);
sl@0
  1507
		return(ret);
sl@0
  1508
		}
sl@0
  1509
sl@0
  1510
	iMatchEntry = KEntryAttMaskSupported;
sl@0
  1511
	if((aSwitches&ERecurse)==0 && iMovingContents)
sl@0
  1512
		{
sl@0
  1513
		iMatchEntry = KMovingFilesMask;
sl@0
  1514
		}
sl@0
  1515
sl@0
  1516
	// Do the Move or Rename Operation
sl@0
  1517
	TRAP(r,RunL());
sl@0
  1518
	ret = (r==KErrNone) ? iLastError : r;
sl@0
  1519
	DoSynchronize(r);
sl@0
  1520
sl@0
  1521
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManMove2Return, MODULEUID, ret);
sl@0
  1522
	return(ret);
sl@0
  1523
	}
sl@0
  1524
sl@0
  1525
sl@0
  1526
TBool CFileMan::SrcTrgDrivesIdentical()
sl@0
  1527
//
sl@0
  1528
// Returns ETrue if the source and target drives are the same
sl@0
  1529
//	- Used by CFileMan::Move operations to determine whether to rename or move the files
sl@0
  1530
//
sl@0
  1531
	{
sl@0
  1532
	return iSrcFile.Drive().MatchF(iTrgFile.Drive()) != KErrNotFound;
sl@0
  1533
	}
sl@0
  1534
sl@0
  1535
sl@0
  1536
TInt CFileMan::SetupDirectoryForMove(TBool& aSrcIsDir)
sl@0
  1537
/**
sl@0
  1538
 * Sets up the target specification to include the new target directory if required.
sl@0
  1539
 * 
sl@0
  1540
 * @param aSrcIsDir	Set to ETrue if the source specifies that the directory is to be moved in its entirety,
sl@0
  1541
 * 					or EFalse if only the contents of the directory need to be moved.
sl@0
  1542
 * 
sl@0
  1543
 * @return KErrNone if successful, otherwise one of the system wide error codes.
sl@0
  1544
 */
sl@0
  1545
	{
sl@0
  1546
	iMovingContents = ETrue;
sl@0
  1547
	aSrcIsDir = EFalse;
sl@0
  1548
	
sl@0
  1549
	TPtrC nameAndExt(iSrcFile.NameAndExt());
sl@0
  1550
	if (nameAndExt == _L("*") || nameAndExt == _L("*.*"))
sl@0
  1551
		{
sl@0
  1552
		// Wildcard specification - Move the entire contents of the directory to the target
sl@0
  1553
		aSrcIsDir = ETrue;
sl@0
  1554
		}
sl@0
  1555
	else
sl@0
  1556
		{
sl@0
  1557
		TInt src = iFs.Entry(iSrcFile.FullName(), iTmpEntry);
sl@0
  1558
		if ((src == KErrNone && iTmpEntry.iAtt&KEntryAttDir) || (!iSrcFile.NamePresent() && iSrcFile.IsRoot()))
sl@0
  1559
			{
sl@0
  1560
			aSrcIsDir = ETrue;
sl@0
  1561
sl@0
  1562
			// A directory is specified.
sl@0
  1563
			//  - Mandatory recursion with Wildcard Copy
sl@0
  1564
			//	- Target is a directory (Enforced by MakeParseWild)
sl@0
  1565
sl@0
  1566
			MakeParseWild(iTrgFile, iTmpName1);
sl@0
  1567
sl@0
  1568
			// Construct the target name by parsing
sl@0
  1569
			// the source path for the directory name.
sl@0
  1570
			TPtrC srcPath(iSrcFile.FullName());
sl@0
  1571
			TInt srcPathLen = srcPath.Length() - 1;
sl@0
  1572
sl@0
  1573
			iMovingContents = (srcPath[srcPathLen] == KPathDelimiter);	// Moving the directory itself, or the contents?
sl@0
  1574
sl@0
  1575
			if(!iMovingContents)
sl@0
  1576
				{
sl@0
  1577
				// No path delimiter specified
sl@0
  1578
				//	- move the whole directory (if specified)
sl@0
  1579
				TInt len = srcPath.Length();
sl@0
  1580
sl@0
  1581
				TInt idx = srcPath.Left(len).LocateReverse(KPathDelimiter);
sl@0
  1582
sl@0
  1583
				if((idx >= 2) && (idx != KErrNotFound))
sl@0
  1584
					{
sl@0
  1585
					// Source path is a directory (not just the drive)
sl@0
  1586
					TPtrC mid(srcPath.Left(len).Mid(1+idx));
sl@0
  1587
					TInt r = iTrgFile.AddDir(mid);
sl@0
  1588
					if (r != KErrNone)
sl@0
  1589
						return r;
sl@0
  1590
					}
sl@0
  1591
				}
sl@0
  1592
			}
sl@0
  1593
		}
sl@0
  1594
sl@0
  1595
	return KErrNone;
sl@0
  1596
	}
sl@0
  1597
sl@0
  1598
sl@0
  1599
TInt CFileMan::SetupTargetDirectory(TBool aOverWrite, TBool& aComplete)
sl@0
  1600
	{
sl@0
  1601
	aComplete = EFalse;
sl@0
  1602
sl@0
  1603
	TInt trgErr = iFs.Entry(iTrgFile.DriveAndPath(), iTmpEntry);
sl@0
  1604
sl@0
  1605
	TEntry srcEntry;
sl@0
  1606
	TInt srcErr = iFs.Entry(iSrcFile.FullName(), srcEntry);
sl@0
  1607
sl@0
  1608
	if(srcErr == KErrNone && trgErr == KErrNone)
sl@0
  1609
		{
sl@0
  1610
        if ((srcEntry.iAtt&KEntryAttDir) != (iTmpEntry.iAtt&KEntryAttDir))
sl@0
  1611
        	{
sl@0
  1612
        	// return KErrAccessDenied if it is trying to overwrite a file to a dir or vice versa.
sl@0
  1613
        	return KErrAccessDenied;
sl@0
  1614
        	}
sl@0
  1615
		}
sl@0
  1616
sl@0
  1617
	if(trgErr == KErrNone)
sl@0
  1618
		{
sl@0
  1619
		// Already Exists - Overwrite if flags set
sl@0
  1620
		if(!aOverWrite)
sl@0
  1621
			{
sl@0
  1622
			trgErr = KErrAlreadyExists;
sl@0
  1623
			}
sl@0
  1624
		else
sl@0
  1625
			{
sl@0
  1626
			iNumberOfFilesProcessed++;
sl@0
  1627
			}
sl@0
  1628
		}
sl@0
  1629
	else if((trgErr == KErrNotFound) || (trgErr == KErrPathNotFound))
sl@0
  1630
		{
sl@0
  1631
		if(SrcTrgDrivesIdentical())
sl@0
  1632
			{
sl@0
  1633
			// When moving a directory on the same drive, the directory can simply be renamed...
sl@0
  1634
			TParse& midDir = iTmpParse;
sl@0
  1635
			midDir = iTrgFile;
sl@0
  1636
			if(midDir.PopDir() == KErrNone)
sl@0
  1637
				{
sl@0
  1638
				// ...before renaming, ensure that all intermediate directories exist
sl@0
  1639
				trgErr = iFs.MkDirAll(midDir.DriveAndPath());
sl@0
  1640
				if(trgErr == KErrAlreadyExists)
sl@0
  1641
					{
sl@0
  1642
					trgErr = KErrNone;
sl@0
  1643
					}
sl@0
  1644
				}
sl@0
  1645
sl@0
  1646
			if (trgErr == KErrNone)
sl@0
  1647
				{
sl@0
  1648
				// ...and finally rename the source directory
sl@0
  1649
				trgErr = iFs.Rename(iSrcFile.FullName(),iTrgFile.DriveAndPath());
sl@0
  1650
				aComplete = ETrue;
sl@0
  1651
				}
sl@0
  1652
			}
sl@0
  1653
		else
sl@0
  1654
			{
sl@0
  1655
			trgErr = iFs.MkDirAll(iTrgFile.FullName());
sl@0
  1656
			}
sl@0
  1657
		iNumberOfFilesProcessed++;
sl@0
  1658
		}
sl@0
  1659
sl@0
  1660
	return(trgErr);
sl@0
  1661
	}
sl@0
  1662
sl@0
  1663
sl@0
  1664
TInt CFileMan::SetupMoveOnSameDrive(TUint aSwitches, TBool& aComplete)
sl@0
  1665
	{
sl@0
  1666
	// Moving on the same drive.
sl@0
  1667
sl@0
  1668
	aComplete = EFalse;
sl@0
  1669
sl@0
  1670
	TBool srcIsDir = EFalse;
sl@0
  1671
    TInt ret = SetupDirectoryForMove(srcIsDir);
sl@0
  1672
    if (ret != KErrNone)
sl@0
  1673
		{
sl@0
  1674
        return ret;
sl@0
  1675
		}
sl@0
  1676
sl@0
  1677
	TBool scanDown = ETrue;
sl@0
  1678
	TBool recurse = (aSwitches & ERecurse);
sl@0
  1679
sl@0
  1680
	iAction = EInternalRenameForMove;
sl@0
  1681
sl@0
  1682
	TFileName& srcpath = iTmpName1;
sl@0
  1683
	srcpath.Copy(iSrcFile.FullName());
sl@0
  1684
	if(srcpath.Length()<KMaxFileName && srcpath.Length()>1 && srcpath[srcpath.Length()-1]!=KPathDelimiter)
sl@0
  1685
		{
sl@0
  1686
		srcpath.Append(KPathDelimiter);
sl@0
  1687
		}
sl@0
  1688
sl@0
  1689
	// If the source path is a subset of the target path then Move operation is not allowed
sl@0
  1690
	if((srcIsDir && recurse) || (srcIsDir && !iTrgFile.IsRoot() && !iMovingContents))
sl@0
  1691
		{
sl@0
  1692
		if(iTrgFile.FullName().Left(srcpath.Length()).MatchF(srcpath)==0)
sl@0
  1693
			{
sl@0
  1694
			aComplete = ETrue;
sl@0
  1695
			return KErrInUse;
sl@0
  1696
			}
sl@0
  1697
		}
sl@0
  1698
	// if any of the SRC folders already existing in TRG, scan upwards
sl@0
  1699
	if(iMovingContents)
sl@0
  1700
		{
sl@0
  1701
		CDirScan* srcScanDir = NULL;
sl@0
  1702
		CDirScan* trgScanDir = NULL;
sl@0
  1703
		CDir* srcEntryList = NULL;
sl@0
  1704
		CDir* trgEntryList = NULL;
sl@0
  1705
		TInt trgCnt = 0;
sl@0
  1706
		TInt srcCnt = 0;
sl@0
  1707
sl@0
  1708
		TRAP(ret,(srcScanDir = CDirScan::NewL(iFs)));
sl@0
  1709
		if (ret!=KErrNone)
sl@0
  1710
			{
sl@0
  1711
			goto CleanUp;
sl@0
  1712
			}
sl@0
  1713
		TRAP(ret,srcScanDir->SetScanDataL(iSrcFile.FullName(),KEntryAttMaskSupported,ESortByName));
sl@0
  1714
		if (ret!=KErrNone)
sl@0
  1715
			{
sl@0
  1716
			goto CleanUp;
sl@0
  1717
			}
sl@0
  1718
		TRAP(ret,srcScanDir->NextL(srcEntryList));
sl@0
  1719
		if(ret!=KErrNone)
sl@0
  1720
			{
sl@0
  1721
			goto CleanUp;
sl@0
  1722
			}
sl@0
  1723
		TRAP(ret,(trgScanDir=CDirScan::NewL(iFs)));
sl@0
  1724
		if (ret!=KErrNone)
sl@0
  1725
			{
sl@0
  1726
			goto CleanUp;
sl@0
  1727
			}
sl@0
  1728
		TRAP(ret,trgScanDir->SetScanDataL(iTrgFile.FullName(),KEntryAttMaskSupported,ESortByName));
sl@0
  1729
		if (ret!=KErrNone)
sl@0
  1730
			{
sl@0
  1731
			goto CleanUp;
sl@0
  1732
			}
sl@0
  1733
		TRAP(ret,trgScanDir->NextL(trgEntryList));
sl@0
  1734
		if(ret!=KErrNone)
sl@0
  1735
			{
sl@0
  1736
			goto CleanUp;
sl@0
  1737
			}
sl@0
  1738
		for(trgCnt=trgEntryList->Count()-1; trgCnt>-1; trgCnt--)
sl@0
  1739
			{
sl@0
  1740
			for(srcCnt=srcEntryList->Count()-1; srcCnt>-1; srcCnt--)
sl@0
  1741
				{
sl@0
  1742
				if( (*srcEntryList)[srcCnt].iName == (*trgEntryList)[trgCnt].iName
sl@0
  1743
					&& ((*srcEntryList)[srcCnt].iAtt & KEntryAttDir)
sl@0
  1744
					&& ((*trgEntryList)[trgCnt].iAtt & KEntryAttDir))
sl@0
  1745
					{
sl@0
  1746
					// Set scan upwards
sl@0
  1747
					scanDown = EFalse;
sl@0
  1748
					goto CleanUp;
sl@0
  1749
					}
sl@0
  1750
				}// end inner for loop
sl@0
  1751
			} // end outer for loop
sl@0
  1752
CleanUp:
sl@0
  1753
		// clean up
sl@0
  1754
		if(srcEntryList!=NULL)
sl@0
  1755
			delete srcEntryList;
sl@0
  1756
		if(trgEntryList!=NULL)
sl@0
  1757
			delete trgEntryList;
sl@0
  1758
		if(srcScanDir!=NULL)
sl@0
  1759
			delete srcScanDir;
sl@0
  1760
		if(trgScanDir!=NULL)
sl@0
  1761
			delete trgScanDir;
sl@0
  1762
		}// end if(iMovingContents)
sl@0
  1763
sl@0
  1764
	if(srcIsDir && !iTrgFile.IsRoot() && !iMovingContents)
sl@0
  1765
		{
sl@0
  1766
		ret = SetupTargetDirectory(aSwitches & EOverWrite, aComplete);
sl@0
  1767
		if(ret != KErrNone || aComplete)
sl@0
  1768
			{
sl@0
  1769
			return(ret);
sl@0
  1770
			}
sl@0
  1771
		}
sl@0
  1772
	if(!iMovingContents)
sl@0
  1773
		{
sl@0
  1774
		recurse = ETrue;
sl@0
  1775
		scanDown = EFalse;
sl@0
  1776
		}
sl@0
  1777
	if(srcIsDir)
sl@0
  1778
		{
sl@0
  1779
		MakeParseWild(iSrcFile, iTmpName1);
sl@0
  1780
		}
sl@0
  1781
sl@0
  1782
	SetFlags(aSwitches & EOverWrite, recurse, scanDown, ETrue);
sl@0
  1783
	return(KErrNone);
sl@0
  1784
	}
sl@0
  1785
sl@0
  1786
sl@0
  1787
TInt CFileMan::SetupMoveAcrossDrives(TUint aSwitches)
sl@0
  1788
	{
sl@0
  1789
	// Moving across drives.  We may need to recurse,
sl@0
  1790
	// depending on the supplied source path.
sl@0
  1791
sl@0
  1792
	TBool srcIsDir = EFalse;
sl@0
  1793
    TInt ret = SetupDirectoryForMove(srcIsDir);
sl@0
  1794
    if (ret != KErrNone)
sl@0
  1795
		{
sl@0
  1796
        return ret;
sl@0
  1797
		}
sl@0
  1798
    
sl@0
  1799
	TBool recurse = (aSwitches & ERecurse);
sl@0
  1800
	TBool scanDown = (recurse) ? (TBool)EFalse : (TBool)ETrue;
sl@0
  1801
sl@0
  1802
	if(srcIsDir)
sl@0
  1803
		{
sl@0
  1804
		if(!iMovingContents)
sl@0
  1805
			{
sl@0
  1806
			recurse = ETrue;
sl@0
  1807
			if(!iTrgFile.IsRoot())
sl@0
  1808
				{
sl@0
  1809
				TBool complete = EFalse;
sl@0
  1810
				ret = SetupTargetDirectory(aSwitches & EOverWrite, complete);
sl@0
  1811
				if(ret != KErrNone || complete)
sl@0
  1812
					{
sl@0
  1813
					return(ret);
sl@0
  1814
					}
sl@0
  1815
				}
sl@0
  1816
			}
sl@0
  1817
		}
sl@0
  1818
sl@0
  1819
	CheckForDirectory();
sl@0
  1820
	iAction = EInternalCopyForMove;
sl@0
  1821
	SetFlags(aSwitches & EOverWrite, recurse, scanDown, EFalse);
sl@0
  1822
	return(KErrNone);
sl@0
  1823
	}
sl@0
  1824
sl@0
  1825
TInt CFileMan::RenameInvalidEntry(const TDesC& /*aName*/,const TDesC& /*aNewName*/,TUint /*aSwitches*/)
sl@0
  1826
//
sl@0
  1827
// Start rename operation
sl@0
  1828
//
sl@0
  1829
	{
sl@0
  1830
	return KErrNotSupported;
sl@0
  1831
	}
sl@0
  1832
sl@0
  1833
sl@0
  1834
sl@0
  1835
sl@0
  1836
EXPORT_C TInt CFileMan::Rename(const TDesC& aName,const TDesC& aNewName,TUint aSwitches,TRequestStatus& aStatus)
sl@0
  1837
/**
sl@0
  1838
Renames one or more files.
sl@0
  1839
sl@0
  1840
This is an asynchronous function.
sl@0
  1841
Its behaviour is the same as the synchronous overload.
sl@0
  1842
sl@0
  1843
@param aName     Path specifying the file(s) to be renamed. Any path components
sl@0
  1844
				 which are not specified
sl@0
  1845
                 here will be taken from the session path.
sl@0
  1846
@param aNewName  Path specifying the new name for the files and/or
sl@0
  1847
                 the new directory. Any directories specified in this path
sl@0
  1848
                 that do not exist, will be created. Any path components
sl@0
  1849
				 which are not specified here will be taken from the session path.
sl@0
  1850
@param aSwitches Specify zero for no overwriting;
sl@0
  1851
                 CFileMan::EOverWrite to overwrite files with the same name.
sl@0
  1852
                 This function cannot operate recursively.
sl@0
  1853
@param aStatus   The request status object. On request completion,
sl@0
  1854
                 indicates how the request completed:
sl@0
  1855
                 KErrNone, if successful, otherwise one of the other system-wide error
sl@0
  1856
                 codes.
sl@0
  1857
sl@0
  1858
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
  1859
					is still pending; otherwise one of the other system-wide error codes
sl@0
  1860
sl@0
  1861
@capability Dependent If either aName or aNewName is /Sys then Tcb capability is required.
sl@0
  1862
@capability Dependent If either aName or aNewName begins with /Private and does not match
sl@0
  1863
					  this process' SID then AllFiles capability is required.
sl@0
  1864
@capability Dependent If either aName or aNewName is /Resource then Tcb capability is required.
sl@0
  1865
sl@0
  1866
*/
sl@0
  1867
	{
sl@0
  1868
	TRACEMULT5(UTF::EBorder, UTraceModuleEfsrv::ECFileManRename1, MODULEUID,
sl@0
  1869
		(TUint) this, aName, aNewName, aSwitches, (TUint) &aStatus);
sl@0
  1870
sl@0
  1871
	TInt r;
sl@0
  1872
	if (iSwitches&KFManBusyFlag)
sl@0
  1873
		{
sl@0
  1874
		r = KErrInUse;
sl@0
  1875
		}
sl@0
  1876
	else
sl@0
  1877
		{
sl@0
  1878
		iStatus=&aStatus;
sl@0
  1879
		r = Rename(aName,aNewName,aSwitches);
sl@0
  1880
		}
sl@0
  1881
sl@0
  1882
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManRename1Return, MODULEUID, r);
sl@0
  1883
	return(r);
sl@0
  1884
	}
sl@0
  1885
sl@0
  1886
sl@0
  1887
sl@0
  1888
sl@0
  1889
EXPORT_C TInt CFileMan::Rename(const TDesC& aName,const TDesC& aNewName,TUint aSwitches)
sl@0
  1890
/**
sl@0
  1891
Renames one or more files, or a directory
sl@0
  1892
sl@0
  1893
This is a synchronous function.
sl@0
  1894
sl@0
  1895
The function can also be used to move files by specifying different destination
sl@0
  1896
and source directories.
sl@0
  1897
sl@0
  1898
Some rules for using CFileMan::Rename():
sl@0
  1899
sl@0
  1900
1. General rules:
sl@0
  1901
sl@0
  1902
1.1. Trailing backslash ("\") in either source path (aName) or target path (aNewName)
sl@0
  1903
will be interpreted to "\*.*";
sl@0
  1904
sl@0
  1905
For example, following code should behave identically:
sl@0
  1906
@code
sl@0
  1907
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1908
...
sl@0
  1909
fm->Rename(_L("C:\\SRC\\"), _L("C:\\TRG\\"));
sl@0
  1910
fm->Rename(_L("C:\\SRC\\*.*"), _L("C:\\TRG\\"));
sl@0
  1911
fm->Rename(_L("C:\\SRC\\"), _L("C:\\TRG\\*.*"));
sl@0
  1912
fm->Rename(_L("C:\\SRC\\*.*"), _L("C:\\TRG\\*.*"));
sl@0
  1913
@endcode
sl@0
  1914
sl@0
  1915
1.2 The behaviour of the rename operation is sensitive to the presence (or absence) of
sl@0
  1916
a trailing backslash ("\") character on the end of the target path (aNewName);
sl@0
  1917
sl@0
  1918
For example, under all other constraints (see rules 2. and 3.),
sl@0
  1919
@code
sl@0
  1920
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1921
...
sl@0
  1922
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG\"));
sl@0
  1923
@endcode
sl@0
  1924
will result in renaming "C:\\SRC" to "C:\\TRG\\SRC", while
sl@0
  1925
@code
sl@0
  1926
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1927
...
sl@0
  1928
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG"));
sl@0
  1929
@endcode
sl@0
  1930
will result in renaming "C:\\SRC" to "C:\\TRG".
sl@0
  1931
sl@0
  1932
2. Renaming file(s):
sl@0
  1933
sl@0
  1934
2.1 Wildcards:
sl@0
  1935
sl@0
  1936
A file's name and extension are interpreted separately, for example:
sl@0
  1937
sl@0
  1938
@code
sl@0
  1939
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1940
...
sl@0
  1941
fm->Rename(_L("C:\\SRC\\1234.567"), _L("C:\\TRG\\AB*CD.TXT"));
sl@0
  1942
@endcode
sl@0
  1943
renames the source file to file "C:\\TRG\\AB34CD.TXT".
sl@0
  1944
sl@0
  1945
Wildcards can be used for renaming multiple files, for example;
sl@0
  1946
@code
sl@0
  1947
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1948
...
sl@0
  1949
fm->Rename(_L("C:\\SRC\\*.567"), _L("C:\\TRG\\*.TXT"));
sl@0
  1950
@endcode
sl@0
  1951
renames all the file under "C:\\SRC\\" having extension ".567" to the files under
sl@0
  1952
"C:\\TRG\\" having extension ".TXT".
sl@0
  1953
sl@0
  1954
2.2 An option is provided to allow the user to overwrite any files with the same
sl@0
  1955
name which may exist in the target directory; If the flag is set for no overwriting,
sl@0
  1956
any files with the same name will not be overwritten, and an error (KErrAlreadyExists)
sl@0
  1957
will be returned for that file, as retrieved by CFileBase::GetLastError().
sl@0
  1958
sl@0
  1959
2.3 It can only operate non-recursively, so that only the matching files located
sl@0
  1960
in the single directory specified by anOld may be renamed.
sl@0
  1961
sl@0
  1962
2.4 Trying to rename file(s) to existing directory(ies) will fail;
sl@0
  1963
sl@0
  1964
For example, giving following directory structure:
sl@0
  1965
@code
sl@0
  1966
C:\SRC\ITEM01
sl@0
  1967
C:\SRC\ITEM02
sl@0
  1968
C:\TRG\ITEM01\
sl@0
  1969
C:\TRG\ITEM02\
sl@0
  1970
@endcode
sl@0
  1971
sl@0
  1972
Following code will fail:
sl@0
  1973
@code
sl@0
  1974
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1975
...
sl@0
  1976
fm->Rename(_L("C:\\SRC\\ITEM01"), _L("C:\\TRG\\ITEM01"));
sl@0
  1977
fm->Rename(_L("C:\\SRC\\ITEM*"), _L("C:\\TRG\\ITEM*"));
sl@0
  1978
fm->Rename(_L("C:\\SRC\\"), _L("C:\\TRG\\"));
sl@0
  1979
@endcode
sl@0
  1980
sl@0
  1981
3. When renamnig a directory:
sl@0
  1982
sl@0
  1983
3.1. Only when the trailing backslash ("\") is missing from the source path (aName),
sl@0
  1984
will the source directory be renamed, otherwise, see rule 1.1.
sl@0
  1985
sl@0
  1986
For example, following code will result in moving "C:\SRC" directory including all
sl@0
  1987
its contents:
sl@0
  1988
@code
sl@0
  1989
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  1990
...
sl@0
  1991
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG"));
sl@0
  1992
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG\\"));
sl@0
  1993
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG\\*.*"));
sl@0
  1994
@endcode
sl@0
  1995
sl@0
  1996
3.2. Wildcards can not be used for moving directories;
sl@0
  1997
sl@0
  1998
3.3. Overwriting is not permitted;
sl@0
  1999
sl@0
  2000
For example, giving directory structure as following:
sl@0
  2001
@code
sl@0
  2002
C:\SRC\FILE.TXT
sl@0
  2003
C:\TRG\
sl@0
  2004
C:\TRG\SRC\
sl@0
  2005
@endcode
sl@0
  2006
sl@0
  2007
following code will fail:
sl@0
  2008
@code
sl@0
  2009
CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle
sl@0
  2010
...
sl@0
  2011
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG"));
sl@0
  2012
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG\\"));
sl@0
  2013
fm->Rename(_L("C:\\SRC"), _L("C:\\TRG\\*.*"));
sl@0
  2014
@endcode
sl@0
  2015
sl@0
  2016
4. Notes:
sl@0
  2017
sl@0
  2018
4.1. The target and source directories must be on the same drive.
sl@0
  2019
sl@0
  2020
4.2. Read-only, hidden and system files can be moved and the source file's
sl@0
  2021
attributes are preserved in the target file, but open files cannot
sl@0
  2022
be moved. Attempting to move an open file will return an error for
sl@0
  2023
that file, as retrieved by CFileBase::GetLastError().
sl@0
  2024
sl@0
  2025
@param aName     Path specifying the file(s) to be renamed. Any path components
sl@0
  2026
				 which are not specified
sl@0
  2027
                 here will be taken from the session path.
sl@0
  2028
@param aNewName  Path specifying the new name for the files and/or
sl@0
  2029
                 the new directory. Any directories specified in this path
sl@0
  2030
                 that do not exist, will be created. Any path components which
sl@0
  2031
				 are not specified here will be taken from the session path.
sl@0
  2032
@param aSwitches Specify zero for no overwriting;
sl@0
  2033
                 CFileMan::EOverWrite to overwrite files with the same name.
sl@0
  2034
                 This function cannot operate recursively.
sl@0
  2035
sl@0
  2036
@return KErrNone if successful, otherwise one of the other system-wide error
sl@0
  2037
        codes.
sl@0
  2038
sl@0
  2039
@see CFileBase::GetLastError()
sl@0
  2040
sl@0
  2041
@capability Dependent If either aName or aNewName is /Sys then Tcb capability is required.
sl@0
  2042
@capability Dependent If either aName or aNewName begins with /Private and does not match
sl@0
  2043
					  this process' SID then AllFiles capability is required.
sl@0
  2044
@capability Dependent If either aName or aNewName is /Resource then Tcb capability is required.
sl@0
  2045
sl@0
  2046
*/
sl@0
  2047
	{
sl@0
  2048
	TRACEMULT4(UTF::EBorder, UTraceModuleEfsrv::ECFileManRename2, MODULEUID,
sl@0
  2049
		(TUint) this, aName, aNewName, aSwitches);
sl@0
  2050
sl@0
  2051
	TInt ret;
sl@0
  2052
	if (iSwitches&KFManBusyFlag)
sl@0
  2053
		{
sl@0
  2054
		ret = KErrInUse;
sl@0
  2055
		}
sl@0
  2056
	else
sl@0
  2057
		{
sl@0
  2058
		SetFlags(aSwitches&EOverWrite,EFalse,ETrue,EFalse);
sl@0
  2059
		RETURNIFERRORD(r,iFs.Parse(aName,iSrcFile),UTraceModuleEfsrv::ECFileManRename2Return);
sl@0
  2060
		RETURNIFERROR(r,iFs.Parse(aNewName,_L("*"),iTrgFile),UTraceModuleEfsrv::ECFileManRename2Return);
sl@0
  2061
sl@0
  2062
		iAction = EInternalRename;
sl@0
  2063
		iMatchEntry=KEntryAttMaskSupported;
sl@0
  2064
		iNumberOfFilesProcessed = 0;
sl@0
  2065
		TRAP(r,RunL());
sl@0
  2066
		ret=(r==KErrNone) ? iLastError : r;
sl@0
  2067
		DoSynchronize(r);
sl@0
  2068
		}
sl@0
  2069
sl@0
  2070
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManRename2Return, MODULEUID, ret);
sl@0
  2071
	return(ret);
sl@0
  2072
	}
sl@0
  2073
sl@0
  2074
sl@0
  2075
EXPORT_C TInt CFileMan::RmDir(const TDesC& aDirName,TRequestStatus& aStatus)
sl@0
  2076
/**
sl@0
  2077
Deletes a directory and all files and directories contained in the
sl@0
  2078
directory structure below it.
sl@0
  2079
sl@0
  2080
Other than being asynchronous, the behaviour of this function is the same
sl@0
  2081
as is documented in its synchronous overload.
sl@0
  2082
sl@0
  2083
@param aDirName Path specifying the directory to be deleted. Any path components
sl@0
  2084
				which are not specified here will be taken from the session path.
sl@0
  2085
@param aStatus  The request status object. On request completion, indicates how
sl@0
  2086
                the request completed:
sl@0
  2087
                KErrNone if successful, otherwise one of the other system-wide
sl@0
  2088
                error codes.
sl@0
  2089
sl@0
  2090
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
  2091
					is still pending; otherwise one of the other system-wide error codes
sl@0
  2092
sl@0
  2093
@capability Dependent If aDirName starts with /Sys then Tcb capability is required.
sl@0
  2094
@capability Dependent If aDirName begins with /Private and does not match this process' SID
sl@0
  2095
					  then AllFiles capability is required.
sl@0
  2096
@capability Dependent If aDirName starts with /Resource then Tcb capability is required.
sl@0
  2097
sl@0
  2098
*/
sl@0
  2099
	{
sl@0
  2100
	TRACEMULT3(UTF::EBorder, UTraceModuleEfsrv::ECFileManRmDir1, MODULEUID, (TUint) this, aDirName, (TUint) &aStatus);
sl@0
  2101
sl@0
  2102
	TInt r;
sl@0
  2103
	if (iSwitches&KFManBusyFlag)
sl@0
  2104
		{
sl@0
  2105
		r = KErrInUse;
sl@0
  2106
		}
sl@0
  2107
	else
sl@0
  2108
		{
sl@0
  2109
		iStatus=&aStatus;
sl@0
  2110
		r = RmDir(aDirName);
sl@0
  2111
		}
sl@0
  2112
sl@0
  2113
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManRmDir1Return, MODULEUID, r);
sl@0
  2114
	return r;
sl@0
  2115
	}
sl@0
  2116
sl@0
  2117
sl@0
  2118
EXPORT_C TInt CFileMan::RmDir(const TDesC& aDirName)
sl@0
  2119
/**
sl@0
  2120
Deletes a directory and all files and directories contained in the
sl@0
  2121
directory structure below it.
sl@0
  2122
sl@0
  2123
This is a synchronous function.
sl@0
  2124
sl@0
  2125
The function cannot be used non-recursively. For a non-recursive
sl@0
  2126
directory deletion, use RFs::RmDir().
sl@0
  2127
sl@0
  2128
Note:
sl@0
  2129
sl@0
  2130
1. All files in the directory hierarchy to be deleted must be closed and
sl@0
  2131
   none may have the read-only attribute. Otherwise, not all of the hierarchy will
sl@0
  2132
   be deleted, and this function will return KErrInUse.
sl@0
  2133
sl@0
  2134
@param aDirName Path specifying the directory to be deleted. Any path components
sl@0
  2135
				which are not specified here will be taken from the session path.
sl@0
  2136
sl@0
  2137
@return KErrNone if successful, otherwise one of the other system-wide error
sl@0
  2138
        codes.
sl@0
  2139
sl@0
  2140
@capability Dependent If aDirName starts with /Sys then Tcb capability is required.
sl@0
  2141
@capability Dependent If aDirName begins with /Private and does not match this process' SID
sl@0
  2142
					  then AllFiles capability is required.
sl@0
  2143
@capability Dependent If aDirName starts with /Resource then Tcb capability is required.
sl@0
  2144
sl@0
  2145
sl@0
  2146
*/
sl@0
  2147
	{
sl@0
  2148
	TRACEMULT2(UTF::EBorder, UTraceModuleEfsrv::ECFileManRmDir2, MODULEUID, (TUint) this, aDirName);
sl@0
  2149
sl@0
  2150
	TInt ret;
sl@0
  2151
	if (iSwitches&KFManBusyFlag)
sl@0
  2152
		{
sl@0
  2153
		ret = KErrInUse;
sl@0
  2154
		}
sl@0
  2155
	else
sl@0
  2156
		{
sl@0
  2157
		SetFlags(ETrue,ETrue,EFalse,EFalse);
sl@0
  2158
		RETURNIFERRORD(r,iFs.Parse(aDirName,iTrgFile),UTraceModuleEfsrv::ECFileManRmDir2Return);
sl@0
  2159
		iSrcFile.Set(iTrgFile.DriveAndPath(),NULL,NULL);
sl@0
  2160
		iAction = EInternalRmDir;
sl@0
  2161
		iMatchEntry=KEntryAttMaskSupported;
sl@0
  2162
		iNumberOfFilesProcessed = 0;
sl@0
  2163
		TRAP(r,RunL());
sl@0
  2164
		DoSynchronize(r);
sl@0
  2165
		ret = (r!=KErrNone) ? iLastError : KErrNone;
sl@0
  2166
		}
sl@0
  2167
sl@0
  2168
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManRmDir2Return, MODULEUID, ret);
sl@0
  2169
	return ret;
sl@0
  2170
	}
sl@0
  2171
sl@0
  2172
sl@0
  2173
void CFileMan::DoOperationL()
sl@0
  2174
// Call the action in progress.
sl@0
  2175
	{
sl@0
  2176
	switch (iAction)
sl@0
  2177
		{
sl@0
  2178
	case EInternalAttribs:
sl@0
  2179
		DoAttribsL();
sl@0
  2180
		break;
sl@0
  2181
	case EInternalCopy:
sl@0
  2182
	case EInternalCopyForMove:
sl@0
  2183
		DoCopyOrMoveL();
sl@0
  2184
		break;
sl@0
  2185
	case EInternalDelete:
sl@0
  2186
		DoDeleteL();
sl@0
  2187
		break;
sl@0
  2188
	case EInternalRenameInvalidEntry:
sl@0
  2189
	case EInternalRenameForMove:
sl@0
  2190
	case EInternalRename:
sl@0
  2191
		DoRenameL();
sl@0
  2192
		break;
sl@0
  2193
	case EInternalRmDir:
sl@0
  2194
		DoRmDirL();
sl@0
  2195
		break;
sl@0
  2196
	case EInternalCopyFromHandle:
sl@0
  2197
		DoCopyFromHandleL();
sl@0
  2198
		break;
sl@0
  2199
	default:
sl@0
  2200
		Panic(EFManUnknownAction);
sl@0
  2201
		}
sl@0
  2202
	}
sl@0
  2203
sl@0
  2204
void CFileMan::DoAttribsL()
sl@0
  2205
//
sl@0
  2206
// Do attribs operation step
sl@0
  2207
//
sl@0
  2208
	{
sl@0
  2209
	TPtrC fullPath(FullPath());
sl@0
  2210
	iTmpParse.Set(CurrentEntry().iName, &fullPath, NULL);
sl@0
  2211
	User::LeaveIfError(iFs.SetEntry(iTmpParse.FullName(), iTime, iSetMask, iClearMask));
sl@0
  2212
	}
sl@0
  2213
sl@0
  2214
void CFileMan::DoCopyOrMoveL()
sl@0
  2215
//
sl@0
  2216
// Do copy or move operation
sl@0
  2217
//
sl@0
  2218
	{
sl@0
  2219
	// Following 'if' statements are to prevent incorrect recursive Move() or Copy() from "destination"
sl@0
  2220
	//  to "destination", this problem occurs when the initial source directory contains destination
sl@0
  2221
	//  directory.
sl@0
  2222
	//  (e.g. CFileMan::Move(_L("C:\\SRC\\*.TXT"), _L("C:\\SRC\\Sub\\"), CFileMan::ERecurse);)
sl@0
  2223
	// Note that CFileMan::Rename() does not suffer from this particular case, as CFileMan::Rename() API
sl@0
  2224
	//  can only operate non-recursively.
sl@0
  2225
	if (iSrcFile.DriveAndPath().Length() < iTrgFile.DriveAndPath().Length())
sl@0
  2226
		{
sl@0
  2227
		if (iTrgFile.DriveAndPath().Left(iSrcFile.DriveAndPath().Length()) == iSrcFile.DriveAndPath())
sl@0
  2228
		// If source directory path contains destination directory path, including drive number, we consider
sl@0
  2229
		//  this is "...\\ROOT\\" -> "...\\ROOT\\SUB\\" type of operation. Therefore skips all the items we
sl@0
  2230
		//  found in "...\\ROOT\\SUB\\". We achieve this by checking current scanning directory path:
sl@0
  2231
			{
sl@0
  2232
			if (iTrgFile.DriveAndPath() == iScanner->FullPath().Left(iTrgFile.DriveAndPath().Length()))
sl@0
  2233
				{
sl@0
  2234
				return;
sl@0
  2235
				}
sl@0
  2236
			}
sl@0
  2237
		}
sl@0
  2238
sl@0
  2239
	TParse& srcName = iTmpParse;
sl@0
  2240
	TFileName& trgName = iTmpName1;
sl@0
  2241
	GetSrcAndTrg(srcName,trgName);
sl@0
  2242
sl@0
  2243
	// Handle case when source is directory
sl@0
  2244
	if (CurrentEntry().iAtt&KEntryAttDir)
sl@0
  2245
		{
sl@0
  2246
		if(!(iSwitches&KRecurseFlag))
sl@0
  2247
			{
sl@0
  2248
			User::Leave(KErrNone);
sl@0
  2249
			}
sl@0
  2250
		trgName.Append(KPathDelimiter);
sl@0
  2251
		TInt r = iFs.MkDirAll(trgName);
sl@0
  2252
		if (r!=KErrNone && r!=KErrAlreadyExists)
sl@0
  2253
			User::Leave(r);
sl@0
  2254
sl@0
  2255
		if(iAction == EInternalCopyForMove)
sl@0
  2256
			{
sl@0
  2257
			// Move operation - Attempt to delete the source directory.
sl@0
  2258
			if((iMatchEntry & KMovingFilesMask) != KMovingFilesMask)
sl@0
  2259
				{
sl@0
  2260
				iTmpName2 = srcName.FullName();
sl@0
  2261
				iTmpName2.Append(KPathDelimiter);
sl@0
  2262
				TInt rdErr = iFs.RmDir(iTmpName2);
sl@0
  2263
				if(rdErr != KErrNone && rdErr != KErrInUse)
sl@0
  2264
					{
sl@0
  2265
					User::Leave(rdErr);
sl@0
  2266
					}
sl@0
  2267
				}
sl@0
  2268
			}
sl@0
  2269
		return;
sl@0
  2270
		}
sl@0
  2271
sl@0
  2272
#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
sl@0
  2273
	RFile srcFile,trgFile;
sl@0
  2274
#else
sl@0
  2275
	RFile64 srcFile,trgFile;
sl@0
  2276
#endif
sl@0
  2277
	TInt r=KErrNone;
sl@0
  2278
	if (FileNamesIdentical(srcName.FullName(),trgName))
sl@0
  2279
		{
sl@0
  2280
		if (iSwitches & KOverWriteFlag)
sl@0
  2281
			// Source and target are identical, KOverWriteFlag makes copying
sl@0
  2282
			// having no effect.
sl@0
  2283
			return;
sl@0
  2284
		else
sl@0
  2285
			User::Leave(KErrAlreadyExists);
sl@0
  2286
		}
sl@0
  2287
sl@0
  2288
	r=srcFile.Open(iFs, srcName.FullName(),
sl@0
  2289
	                iAction==EInternalCopy ? EFileRead|EFileShareReadersOnly  // Copy access
sl@0
  2290
	                                : EFileWrite|EFileWriteDirectIO|EFileShareExclusive); // Move access
sl@0
  2291
	TBool isRO = EFalse;
sl@0
  2292
	if(r==KErrAccessDenied && iAction==EInternalCopyForMove)
sl@0
  2293
		{
sl@0
  2294
		TEntry& entry = iTmpEntry;
sl@0
  2295
		r = iFs.Entry(srcName.FullName(), entry);
sl@0
  2296
		if(r==KErrNone && (entry.iAtt&KEntryAttReadOnly))
sl@0
  2297
			{
sl@0
  2298
			isRO = ETrue;
sl@0
  2299
			r = iFs.SetAtt(srcName.FullName(), 0, KEntryAttReadOnly);
sl@0
  2300
			if(r==KErrNone)
sl@0
  2301
				{
sl@0
  2302
				r = srcFile.Open(iFs, srcName.FullName(), EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
sl@0
  2303
				}
sl@0
  2304
			}
sl@0
  2305
		}
sl@0
  2306
	if (r!=KErrNone)
sl@0
  2307
		{
sl@0
  2308
		iErrorInfo=ESrcOpenFailed;
sl@0
  2309
		if(isRO)
sl@0
  2310
			{
sl@0
  2311
			iFs.SetAtt(srcName.FullName(), KEntryAttReadOnly, 0);
sl@0
  2312
			}
sl@0
  2313
		User::Leave(r);
sl@0
  2314
		}
sl@0
  2315
sl@0
  2316
	if ((iSwitches&KOverWriteFlag)==0)
sl@0
  2317
		r=trgFile.Create(iFs,trgName,EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
sl@0
  2318
	else
sl@0
  2319
		r=trgFile.Replace(iFs,trgName,EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
sl@0
  2320
sl@0
  2321
	if (r==KErrPathNotFound && (iSwitches&KRecurseFlag))
sl@0
  2322
		{
sl@0
  2323
		r=iFs.MkDirAll(trgName);
sl@0
  2324
		if (r==KErrNone)
sl@0
  2325
			r=trgFile.Create(iFs,trgName,EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
sl@0
  2326
		}
sl@0
  2327
sl@0
  2328
	if (r!=KErrNone)
sl@0
  2329
		iErrorInfo=ETrgOpenFailed;
sl@0
  2330
sl@0
  2331
	TInt ret=0;
sl@0
  2332
	if (r == KErrNone)
sl@0
  2333
		r = DoCopy(srcFile, trgFile, ret);
sl@0
  2334
sl@0
  2335
	srcFile.Close();
sl@0
  2336
	trgFile.Close();
sl@0
  2337
	if ((r!=KErrNone && (r!=KErrAlreadyExists && iErrorInfo!=ETrgOpenFailed)) || (ret==MFileManObserver::ECancel))
sl@0
  2338
		iFs.Delete(trgName);
sl@0
  2339
	if(r==KErrNone && isRO)
sl@0
  2340
		{
sl@0
  2341
		r = iFs.SetAtt(trgName, KEntryAttReadOnly, 0);
sl@0
  2342
		}
sl@0
  2343
	User::LeaveIfError(r);
sl@0
  2344
sl@0
  2345
	//
sl@0
  2346
	// Move operation
sl@0
  2347
	//
sl@0
  2348
	if (iAction == EInternalCopyForMove && ret != MFileManObserver::ECancel)
sl@0
  2349
		{
sl@0
  2350
		r=iFs.Delete(srcName.FullName());
sl@0
  2351
		if (r==KErrNone)
sl@0
  2352
			return;
sl@0
  2353
		iFs.Delete(trgName);
sl@0
  2354
		User::Leave(r);
sl@0
  2355
		}
sl@0
  2356
	}
sl@0
  2357
sl@0
  2358
void CFileMan::DoDeleteL()
sl@0
  2359
//
sl@0
  2360
// Do delete operation step
sl@0
  2361
//
sl@0
  2362
	{
sl@0
  2363
	TFileName& pathname = iTmpName1;
sl@0
  2364
	TFileName& filename = iTmpName2;
sl@0
  2365
	pathname.Copy(FullPath());
sl@0
  2366
	filename.Copy(CurrentEntry().iName);
sl@0
  2367
	if(CurrentEntry().iName.Length() + pathname.Length() > KMaxFileName)
sl@0
  2368
		{
sl@0
  2369
		User::LeaveIfError(ShrinkNames(iFs, pathname, filename, EFalse));
sl@0
  2370
		}
sl@0
  2371
	iTmpParse.Set(filename, &pathname, NULL);
sl@0
  2372
	User::LeaveIfError(iFs.Delete(iTmpParse.FullName()));
sl@0
  2373
	}
sl@0
  2374
sl@0
  2375
void CFileMan::DoRenameL()
sl@0
  2376
//
sl@0
  2377
// Do rename operation step
sl@0
  2378
//
sl@0
  2379
	{
sl@0
  2380
	// Following 'if' statements are to prevent incorrect recursive Move() or Copy() from "destination"
sl@0
  2381
	//  to "destination", this problem occurs when the initial source directory contains destination
sl@0
  2382
	//  directory.
sl@0
  2383
	//  (e.g. CFileMan::Move(_L("C:\\SRC\\*.TXT"), _L("C:\\SRC\\Sub\\"), CFileMan::ERecurse);)
sl@0
  2384
	// Note that CFileMan::Rename() does not suffer from this particular case, as CFileMan::Rename() API
sl@0
  2385
	//  can only operate non-recursively.
sl@0
  2386
	if (iSrcFile.DriveAndPath().Length() < iTrgFile.DriveAndPath().Length())
sl@0
  2387
		{
sl@0
  2388
		if (iTrgFile.DriveAndPath().Left(iSrcFile.DriveAndPath().Length()) == iSrcFile.DriveAndPath())
sl@0
  2389
		// If source directory path contains destination directory path, including drive number, we consider
sl@0
  2390
		//  this is "...\\ROOT\\" -> "...\\ROOT\\SUB\\" type of operation. Therefore skips all the items we
sl@0
  2391
		//  found in "...\\ROOT\\SUB\\". We achieve this by checking current scanning directory path:
sl@0
  2392
			{
sl@0
  2393
			if (iTrgFile.DriveAndPath() == iScanner->FullPath().Left(iTrgFile.DriveAndPath().Length()))
sl@0
  2394
				{
sl@0
  2395
				return;
sl@0
  2396
				}
sl@0
  2397
			}
sl@0
  2398
		}
sl@0
  2399
sl@0
  2400
	TParse& srcName = iTmpParse;
sl@0
  2401
	TFileName& trgName = iTmpName1;
sl@0
  2402
	GetSrcAndTrg(srcName, trgName);
sl@0
  2403
sl@0
  2404
	TInt r = iFs.Rename(srcName.FullName(),trgName);
sl@0
  2405
	if (r==KErrAlreadyExists && (iSwitches&KOverWriteFlag)!=0)
sl@0
  2406
		{
sl@0
  2407
		// Target already exists, with the overwrite flag enabled
sl@0
  2408
		if((CurrentEntry().iAtt & KEntryAttDir) == 0)
sl@0
  2409
			{
sl@0
  2410
			// Renaming a file
sl@0
  2411
			r=iFs.Replace(srcName.FullName(),trgName);
sl@0
  2412
			}
sl@0
  2413
		else if (iAction == EInternalRenameForMove)
sl@0
  2414
			{
sl@0
  2415
			trgName = srcName.FullName();
sl@0
  2416
			trgName.Append(KPathDelimiter);
sl@0
  2417
			r = iFs.RmDir(trgName); // remove empty directory after move
sl@0
  2418
			if(r == KErrInUse)
sl@0
  2419
				{
sl@0
  2420
				r = KErrNone;
sl@0
  2421
				}
sl@0
  2422
			}
sl@0
  2423
		}
sl@0
  2424
sl@0
  2425
	if (r==KErrPathNotFound)
sl@0
  2426
		{
sl@0
  2427
		if((iSwitches&KMoveRenameFlag) && !(iSwitches&KRecurseFlag))
sl@0
  2428
			User::Leave(r);
sl@0
  2429
		r=iFs.MkDirAll(trgName);
sl@0
  2430
		if (r==KErrNone)
sl@0
  2431
			 r=iFs.Rename(srcName.FullName(),trgName);
sl@0
  2432
		}
sl@0
  2433
	if (r==KErrBadName)
sl@0
  2434
		{
sl@0
  2435
		TEntry& entry = iTmpEntry;
sl@0
  2436
		TInt retcode=iFs.Entry(srcName.FullName(), entry);
sl@0
  2437
		if (retcode!=KErrNone)
sl@0
  2438
			iErrorInfo=ESrcOpenFailed;
sl@0
  2439
		else
sl@0
  2440
			iErrorInfo=ETrgOpenFailed;
sl@0
  2441
		}
sl@0
  2442
	User::LeaveIfError(r);
sl@0
  2443
	}
sl@0
  2444
sl@0
  2445
void CFileMan::DoRmDirL()
sl@0
  2446
//
sl@0
  2447
// Do rmdir operation step
sl@0
  2448
//
sl@0
  2449
	{
sl@0
  2450
	TFileName& srcName = iTmpName1;
sl@0
  2451
	srcName.Copy(FullPath());
sl@0
  2452
	if (srcName.Length() + CurrentEntry().iName.Length() > KMaxFileName)
sl@0
  2453
		{
sl@0
  2454
		TFileName& current = iTmpName2;
sl@0
  2455
		current.Copy(CurrentEntry().iName);
sl@0
  2456
		User::LeaveIfError(ShrinkNames(iFs, srcName, current, ETrue));
sl@0
  2457
		}
sl@0
  2458
	else
sl@0
  2459
		{
sl@0
  2460
		srcName.Append(CurrentEntry().iName);
sl@0
  2461
		}
sl@0
  2462
sl@0
  2463
	if ((CurrentEntry().iAtt&KEntryAttDir)==0)
sl@0
  2464
		User::LeaveIfError(iFs.Delete(srcName));
sl@0
  2465
	else
sl@0
  2466
		{
sl@0
  2467
		srcName.Append(KPathDelimiter);
sl@0
  2468
		User::LeaveIfError(iFs.RmDir(srcName));
sl@0
  2469
		}
sl@0
  2470
	}
sl@0
  2471
sl@0
  2472
sl@0
  2473
void CFileMan::CompleteOperationL()
sl@0
  2474
//
sl@0
  2475
// Tidy up after an operation
sl@0
  2476
// The last step to remove directory or to a move directory operation
sl@0
  2477
// is to remove the source directory...
sl@0
  2478
//
sl@0
  2479
	{
sl@0
  2480
	TInt r=KErrNotFound;
sl@0
  2481
	if (iAction == EInternalRmDir ||
sl@0
  2482
	    (iAction == EInternalCopyForMove && ((iMatchEntry & KMovingFilesMask) != KMovingFilesMask) && !iMovingContents && !iSrcFile.IsRoot()) ||
sl@0
  2483
	    iAction == EInternalRenameForMove && !iMovingContents && iNumberOfFilesProcessed)
sl@0
  2484
		{
sl@0
  2485
		r=iFs.RmDir(iSrcFile.FullName());
sl@0
  2486
		if ((r!=KErrNone && r!=KErrNotFound && iAction!=EInternalRenameForMove && r!=KErrInUse) || (iAction == EInternalRmDir && r == KErrInUse))
sl@0
  2487
			{
sl@0
  2488
			iLastError=r;
sl@0
  2489
			User::Leave(r);
sl@0
  2490
			}
sl@0
  2491
		}
sl@0
  2492
sl@0
  2493
	if (iLastError == KErrCancel && iNumberOfFilesProcessed==0 )
sl@0
  2494
	{
sl@0
  2495
		iLastError=KErrCancel;
sl@0
  2496
		iErrorInfo=ENoFilesProcessed;
sl@0
  2497
		User::Leave(KErrCancel);
sl@0
  2498
	}
sl@0
  2499
sl@0
  2500
	if (iLastError==KErrNone && r==KErrNotFound && iNumberOfFilesProcessed==0)
sl@0
  2501
		{
sl@0
  2502
		iLastError=KErrNotFound;
sl@0
  2503
		iErrorInfo=ENoFilesProcessed;
sl@0
  2504
		User::Leave(KErrNotFound);
sl@0
  2505
		}
sl@0
  2506
	}
sl@0
  2507
sl@0
  2508
void CFileMan::SetFlags(TBool anOverWrite,TBool aRecurse,TBool aScanDownTree,TBool aMoveRename)
sl@0
  2509
//
sl@0
  2510
// Set or clear flags
sl@0
  2511
//
sl@0
  2512
	{
sl@0
  2513
sl@0
  2514
	iSwitches=0;
sl@0
  2515
	if (aRecurse)
sl@0
  2516
		iSwitches|=KRecurseFlag;
sl@0
  2517
	if (anOverWrite)
sl@0
  2518
		iSwitches|=KOverWriteFlag;
sl@0
  2519
	if (aScanDownTree)
sl@0
  2520
		iSwitches|=KScanDownFlag;
sl@0
  2521
	if (aMoveRename)
sl@0
  2522
		iSwitches|=KMoveRenameFlag;
sl@0
  2523
	}
sl@0
  2524
sl@0
  2525
sl@0
  2526
EXPORT_C TInt CFileMan::Copy(const RFile& anOld, const TDesC& aNew, TUint aSwitches)
sl@0
  2527
/**
sl@0
  2528
Copies from an open file handle to a destination file name.
sl@0
  2529
sl@0
  2530
This is a synchronous function.
sl@0
  2531
sl@0
  2532
Optionally, this function can be set to overwrite the target file.
sl@0
  2533
If the flag is set for no overwriting and the target file already exists,
sl@0
  2534
then the target file will not be overwritten, and an error (KErrAlreadyExists)
sl@0
  2535
will be returned.
sl@0
  2536
Error codes may be retrieved using CFileBase::GetLastError().
sl@0
  2537
sl@0
  2538
Notes:
sl@0
  2539
sl@0
  2540
-# The file can be copied across drives.
sl@0
  2541
-# Read-only, hidden and system files can be copied and
sl@0
  2542
   the source file's attributes are preserved in the target file.
sl@0
  2543
sl@0
  2544
@param anOld     Open file handle indicating the file to be copied.
sl@0
  2545
@param aNew      Path indicating the directory (and optionally the filename)
sl@0
  2546
				 into which the file is to be copied.
sl@0
  2547
				 Any path components which are not specified here will be
sl@0
  2548
                 taken from the session path
sl@0
  2549
@param aSwitches Specify zero for no overwriting;
sl@0
  2550
                 CFileMan::EOverWrite to overwrite files with the same name;
sl@0
  2551
                 Any other flags are illegal
sl@0
  2552
                 By default, the synchronous variant of this function operates
sl@0
  2553
                 with overwriting.
sl@0
  2554
sl@0
  2555
@return KErrNone if successful, otherwise one of the other system-wide error codes.
sl@0
  2556
sl@0
  2557
@see CFileBase::GetLastError()
sl@0
  2558
@see CFileMan::Move()
sl@0
  2559
sl@0
  2560
@capability Dependent If the path for aNew begins with /Sys then Tcb capability is required.
sl@0
  2561
@capability Dependent If the path for aNew begins with /Private and does not match
sl@0
  2562
					  this process' SID then AllFiles capability is required.
sl@0
  2563
@capability Dependent If the path for aNew begins with /Resource then Tcb capability is required.
sl@0
  2564
*/
sl@0
  2565
	{
sl@0
  2566
	TRACEMULT4(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy3, MODULEUID,
sl@0
  2567
		(TUint) this, anOld.SubSessionHandle(), aNew, aSwitches);
sl@0
  2568
sl@0
  2569
	TInt ret;
sl@0
  2570
	if (iSwitches&KFManBusyFlag)
sl@0
  2571
		{
sl@0
  2572
		ret = KErrInUse;
sl@0
  2573
		}
sl@0
  2574
		// The only switch that is legal for single file copies is EOverWrite
sl@0
  2575
	else if ((aSwitches & ~EOverWrite) != 0)
sl@0
  2576
		{
sl@0
  2577
		ret = KErrArgument;
sl@0
  2578
		}
sl@0
  2579
	else
sl@0
  2580
		{
sl@0
  2581
sl@0
  2582
		SetFlags(aSwitches & EOverWrite, EFalse, EFalse, EFalse);
sl@0
  2583
sl@0
  2584
		// need to signal to CFileBase that we're copying from a handle
sl@0
  2585
		// and that iSrcFile is invalid
sl@0
  2586
		iSwitches|= KCopyFromHandle;
sl@0
  2587
sl@0
  2588
		TInt r;
sl@0
  2589
		RETURNIFERROR(r, iFs.Parse(aNew, iTrgFile),UTraceModuleEfsrv::ECFileManCopy3Return);
sl@0
  2590
sl@0
  2591
		// Need to duplicate the RFile handle so that any threads owned
sl@0
  2592
		// by this process can use it - i.e. the worker thread
sl@0
  2593
		RETURNIFERROR(r, iSrcFileHandle.Duplicate(anOld, EOwnerProcess),UTraceModuleEfsrv::ECFileManCopy3Return);
sl@0
  2594
sl@0
  2595
		iAction = EInternalCopyFromHandle;
sl@0
  2596
		iNumberOfFilesProcessed = 0;
sl@0
  2597
		TRAP(r,RunL());
sl@0
  2598
		ret=(r==KErrNone) ? iLastError : r;
sl@0
  2599
		DoSynchronize(r);
sl@0
  2600
		}
sl@0
  2601
sl@0
  2602
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy3Return, MODULEUID, ret);
sl@0
  2603
	return(ret);
sl@0
  2604
	}
sl@0
  2605
sl@0
  2606
EXPORT_C TInt CFileMan::Copy(const RFile& anOld,const TDesC& aNew,TUint aSwitches,TRequestStatus& aStatus)
sl@0
  2607
/**
sl@0
  2608
Copies from an open file handle to a destination file name.
sl@0
  2609
sl@0
  2610
This is an asynchronous function.
sl@0
  2611
Its behaviour is the same as the synchronous overload.
sl@0
  2612
sl@0
  2613
@param anOld     Open file handle indicating the file to be copied.
sl@0
  2614
@param aNew      Path indicating the directory (and optionally the filename)
sl@0
  2615
				 into which the file is to be copied.
sl@0
  2616
				 Any path components which are not specified here will be
sl@0
  2617
                 taken from the session path
sl@0
  2618
@param aSwitches Specify zero for no overwriting;
sl@0
  2619
                 CFileMan::EOverWrite to overwrite files with the same name;
sl@0
  2620
                 Any other flags are illegal.
sl@0
  2621
sl@0
  2622
@param aStatus   The request status object. On request completion,
sl@0
  2623
                 indicates how the request completed:
sl@0
  2624
                 KErrNone, if successful, otherwise one of the other system-wide error
sl@0
  2625
                 codes.
sl@0
  2626
sl@0
  2627
@return KErrNone if the asynchronous request is made successfully; KErrInUse if an asynchronous request
sl@0
  2628
					is still pending; otherwise one of the other system-wide error codes
sl@0
  2629
sl@0
  2630
@see CFileBase::GetLastError()
sl@0
  2631
sl@0
  2632
@capability Dependent If the path for aNew begins with /Sys then Tcb capability is required.
sl@0
  2633
@capability Dependent If the path for aNew begins with /Private and does not match
sl@0
  2634
					  this process' SID then AllFiles capability is required.
sl@0
  2635
@capability Dependent If the path for aNew begins with /Resource then Tcb capability is required.
sl@0
  2636
*/
sl@0
  2637
	{
sl@0
  2638
	TRACEMULT5(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy4, MODULEUID,
sl@0
  2639
		(TUint) this, anOld.SubSessionHandle(), aNew, aSwitches, (TUint) &aStatus);
sl@0
  2640
sl@0
  2641
	TInt r;
sl@0
  2642
	if (iSwitches&KFManBusyFlag)
sl@0
  2643
		{
sl@0
  2644
		r = KErrInUse;
sl@0
  2645
		}
sl@0
  2646
	else
sl@0
  2647
		{
sl@0
  2648
		iStatus=&aStatus;
sl@0
  2649
		r = Copy(anOld,aNew,aSwitches);
sl@0
  2650
		}
sl@0
  2651
sl@0
  2652
	TRACERET1(UTF::EBorder, UTraceModuleEfsrv::ECFileManCopy4Return, MODULEUID, r);
sl@0
  2653
	return(r);
sl@0
  2654
	}
sl@0
  2655
sl@0
  2656
void CFileMan::DoCopyFromHandleL()
sl@0
  2657
//
sl@0
  2658
// Copy from open file handle
sl@0
  2659
//
sl@0
  2660
	{
sl@0
  2661
	TInt ret=0;
sl@0
  2662
	TFileName& trgName = iTmpName1;
sl@0
  2663
sl@0
  2664
	if (iTrgFile.NamePresent())
sl@0
  2665
		{
sl@0
  2666
		trgName = iTrgFile.FullName();
sl@0
  2667
		}
sl@0
  2668
	else
sl@0
  2669
		{
sl@0
  2670
		iSrcFileHandle.Name(trgName);
sl@0
  2671
		if ((trgName.Length() + iTrgFile.DriveAndPath().Length()) > KMaxFileName)
sl@0
  2672
			{
sl@0
  2673
			iSrcFileHandle.Close();
sl@0
  2674
			User::Leave(KErrBadName);
sl@0
  2675
			}
sl@0
  2676
		trgName.Insert(0, iTrgFile.DriveAndPath());
sl@0
  2677
		}
sl@0
  2678
sl@0
  2679
#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
sl@0
  2680
	RFile trgFile;
sl@0
  2681
#else
sl@0
  2682
	RFile64 trgFile;
sl@0
  2683
#endif
sl@0
  2684
	TInt r=KErrNone;
sl@0
  2685
sl@0
  2686
	if ((iSwitches&KOverWriteFlag)==0)
sl@0
  2687
		r=trgFile.Create(iFs,trgName,EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
sl@0
  2688
	else
sl@0
  2689
		r=trgFile.Replace(iFs,trgName,EFileWrite|EFileWriteDirectIO|EFileShareExclusive);
sl@0
  2690
	if (r!=KErrNone)
sl@0
  2691
		iErrorInfo = ETrgOpenFailed;
sl@0
  2692
sl@0
  2693
	if (r == KErrNone)
sl@0
  2694
		r = DoCopy(iSrcFileHandle, trgFile, ret);
sl@0
  2695
sl@0
  2696
	// close the (duplicated) source file handle
sl@0
  2697
	iSrcFileHandle.Close();
sl@0
  2698
sl@0
  2699
	trgFile.Close();
sl@0
  2700
	if (ret == MFileManObserver::ECancel || (r!=KErrNone && r!=KErrAlreadyExists && iErrorInfo!=ETrgOpenFailed))
sl@0
  2701
		iFs.Delete(trgName);
sl@0
  2702
	User::LeaveIfError(r);
sl@0
  2703
	}
sl@0
  2704
sl@0
  2705
#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
sl@0
  2706
TInt CFileMan::DoCopy(const RFile& aSrcFile, RFile& aDstFile, TInt& aRet)
sl@0
  2707
	{
sl@0
  2708
	TInt rem;
sl@0
  2709
#else
sl@0
  2710
TInt CFileMan::DoCopy(const RFile64& aSrcFile, RFile64& aDstFile, TInt& aRet)
sl@0
  2711
	{
sl@0
  2712
	TInt64 rem;
sl@0
  2713
#endif
sl@0
  2714
	RETURNIFERRORD(r,aSrcFile.Size(rem),EFalse);
sl@0
  2715
	RETURNIFERROR(r, aDstFile.SetSize(rem),EFalse);
sl@0
  2716
sl@0
  2717
	HBufC8* bufPtr = NULL;
sl@0
  2718
	bufPtr = AllocateBuffer(rem);
sl@0
  2719
	if (bufPtr == NULL)
sl@0
  2720
		return KErrNoMemory;
sl@0
  2721
	TPtr8 copyBuf=bufPtr->Des();
sl@0
  2722
sl@0
  2723
#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
sl@0
  2724
	TInt pos=0;
sl@0
  2725
#else
sl@0
  2726
	TInt64 pos=0;
sl@0
  2727
#endif
sl@0
  2728
	aRet = MFileManObserver::EContinue;
sl@0
  2729
	while(rem && aRet == MFileManObserver::EContinue)
sl@0
  2730
		{
sl@0
  2731
#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
sl@0
  2732
		TInt s=Min(rem,copyBuf.MaxSize());
sl@0
  2733
#else
sl@0
  2734
		// Min result shall be of TInt size
sl@0
  2735
		TInt s=(TInt)(Min(rem,(TInt64)copyBuf.MaxSize()));
sl@0
  2736
#endif
sl@0
  2737
		r=aSrcFile.Read(pos,copyBuf,s);
sl@0
  2738
		if (r==KErrNone && copyBuf.Length()!=s)
sl@0
  2739
			r = KErrCorrupt;
sl@0
  2740
		if (r==KErrNone)
sl@0
  2741
			r=aDstFile.Write(pos,copyBuf,s);
sl@0
  2742
		if (r!=KErrNone)
sl@0
  2743
			break;
sl@0
  2744
		pos+= s;
sl@0
  2745
		rem-= s;
sl@0
  2746
		iBytesTransferred = s;
sl@0
  2747
		aRet = (iObserver) ? iObserver->NotifyFileManOperation() : MFileManObserver::EContinue;
sl@0
  2748
		if (aRet != MFileManObserver::EContinue && aRet != MFileManObserver::ECancel)
sl@0
  2749
			Panic(EFManBadValueFromObserver);
sl@0
  2750
		}
sl@0
  2751
sl@0
  2752
	// need to flush the target file - otherwise if there is any dirty data this will be flushed
sl@0
  2753
	// when the file is closed and this will set the archive attribute, resulting in the file
sl@0
  2754
	// having potentially a different attribute from the source file
sl@0
  2755
	if (r == KErrNone)
sl@0
  2756
		r = aDstFile.Flush();
sl@0
  2757
sl@0
  2758
	if (aRet != MFileManObserver::ECancel)
sl@0
  2759
		{
sl@0
  2760
		TTime lastMod;
sl@0
  2761
		if (r == KErrNone)
sl@0
  2762
			r = aSrcFile.Modified(lastMod);
sl@0
  2763
		if (r == KErrNone)
sl@0
  2764
			r = aDstFile.SetModified(lastMod);
sl@0
  2765
sl@0
  2766
		TUint fileAttributes=0;
sl@0
  2767
		if (r == KErrNone)
sl@0
  2768
			r = aSrcFile.Att(fileAttributes);
sl@0
  2769
		if (r == KErrNone)
sl@0
  2770
			r = aDstFile.SetAtt(fileAttributes,(~fileAttributes)&KEntryAttMaskSupported);
sl@0
  2771
sl@0
  2772
		if(r == KErrNone)
sl@0
  2773
  			r = aDstFile.Flush();
sl@0
  2774
		}
sl@0
  2775
sl@0
  2776
	delete bufPtr;
sl@0
  2777
sl@0
  2778
	return r;
sl@0
  2779
	}