os/kernelhwsrv/userlibandfileserver/fileserver/etshell/ts_com.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\etshell\ts_com.cpp
    15 // Shell commands
    16 // 
    17 //
    18 
    19 #ifdef __VC32__
    20   // Solve compilation problem caused by non-English locale
    21   #pragma setlocale("english")
    22 #endif
    23 
    24 #include "ts_std.h"
    25 
    26 #include <hal.h>
    27 #include <d32locd.h>
    28 #include <e32math.h>
    29 #include "u32std.h"
    30 #include <u32hal.h>
    31 #include <nkern/nk_trace.h>
    32 #include "filesystem_fat.h"
    33 
    34     TPtrC ptrFormatHelp=_L("Drive:[\\] [fat12|fat16|fat32] [spc:X] [rs:Y] [ft:Z] [/Q][/S][/E][/F]\nfat12 or fat16 or fat32 specifies explicit FAT type\nspc:X specifies \"X\" sectors per cluster\nrs:Y specifies \"Y\" reserved sectors\nft:Z specifies \"Z\" FAT tables (1 or 2)\n\n/q - QuickFormat, /s - SpecialFormat, /e - ForcedErase\n/f - force formatting (ignore volume being in use)");
    35     TPtrC ptrMountHelp=_L("Drive:[\\]  <fsy:X> <fs:Y> [pext:Z] [/S][/U][/F][/R]\n'X' *.fsy module name, like elocal.fsy\n'Y' file system name, like 'FAT'\n'Z' optional primary extension module name\n/U - dismount FS from the drive e.g 'mount d: /u' \n/F - force mounting with dismounting existing FS \n/S - mount drive as synchronous\n/R - remount the file system ");
    36 
    37 
    38 //	lint -e40,e30
    39 const TShellCommand CShell::iCommand[ENoShellCommands]=
    40 	{
    41 //	TShellCommand(_L("BLANK"),_L("Help"),_L("-?"),TShellCommand::EDSwitch,ShellFunction::BLANK),
    42 	TShellCommand(_L("ATTRIB"),_L("Displays or changes file attributes"),_L("[drive:][path][filename] [+R | -R] [+H |-H] [+S | -S] [+A | -A] [/p]\n\n  /p - Pause after each screen of information"), TShellCommand::EPSwitch, ShellFunction::Attrib),
    43 	TShellCommand(_L("CD"),_L("Change the current directory for a drive"),_L("[path] [/d]\n\n  /d - Change drive"),TShellCommand::EDSwitch,ShellFunction::Cd),
    44 	TShellCommand(_L("CHKDEPS"),_L("Check the dependencies of an executable or a Dll (ARM only)"),_L("[Filename.EXE] or [Filename.DLL]"),0,ShellFunction::ChkDeps),
    45 	TShellCommand(_L("CHKDSK"),_L("Check disk for corruption"),_L("[drive:] [/s][/f|/u]\n\n/s - start ScanDrive instead of CheckDisk\n/f - finalise drive\n/u - unfinalise drive"),TShellCommand::ESSwitch|TShellCommand::EFSwitch|TShellCommand::EUSwitch,ShellFunction::ChkDsk),
    46 	TShellCommand(_L("COPY"),_L("Copy one (or more) file(s)"),_L("source [destination]"),TShellCommand::ESSwitch,ShellFunction::Copy),
    47 	TShellCommand(_L("DEL"),_L("Delete one file"),_L("[drive:][path][filename]"),TShellCommand::ESSwitch,ShellFunction::Del),
    48 	TShellCommand(_L("DIR"),_L("Show directory contents"),_L("[drive:][path][filename] [/p][/w]\n\n  /p - Pause after each screen of information\n  /w - Wide format"),TShellCommand::EPSwitch|TShellCommand::EWSwitch|TShellCommand::EASwitch,ShellFunction::Dir),
    49 //	TShellCommand(_L("EDLIN"),_L("Edit a text file"),_L("[drive:][path][filename] [/p]\n\n  /p - Pause after each screen of information"),TShellCommand::EPSwitch,ShellFunction::Edit),
    50     TShellCommand(_L("FORMAT"),_L("Format a disk"),ptrFormatHelp,TShellCommand::EQSwitch|TShellCommand::ESSwitch|TShellCommand::EESwitch|TShellCommand::EFSwitch,ShellFunction::Format),
    51     TShellCommand(_L("GOBBLE"),_L("Create a file"),_L("[filename] size [/e]\n\n /e - create an empty file, without writing any data"),TShellCommand::EESwitch,ShellFunction::Gobble),
    52 	TShellCommand(_L("HEXDUMP"),_L("Display the contents of a file in hexadecimal"),_L("[drive:][path][filename] [/p]\n\n  /p - Pause after each screen of information\n\n  Hit escape to exit from hexdump "),TShellCommand::EPSwitch,ShellFunction::Hexdump),
    53 	TShellCommand(_L("LABEL"),_L("Set or return the volume label"),_L("[newlabel]"),0,ShellFunction::VolumeLabel),
    54 	TShellCommand(_L("MD"),_L("Make a new directory"),_L("name"),0,ShellFunction::Md),
    55 	TShellCommand(_L("MOVE"),_L("Move files"),_L("name [destination]"),TShellCommand::ESSwitch,ShellFunction::Move),
    56 	TShellCommand(_L("PS"),_L("Display information about processes"),_L(""),0,ShellFunction::Ps),
    57 	TShellCommand(_L("RENAME"),_L("Rename a file"),_L("oldfilename newfilename"),TShellCommand::ESSwitch,ShellFunction::Rename),
    58 	TShellCommand(_L("RD"),_L("Delete one directory"),_L("[drive:][path]directoryname"),TShellCommand::ESSwitch,ShellFunction::Rd),
    59 	TShellCommand(_L("START"),_L("Run a program in a separate window"),_L("filename[.exe]"),0,ShellFunction::Start),
    60 	TShellCommand(_L("TIME"),_L("Display the system time"),_L(""),0,ShellFunction::Time),
    61 	TShellCommand(_L("TRACE"),_L("Set the debug trace mask"),_L("[mask value in hex] [index] [/S/L/F/T/I/N/M/O/C/H]\n  /S - KFSERV\n  /L - KFLDR\n  /F - KFSYS\n  /T - KLFFS\n  /I - KISO9660\n  /N - KNTFS\n  /M - KTHRD\n  /O - KROFS\n  /C - KCOMPFS\n  /H - KCACHE"),TShellCommand::ELSwitch|TShellCommand::ESSwitch|TShellCommand::EFSwitch|TShellCommand::ETSwitch|TShellCommand::EISwitch|TShellCommand::ENSwitch|TShellCommand::EMSwitch|TShellCommand::EOSwitch|TShellCommand::ECSwitch|TShellCommand::EHSwitch,ShellFunction::Trace),
    62 	TShellCommand(_L("TREE"),_L("Graphically display the directory structure"),_L("[drive:][path] [/f][/p]\n\n  /f - Show files\n  /p - Pause after each screen of information"),TShellCommand::EFSwitch|TShellCommand::EPSwitch,ShellFunction::Tree),
    63 	TShellCommand(_L("TYPE"),_L("Display the contents of a text file"),_L("[drive:][path]filename [/p]\n\n  /p - Pause after each screen of information"),TShellCommand::EPSwitch,ShellFunction::Type),
    64 	TShellCommand(_L("VNAME"),_L("Check whether a filename is valid.  Return any invalid character"),_L("[drive:][path]filename \n\n "),0,ShellFunction::ValidName),
    65 	TShellCommand(_L("LOCK"),_L("Lock a password-enabled media"),_L("drive-number cur-pswd new-pswd [/s]"), TShellCommand::ESSwitch, ShellFunction::Lock),
    66 	TShellCommand(_L("UNLOCK"),_L("Unlock a locked password-enabled media"),_L("drive-number cur-pswd [/s]"), TShellCommand::ESSwitch, ShellFunction::Unlock),
    67 	TShellCommand(_L("CLEAR"),_L("Clear password from password-enabled media"),_L("drive-number cur-pswd"), 0x00000000, ShellFunction::Clear),
    68 	TShellCommand(_L("SETSIZE"),_L("Set size of a file"),_L("[filename] size"),0,ShellFunction::SetSize),
    69 	TShellCommand(_L("DEBUGPORT"),_L("Set or get debug port"),_L("[port]"),0,ShellFunction::DebugPort),
    70 	TShellCommand(_L("PLUGIN"),_L("Manage Plugins"),_L("[name][/A][/R][/M][/D]"),TShellCommand::EASwitch|TShellCommand::ERSwitch|TShellCommand::EMSwitch|TShellCommand::EDSwitch,ShellFunction::Plugin),
    71     TShellCommand(_L("DRVINFO"),_L("Print information about present drive(s) in the system"),_L("[DriveLetter:[\\]] [/p]\n/p - pause after each drive"),TShellCommand::EPSwitch,ShellFunction::DrvInfo),
    72 	TShellCommand(_L("SYSINFO"),_L("Print information about system features and status"),_L(""),0,ShellFunction::SysInfo),
    73     TShellCommand(_L("MOUNT"),_L("Mount / dismount file system on specified drive"),ptrMountHelp,TShellCommand::EUSwitch|TShellCommand::ESSwitch|TShellCommand::EFSwitch|TShellCommand::ERSwitch,ShellFunction::MountFileSystem),
    74     TShellCommand(_L("ECHO"),_L("Print out the command line to the console and standard debug port."),_L("[line to print out]"),0,ShellFunction::ConsoleEcho),
    75 	TShellCommand(_L("RUNEXEC"),_L("Run a program in a loop"),_L("count filename[.exe] [/E/S/R]\n	/E - exit early on error\n	/S - count in seconds\n	     zero - run forever\n	/R - reset debug regs after each run"),TShellCommand::EESwitch|TShellCommand::ESSwitch|TShellCommand::ERSwitch,ShellFunction::RunExec),
    76 
    77     };
    78 
    79 
    80 LOCAL_C TInt pswd_DrvNbr(TDes &aPath, TInt &aDN);
    81 LOCAL_C TInt pswd_Password(TDes &aPath, TInt aPWNbr, TMediaPassword &aPW);
    82 
    83 _LIT(KLitNewLine,"\n");
    84 void CShell::NewLine()
    85 	{
    86 	TheConsole->Printf(KLitNewLine());
    87 	}
    88 
    89 //
    90 // Skip the hexadecimal prefix if present and return EHex.  Return
    91 // EDecimal otherwise.
    92 //
    93 
    94 static TRadix ParseHexaPrefixIfAny(TLex& aLex)
    95 	{
    96 	_LIT(KPrefix, "0x");
    97 	if (aLex.Remainder().Length() > 2)
    98 		{
    99 		aLex.Mark();
   100 		aLex.Inc(2);
   101 		if (aLex.MarkedToken().MatchF(KPrefix) != KErrNotFound)
   102 			return EHex;
   103 		else
   104 			aLex.UnGetToMark();
   105 		}
   106 
   107 	return EDecimal;
   108 	}
   109 
   110 
   111 //
   112 //	TWord class
   113 //	Used to locate spaces in the command line, and return the next word
   114 //
   115 
   116 TWord::TWord(const TDesC& aDes)
   117 	: iSpace(0),iNextSpace(0)
   118 //
   119 //	Constructor
   120 //
   121 	{
   122 	Init(aDes);
   123 	}
   124 
   125 
   126 void TWord::Init(const TDesC& aDes)
   127 //
   128 // Resets to the start of the buffer
   129 //
   130 	{
   131 	iDes.Set(aDes);
   132 	}
   133 
   134 TInt TWord::FindNextWord(TDes& aWord)
   135 //
   136 //	Returns the next word from the buffer
   137 //
   138 	{
   139 	iSpace=aWord.Locate(' ');
   140 
   141 	if (iSpace==KErrNotFound)		//	No spaces in command line
   142 		{
   143 		if (aWord.Length()==0)		//	Command line has zero length:
   144 			return (KErrNotFound);	//	User just typed "command"
   145 		else
   146 			{						//	User typed "command aWord"
   147 			iRightString=aWord;
   148 			iNextWord=aWord;
   149 			return (0);
   150 			}
   151 		}
   152 
   153 	else if (iSpace<aWord.Length())	//	Spaces may be command switches or part of the filename
   154 		{
   155 		iRightString=(aWord.Right((aWord.Length()-iSpace)-1));
   156 
   157 		iNextSpace=iRightString.Locate(' ');	//	Check for another space
   158 		if (iNextSpace==KErrNotFound)			//	No more spaces
   159 			{
   160 			iNextWord=iRightString;
   161 			return((iDes.Length())-(iRightString.Length()));//	Position of the (last) word
   162 			}
   163 
   164 		if (iNextSpace<iRightString.Length())	//	More spaces - assign iNextWord to be
   165 			{									//	the text in between the two spaces
   166 			iNextWord=(iRightString.Left(iNextSpace));
   167 			return ((iDes.Length())-(iRightString.Length()));//	Position of the word
   168 			}
   169 
   170 		else
   171 			return(KErrNotFound);
   172 		}
   173 
   174 	else
   175 		return(KErrNotFound);
   176 	}
   177 
   178 //-------------------------------------------------------------------------
   179 
   180 
   181 TInt ShellFunction::Cd(TDes& aPath,TUint aSwitches)
   182 //
   183 // Change directory
   184 //
   185 	{
   186 	ShellFunction::StripQuotes(aPath);
   187 
   188 	TBool drvNameOnly=aPath.Length()==2 && aPath[1]==KDriveDelimiter;
   189 	TBool dSwitchSet=aSwitches&TShellCommand::EDSwitch;
   190 	if (aPath.Length()==0 || (drvNameOnly && !dSwitchSet))
   191 		{
   192 		TInt drvNum=(aPath.Length() ? aPath[0] : TheShell->currentPath[0])-'A';
   193 		if (drvNum<0 || drvNum>=KMaxDrives)
   194 			return(KErrBadName);
   195 		CShell::TheConsole->Printf(_L("%S\n"),&TheShell->drivePaths[drvNum]);
   196 		return(KErrNone);
   197 		}
   198 	if (aPath.Find(_L("*"))!=KErrNotFound)
   199 		return(KErrBadName);
   200 	if (aPath[aPath.Length()-1]!=KPathDelimiter && !drvNameOnly)
   201 		aPath.Append(KPathDelimiter);
   202 	aPath.Append('*');
   203 	TChar drvLetter = aPath[0];
   204 	drvLetter.UpperCase();
   205 	aPath[0] = (TText) drvLetter;
   206 	TParse dirParse;
   207 	TInt r=GetFullPath(aPath,dirParse);
   208 	if (r!=KErrNone)
   209 		return(KErrBadName);
   210 	TPtrC fullName=dirParse.FullName();
   211 	RDir dir;
   212 	r=dir.Open(TheShell->TheFs,fullName,KEntryAttMaskSupported);
   213 	if (r!=KErrNone)
   214 		return(r);
   215 	dir.Close();
   216 	if (dSwitchSet || fullName[0]==TheShell->currentPath[0])
   217 		r=TheShell->TheFs.SetSessionPath(dirParse.DriveAndPath());
   218 	if (r==KErrNone)
   219 		TheShell->SetDrivePath(dirParse.DriveAndPath());
   220 	return(r);
   221 	}
   222 
   223 TInt ShellFunction::ChkDeps(TDes& aPath,TUint /*aSwitches*/)
   224 	{
   225 	ShellFunction::StripQuotes(aPath);
   226 
   227 	aPath.Trim();
   228 	TBool appendedExe=EFalse;
   229 
   230 //	Determine whether aPath is an executable or a Dll
   231 
   232 	TInt r=aPath.FindF(_L(".EXE"));
   233 	if (r==KErrNotFound)
   234 		{
   235 		r=aPath.FindF(_L(".DLL"));
   236 		if (r==KErrNotFound)//	aPath does not include .exe or .dll extensions
   237 			{
   238 			aPath.Append(_L(".EXE"));	//	append a .exe extension
   239 			appendedExe=ETrue;
   240 			}
   241 		}
   242 
   243 	if (aPath.Length()>2 && aPath[1]==':' && aPath[2]!='\\')
   244 		{
   245 		TInt drive;
   246 		__ASSERT_ALWAYS(RFs::CharToDrive(aPath[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
   247  		TheShell->currentPath=TheShell->drivePaths[drive];
   248    		aPath.Delete(0,2);
   249    		aPath.Insert(0,TheShell->currentPath);
   250 		}
   251 	if (aPath.Length()>2 && aPath[1]!=':')
   252 		{
   253 		if (aPath[0]!='\\')
   254     		aPath.Insert(0,TheShell->currentPath);
   255 		else
   256 			aPath.Insert(0,TheShell->currentPath.Left(2));
   257 		}
   258 
   259 	RFile file;
   260 	r=file.Open(CShell::TheFs,aPath,EFileStream);
   261 	if (r!=KErrNone)	//		File could not be opened
   262 		{
   263 		if (appendedExe)	//	If .EXE was appended earlier
   264 			{
   265 //	Remove .EXE and append .DLL instead.  Try to open the file again
   266 //	If this fails too, the user entered an invalid filename that is neither
   267 //	an executable or a Dll
   268 			aPath.Delete(aPath.Length()-4,4);
   269 			appendedExe=EFalse;
   270 			aPath.Append(_L(".DLL"));	//	Try a .DLL extension
   271 			r=file.Open(CShell::TheFs,aPath,EFileStream);
   272 			if (r!=KErrNone)	//	Still could not open file
   273 				return(r);	//	Neither an executable or a Dll
   274 		//	Runs to here if the file is opened -> .DLL extension appended
   275 			}
   276 		else
   277 			return(r);	//	User had typed in an incorrect filename with
   278 						//	a .DLL or .EXE extension
   279 		}
   280 
   281 	file.Close();
   282 	CDllChecker check;
   283 	TRAPD(leaveCode,check.ConstructL());//	Allocates 4 elements at a time
   284 	if (leaveCode!=KErrNone)	//	If function leaves
   285 		return(leaveCode);		//	return the leave code
   286 
   287 	TRAPD(result,check.GetImportDataL(aPath,NULL));
   288 	if (result==KErrGeneral)
   289 		{
   290 		CShell::TheConsole->Printf(_L(" %S has no import data\n"),&aPath);
   291 		return(KErrNone);
   292 		}
   293 	else
   294 		check.ListArray();	//	Print out the results of DllCheck
   295 	return(KErrNone);
   296 	}
   297 
   298 //
   299 // Check disk for corruption
   300 //
   301 // Spec:
   302 //
   303 // ChkDsk DriveLetter:[\] [/S] [/F] [/U]
   304 //
   305 //			/S : Starts a ScanDrive instead of CheckDisk
   306 //			/F : Finalise given drive
   307 //			/U : UnFinalise given drive
   308 
   309 TInt ShellFunction::ChkDsk(TDes& aPath,TUint aSwitches)
   310 	{
   311 	ShellFunction::StripQuotes(aPath);
   312     
   313     const TBool bRunScanDrv     = aSwitches & TShellCommand::ESSwitch;
   314     const TBool bFinaliseDrv    = aSwitches & TShellCommand::EFSwitch;
   315     const TBool bUnFinaliseDrv  = aSwitches & TShellCommand::EUSwitch; 
   316 
   317     TInt nRes;
   318     TInt drive=EDriveZ;
   319 
   320 	if(aPath.Length() < 1)
   321     {
   322         nRes = KErrArgument;
   323     }
   324     else
   325     {
   326         nRes=CShell::TheFs.CharToDrive(aPath[0], drive);
   327 	}
   328 
   329     if (nRes != KErrNone)
   330 	{
   331     	CShell::TheConsole->Printf(_L("Wrong drive specified!\n"));
   332         return nRes;
   333     }
   334     
   335     if(bRunScanDrv)
   336     {//-- run ScanDrive on the specified drive
   337         CShell::TheConsole->Printf(_L("Starting ScanDrive...\n"));
   338         nRes=TheShell->TheFs.ScanDrive(aPath);
   339         if(nRes == KErrNone)
   340         {
   341             CShell::TheConsole->Printf(_L("No errors.\n"));
   342         }
   343     }
   344     else if(bFinaliseDrv)
   345     {//-- finalise the drive
   346         nRes = CShell::TheFs.FinaliseDrive(drive, RFs::EFinal_RW);
   347         if(nRes != KErrNone)
   348             return nRes;
   349 
   350         CShell::TheConsole->Printf(_L("Drive %c: is finalised RW\n"), 'A'+drive);
   351     }
   352     else if(bUnFinaliseDrv)
   353     {//-- Unfinalise the drive
   354         nRes = CShell::TheFs.FinaliseDrive(drive, RFs::EForceUnfinalise);
   355         if(nRes != KErrNone)
   356             return nRes;
   357 
   358         CShell::TheConsole->Printf(_L("Drive %c: is Unfinalised\n"), 'A'+drive);
   359     }
   360     else
   361     {//-- run CheckDisk on the specified drive
   362         nRes=TheShell->TheFs.CheckDisk(aPath);
   363 	    if (nRes<0)
   364 		    return(nRes);
   365 
   366 	    switch(nRes)
   367 		    {
   368 	    case 0:
   369 		    CShell::TheConsole->Printf(_L("Complete - no errors\n"));
   370 		    break;
   371 	    case 1:
   372 		    CShell::TheConsole->Printf(_L("Error - File cluster chain contains a bad value (<2 or >maxCluster)\n"));
   373 		    break;
   374 	    case 2:
   375 		    CShell::TheConsole->Printf(_L("Error - Two files are linked to the same cluster\n"));
   376 		    break;
   377 	    case 3:
   378 		    CShell::TheConsole->Printf(_L("Error - Unallocated cluster contains a value != 0\n"));
   379 		    break;
   380 	    case 4:
   381 		    CShell::TheConsole->Printf(_L("Error - Size of file != number of clusters in chain\n"));
   382 		    break;
   383 	    default:
   384 		    CShell::TheConsole->Printf(_L("Undefined Error value\n"));
   385 		    }
   386 	 }
   387     return nRes;
   388 	}
   389 
   390 TInt ShellFunction::Copy(TDes& aPath,TUint aSwitches)
   391 //
   392 // DOS spec:
   393 //
   394 // COPY [/A | /B] source [/A | /B] [+ source [/A | /B] [+ ...]] [destination] [/A | /B]] [/V] [/N]
   395 // source		Specifies the file or files to be copied.
   396 // /A			Indicates an ASCII text file.
   397 // /B			Indicates a binary file.
   398 // destination	Specifies the directory and/or filename for the new file(s).
   399 // /V			Verifies that new files are written correctly.
   400 // /Y			Supresses prompting to confirm you want to overwrite existing destination file
   401 // /N			Uses short filename, if available, when copying a file with a non-8dot3 name.
   402 //
   403 // To append files, specify a single file for destination, but multiple files
   404 // for source (using wildcards or file1+file2+file3 format).
   405 //
   406 // My spec:
   407 //
   408 // COPY source [destination]
   409 // source		Specifies the file or files to be copied to the current directory
   410 
   411 // Modified November 1997 to allow spaces in filenames
   412 
   413 	{
   414 	if (aPath.Length() == 0)
   415 	    return KErrNotFound;    // no source file
   416 
   417 	ShellFunction::StripQuotes(aPath);
   418 
   419 	TBuf<KShellMaxCommandLine> destination;
   420 	TBuf<KShellMaxCommandLine> tempPath;
   421 	TWord word(aPath);
   422 
   423 	TBool endOfCommandLine=EFalse;
   424 
   425 //	Check if the word returned is a valid filename.  If not, scan the next
   426 //	word too in case the filename contains spaces.  If, at the end of the
   427 //	the line, the filename is not recognised, it is invalid.  If there are no
   428 //	spaces the user has not used the correct format for this command.
   429 
   430 	TInt r=word.FindNextWord(aPath);
   431 	do	{
   432 		TParse dirPath;
   433 
   434 		if (r==0)	//	No destination was specified
   435 			{
   436 		//	Work out the destination
   437 			tempPath.SetLength(0);
   438 			r=GetFullPath(tempPath,dirPath);
   439 			if (r!=KErrNone)
   440 				return(r);
   441 			destination=dirPath.FullName();
   442 		//	Now get the path of the source
   443 			tempPath=aPath;
   444 			r=GetFullPath(tempPath,dirPath);
   445 			if (r!=KErrNone)
   446 				return(r);
   447 			endOfCommandLine=ETrue;	//	So we don't get stuck in an infinite loop
   448 			}
   449 		else
   450 			{
   451 		//	Work out the destination
   452 			destination=aPath.Right(aPath.Length()-r);
   453 			if (!destination.Compare(_L(".")))
   454 				GetFullPath(destination,dirPath);
   455 		//	Now get the path of the source
   456 			tempPath=aPath;
   457 			tempPath.SetLength(r);
   458 			r=GetFullPath(tempPath,dirPath);
   459 			if (r!=KErrNone)
   460 				return(r);
   461 			}
   462 
   463 		TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
   464 		TUint switches=(recursive) ? CFileMan::EOverWrite|CFileMan::ERecurse : CFileMan::EOverWrite;
   465 		r=CShell::TheFileMan->Copy(dirPath.FullName(),destination,switches);
   466 		if (r==KErrNone)
   467 			return(r);	//	Copy was successful
   468 
   469 		else			//	Not a valid filename - move one word along the command line
   470 			r=word.FindNextWord(word.iRightString);
   471 		} while ((r>=0)&&(!endOfCommandLine));
   472 
   473 	if (r<0)			//	Some error
   474 		return (r);
   475 	else				//	End of command line, user typed invalid line, return not found
   476 		return (KErrNotFound);
   477 	}
   478 
   479 
   480 TInt ShellFunction::VolumeLabel(TDes& aPath,TUint /*aSwitches*/)
   481 /**
   482 Sets or returns the default path
   483 
   484 @param aPath The volume label being set or returned
   485 */
   486 	{
   487 	ShellFunction::StripQuotes(aPath);
   488 
   489 	TVolumeInfo vol;
   490 	TInt drive;
   491 	TInt r=CShell::TheFs.CharToDrive(CShell::currentPath[0], drive);
   492 	if (r!=KErrNone)
   493 		return(r);
   494 	if (aPath.Length()==0)
   495 		{
   496 		r=CShell::TheFs.Volume(vol, drive);
   497 		if (r==KErrNone)
   498 			CShell::TheConsole->Printf(_L("Volume = %S\n"),&vol.iName);
   499 		return(r);
   500 		}
   501 	r=CShell::TheFs.SetVolumeLabel(aPath, drive);
   502 	return(r);
   503 	}
   504 
   505 TInt ShellFunction::Del(TDes& aPath,TUint aSwitches)
   506 	{
   507 	TParse filePath;
   508 	if (aPath.Length()==0)
   509 		return(KErrNone);
   510 
   511 	ShellFunction::StripQuotes(aPath);
   512 
   513 	GetFullPath(aPath,filePath);
   514 	TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
   515 	TUint switches=(recursive) ? CFileMan::ERecurse : 0;
   516 	TInt r=CShell::TheFileMan->Delete(filePath.FullName(),switches);
   517 	return(r);
   518 	}
   519 
   520 
   521 void ShellFunction::AlignTextIntoColumns(RPointerArray<HBufC>& aText)
   522 //function which tries to arrange text as a set of columns if console width greater then the longest string
   523 {
   524 	TInt ind=0;
   525 	if (aText.Count()<=0) return;
   526 	//detect the longest string
   527 	for (TInt i=0;i<aText.Count();i++)
   528 		if (aText[i]->Length()>aText[ind]->Length())
   529 			ind=i;
   530 	TInt max_string_length=aText[ind]->Length()+2;
   531 
   532 	//calculate how many columns fit into the screen
   533 	TInt number_of_columns=(CShell::TheConsole->ScreenSize().iWidth)/max_string_length;
   534 
   535 	//if we cannot fit more than one column into screen when we do nothing
   536 	if (number_of_columns<2) return;
   537 
   538 	//calculate column width
   539 	TInt column_width=CShell::TheConsole->ScreenSize().iWidth/number_of_columns;
   540 
   541 	TInt current_source_string=0;
   542 	TInt current_destination_string=0;
   543 
   544 	TInt count=aText.Count();
   545 	//join strings together into string which fits in a single line
   546 	while (current_source_string<count)
   547 		{
   548 		TPtr string= aText[current_destination_string++]->Des();
   549 		TInt to_skip=0;
   550 
   551 		for (TInt i=0;i<number_of_columns;i++)
   552 			{
   553 			if (current_source_string==count)
   554 				break;
   555 			//skip several characters to keep even distance between columns
   556 			for (TInt j=0;j<to_skip;j++)
   557 				string.Append(_L(" "));
   558 
   559 			if (i==0)
   560 				string=(*aText[current_source_string]);
   561 			else
   562 				string.Append(*aText[current_source_string]);
   563 			to_skip=column_width-aText[current_source_string]->Length();
   564 			current_source_string++;
   565 			}
   566 		}
   567 
   568 	//resize aText array to the new size
   569 
   570 	for (TInt j=aText.Count()-1;j>=current_destination_string;j--)
   571 		{
   572 		delete aText[j];
   573 		aText.Remove(j);
   574 		}
   575 
   576 }
   577 
   578 
   579 void ShellFunction::OutputContentsToConsole(RPointerArray<HBufC>& aText,TUint aSwitches)
   580 //outputs content of the buffer to console according to settings passed in aSwitches
   581 	{
   582 	if ((aText.Count()>0)&&((aSwitches&TShellCommand::EWSwitch)!=0))
   583 		AlignTextIntoColumns(aText);
   584 
   585 	for (TInt i=0;i<aText.Count();i++)
   586 		{
   587 		CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),*aText[i]);
   588 		CShell::OutputStringToConsole(EFalse,_L("\n"));
   589 		delete aText[i];
   590 		}
   591 	//empty string array
   592 	aText.Reset();
   593 	}
   594 
   595 
   596 void ShellFunction::OutputDirContentL(CDir* aDirList,RPointerArray<HBufC>& aText,TUint aSwitches)
   597 //outputs content of a directory to console according to settings passed in aSwitches
   598 	{
   599 	TInt count=aDirList->Count();
   600 	TInt fileCount=0, dirCount=0, printCount=0;
   601 	TInt64 byteCount=0;
   602 
   603 	//compose an array of strings describing entries in the directory
   604 	for (TInt j=0;j<count;j++)
   605 		{
   606 		HBufC* buf=NULL;
   607 		TEntry entry=(*aDirList)[j];
   608 		TDateTime modTime=entry.iModified.DateTime();
   609 		if ((aSwitches&TShellCommand::EWSwitch)!=0)//if we are asked to output brief information about directory content
   610 			{
   611 			TInt length=(KMaxFileName>CShell::TheConsole->ScreenSize().iWidth)?KMaxFileName:CShell::TheConsole->ScreenSize().iWidth;
   612 			buf = HBufC::NewL(length);
   613 
   614 			CleanupStack::PushL(buf);
   615 			TPtr name=buf->Des();
   616 			name=entry.iName;
   617 
   618 			if (entry.IsDir())
   619 				{
   620 				dirCount++;
   621 				name.Insert(0,_L("["));
   622 				name.Append(']');
   623 				}
   624 			else
   625 				{
   626 				byteCount+=entry.FileSize();
   627 				fileCount++;
   628 				}
   629 			}
   630 		else//if we are asked to output full information about directory content
   631 			{
   632 			buf = HBufC::NewL(KMaxFileName+100);//reserve additional space for the creation time information
   633 			CleanupStack::PushL(buf);
   634 			TPtr name=buf->Des();
   635 			name=entry.iName;
   636 
   637 			if (entry.IsDir())
   638 				{
   639 				dirCount++;
   640 				name.Format(_L(" %- 26S   <DIR>         %+02d/%+02d/%- 4d  %02d:%02d:%02d.%06d"),
   641 											&entry.iName,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
   642 				}
   643 			else
   644 				{
   645 				TInt64 entrySize = entry.FileSize();
   646 				byteCount+=entrySize;
   647 				fileCount++;
   648  				name.Format(_L(" %- 32S%+ 15Lu   %+02d/%+02d/%- 4d  %02d:%02d:%02d.%06d"),
   649  											&entry.iName,entrySize,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
   650 				}
   651 			}
   652 		User::LeaveIfError(aText.Append(buf ));
   653 		printCount++;
   654 		//print the contents if a screen size of data is available. This will prevent huge buffer allocation.
   655 		if(printCount == CShell::TheConsole->ScreenSize().iHeight)
   656 			{
   657 			OutputContentsToConsole(aText,aSwitches);
   658 			printCount=0;
   659 			}
   660 		CleanupStack::Pop();
   661 
   662 		}
   663 	OutputContentsToConsole(aText,aSwitches);
   664 
   665 	//output summary information
   666 	CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L("    %d File%c\n"),fileCount,(fileCount==1)?' ':'s');
   667 	if (fileCount!=0)
   668 		{
   669 		CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L("  %lu byte%c\n"),byteCount,(fileCount==1)?' ':'s');
   670 		}
   671 
   672 	TBuf<50> buf;// allocate string long enough for additional information(number of directories)
   673 	buf.Format(_L("    %d Director"),dirCount);
   674 	if (dirCount==1)
   675 		buf.AppendFormat(_L("y\n"));
   676 	else
   677 		buf.AppendFormat(_L("ies\n"));
   678 
   679 	CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),buf);
   680 	}
   681 
   682 TInt ShellFunction::Dir(TDes& aPath,TUint aSwitches)
   683 //
   684 //	Modified December 1997, to sort entries alphabetically
   685 //
   686 	{
   687 	ShellFunction::StripQuotes(aPath);
   688 
   689 	RDir    dir;
   690 	RFile64 file;
   691 	TParse dirParse;
   692 //	Parses the given path to give a full path
   693 	GetFullPath(aPath,dirParse);
   694 //	Sets aPath to a full path name
   695 	aPath=dirParse.FullName();
   696 	if (aPath[aPath.Length()-1]==KPathDelimiter)
   697 		aPath.Append('*');
   698 	else if (aPath.Locate(KMatchAny)==KErrNotFound && aPath.Locate(KMatchOne)==KErrNotFound && file.Open(TheShell->TheFs,aPath,KEntryAttMatchExclude|KEntryAttDir)!=KErrNone)
   699 		aPath.Append(_L("\\*"));
   700 	else file.Close();
   701 
   702 	TInt r=dir.Open(TheShell->TheFs,aPath,KEntryAttMaskSupported);
   703 	if (r!=KErrNone)
   704 		{
   705 		CShell::TheConsole->Printf(_L("File or directory not found\n"));
   706 		return(KErrNone);
   707 		}
   708 
   709 	CDir* anEntryList;
   710 	r=TheShell->TheFs.GetDir(aPath,KEntryAttMaskSupported,ESortByName,anEntryList);
   711 	if (r!=KErrNone)
   712 		{
   713 		dir.Close();
   714 		return(r);
   715 		}
   716     CleanupStack::PushL(anEntryList);
   717 
   718 	//Sets the new length of path to the position of the last path delimiter +1
   719 	aPath.SetLength(aPath.LocateReverse(KPathDelimiter)+1);
   720 	CShell::TheConsole->Printf(_L("Directory of %S\n"),&aPath);
   721 
   722 	//allocate array to be used as an output buffer
   723 	RPointerArray<HBufC>* text=new(ELeave) RPointerArray<HBufC>();
   724 	TRAPD(error,OutputDirContentL(anEntryList,*text,aSwitches));
   725 	//we are not interesed in the error code because we need empty the buffer in any case
   726 	for (TInt i=0;i<text->Count();i++)
   727 		delete (*text)[i];
   728 	delete text;
   729 	CleanupStack::PopAndDestroy(anEntryList);
   730 	dir.Close();
   731 	if (error )
   732 		return (error);
   733 	else
   734 		return(KErrNone);
   735 	};
   736 
   737 
   738 TInt ShellFunction::Edit(TDes& /*aPath*/,TUint /*aSwitches*/)
   739 //
   740 //	Dummy, used by edlin (now retired)
   741 //
   742 	{
   743 	return(KErrNone);
   744 	}
   745 
   746 
   747 TInt ShellFunction::Attrib(TDes& aPath,TUint aSwitches)
   748 {
   749 	ShellFunction::StripQuotes(aPath);
   750 
   751 //	Use TWord::NextWord(aPath) to find any spaces in the command line
   752 	TWord nextWord(aPath);
   753 	TInt r=nextWord.FindNextWord(aPath);
   754 	TInt signal=0;
   755 	const TPtrC settings[8]={(_L("+R")),(_L("-R")),(_L("+H")),(_L("-H")),(_L("+S")),(_L("-S")),(_L("+A")),(_L("-A"))};
   756 	TInt numberOfSettings=(sizeof(settings)/sizeof(*settings));
   757 
   758 	if (r==KErrNotFound)	//	User just typed ATTRIB
   759 		aPath.SetLength(aPath.Length());
   760 	else if (r==0)				//	User typed ATTRIB aWord
   761 		{						//	Check the word for a valid attributes
   762 		for (TInt index=0; index<numberOfSettings; index++)
   763 			{
   764 			signal=(nextWord.iNextWord).FindF(settings[index]);
   765 			if (signal!=KErrNotFound)
   766 				break;
   767 			}
   768 		if (signal==KErrNotFound)	//	No valid attributes settings
   769 			aPath.SetLength(aPath.Length());
   770 		else						//	Valid attributes settings
   771 			aPath.SetLength(r);
   772 		}
   773 	else	//	User typed ATTRIB aWord1 aWord2
   774 		{	//	Check the word for a valid attributes switch
   775 		while (r!=KErrNotFound)
   776 			{
   777 			for (TInt index=0; index<numberOfSettings; index++)
   778 				{
   779 				signal=(nextWord.iNextWord).FindF(settings[index]);
   780 				if (signal!=KErrNotFound)
   781 					break;
   782 				}
   783 			if (signal!=KErrNotFound)  //	Matched valid switches
   784 				{
   785 			//	Divide up command line
   786 			//	Include all settings (in case of "ATTRIB aWord +R +S")
   787 				nextWord.iRightString=aPath.Right(aPath.Length()-r);
   788 				aPath.SetLength(r);
   789 				break;
   790 				}
   791 			else							//	No valid switches found in word
   792 				r=nextWord.FindNextWord(nextWord.iRightString);	//	Check the next word
   793 				if (r==0)	//	Reached the end of a spaced command line without finding settings
   794 					{
   795 					nextWord.iRightString=aPath.Right(r);
   796 					break;
   797 					}
   798 			}
   799 		}
   800 
   801 	TParse dirParse;
   802 	GetFullPath(aPath,dirParse);
   803 	aPath=dirParse.FullName();
   804 
   805 	RFile64 file;
   806 	if (aPath[aPath.Length()-1]==KPathDelimiter)
   807 		aPath.Append('*');
   808 	else if( (aPath.Locate(KMatchAny)==KErrNotFound) && (aPath.Locate(KMatchOne)==KErrNotFound) )
   809 		{
   810 		TInt error=file.Open(TheShell->TheFs,aPath,KEntryAttMatchExclude|KEntryAttDir);
   811 		if (error!=KErrNone)
   812 			aPath.Append(_L("\\*"));//Path does not end in a valid file
   813 		else
   814 			file.Close();//	Path ends in a valid file
   815 		}
   816 
   817 //	Changes attributes settings (files only) if requested and if necessary
   818 	if (r!=KErrNotFound)
   819 		{
   820 		CDir* entryList;
   821 		r=CShell::TheFs.GetDir(aPath,KEntryAttMaskSupported,ESortByName,entryList);
   822 		if (r!=KErrNone)
   823 			return (r);
   824 		CleanupStack::PushL(entryList);
   825 		TInt entryCount=entryList->Count();
   826 //		Save session path
   827 		TBuf<KShellMaxCommandLine> aSessionPath;
   828 		r=TheShell->TheFs.SessionPath(aSessionPath);
   829 //		Temporarily assign session path to be the path requested
   830 //		Use the heap as we're running out of stack space
   831 		HBufC* pTempPath=NULL;
   832 		TRAP(r,pTempPath=HBufC::NewL(aPath.Length()))
   833 		if (r!=KErrNone)
   834 			{
   835 			CleanupStack::PopAndDestroy(entryList);
   836 			return (r);
   837 			}
   838 		*pTempPath=aPath;
   839 		pTempPath->Des().SetLength(aPath.LocateReverse(KPathDelimiter)+1);
   840 		r=TheShell->TheFs.SetSessionPath(pTempPath->Des());
   841 		User::Free(pTempPath);
   842 
   843 //		Looks clumsy, but necessary to change attributes of files in higher level directories
   844 		for (TInt i=0;i<entryCount;i++)
   845 			{
   846 			TEntry entry=(*entryList)[i];
   847 			if (!entry.IsDir())
   848 				{
   849 				for (TInt index=0; index<numberOfSettings; index++)
   850 					{
   851 					TInt attToSet=0;
   852 					TInt attToRemove=0;
   853 					signal=(nextWord.iRightString).FindF(settings[index]);
   854 					if (signal==KErrNotFound)
   855 						continue;
   856 					else
   857 						switch (index)
   858 						{
   859 					case 0:
   860 						attToSet|=KEntryAttReadOnly;
   861 						break;
   862 					case 1:
   863 						attToRemove|=KEntryAttReadOnly;
   864 						break;
   865 					case 2:
   866 						attToSet|=KEntryAttHidden;
   867 						break;
   868 					case 3:
   869 						attToRemove|=KEntryAttHidden;
   870 						break;
   871 					case 4:
   872 						attToSet|=KEntryAttSystem;
   873 						break;
   874 					case 5:
   875 						attToRemove|=KEntryAttSystem;
   876 						break;
   877 					case 6:
   878 						attToSet|=KEntryAttArchive;
   879 						break;
   880 					case 7:
   881 						attToRemove|=KEntryAttArchive;
   882 						break;
   883 					default:	//	Will never reach here
   884 						break;
   885 						}
   886 					r=TheShell->TheFs.SetAtt((entry.iName),attToSet,attToRemove);
   887 					continue;
   888 					}
   889 				}
   890 			else continue;
   891 			}
   892 //		Set session path to previous setting
   893 		r=TheShell->TheFs.SetSessionPath(aSessionPath);
   894 		CleanupStack::PopAndDestroy(entryList);
   895 		}
   896 
   897 //	Runs to here if no requested attributes changes:
   898 	CDir* alphaEntryList;
   899 	r=CShell::TheFs.GetDir(aPath,KEntryAttMaskSupported,ESortByName,alphaEntryList);
   900 	if (r!=KErrNone)
   901 		return (r);
   902 	TInt count=alphaEntryList->Count();
   903 
   904 	RDir dir;
   905 	r=dir.Open(TheShell->TheFs,aPath,KEntryAttMaskSupported);
   906 	if (r!=KErrNone)
   907         {
   908         delete alphaEntryList;
   909 		return(r);
   910         }
   911 
   912 	aPath.SetLength(aPath.LocateReverse(KPathDelimiter)+1);
   913 
   914 
   915 	TEntry entry;
   916 	TUint fileCount=0;
   917 
   918 //	Lists attributes settings (files only)
   919 	for (TInt j=0;j<count;j++)
   920 		{
   921 		entry=alphaEntryList->operator[](j);
   922 		if (!entry.IsDir())
   923 			{
   924 			TBuf<4> attrBuf=entry.IsReadOnly()?_L("R"):_L("");
   925 			if (entry.IsHidden())
   926 				attrBuf.Append('H');
   927 			if (entry.IsSystem())
   928 				attrBuf.Append('S');
   929 			if (entry.IsArchive())
   930 				attrBuf.Append('A');
   931 			CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L(" %-10S %S%S\n"),&attrBuf, &aPath,&entry.iName);
   932 			fileCount++;
   933 			}
   934 		}
   935 
   936 	dir.Close();
   937 
   938 	if (fileCount==0)
   939 		CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L("No files found in %S\n"),&aPath);
   940 
   941 	delete alphaEntryList;
   942 	return(KErrNone);
   943   }
   944 
   945 
   946 
   947 
   948 
   949 //--------------------------------------------------------
   950 
   951 /**
   952     Format TMediaType description.
   953 
   954     @param  aDrvInfo    drive info structure
   955     @param  aPrintBuf   buffer where the information will be printed to.
   956 */
   957 void FormatDrvMediaTypeInfo(const TDriveInfo& aDrvInfo, TDes& aPrintBuf)
   958     {
   959         aPrintBuf.Format(_L("TMediaType:%d "),aDrvInfo.iType);
   960 
   961         switch(aDrvInfo.iType)
   962         {
   963         case EMediaNotPresent:      aPrintBuf.Append(_L("EMediaNotPresent"));   break;
   964         case EMediaUnknown:	        aPrintBuf.Append(_L("EMediaUnknown"));      break;
   965         case EMediaFloppy:          aPrintBuf.Append(_L("EMediaFloppy"));       break;
   966         case EMediaHardDisk:        aPrintBuf.Append(_L("EMediaHardDisk"));     break;
   967         case EMediaCdRom:		    aPrintBuf.Append(_L("EMediaCdRom"));        break;
   968         case EMediaRam:             aPrintBuf.Append(_L("EMediaRam"));          break;
   969         case EMediaFlash:           aPrintBuf.Append(_L("EMediaFlash"));        break;
   970         case EMediaRom:             aPrintBuf.Append(_L("EMediaRom"));          break;
   971         case EMediaRemote:          aPrintBuf.Append(_L("EMediaRemote"));       break;
   972         case EMediaNANDFlash:       aPrintBuf.Append(_L("EMediaNANDFlash"));    break;
   973         case EMediaRotatingMedia:   aPrintBuf.Append(_L("EMediaRotatingMedia"));break;
   974         
   975         default:                    aPrintBuf.Append(_L("??? Unknown Type"));   break;
   976         };
   977 
   978 
   979         aPrintBuf.Append(_L("\n"));
   980     }
   981 
   982 //--------------------------------------------------------
   983 
   984 /**
   985     Format DriveAtt description.
   986 
   987     @param  aDrvInfo    drive info structure
   988     @param  aPrintBuf   buffer where the information will be printed to.
   989 */
   990 void FormatDriveAttInfo(const TDriveInfo& aDrvInfo, TDes& aPrintBuf)
   991     {
   992         aPrintBuf.Format(_L("DriveAtt:0x%x "),aDrvInfo.iDriveAtt);
   993 
   994         if(aDrvInfo.iDriveAtt & KDriveAttLocal)         aPrintBuf.Append(_L("KDriveAttLocal,"));
   995         if(aDrvInfo.iDriveAtt & KDriveAttRom)           aPrintBuf.Append(_L("KDriveAttRom,"));
   996         if(aDrvInfo.iDriveAtt & KDriveAttRedirected)    aPrintBuf.Append(_L("KDriveAttRedirected,"));
   997         if(aDrvInfo.iDriveAtt & KDriveAttSubsted)       aPrintBuf.Append(_L("KDriveAttSubsted,"));
   998         if(aDrvInfo.iDriveAtt & KDriveAttInternal)      aPrintBuf.Append(_L("KDriveAttInternal,"));
   999         if(aDrvInfo.iDriveAtt & KDriveAttRemovable)     aPrintBuf.Append(_L("KDriveAttRemovable"));
  1000 
  1001         if(aDrvInfo.iDriveAtt & KDriveAttRemote)        aPrintBuf.Append(_L("KDriveAttRemote"));
  1002         if(aDrvInfo.iDriveAtt & KDriveAttTransaction)   aPrintBuf.Append(_L("KDriveAttTransaction"));
  1003 
  1004         if(aDrvInfo.iDriveAtt & KDriveAttPageable)              aPrintBuf.Append(_L("KDriveAttPageable"));
  1005         if(aDrvInfo.iDriveAtt & KDriveAttLogicallyRemovable)    aPrintBuf.Append(_L("KDriveAttLogicallyRemovable"));
  1006         if(aDrvInfo.iDriveAtt & KDriveAttHidden)                aPrintBuf.Append(_L("KDriveAttHidden"));
  1007 
  1008         aPrintBuf.Append(_L("\n"));
  1009     }
  1010 
  1011 //--------------------------------------------------------
  1012 
  1013 /**
  1014     Format MediaAtt description.
  1015 
  1016     @param  aDrvInfo    drive info structure
  1017     @param  aPrintBuf   buffer where the information will be printed to.
  1018 */
  1019 void FormatMediaAttInfo(const TDriveInfo& aDrvInfo, TDes& aPrintBuf)
  1020     {
  1021         aPrintBuf.Format(_L("MediaAtt:0x%x "),aDrvInfo.iMediaAtt);
  1022 
  1023         if(aDrvInfo.iMediaAtt & KMediaAttVariableSize)      aPrintBuf.Append(_L("KMediaAttVariableSize,"));
  1024         if(aDrvInfo.iMediaAtt & KMediaAttDualDensity)       aPrintBuf.Append(_L("KMediaAttDualDensity,"));
  1025         if(aDrvInfo.iMediaAtt & KMediaAttFormattable)       aPrintBuf.Append(_L("KMediaAttFormattable,"));
  1026         if(aDrvInfo.iMediaAtt & KMediaAttWriteProtected)    aPrintBuf.Append(_L("KMediaAttWriteProtected,"));
  1027         if(aDrvInfo.iMediaAtt & KMediaAttLockable)          aPrintBuf.Append(_L("KMediaAttLockable,"));
  1028         if(aDrvInfo.iMediaAtt & KMediaAttLocked)            aPrintBuf.Append(_L("KMediaAttLocked"));
  1029 
  1030         if(aDrvInfo.iMediaAtt & KMediaAttHasPassword)       aPrintBuf.Append(_L("KMediaAttHasPassword"));
  1031         if(aDrvInfo.iMediaAtt & KMediaAttReadWhileWrite)    aPrintBuf.Append(_L("KMediaAttReadWhileWrite"));
  1032         if(aDrvInfo.iMediaAtt & KMediaAttDeleteNotify)      aPrintBuf.Append(_L("KMediaAttDeleteNotify"));
  1033         if(aDrvInfo.iMediaAtt & KMediaAttPageable)          aPrintBuf.Append(_L("KMediaAttPageable"));
  1034         
  1035 
  1036         aPrintBuf.Append(_L("\n"));
  1037     }
  1038 
  1039 //--------------------------------------------------------
  1040 
  1041 /**
  1042     Format TVolumeInfo description.
  1043 
  1044     @param  volInfo     volume information
  1045     @param  aPrintBuf   buffer where the information will be printed to.
  1046 */
  1047 void FormatVolInfo(const TVolumeInfo& volInfo , TDes& aPrintBuf)
  1048     {
  1049    	aPrintBuf.Format(_L("VolSz:%ld Free:%ld\n"),volInfo.iSize, volInfo.iFree);
  1050    	aPrintBuf.AppendFormat(_L("VolId:0x%x VolName:%S\n"),volInfo.iUniqueID, &volInfo.iName);
  1051     }
  1052 
  1053 //--------------------------------------------------------
  1054 
  1055 /** Bit flags that specify which information will be printed by PrintDrvInfo() */
  1056 enum TPrintDrvInfoFlags
  1057 {
  1058     EFSInfo         = 0x01, //-- file system information
  1059     EFSInfoEx       = 0x02, //-- extended file system information
  1060     EMediaTypeInfo  = 0x04, //-- media type
  1061     EMediaAttInfo   = 0x08, //-- media attributes etc.
  1062     EDrvAttInfo     = 0x10, //-- drive attributes etc
  1063     EVolInfo        = 0x20, //-- volume information
  1064 
  1065     EAll            = 0xFFFF
  1066 };
  1067 
  1068 //-----------------------------------------------------------------------------------------------------------------------
  1069 /**
  1070     Prints information about specified drive.
  1071 
  1072     @param  aFs         file system object
  1073     @param  aDrvNum     drive number
  1074     @param  apConsole   pointer to the console to print information into
  1075     @param  aFlags      specifies which information to print out, @see TPrintDrvInfoFlags
  1076 
  1077     @return standard error code
  1078 */
  1079 TInt PrintDrvInfo(RFs& aFs, TInt aDrvNum, CConsoleBase* apConsole, TUint aFlags = EAll)
  1080     {
  1081 	TInt        nRes;
  1082 	TDriveInfo 	driveInfo;
  1083 	TVolumeInfo volInfo;
  1084 	TBuf<256>   Buf;
  1085 
  1086 	//-- get drive info
  1087 	nRes = aFs.Drive(driveInfo, aDrvNum);
  1088 	if(nRes != KErrNone)
  1089 		{
  1090 		CShell::TheConsole->Printf(_L("Error: %d\n"), nRes);
  1091 		return nRes;   //-- can't get information about the drive
  1092 		}
  1093 
  1094 	
  1095     nRes = aFs.Volume(volInfo, aDrvNum);
  1096     const TBool bVolumeOK  = (nRes == KErrNone);
  1097 	if(!bVolumeOK)
  1098 	{//-- can't get information about the volume. It might be just corrupt/unformatted
  1099 		CShell::TheConsole->Printf(_L("Error getting volume info. code: %d\n"), nRes);
  1100         if(nRes == KErrCorrupt)
  1101         {
  1102             CShell::TheConsole->Printf(_L("The volume might be corrupted or not formatted.\n"));
  1103         }
  1104 	}
  1105 
  1106 
  1107 	//-- Print out information about file system installed
  1108 	if(aFlags & EFSInfo)
  1109     {
  1110         
  1111         apConsole->Printf(_L("\nDrive %c: number:%d\n"), 'A'+aDrvNum, aDrvNum);
  1112 
  1113 	    //-- print the FS name
  1114 	    if(aFs.FileSystemName(Buf, aDrvNum) == KErrNone)
  1115 	    {
  1116 	        TFSName fsName;
  1117             
  1118             nRes = aFs.FileSystemSubType(aDrvNum, fsName); 
  1119             if(nRes == KErrNone && Buf.CompareF(fsName) !=KErrNone)
  1120             {
  1121                 Buf.AppendFormat(_L(" (%S)"), &fsName);
  1122             }
  1123 
  1124             //-- try to find out primary extension name if present
  1125             nRes = aFs.ExtensionName(fsName, aDrvNum, 0);
  1126             if(nRes == KErrNone)
  1127             {   
  1128                  Buf.AppendFormat(_L(" PExt:%S"), &fsName);
  1129             }
  1130 
  1131 
  1132             apConsole->Printf(_L("Mounted FS:%S\n"), &Buf);
  1133 
  1134             //-- print out the list of supported file systems if there are more than 1
  1135             nRes = aFs.SupportedFileSystemName(fsName, aDrvNum, 0+1); //-- try to get 2nd child name
  1136             if(nRes == KErrNone)
  1137             {
  1138                 Buf.Copy(_L("Supported FS: "));
  1139                 for(TInt i=0; ;++i)
  1140                 {
  1141                     nRes = aFs.SupportedFileSystemName(fsName, aDrvNum, i); 
  1142                     if(nRes != KErrNone)
  1143                         break;
  1144 
  1145                     Buf.AppendFormat(_L("%S, "), &fsName);
  1146                 }
  1147             
  1148                 Buf.Append(_L("\n"));
  1149                 apConsole->Printf(Buf);
  1150             }
  1151 
  1152 
  1153 
  1154             //-- print out FileSystem volume finalisation info
  1155             if(bVolumeOK && (aFlags & EFSInfoEx))
  1156             {
  1157 
  1158                 TPckgBuf<TBool> boolPckg;
  1159                 nRes = aFs.QueryVolumeInfoExt(aDrvNum, EIsDriveFinalised, boolPckg);
  1160                 if(nRes == KErrNone)
  1161                 {
  1162                     if(boolPckg() >0)
  1163                         apConsole->Printf(_L("Volume Finalised\n"));
  1164                     else
  1165                         apConsole->Printf(_L("Volume Not finalised\n"));
  1166                 }
  1167             }
  1168 	    }
  1169     }//if(aFlags & EFSInfo)
  1170 
  1171 	//-- print media attributes
  1172 	if(aFlags & EMediaTypeInfo)
  1173     {
  1174         FormatDrvMediaTypeInfo(driveInfo, Buf);
  1175 	    apConsole->Printf(Buf);
  1176 
  1177 	}
  1178     
  1179     //-- print drive attributes
  1180 	if(aFlags & EDrvAttInfo)
  1181     {
  1182         FormatDriveAttInfo(driveInfo, Buf);
  1183 	    apConsole->Printf(Buf);
  1184     }
  1185 
  1186     //-- print media attributes
  1187 	if(aFlags & EMediaAttInfo)
  1188     {
  1189 	    FormatMediaAttInfo(driveInfo, Buf);
  1190 	    apConsole->Printf(Buf);
  1191     }
  1192 
  1193 
  1194 	//-- print volume information
  1195 	if(bVolumeOK && (aFlags & EVolInfo))
  1196     {
  1197 	    FormatVolInfo(volInfo, Buf);
  1198 	    apConsole->Printf(Buf);
  1199     }
  1200 	
  1201     return KErrNone;
  1202 	}
  1203 
  1204 //-----------------------------------------------------------------------------------------------------------------------
  1205 
  1206 /**
  1207     Extracts drive specifier from the given string that shall look like 'd:\' or 'd:'
  1208     And converts it to the drive number.
  1209     
  1210     @param  aStr a string with drive specifier
  1211     @return Drive number EDriveA..EDriveZ if drive letter is correct
  1212             negative value (KErrArgument) if drive specifier is incorrect
  1213 */
  1214 TInt DoExtractDriveLetter(const TDesC& aStr)
  1215 {
  1216     TLex    lex(aStr);    
  1217     TPtrC   token;
  1218 
  1219     lex.SkipSpace();
  1220     token.Set(lex.NextToken());
  1221     
  1222     if(token.Length() < 2 || token.Length() > 3 || token[1] != ':')
  1223         return KErrArgument;
  1224 
  1225     if(token.Length() == 3 && token[2] != '\\')
  1226         return KErrArgument;
  1227 
  1228     const TChar chDrv = token[0];
  1229     const TInt drvNum = chDrv.GetUpperCase() - (TUint)'A'; //-- drive number
  1230 
  1231     if(drvNum < 0 || drvNum > EDriveZ)
  1232         return KErrArgument;
  1233 
  1234 
  1235     //-- ensure that the only drive token specified
  1236     token.Set(lex.NextToken());
  1237     if(token.Length())
  1238         return KErrArgument;
  1239 
  1240     return drvNum;
  1241 
  1242 }
  1243 
  1244 
  1245 //-----------------------------------------------------------------------------------------------------------------------
  1246 //
  1247 // Print information about specified drive or about all present drives in the system.
  1248 //
  1249 // DRVINFO [DriveLetter:[\]] [/p]
  1250 //
  1251 //          if drive letter is specified print out information about only this one.
  1252 //			/P : pause after each drive
  1253 //
  1254 TInt ShellFunction::DrvInfo(TDes& aArgs, TUint aSwitches)
  1255 	{
  1256 
  1257 	TInt nDrv=-1;
  1258 
  1259 	const TInt KCmdLineLen = aArgs.Length();
  1260 	if(KCmdLineLen == 0)
  1261 		{//-- print information about all drives in the system
  1262 		nDrv = -1;
  1263 		}
  1264 	else
  1265 		{//-- print info about specified drive
  1266 		nDrv = DoExtractDriveLetter(aArgs);
  1267         if(nDrv < 0)
  1268             {
  1269             CShell::TheConsole->Printf(_L("Invalid drive specifier!\n"));    
  1270             return KErrNone;
  1271             }
  1272 		}
  1273 
  1274 	TInt nRes;
  1275 	TDriveList 	driveList;
  1276 
  1277 	//-- get drives list
  1278 	nRes=TheShell->TheFs.DriveList(driveList);
  1279 	if(nRes != KErrNone)
  1280 		{
  1281 		CShell::TheConsole->Printf(_L("\nError: %d"), nRes);
  1282 		return nRes;
  1283 		}
  1284 
  1285 	if(nDrv >=0)
  1286 		{//-- the drive is specified
  1287 		if(!driveList[nDrv])
  1288 			{
  1289 			CShell::TheConsole->Printf(_L("Invalid drive specification\n"));
  1290 			return KErrNone;
  1291 			}
  1292 
  1293 		PrintDrvInfo(TheShell->TheFs, nDrv, CShell::TheConsole);
  1294 		}
  1295 	else
  1296 		{//-- print information about all drives in the system
  1297 		for (nDrv=0; nDrv < KMaxDrives; nDrv++)
  1298 			{
  1299 			if(!driveList[nDrv])
  1300 				continue;   //-- skip unexisting drive
  1301 
  1302 			PrintDrvInfo(TheShell->TheFs, nDrv, CShell::TheConsole);
  1303 
  1304 			if(aSwitches & TShellCommand::EPSwitch)
  1305 				{//-- /p switch, pause after each drive
  1306 				CShell::TheConsole->Printf(_L("\n--- press any key to continue or Esc to exit ---\n"));
  1307 
  1308 				TKeyCode key = CShell::TheConsole->Getch();
  1309 				if (key==EKeyEscape)
  1310 					break;
  1311 				}
  1312 			else
  1313 				{
  1314 				CShell::TheConsole->Printf(_L("\n----------\n"));
  1315 				}
  1316 		}
  1317 	}
  1318 
  1319 	return KErrNone;
  1320 	}
  1321 
  1322 //-----------------------------------------------------------------------------------------------------------------------
  1323 
  1324 /**
  1325     Just a helper method. Looks for a given pattern in the given string and returns the rest of the found token.
  1326     @param  aSrc        source string
  1327     @param  aPattern    pattern to look for
  1328     @param  aToken      if the aPattern is found in the string, will contain characters from the pattern end to the next space.
  1329 
  1330     @return EFalse if the aPattern wasn't found in aSrc
  1331             ETrue otherwise and the rest of the token in aToken
  1332 */
  1333 static TBool DoFindToken(const TDesC& aSrc, const TDesC& aPattern, TPtrC& aToken)
  1334 {
  1335     TLex    lex(aSrc);
  1336     TPtrC   token;
  1337 
  1338     for(;;)
  1339     {
  1340         lex.SkipSpace();
  1341         token.Set(lex.NextToken());
  1342 
  1343         if(token.Length() == 0)
  1344             return EFalse;
  1345 
  1346         if(token.FindF(aPattern) == 0)
  1347         {//-- found a requires patern, extract substring next to it
  1348             aToken.Set(token.Right(token.Length() - aPattern.Length()));
  1349             break;
  1350         }
  1351 
  1352 
  1353     }
  1354 
  1355     return ETrue;
  1356 }
  1357 
  1358 
  1359 
  1360 
  1361 
  1362 //-----------------------------------------------------------------------------------------------------------------------
  1363 TInt DoDismountFS(RFs& aFs, TInt aDrvNum)
  1364 {
  1365     TInt        nRes;
  1366     TBuf<40>    fsName;
  1367 
  1368     nRes = aFs.FileSystemName(fsName, aDrvNum);
  1369 
  1370     if(nRes != KErrNone)
  1371         return KErrNotFound;//-- nothing to dismount
  1372         
  1373     nRes = aFs.DismountFileSystem(fsName, aDrvNum);
  1374     if(nRes != KErrNone)
  1375     {
  1376         CShell::TheConsole->Printf(_L("Can't dismount FS!\n"));
  1377         return nRes;
  1378     }
  1379     else
  1380     {
  1381     CShell::TheConsole->Printf(_L("'%S' filesystem dismounted from drive %c:\n"), &fsName, 'A'+aDrvNum);
  1382     return KErrNone;
  1383     }
  1384 }
  1385 
  1386 //-----------------------------------------------------------------------------------------------------------------------
  1387 TInt DoRemountFS(RFs& aFs, TInt aDrvNum)
  1388 {
  1389     TInt        nRes;
  1390     TBuf<40>    fsName;
  1391     TBuf<40>    pextName;
  1392 
  1393     //-- 1. get file system name
  1394     nRes = aFs.FileSystemName(fsName, aDrvNum);
  1395     if(nRes != KErrNone)
  1396         return KErrNotFound;
  1397 
  1398     //-- 2. find out if the drive sync/async
  1399     TPckgBuf<TBool> drvSyncBuf;
  1400     TBool& drvSynch = drvSyncBuf();
  1401 
  1402     nRes = aFs.QueryVolumeInfoExt(aDrvNum, EIsDriveSync, drvSyncBuf);
  1403     if(nRes != KErrNone)
  1404     {//-- pretend that the drive is asynch. in the case of file system being corrupted. this is 99.9% true
  1405        drvSynch = EFalse;
  1406     }
  1407    
  1408     //-- 3. find out primary extension name if it is present; we will need to add it again when mounting the FS
  1409     //-- other extensions (non-primary) are not supported yet
  1410     nRes = aFs.ExtensionName(pextName, aDrvNum, 0);
  1411     if(nRes != KErrNone)
  1412     {
  1413         pextName.SetLength(0);
  1414     }
  1415     
  1416     //-- 3.1 check if the drive has non-primary extensions, fail in this case
  1417     {
  1418         TBuf<40> extName;
  1419         nRes = aFs.ExtensionName(extName, aDrvNum, 1);
  1420         if(nRes == KErrNone)
  1421         {   
  1422             CShell::TheConsole->Printf(_L("Non-primary extensions are not supported!\n"));
  1423             return KErrNotSupported;
  1424         }
  1425     }
  1426 
  1427     //-- 4. dismount the file system
  1428     nRes = DoDismountFS(aFs, aDrvNum);
  1429     if(nRes != KErrNone)
  1430         return nRes;
  1431 
  1432     //-- 5. mount the FS back
  1433     if(pextName.Length() > 0)
  1434     {//-- we need to mount FS with the primary extension
  1435         nRes = aFs.AddExtension(pextName);
  1436         if(nRes != KErrNone && nRes != KErrAlreadyExists)
  1437         {
  1438             return nRes;
  1439         }
  1440         
  1441         nRes = aFs.MountFileSystem(fsName, pextName, aDrvNum, drvSynch);
  1442     }
  1443     else
  1444     {//-- the FS did not have primary extension
  1445         nRes = aFs.MountFileSystem(fsName, aDrvNum, drvSynch);
  1446     }
  1447 
  1448     if(nRes == KErrNone)
  1449     {
  1450         CShell::TheConsole->Printf(_L("mounted filesystem:%S\n"), &fsName);
  1451     }
  1452 
  1453     return nRes;
  1454 }
  1455 
  1456 //-----------------------------------------------------------------------------------------------------------------------
  1457 /**
  1458     Mount or dismount the file system on the specified drive.
  1459 
  1460     MOUNT <DriveLetter:[\]> <FSY:xxx> <FS:yyy> [PEXT:zzz] [/S] [/U]
  1461   
  1462     xxx is the *.fsy file system plugin name, like "elocal.fsy" or "elocal"
  1463     yyy is the file system name that the fsy module exports, like "FAT"
  1464     zzz is the optional parameter that specifies primary extension name
  1465 
  1466     /u dismounts a filesystem on the specified drive; e.g. "mount d: /u"
  1467     /s for mounting FS specifies that the drive will be mounted as synchronous one.
  1468     /f for forcing mounting the FS; the previous one will be automatically dismounted
  1469     /r remount existing FS (dismount and mount it back)
  1470 */
  1471 TInt ShellFunction::MountFileSystem(TDes& aArgs, TUint aSwitches)
  1472 {
  1473 	ShellFunction::StripQuotes(aArgs);
  1474     aArgs.UpperCase();
  1475  
  1476     TLex        lex(aArgs);
  1477     TInt        nRes;
  1478     TBuf<40>    fsName;
  1479     RFs&        fs = TheShell->TheFs; 
  1480 
  1481 
  1482     //-- extract drive specification; this must be 1st token
  1483     _LIT(KErrInvalidDrive, "Invalid drive specifier\n");
  1484     lex.SkipSpace();
  1485     TPtrC token = lex.NextToken(); 
  1486     
  1487     nRes = DoExtractDriveLetter(token);
  1488     if(nRes < 0)
  1489     {
  1490         CShell::TheConsole->Printf(KErrInvalidDrive);
  1491         return KErrArgument;
  1492     }
  1493 
  1494     const TInt drvNum = nRes; //-- this is the drive number;
  1495 
  1496 
  1497     //-- remounting the existing FS (/R switch)
  1498     if(aSwitches & TShellCommand::ERSwitch)
  1499     {
  1500         nRes = DoRemountFS(fs, drvNum);
  1501         return nRes;
  1502     }
  1503     
  1504     //-- check if we dismounting the FS (/U switch)
  1505     if(aSwitches & TShellCommand::EUSwitch)
  1506     {
  1507         nRes = DoDismountFS(fs, drvNum);
  1508         
  1509         if(nRes == KErrNotFound)
  1510         {//-- nothing to dismount
  1511             CShell::TheConsole->Printf(_L("specified drive doesn't have FS mounted\n"));
  1512             return KErrNone;
  1513         }
  1514 
  1515         return nRes;
  1516     }
  1517     
  1518     //-- check if we need to forcedly dismount the existing FS (/F switch)
  1519     if(aSwitches & TShellCommand::EFSwitch)
  1520     {
  1521         nRes = DoDismountFS(fs, drvNum);
  1522         
  1523         if(nRes != KErrNotFound && nRes !=KErrNone)
  1524             return nRes;
  1525     }
  1526 
  1527     //-- request to mount the filesystem
  1528 
  1529     //-- 1. check that the specified drive doesn't have already mounted file system
  1530     nRes = fs.FileSystemName(fsName, drvNum);
  1531     if(nRes == KErrNone)
  1532     {
  1533         CShell::TheConsole->Printf(_L("specified drive already has '%S' file system mounted.\n"), &fsName);
  1534         CShell::TheConsole->Printf(_L("Dismount it first using '/U' switch or use '/F' switch.\n"));
  1535         return KErrNone;
  1536     }
  1537 
  1538     //-- 2. check '/S' switch that specifies synchronous drive
  1539     const TBool bDrvSynch = aSwitches & TShellCommand::ESSwitch;
  1540 
  1541     //-- 3. extract FSY name, file system name and optional primary extension name from the command line parameters
  1542     _LIT(KFSY_Param,     "fsy:");
  1543     _LIT(KFsName_Param,  "fs:");
  1544     _LIT(KPrimExt_Param, "pext:");
  1545 
  1546     TPtrC ptrFSYName;
  1547     TPtrC ptrFSName;
  1548     TPtrC ptrPExtName;
  1549 
  1550     if(!DoFindToken(aArgs, KFSY_Param, ptrFSYName))
  1551     {//-- FSY plugin name, like "elocal.fsy"
  1552         CShell::TheConsole->Printf(_L("'%S' parameter is required!\n"), &KFSY_Param);
  1553         return KErrNone;
  1554     }
  1555 
  1556     if(!DoFindToken(aArgs, KFsName_Param, ptrFSName))
  1557     {//-- file system name, like "FAT"
  1558         CShell::TheConsole->Printf(_L("'%S' parameter is required!\n"), &KFsName_Param);
  1559         return KErrNone;
  1560     }
  1561 
  1562     //-- note: it is possible to find out the file system name from loaded .fsy plugin.
  1563     //-- but it will require some coding. Probably later.
  1564 
  1565 
  1566     //-- optional primary extension name, like "something.fxt"
  1567     const TBool bPExtPresent = DoFindToken(aArgs, KPrimExt_Param, ptrPExtName);
  1568 
  1569 
  1570     //-- add new file system + optional extension
  1571     nRes = fs.AddFileSystem(ptrFSYName);
  1572     if(nRes != KErrNone && nRes != KErrAlreadyExists)
  1573     {
  1574         CShell::TheConsole->Printf(_L("Can't load '%S' file system plugin!\n"), &ptrFSYName);        
  1575         return nRes;
  1576     }
  1577 
  1578     if(bPExtPresent)
  1579     {
  1580         nRes = fs.AddExtension(ptrPExtName);
  1581         if(nRes != KErrNone && nRes != KErrAlreadyExists)
  1582         {
  1583             CShell::TheConsole->Printf(_L("Can't load '%S' FS extension plugin!\n"), &ptrPExtName);        
  1584             return nRes;
  1585         }
  1586     }
  1587 
  1588     //-- 4. mount new file system + optional primary extension
  1589     if(bPExtPresent)
  1590     {
  1591         nRes = fs.MountFileSystem(ptrFSName, ptrPExtName, drvNum, bDrvSynch);
  1592     }
  1593     else
  1594     {
  1595         nRes = fs.MountFileSystem(ptrFSName, drvNum, bDrvSynch);
  1596     }
  1597 
  1598     CShell::TheConsole->Printf(_L("Mounting new file system...\n"));        
  1599 
  1600     if(nRes != KErrNone && nRes != KErrCorrupt)
  1601     {//-- KErrCorrupt might mean that the FS mounted OK onto the drive, but ve volume itself needs formatting
  1602         CShell::TheConsole->Printf(_L("Error mounting the filesystem! (%d)\n"), nRes);
  1603         return nRes;
  1604     }
  1605 
  1606 
  1607     PrintDrvInfo(fs, drvNum, CShell::TheConsole, EFSInfo | EVolInfo);
  1608 
  1609     return KErrNone;
  1610 }
  1611 
  1612 
  1613 //-----------------------------------------------------------------------------------------------------------------------
  1614 
  1615 /**
  1616     Format the specified disk
  1617 
  1618     FORMAT DriveLetter:[\] [fat12|fat16|fat32] [spc:X] [rs:Y] [ft:Z] [/Q] [/S] [/E]
  1619 
  1620         fat12|fat16|fat32 : specifies explicitly FAT type to format drive with (if it is a FAT drive)
  1621         spc:X   "X" specifies FAT sectors per cluster, e.g. spc:16
  1622         rs:Y    "Y" specifies the number of reserved sectors  (FAT FS only)
  1623         ft:Z    "Z" specifies the number of FAT tables 1 or 2 (FAT FS only)
  1624 		/Q : Quick Format
  1625 		/S : Special Format
  1626 		/E : Remove Password and Format
  1627         /F : force formatting, even if there are files opened on the drive
  1628 */
  1629 
  1630 TInt ShellFunction::Format(TDes& aPath, TUint aSwitches)
  1631 	{
  1632     _LIT(KFormatStars,"********************");
  1633 
  1634 	using namespace FileSystem_FAT;
  1635 
  1636     ShellFunction::StripQuotes(aPath);
  1637     aPath.UpperCase();
  1638 
  1639     TUint fmtMode = ESpecialFormat;
  1640 
  1641     //-- Format /Q - quick format
  1642     if (aSwitches & TShellCommand::EQSwitch)
  1643 		fmtMode|=EQuickFormat;
  1644 
  1645     //-- Format /S - special format
  1646 	if (aSwitches & TShellCommand::ESSwitch)
  1647 		fmtMode|=ESpecialFormat;
  1648 
  1649 	//-- Format /E - force erase
  1650     if (aSwitches & TShellCommand::EESwitch)
  1651 		fmtMode|=EForceErase;
  1652 
  1653 	//-- Format /F - force format. The volume will be formatted even if there are files or directories opened on this drive
  1654     if (aSwitches & TShellCommand::EFSwitch)
  1655 		fmtMode|=EForceFormat;
  1656 
  1657 
  1658 	TInt    fmtCnt = 0;
  1659 	RFormat format;
  1660 	TInt    nRes;
  1661     TLex    lex(aPath);
  1662     
  1663     //-- 1st token - drive path; it shall look like "d:"
  1664     lex.SkipSpace();
  1665     TPtrC ptrPath = lex.NextToken();    
  1666     
  1667     const TInt nDrv = DoExtractDriveLetter(ptrPath);
  1668     if(nDrv < 0 )
  1669         {
  1670         CShell::TheConsole->Printf(_L("type \"format /?\" for help.\n"));
  1671         return KErrNone;
  1672         }
  1673 
  1674     enum TFmtState
  1675         {
  1676         EFsNameNotSpecified,
  1677         EFormattingFAT,
  1678         EFormattingOtherFS
  1679         };
  1680     
  1681     
  1682     TFmtState formattingState = EFsNameNotSpecified;
  1683     TName fsName; //-- file system name
  1684 
  1685 
  1686     TVolFormatParamBuf volFmtParamBuf;
  1687     TVolFormatParam& volFmtParam = volFmtParamBuf();
  1688     
  1689 
  1690 
  1691     //-- 2nd token - file system name. 
  1692     //-- FAT fs is a special case, because it has subtypes; FAT FS name can be: FAT, FAT12, FAT16, FAT32
  1693     //-- everything else is considered as another file system name
  1694     lex.SkipSpace();
  1695     TPtrC ptrFsName = lex.NextToken();    
  1696     TFatSubType fatSubType = ENotSpecified;
  1697     
  1698     if(ptrFsName.Length() > 0)
  1699         {//-- there is a 2nd token, though it is not guaranteed to be the FS name
  1700         formattingState = EFormattingOtherFS;
  1701         
  1702         if(ptrFsName.FindF(KFileSystemName_FAT) == 0)
  1703             {//-- it looks like "FATxx"
  1704             fsName.Copy(KFileSystemName_FAT); 
  1705 
  1706             if(ptrFsName.CompareF(KFileSystemName_FAT) == 0)
  1707                 fatSubType = ENotSpecified; //-- generic "FAT", no subtype
  1708             else if(ptrFsName.CompareF(KFSSubType_FAT12) == 0)
  1709                 fatSubType = EFat12;
  1710             else if(ptrFsName.CompareF(KFSSubType_FAT16) == 0)
  1711                 fatSubType = EFat16;
  1712             else if(ptrFsName.CompareF(KFSSubType_FAT32) == 0)
  1713                 fatSubType = EFat32;
  1714             else
  1715                 fsName.Copy(ptrFsName); //-- none of the FAT types, probably some weird FS name.
  1716             }
  1717         else
  1718             {
  1719             fsName.Copy(ptrFsName); 
  1720             }
  1721         }
  1722 
  1723     if(fsName == KFileSystemName_FAT) 
  1724         formattingState = EFormattingFAT;
  1725     
  1726     volFmtParam.Init();
  1727 
  1728     if(formattingState != EFsNameNotSpecified)
  1729         volFmtParam.SetFileSystemName(fsName);
  1730 
  1731     //-- process formatting parameters if they are present
  1732 
  1733     _LIT(KTok_SPC,      "spc:");    //-- "sectors per cluster"; valid for: FAT, exFAT
  1734     _LIT(KTok_RsvdSect, "rs:");     //-- "reserved sectors"   ; valid for: FAT
  1735     _LIT(KTok_NumFATs,  "ft:");     //-- "number of FATs"     ; valid for: FAT, exFAT
  1736     _LIT(KFsNameExFat,  "exfat");
  1737 
  1738     TPtrC   token;
  1739     TPtrC   ptrParams = lex.Remainder();
  1740     TLex    lexParam;
  1741     TInt    nVal;
  1742 
  1743     
  1744     //-- if we formatting FAT, process FAT-specific formatting parameters
  1745     if(formattingState == EFormattingFAT)
  1746         {
  1747         //-- Changing base class via derived class interface is OK here, all derived classes has the same layout and size as TVolFormatParam
  1748         TVolFormatParam_FAT& volFmtParamFAT = (TVolFormatParam_FAT&)volFmtParam;
  1749         
  1750         volFmtParamFAT.Init();
  1751 
  1752         //-- FAT sub type
  1753         if(fatSubType != ENotSpecified)
  1754             volFmtParamFAT.SetFatSubType(fatSubType);
  1755         
  1756         //-- process "Sectors per cluster" token
  1757         if(DoFindToken(ptrParams, KTok_SPC, token))
  1758             {
  1759             lexParam.Assign(token);
  1760             lexParam.SkipSpace();
  1761             nRes = lexParam.Val(nVal);
  1762             if(nRes == KErrNone)
  1763                 {
  1764                 volFmtParamFAT.SetSectPerCluster(nVal);
  1765                 }
  1766                 else
  1767                 {
  1768                 CShell::TheConsole->Printf(_L("Invalid SectorsPerCluster value!\n"));
  1769                 return KErrNone;
  1770                 }
  1771             }
  1772 
  1773         //-- process "reserved sectors" token
  1774         if(DoFindToken(ptrParams, KTok_RsvdSect, token))
  1775             {
  1776             lexParam.Assign(token);
  1777             lexParam.SkipSpace();
  1778             nRes = lexParam.Val(nVal);
  1779             if(nRes == KErrNone && nVal >0 )
  1780                 {
  1781                 volFmtParamFAT.SetReservedSectors(nVal);
  1782                 }
  1783             else
  1784                 {
  1785                 CShell::TheConsole->Printf(_L("Invalid Reserved Sectors value!\n"));
  1786                 return KErrNone;
  1787                 }
  1788             }
  1789         
  1790         //-- process "FAT tables" token
  1791         if(DoFindToken(ptrParams, KTok_NumFATs, token))
  1792             {
  1793             lexParam.Assign(token);
  1794             lexParam.SkipSpace();
  1795             nRes = lexParam.Val(nVal);
  1796             if(nRes == KErrNone && nVal >= 1 && nVal <= 2)
  1797                 {
  1798                 volFmtParamFAT.SetNumFATs(nVal);
  1799                 }
  1800             else
  1801                 {
  1802                 CShell::TheConsole->Printf(_L("Invalid FAT tables number value!\n"));
  1803                 return KErrNone;
  1804                 }
  1805             }
  1806          
  1807         }//if(formattingState == EFormattingFAT)
  1808     else if(formattingState == EFormattingOtherFS && fsName.CompareF(KFsNameExFat)==0)
  1809         {//-- this is actually a h***k. exFAT exported public header file with specific data structures might not be available at all.
  1810 
  1811         //-- this is more serious hack. The parameters layout (SPC & NumFatTables) in the structure is the same for FAT and exFAT
  1812         //-- use TVolFormatParam_FAT because this code doesn't know about TVolFormatParam_exFAT
  1813         TVolFormatParam_FAT& volFmtParamFAT = (TVolFormatParam_FAT&)volFmtParam;
  1814 
  1815         //-- process "Sectors per cluster" token
  1816         if(DoFindToken(ptrParams, KTok_SPC, token))
  1817             {
  1818             lexParam.Assign(token);
  1819             lexParam.SkipSpace();
  1820             nRes = lexParam.Val(nVal);
  1821             if(nRes == KErrNone)
  1822                 {
  1823                 volFmtParamFAT.SetSectPerCluster(nVal);
  1824                 }
  1825                 else
  1826                 {
  1827                 CShell::TheConsole->Printf(_L("Invalid SectorsPerCluster value!\n"));
  1828                 return KErrNone;
  1829                 }
  1830             }
  1831 
  1832         //-- process "FAT tables" token
  1833         if(DoFindToken(ptrParams, KTok_NumFATs, token))
  1834             {
  1835             lexParam.Assign(token);
  1836             lexParam.SkipSpace();
  1837             nRes = lexParam.Val(nVal);
  1838             if(nRes == KErrNone && nVal >= 1 && nVal <= 2)
  1839                 {
  1840                 volFmtParamFAT.SetNumFATs(nVal);
  1841                 }
  1842             else
  1843                 {
  1844                 CShell::TheConsole->Printf(_L("Invalid FAT tables number value!\n"));
  1845                 return KErrNone;
  1846                 }
  1847             }
  1848     
  1849         }
  1850     
  1851 
  1852     //-------- actual formatting
  1853     if(formattingState == EFsNameNotSpecified)
  1854         {
  1855         nRes = format.Open(TheShell->TheFs, ptrPath, fmtMode, fmtCnt);
  1856         }
  1857     else
  1858         {
  1859         CShell::TheConsole->Printf(_L("The new file system is:%S\n"), &fsName);
  1860         nRes = format.Open(TheShell->TheFs, ptrPath, fmtMode, fmtCnt, volFmtParamBuf);
  1861         }
  1862 
  1863 	if(nRes == KErrNone)
  1864 	    {
  1865 	    while(fmtCnt && nRes == KErrNone)
  1866 		    {
  1867 		    TInt length=(104-fmtCnt)/5;
  1868 		    length=Min(length,KFormatStars().Length());
  1869 		    TPtrC stars=KFormatStars().Left(length);
  1870 		    CShell::TheConsole->Printf(_L("\r%S"),&stars);
  1871 		    nRes=format.Next(fmtCnt);
  1872 		    }
  1873 	    
  1874         format.Close();
  1875 
  1876         if(nRes == KErrNone)
  1877             {
  1878             CShell::TheConsole->Printf(_L("\r%S"),&KFormatStars);
  1879 	        CShell::NewLine();
  1880 	        }
  1881         
  1882 	    }
  1883 
  1884 
  1885     //-- format errors processing
  1886     if(nRes != KErrNone)
  1887         {
  1888         CShell::TheConsole->Printf(_L("Format failed.\n"));
  1889         }
  1890 
  1891     switch(nRes)
  1892         {
  1893         case KErrNone:
  1894             CShell::TheConsole->Printf(_L("Format complete.\n"));
  1895         break;
  1896 
  1897         
  1898         case KErrArgument: //-- FORMAT has rejected specified parameters
  1899             CShell::TheConsole->Printf(_L("Possible reason: Invalid combination of formatting parameters.\n"));
  1900             nRes = KErrNone;
  1901         break;
  1902 
  1903         case KErrNotSupported: //-- trying to format SD card with parameters or not supported FS name specified
  1904             CShell::TheConsole->Printf(_L("Possible reasons: media does not support special formatting or specified file system is not supported\n"));
  1905             nRes = KErrNone;
  1906         break;
  1907 
  1908         case KErrNotFound: //-- possible reason: unrecognisable media and automounter FS + formatting without specifying the FS name
  1909             CShell::TheConsole->Printf(_L("Possible reason: Unable to chose appropriate file system (not specified)\n"));
  1910             nRes = KErrNone;
  1911         break;
  1912 
  1913 
  1914         default:
  1915         break;
  1916         };
  1917     
  1918     
  1919     return nRes;
  1920     }
  1921 
  1922 //-----------------------------------------------------------------------------------------------------------------------
  1923 
  1924 TInt ShellFunction::Hexdump(TDes& aPath,TUint aSwitches)
  1925 	{
  1926 	ShellFunction::StripQuotes(aPath);
  1927 
  1928 	ParsePath(aPath);
  1929 	RFile file;
  1930 	TInt r=file.Open(TheShell->TheFs,aPath,EFileStream);
  1931 	if (r!=KErrNone)
  1932 		return(r);
  1933 
  1934 	TInt offset=0;
  1935 	for (;;)
  1936 		{
  1937 		const TInt KLineLength = 16;
  1938 
  1939 		TBuf8<KLineLength> line;
  1940 		r=file.Read(line);
  1941 		if (r != KErrNone || line.Length() == 0)
  1942 			break;
  1943 
  1944 		TBuf<KLineLength*3+2> hexaRep;
  1945 		TBuf<KLineLength> asciiRep;
  1946 		for (TInt i=0; i<KLineLength; i++)
  1947 			{
  1948 			if (i == KLineLength/2)
  1949 				{
  1950 				hexaRep.Append(' ');
  1951 				hexaRep.Append(i<line.Length() ? '|' : ' ');
  1952 				}
  1953 
  1954 			hexaRep.Append(' ');
  1955 
  1956 			if (i<line.Length())
  1957 				{
  1958 				hexaRep.AppendNumFixedWidth(line[i], EHex, 2);
  1959 				asciiRep.Append(TChar(line[i]).IsPrint() ? line[i] : '.');
  1960 				}
  1961 			else
  1962 				hexaRep.AppendFill(' ', 2);
  1963 			}
  1964 
  1965 		_LIT(KPrompt , " Hit escape to quit hexdump or any other key to continue\n");
  1966 		_LIT(KLineFmt, " %+07x0:%S %S\n");
  1967 		TKeyCode key=CShell::OutputStringToConsole(KPrompt ,(aSwitches&TShellCommand::EPSwitch)!=0,KLineFmt, offset++,&hexaRep, &asciiRep);
  1968 
  1969 		if (key==EKeyEscape)
  1970 				break;
  1971 		}
  1972 
  1973 	if (r == KErrNone)
  1974 		CShell::NewLine();
  1975 
  1976 	file.Close();
  1977 	return r;
  1978 	}
  1979 
  1980 /**
  1981     Create a file. The file can be empty or filled with random data.
  1982     The maximal file size depends on the file system of the drive.
  1983 
  1984     Gobble <file name> <aaaa|0xbbbb>  [/E]
  1985 
  1986     aaaa file size decimal
  1987     bbbb file size hexadecimal, shall be prefixed with '0x'
  1988     
  1989     /e for creating an empty file, do not fill it with data
  1990 */
  1991 TInt ShellFunction::Gobble(TDes& aPath,TUint aSwitches)
  1992 	{
  1993 	ShellFunction::StripQuotes(aPath);
  1994 
  1995 	TInt fileNameLen=aPath.LocateReverse(' ');
  1996 	if (fileNameLen==KErrNotFound)	//	No spaces implies no filelength specified
  1997 		{
  1998 		CShell::TheConsole->Printf(_L("Please specify a file name and a file length\n"));
  1999 		return (KErrNone);
  2000 		}
  2001 
  2002 	TInt fileLength=(aPath.Length()-fileNameLen);
  2003 	if (fileLength>16)
  2004 		return (KErrTooBig);	//	Too many digits - too large!
  2005 	TBuf<16> rightString=aPath.Right(fileLength);
  2006 	aPath.SetLength(fileNameLen);
  2007 
  2008 	TLex size(rightString);
  2009 	size.SkipSpace();
  2010 	TRadix radix=ParseHexaPrefixIfAny(size);
  2011 	
  2012     TInt64 fileSize;
  2013 	TInt r=size.Val(fileSize,radix);
  2014 	if (r!=KErrNone || ! size.Eos())
  2015 		{
  2016 		CShell::TheConsole->Printf(_L("Please specify a file length\n"));
  2017 		return (KErrNone);
  2018 		}
  2019 
  2020 	if (aPath.Length()==0)
  2021 		aPath=_L("GOBBLE.DAT");
  2022 
  2023 	TParse fileName;
  2024 	GetFullPath(aPath,fileName);
  2025 	RFile64 file;
  2026 
  2027     const TInt    KBufSize=65536; //-- buffer size for writing data
  2028     const TUint32 K1Megabyte = 1<<20; //-- 1M, 1048576
  2029     TInt64 cntBytes = 0;
  2030     TUint32 cntMegaBytes =0;
  2031 
  2032     //-- allocate buffer for data
  2033     RBuf8 buf;
  2034     r = buf.CreateMax(KBufSize);
  2035     if(r != KErrNone)
  2036         return r;
  2037 
  2038     //-- initialize buffer with random rubbish
  2039     //Mem::Fill((void*)buf.Ptr(),KBufSize,0xa3);
  2040     {
  2041         TInt64 rndSeed = Math::Random();
  2042         for(TInt i=0; i<KBufSize; ++i)
  2043         {
  2044             buf[i] = (TUint8)Math::Rand(rndSeed);
  2045         }
  2046     }
  2047 
  2048 
  2049     TInt64  rem = fileSize;
  2050     TTime startTime;
  2051     TTime endTime;
  2052     TTimeIntervalSeconds timeTaken;
  2053 
  2054     startTime.UniversalTime(); //-- take start time
  2055 
  2056     r=file.Create(CShell::TheFs,fileName.FullName(),EFileRead|EFileWrite);
  2057     if(r != KErrNone)
  2058         goto fail;
  2059 
  2060     //-- this can make write faster on rugged fat.
  2061     if(aSwitches&TShellCommand::EESwitch)
  2062     {//-- /e switch is specified, create an empty file without writing data
  2063         CShell::TheConsole->Printf(_L("Creating an empty file, size:%LD bytes\n"), fileSize);
  2064     }
  2065 
  2066     r=file.SetSize(fileSize);
  2067     if(r != KErrNone)
  2068         goto fail;
  2069 
  2070 
  2071     if(!(aSwitches&TShellCommand::EESwitch))
  2072     {//-- fill created file with randomn data
  2073 
  2074 	    while(rem)
  2075 	    {
  2076 	        const TInt s=(TInt)Min((TInt64)KBufSize, rem);
  2077 
  2078             r=file.Write(buf, s);
  2079 		    if(r!=KErrNone)
  2080 		        goto fail;
  2081 
  2082             rem-=s;
  2083 
  2084             //-- print out number of megabytes written
  2085             cntBytes+=s;
  2086             if(cntBytes > 0 && (cntBytes & (K1Megabyte-1))==0)
  2087             {
  2088                 ++cntMegaBytes;
  2089                 CShell::TheConsole->Printf(_L("%u MB written.\n"),cntMegaBytes);
  2090             }
  2091         }//while(rem)
  2092 
  2093     }
  2094 
  2095     file.Close();
  2096     endTime.UniversalTime(); //-- take end time
  2097     buf.Close();
  2098 
  2099     endTime.SecondsFrom(startTime, timeTaken);
  2100 
  2101     CShell::TheConsole->Printf(_L("Total bytes written:%LD\n"), cntBytes);
  2102     CShell::TheConsole->Printf(_L("Time taken:%d Sec.\n"), timeTaken.Int());
  2103 
  2104     return r;
  2105 
  2106     //-- failure.
  2107  fail:
  2108     file.Close();
  2109     buf.Close();
  2110     if(r!= KErrAlreadyExists) //this is to ensure that an existing file does not get deleted
  2111 	    CShell::TheFs.Delete(fileName.FullName());
  2112 
  2113     CShell::TheConsole->Printf(_L("Error - could not create file, code:%d\n"), r);
  2114 
  2115     return r;
  2116 	}
  2117 
  2118 TInt ShellFunction::Md(TDes& aPath,TUint /*aSwitches*/)
  2119 	{
  2120 	if (aPath.Length()==0)
  2121 		return(KErrBadName);
  2122 
  2123 	ShellFunction::StripQuotes(aPath);
  2124 
  2125 	if (aPath[aPath.Length()-1]!=KPathDelimiter)
  2126 		aPath.Append(KPathDelimiter);
  2127 
  2128 	TParse dirPath;
  2129 	TInt r = GetFullPath(aPath,dirPath);
  2130 	if(r!=KErrNone)
  2131 		{
  2132 		return(r);
  2133 		}
  2134 	return(TheShell->TheFs.MkDir(dirPath.FullName()));
  2135 	}
  2136 
  2137 TInt ShellFunction::Move(TDes& aPath,TUint aSwitches)
  2138 	{
  2139 
  2140 //	Modified to add more helpful error messages and allow spaced filenames
  2141 	ShellFunction::StripQuotes(aPath);
  2142 
  2143 	TBuf<KShellMaxCommandLine> newName;
  2144 	TBuf<KShellMaxCommandLine> tempPath=aPath;
  2145 	RFile64 file;
  2146 	TWord   word(aPath);
  2147 
  2148 	TInt r=word.FindNextWord(aPath);
  2149 //	Check if the word returned is a valid filename.  If not, scan the next
  2150 //	word too in case the filename contains spaces.  If, at the end of the
  2151 //	the line, the filename is not recognised, it is invalid.  If there are no
  2152 //	spaces the user has not used the correct format for this command.
  2153 
  2154 	while (r>0)
  2155 		{
  2156 		newName=aPath.Right(aPath.Length()-r);
  2157 		tempPath.SetLength(r);
  2158 		TParse oldName;
  2159 		TInt result=GetFullPath(tempPath,oldName);
  2160 		if (result!=KErrNone)
  2161 			return(r);
  2162 
  2163 		TBool validFileOrDir = EFalse;
  2164 
  2165 		result=file.Open(TheShell->TheFs,tempPath,KEntryAttMatchExclude|KEntryAttDir);
  2166 		if (result==KErrNone)	//	A valid filename
  2167 			{
  2168 			file.Close();
  2169 			validFileOrDir = ETrue;
  2170 			}
  2171 		else	//	Not a valid filename - move one word along the command line
  2172 			{
  2173 			// Not a valid filename - Could be a directory...
  2174 			RDir directory;
  2175 			result=directory.Open(TheShell->TheFs,tempPath,KEntryAttMatchExclusive|KEntryAttDir);
  2176 			if (result == KErrNone)
  2177 				{
  2178 				directory.Close();
  2179 				validFileOrDir = ETrue;
  2180 				}
  2181 			}
  2182 
  2183 		if(validFileOrDir)
  2184 			{
  2185 			TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
  2186 			TUint switches=(recursive) ? CFileMan::EOverWrite|CFileMan::ERecurse : CFileMan::EOverWrite;
  2187 			r=CShell::TheFileMan->Move(oldName.FullName(),newName,switches);
  2188 			if (r==KErrAccessDenied)
  2189 				{
  2190 				CShell::TheConsole->Printf(_L("Access denied - cannot move %S\n"),&tempPath);
  2191 				CShell::TheConsole->Printf(_L("To move %Sinto directory %S append \\ to the full destination\n"),&tempPath,&newName);
  2192 				return (KErrNone);
  2193 				}
  2194 			return(r);
  2195 			}
  2196 
  2197 		r=word.FindNextWord(word.iRightString);
  2198 		}
  2199 	if (r<0)		//	r = some error code
  2200 		return (r);	//	Error in filename or destination
  2201 	else						//	r = 0
  2202 		return (KErrNotFound);
  2203 	}
  2204 
  2205 TInt GetChunkInfo(TAny* aPtr)
  2206 	{
  2207 
  2208 	TFindChunk findHb;
  2209 	TFullName* namePtr=(TFullName*)aPtr;
  2210 	findHb.Find(*namePtr);
  2211 	TFullName aFN;
  2212 	findHb.Next(aFN);
  2213 	RChunk c;
  2214 	TInt r=c.Open(findHb);
  2215 	if(r==KErrPermissionDenied)
  2216 		{
  2217 		CShell::TheConsole->Printf(_L("...Chunk is protected. No info available.\n"));
  2218 		}
  2219 	else
  2220 		{
  2221 		CShell::TheConsole->Printf(_L("...Size %dk MaxSize %dk Base 0x%x\n"),c.Size()/1024,c.MaxSize()/1024,c.Base());
  2222 		c.Close();
  2223 		}
  2224 /*
  2225 #if defined (__WINS__)
  2226 	c.Close();
  2227 #else
  2228 	if (aFN.Match(_L("*ESHELL*"))<0)
  2229 		c.Close();
  2230 #endif
  2231 */
  2232 	return r;
  2233 	};
  2234 
  2235 TInt GetThreadInfo(TAny* aPtr)
  2236 //	New function added by WR, November 1997
  2237 	{
  2238 	TBuf<80> detail;
  2239 	TFindThread* findHb = (TFindThread*)aPtr;
  2240 	RThread t;
  2241 	TInt err = t.Open(*findHb);
  2242 	if (err != KErrNone)
  2243 		{
  2244 		detail.Format(_L("... can't open thread, err=%d\n"), err);
  2245 		CShell::TheConsole->Printf(detail);
  2246 		return KErrNone;
  2247 		}
  2248 
  2249 	TExitType exit = t.ExitType();
  2250 	TBuf<KMaxExitCategoryName> exitCat=t.ExitCategory();
  2251 	TThreadId threadId = t.Id();
  2252 	TUint id = *(TUint*)&threadId;
  2253 	RProcess proc;
  2254 	TInt pid = t.Process(proc);
  2255 	if (pid==KErrNone)
  2256 		{
  2257 		TProcessId procId = proc.Id();
  2258 		pid = *(TInt*)&procId;
  2259 		proc.Close();
  2260 		}
  2261 
  2262 	switch (exit)
  2263 		{
  2264 	case EExitPending:
  2265 		detail.Format(_L("... ID %d (Proc %d), running\n"), id, pid);
  2266 		break;
  2267 	case EExitPanic:
  2268 	//	lint -e50
  2269 		detail.Format(_L("... ID %d (Proc %d), panic \"%S\" %d\n"), id, pid,
  2270 			&exitCat, t.ExitReason());
  2271 		break;
  2272 	case EExitKill:
  2273 		detail.Format(_L("... ID %d (Proc %d), killed %d\n"), id, pid, t.ExitReason());
  2274 		break;
  2275 	case EExitTerminate:
  2276 		detail.Format(_L("... ID %d (Proc %d), terminated %d\n"), id, pid, t.ExitReason());
  2277 		break;
  2278 	default:
  2279 		detail.Format(_L("... ID %d (Proc %d), ?exit type %d?\n"), id, pid, exit);
  2280 		break;
  2281 		}
  2282 	t.Close();
  2283 	CShell::TheConsole->Printf(detail);
  2284 	return KErrNone;
  2285 	};
  2286 //	End of modification
  2287 
  2288 // Class for showing information about processes
  2289 class TShowProcInfo
  2290 	{
  2291 public:
  2292 	TInt DisplayHelp();
  2293 	TInt DisplayMessage(const TFullName& aName);
  2294 	TInt DisplayCmdUnknown();
  2295 	TInt GetAll(const TDes& aName);
  2296 	TInt GetProcesses(const TDes& aName);
  2297 	TInt GetThreads(const TDes& aName);
  2298 	TInt GetChunks(const TDes& aName);
  2299 	TInt GetServers(const TDes& aName);
  2300 //	TInt GetSessions(const TDes& aName);
  2301 	TInt GetLibraries(const TDes& aName);
  2302 //	TInt GetLogicalChannels(const TDes& aName);
  2303 	TInt GetLogicalDevices(const TDes& aName);
  2304 	TInt GetPhysicalDevices(const TDes& aName);
  2305 	TInt GetSemaphores(const TDes& aName);
  2306 	TInt GetMutexes(const TDes& aName);
  2307 private:
  2308 	void DisplayHelpLine(const TDesC& aCommand, const TDesC& aDescription);
  2309 	TInt Prepare(const TFullName& aName);
  2310 	TInt Prepare(const TFullName& aName,TCallBack& aCallBack);
  2311 	TInt Display(TFullName& aName);
  2312 	TFullName iPrevName;
  2313 	TCallBack iCallBack;
  2314 	TBool useCallBack;
  2315 	};
  2316 
  2317 TInt TShowProcInfo::DisplayHelp()
  2318 	{
  2319 
  2320 	DisplayHelpLine(_L("H or ?"),_L("Show Help"));
  2321 	DisplayHelpLine(_L("Q"),_L("Quit Process Status Mode"));
  2322 	DisplayHelpLine(_L("X<name>"),_L("Switch to a particular Process domain"));
  2323 	DisplayHelpLine(_L("X"),_L("Go Back to standard Process Status Mode"));
  2324 	DisplayHelpLine(_L("A"),_L("Display all container objects"));
  2325 	DisplayHelpLine(_L("P"),_L("List all Processes (irrespective of current domain)"));
  2326 	DisplayHelpLine(_L("T"),_L("List Threads"));
  2327 	DisplayHelpLine(_L("C"),_L("List Chunks, their sizes, maximum sizes and addresses"));
  2328 	DisplayHelpLine(_L("S"),_L("List Servers"));
  2329 //	DisplayHelpLine(_L("I"),_L("List Sessions"));
  2330 	DisplayHelpLine(_L("L"),_L("List Libraries"));
  2331 //	DisplayHelpLine(_L("G"),_L("List Logical Channels"));
  2332 	DisplayHelpLine(_L("V"),_L("List Logical Devices"));
  2333 	DisplayHelpLine(_L("D"),_L("List Physical Devices"));
  2334 	DisplayHelpLine(_L("E"),_L("List Semaphores"));
  2335 	DisplayHelpLine(_L("M"),_L("List Mutexes"));
  2336 	return KErrNone;
  2337 	}
  2338 
  2339 TInt TShowProcInfo::DisplayMessage(const TFullName& aMessage)
  2340 	{
  2341 	CShell::OutputStringToConsole(ETrue,aMessage);
  2342 	CShell::NewLine();
  2343 	return KErrNone;
  2344 	}
  2345 
  2346 TInt TShowProcInfo::DisplayCmdUnknown()
  2347 	{
  2348 	CShell::OutputStringToConsole(ETrue,_L("Not supported\n"));
  2349 	return KErrNone;
  2350 	}
  2351 
  2352 TInt TShowProcInfo::GetAll(const TDes& aName)
  2353 	{
  2354 
  2355 	GetProcesses(aName);
  2356 	GetThreads(aName);
  2357 	GetChunks(aName);
  2358 	GetServers(aName);
  2359 //	GetSessions(aName);
  2360 	GetLibraries(aName);
  2361 //	GetLogicalChannels(aName);
  2362 	GetLogicalDevices(aName);
  2363 	GetPhysicalDevices(aName);
  2364 	GetSemaphores(aName);
  2365 	GetMutexes(aName);
  2366 	return KErrNone;
  2367 	}
  2368 
  2369 TInt TShowProcInfo::GetProcesses(const TDes& aName)
  2370 	{
  2371 
  2372 	TFindProcess findHb;
  2373 	findHb.Find(aName);
  2374 	TFullName name;
  2375 	Prepare(_L("PROCESSES"));
  2376 	while (findHb.Next(name)==KErrNone)
  2377 		{
  2378 		Display(name);
  2379 		}
  2380 	return KErrNone;
  2381 	}
  2382 
  2383 TInt TShowProcInfo::GetThreads(const TDes& aName)
  2384 	{
  2385 	TInt threads=0;
  2386 	TFindThread findHb;
  2387 	findHb.Find(aName);
  2388 	TFullName name;
  2389 	TAny* findPtr=(TAny*)&findHb;
  2390 
  2391 //	Modified by WR, November 1997
  2392 	TCallBack threadCallBack(GetThreadInfo,findPtr);
  2393 	Prepare(_L("THREADS"),threadCallBack);
  2394 	while (findHb.Next(name)==KErrNone)
  2395 		{
  2396 		Display(name);
  2397 		threads += 1;
  2398 		}
  2399 	if (threads==0)
  2400 		{
  2401 		TFullName message;
  2402 		message.Format(_L("? No threads called %S"), &aName);
  2403 		DisplayMessage(message);
  2404 		}
  2405 	return KErrNone;
  2406 //	End of modification
  2407 	}
  2408 
  2409 
  2410 TInt TShowProcInfo::GetChunks(const TDes& aName)
  2411 	{
  2412 
  2413 	TFindChunk findHb;
  2414 	findHb.Find(aName);
  2415 	TFullName name;
  2416 	TAny* namePtr=(TAny*)&name;
  2417 	TCallBack chunkCallBack(GetChunkInfo,namePtr);
  2418 	Prepare(_L("CHUNKS & SIZES"),chunkCallBack);
  2419 	TInt totalChunkSize=0;
  2420 	TInt protectedChunks = 0;
  2421 	while (findHb.Next(name)==KErrNone)
  2422 		{
  2423 		Display(name);
  2424 		RChunk c;
  2425 		TInt r=c.Open(findHb);
  2426 		if(r!=KErrNone)
  2427 			++protectedChunks;
  2428 		else
  2429 			{
  2430 			totalChunkSize+=c.Size()/1024;
  2431 			c.Close();
  2432 			}
  2433 /*
  2434 #if defined(__WINS__)
  2435 		c.Close();
  2436 #else
  2437 		if (name.Match(_L("*ESHELL*"))<0)
  2438 			c.Close();
  2439 #endif
  2440 */
  2441 		}
  2442 	CShell::OutputStringToConsole(ETrue,_L("  Total Chunk Size = %dk\n"),totalChunkSize);
  2443 	if(protectedChunks)
  2444 		CShell::OutputStringToConsole(ETrue,_L("  %d Protected chunks not counted\n"),protectedChunks);
  2445 	return KErrNone;
  2446 	}
  2447 
  2448 TInt TShowProcInfo::GetServers(const TDes& aName)
  2449 	{
  2450 
  2451 	TFindServer findHb;
  2452 	findHb.Find(aName);
  2453 	TFullName name;
  2454 	Prepare(_L("SERVERS"));
  2455 	while (findHb.Next(name)==KErrNone)
  2456 		{
  2457 		Display(name);
  2458 		}
  2459 	return KErrNone;
  2460 	}
  2461 
  2462 /*	TInt TShowProcInfo::GetSessions(const TDes& aName)
  2463 	{
  2464 
  2465 	TFindSession findHb;
  2466 	findHb.Find(aName);
  2467 	TFullName name;
  2468 	Prepare(_L("SESSIONS"));
  2469 	while (findHb.Next(name)==KErrNone)
  2470 		{
  2471 		Display(name);
  2472 		}
  2473 	return KErrNone;
  2474 	}
  2475 */
  2476 TInt TShowProcInfo::GetLibraries(const TDes& aName)
  2477 	{
  2478 
  2479 	TFindLibrary findHb;
  2480 	findHb.Find(aName);
  2481 	TFullName name;
  2482 	Prepare(_L("LIBRARIES"));
  2483 	while (findHb.Next(name)==KErrNone)
  2484 		{
  2485 		Display(name);
  2486 		}
  2487 	return KErrNone;
  2488 	}
  2489 /*
  2490 TInt TShowProcInfo::GetLogicalChannels(const TDes& aName)
  2491 	{
  2492 
  2493 	TFindLogicalChannel findHb;
  2494 	findHb.Find(aName);
  2495 	TFullName name;
  2496 	Prepare(_L("LOGICAL CHANNELS"));
  2497 	while (findHb.Next(name)==KErrNone)
  2498 		{
  2499 		Display(name);
  2500 		}
  2501 	return KErrNone;
  2502 	}
  2503 */
  2504 
  2505 TInt TShowProcInfo::GetLogicalDevices(const TDes& aName)
  2506 	{
  2507 
  2508 	TFindLogicalDevice findHb;
  2509 	findHb.Find(aName);
  2510 	TFullName name;
  2511 	Prepare(_L("LOGICAL DEVICES"));
  2512 	while (findHb.Next(name)==KErrNone)
  2513 		{
  2514 		Display(name);
  2515 		}
  2516 	return KErrNone;
  2517 	}
  2518 
  2519 TInt TShowProcInfo::GetPhysicalDevices(const TDes& aName)
  2520 	{
  2521 
  2522 	TFindPhysicalDevice findHb;
  2523 	findHb.Find(aName);
  2524 	TFullName name;
  2525 	Prepare(_L("PHYSICAL DEVICES"));
  2526 	while (findHb.Next(name)==KErrNone)
  2527 		{
  2528 		Display(name);
  2529 		}
  2530 	return KErrNone;
  2531 	}
  2532 
  2533 TInt TShowProcInfo::GetSemaphores(const TDes& aName)
  2534 	{
  2535 	TFindSemaphore findHb;
  2536 	findHb.Find(aName);
  2537 	TFullName name;
  2538 	Prepare(_L("SEMAPHORES"));
  2539 	while (findHb.Next(name)==KErrNone)
  2540 		{
  2541 		Display(name);
  2542 		}
  2543 	return KErrNone;
  2544 	}
  2545 
  2546 TInt TShowProcInfo::GetMutexes(const TDes& aName)
  2547 	{
  2548 
  2549 	TFindMutex findHb;
  2550 	findHb.Find(aName);
  2551 	TFullName name;
  2552 	Prepare(_L("MUTEXES"));
  2553 	while (findHb.Next(name)==KErrNone)
  2554 		{
  2555 		Display(name);
  2556 		}
  2557 	return KErrNone;
  2558 	}
  2559 
  2560 void TShowProcInfo::DisplayHelpLine(const TDesC& aCommand, const TDesC& aDescription)
  2561 	{
  2562 	CShell::OutputStringToConsole(ETrue,_L("%- *S%S\n"),8,&aCommand,&aDescription);
  2563 	}
  2564 
  2565 
  2566 TInt TShowProcInfo::Prepare(const TFullName& aName)
  2567 	{
  2568 
  2569 	iPrevName=_L("");
  2570 	CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
  2571 	useCallBack=EFalse;
  2572 	return KErrNone;
  2573 	}
  2574 
  2575 TInt TShowProcInfo::Prepare(const TFullName& aName,TCallBack& aCallBack)
  2576 	{
  2577 
  2578 	iPrevName=_L("");
  2579 	CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
  2580 	useCallBack=ETrue;
  2581 	iCallBack=aCallBack;
  2582 	return KErrNone;
  2583 	}
  2584 
  2585 TInt TShowProcInfo::Display(TFullName& aName)
  2586 
  2587 //	Modifications by WR, November 1997
  2588 	{
  2589 
  2590 	TFullName prevName=iPrevName;
  2591 	iPrevName=aName;
  2592 	TInt toTab=0;
  2593 	TInt posA=aName.Match(_L("*::*"));
  2594 	if (posA>=0)
  2595 		{
  2596 		TInt posI=prevName.Match(_L("*::*"));
  2597 		while ((posI>=0) && (posA>=0))
  2598 			{
  2599 			TFullName tempAName=(aName.Left(posA));
  2600 			TFullName tempIName=(prevName.Left(posI));
  2601 			if (tempAName.Compare(tempIName)==0)
  2602 				{
  2603 				toTab+=3;
  2604 				aName.Delete(0,posA+2);
  2605 				prevName.Delete(0,posI+2);
  2606 				posA=aName.Match(_L("*::*"));
  2607 				posI=prevName.Match(_L("*::*"));
  2608 				}
  2609 			else
  2610 				break;
  2611 			}
  2612 		while (posA>=0)
  2613 			{
  2614 			TPtrC16 temp_desc=aName.Left(posA);
  2615 			CShell::OutputStringToConsole(ETrue,_L("%+ *S\n"),toTab+temp_desc.Left(posA).Length(),&temp_desc);
  2616 			toTab+=3;
  2617 			aName.Delete(0,posA+2);
  2618 			posA=aName.Match(_L("*::*"));
  2619 			}
  2620 		}
  2621 	CShell::OutputStringToConsole(ETrue,_L("%+ *S\n"),toTab+aName.Length(),&(aName));
  2622 
  2623 
  2624 	if (useCallBack)
  2625 		{
  2626 		toTab+=3;
  2627 		CShell::TheConsole->SetCursorPosRel(TPoint(toTab,0));
  2628 		iCallBack.CallBack();
  2629 		}
  2630 	return KErrNone;
  2631 	}
  2632 //	End of modification
  2633 TInt ShellFunction::Ps(TDes& /* aPath */,TUint /* aSwitches */)
  2634 //
  2635 // satisfy information requests about container objects
  2636 //
  2637 	{
  2638 
  2639 	TShowProcInfo showProcInfo;
  2640 	TInt r=KErrNone;
  2641     TBuf<0x1> asterisk=_L("*");
  2642 	TName processPrefix=asterisk;
  2643 	TBool abort=EFalse;
  2644 	TBool processSelected=EFalse;
  2645 	TBuf<0x16> prompt=_L("ps>");
  2646 	r=showProcInfo.GetProcesses(processPrefix);
  2647 	do
  2648 		{
  2649 		TBuf<0x10> command;
  2650 		CShell::TheEditor->Edit(prompt, &command, ETrue);
  2651 		while (command.Length() && !abort && r==KErrNone)
  2652 			{
  2653 			TInt pos;
  2654 			while ((pos=command.Locate(' '))>=0)
  2655 				command.Delete(pos,1);
  2656 			if (!command.Length())
  2657 				break;
  2658 			command.UpperCase();
  2659 			if (command.CompareF(_L("EXIT"))==0)
  2660 				{
  2661 				abort=ETrue;
  2662 				break;
  2663 				}
  2664 			TText c=command[0];
  2665 			command.Delete(0,1);
  2666 			switch (c)
  2667 				{
  2668 				case 'Q':
  2669 					abort=ETrue;
  2670 					break;
  2671 				case 'H':
  2672 				case '?':
  2673 					{
  2674 					showProcInfo.DisplayHelp();
  2675 					command.Zero();
  2676 					}
  2677 					break;
  2678 				case 'X':
  2679 					{
  2680 					TBuf<0x11> chosenP=command;
  2681 					if (chosenP.Length()<1)
  2682 					    {
  2683 					    if (processSelected)
  2684 						    {
  2685 						    r=showProcInfo.DisplayMessage(_L(" -> back to standard Process Status mode"));
  2686 						    processPrefix=asterisk;
  2687 						    prompt=_L("ps>");
  2688 						    processSelected=EFalse;
  2689 						    }
  2690 					    command.Zero();
  2691 						break;
  2692 					    }
  2693 					command.Zero();
  2694 					chosenP.Append(asterisk);
  2695 					TFindProcess findP;
  2696 					findP.Find(chosenP);
  2697 					TFullName findName;
  2698 					if (findP.Next(findName)!=KErrNone)
  2699 						{
  2700 						r=showProcInfo.DisplayMessage(_L("command prefixes no processes"));
  2701 						//r=showProcInfo.GetProcesses(asterisk);
  2702 						}
  2703 					else
  2704 						{
  2705 						if (findP.Next(findName)==KErrNone)
  2706 							{
  2707 							r=showProcInfo.DisplayMessage(_L("command prefixes more than one process"));
  2708 							r=showProcInfo.GetProcesses(chosenP);
  2709 							}
  2710 						else
  2711 							{
  2712 							processSelected=ETrue;
  2713 							processPrefix=chosenP;
  2714 							prompt=processPrefix;
  2715 							prompt.Append(_L(">"));
  2716 							}
  2717 						}
  2718 					}
  2719 					break;
  2720 				case 'A':
  2721 					{
  2722 					r=showProcInfo.GetAll(processPrefix);
  2723 					command.Zero();
  2724 					}
  2725 					break;
  2726 				case 'P':
  2727 					r=showProcInfo.GetProcesses(asterisk);
  2728 					break;
  2729 				case 'T':
  2730 					r=showProcInfo.GetThreads(processPrefix);
  2731 					break;
  2732 				case 'C':
  2733 					r=showProcInfo.GetChunks(processPrefix);
  2734 					break;
  2735 				case 'S':
  2736 					r=showProcInfo.GetServers(processPrefix);
  2737 					break;
  2738 /*				case 'I':
  2739 					r=showProcInfo.GetSessions(processPrefix);
  2740 					break;
  2741 */				case 'L':
  2742 					r=showProcInfo.GetLibraries(processPrefix);
  2743 					break;
  2744 //				case 'G':
  2745 //					r=showProcInfo.GetLogicalChannels(processPrefix);
  2746 //					break;
  2747 				case 'V':
  2748 					r=showProcInfo.GetLogicalDevices(processPrefix);
  2749 					break;
  2750 				case 'D':
  2751 					r=showProcInfo.GetPhysicalDevices(processPrefix);
  2752 					break;
  2753 				case 'E':
  2754 					r=showProcInfo.GetSemaphores(processPrefix);
  2755 					break;
  2756 				case 'M':
  2757 					r=showProcInfo.GetMutexes(processPrefix);
  2758 					break;
  2759 				default:
  2760 					{
  2761 					showProcInfo.DisplayCmdUnknown();
  2762 					command.Zero();
  2763 					}
  2764 				}
  2765 			}
  2766 		}
  2767 	while(!abort && r==KErrNone);
  2768 		return KErrNone;
  2769 	}
  2770 
  2771 TInt ShellFunction::Rename(TDes& aPath,TUint aSwitches)
  2772 	{
  2773 //	Modified December 1997 to allow for filenames containing spaces
  2774 
  2775 	TBuf<KShellMaxCommandLine> newName;
  2776 	TBuf<KShellMaxCommandLine> tempPath=aPath;
  2777 	RFile64 file;
  2778 	TWord   word(aPath);
  2779 
  2780 	TInt r=word.FindNextWord(aPath);
  2781 //	Check if the word returned is a valid filename.  If not, scan the next
  2782 //	word too in case the filename contains spaces.  If, at the end of the
  2783 //	the line, the filename is not recognised, it is invalid.  If there are no
  2784 //	spaces the user has not used the correct format for this command.
  2785 
  2786 	while (r>0)
  2787 		{
  2788 		newName=aPath.Right(aPath.Length()-r);
  2789 		tempPath.SetLength(r);
  2790 		TParse oldName;
  2791 		TInt result=GetFullPath(tempPath,oldName);
  2792 		if (result!=KErrNone)
  2793 			return(r);
  2794 
  2795 		if (tempPath[tempPath.Length()-2]==KPathDelimiter)
  2796 			tempPath.SetLength(tempPath.Length()-2);
  2797 
  2798 		result=file.Open(TheShell->TheFs,tempPath,KEntryAttMatchExclude|KEntryAttDir);
  2799 		if (result==KErrNone)	//	A valid filename
  2800 			{
  2801 			file.Close();
  2802 			TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
  2803 			TUint switches=(recursive) ? CFileMan::EOverWrite : 0;
  2804 			r=CShell::TheFileMan->Rename(oldName.FullName(),newName,switches);
  2805 		//	r=TheShell->TheFs.Rename(oldName.FullName(),newName);
  2806 			return(r);
  2807 			}
  2808 		else
  2809 			{
  2810 		//	May be a request to rename a directory
  2811 			RDir dir;
  2812 			result=dir.Open(TheShell->TheFs,tempPath,KEntryAttMatchMask);
  2813 			if (result==KErrNone)	//	A valid directory name
  2814 				{
  2815 				dir.Close();
  2816 				TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
  2817 				TUint switches=(recursive) ? CFileMan::EOverWrite : 0;
  2818 				r=CShell::TheFileMan->Rename(oldName.FullName(),newName,switches);
  2819 			//	r=TheShell->TheFs.Rename(oldName.FullName(),newName);
  2820 				return(r);
  2821 				}
  2822 			else
  2823 		//	Not a valid file or directory name - move one word along the command line
  2824 				r=word.FindNextWord(word.iRightString);
  2825 			}
  2826 		}
  2827 
  2828 	if (r<0)	//	Error in filename or destination
  2829 		return (r);
  2830 	else		//	End of command line, user typed invalid line
  2831 		return (KErrNotFound);
  2832 
  2833 }
  2834 
  2835 TInt ShellFunction::Rd(TDes& aPath,TUint /*aSwitches*/)
  2836 	{
  2837 	if (aPath.Length()==0)
  2838 		return(KErrBadName);
  2839 	if (aPath[aPath.Length()-1]!=KPathDelimiter)
  2840 		aPath.Append(KPathDelimiter);
  2841 	TParse dirPath;
  2842 	TInt r = GetFullPath(aPath,dirPath);
  2843 	if(r!=KErrNone)
  2844 		return r;
  2845 
  2846 //	Check whether the directory actually exists.
  2847 	RDir directory;
  2848 	r=directory.Open(TheShell->TheFs,dirPath.FullName(),KEntryAttMatchExclusive|KEntryAttDir);
  2849 	if (r!=KErrNone)
  2850 		{
  2851 		CShell::TheConsole->Printf(_L("Directory %S was not found\n"),&dirPath.FullName());
  2852 		return (KErrNone);
  2853 		}
  2854 	directory.Close();
  2855 
  2856 	TInt ret=TheShell->TheFs.RmDir(dirPath.FullName());
  2857     
  2858     if (ret==KErrNone)
  2859 	    CShell::TheConsole->Printf(_L("Directory %S was removed\n"),&dirPath.FullName());
  2860     else if(ret==KErrInUse)
  2861 	    {
  2862 		CShell::TheConsole->Printf(_L("Directory %S is in use and cannot be deleted\n"),&dirPath.FullName());
  2863 		return KErrNone;
  2864 		}
  2865 	
  2866     return(ret);
  2867 	}
  2868 
  2869 TInt ShellFunction::Start(TDes& aProg,TUint /*aSwitches*/)
  2870 //
  2871 // Runs a program without waiting for completion
  2872 //
  2873 	{
  2874 
  2875 	TInt bat=aProg.FindF(_L(".BAT"));
  2876 	TInt space=aProg.Locate(' ');
  2877 	TInt r=KErrArgument;
  2878 	if (bat>=0 && (space<0 || space>bat))
  2879 		r=CShell::RunBatch(aProg);
  2880 	else if (aProg.Length()!=0)
  2881 		r=CShell::RunExecutable(aProg,EFalse);
  2882 	return(r);
  2883 	}
  2884 
  2885 TInt ShellFunction::Time(TDes&,TUint /*aSwitches*/)
  2886 	{
  2887 	TTime time;
  2888 	time.HomeTime();
  2889 	TDateTime dateTime(time.DateTime());
  2890 	CShell::TheConsole->Printf(_L("  %+02d/%+02d/%+04d %+02d:%+02d:%+02d.%+06d\n"),dateTime.Day()+1,dateTime.Month()+1,dateTime.Year(),dateTime.Hour(),dateTime.Minute(),dateTime.Second(),dateTime.MicroSecond());
  2891 	return(KErrNone);
  2892 	}
  2893 
  2894 TInt ShellFunction::Trace(TDes& aState,TUint aSwitches)
  2895 //
  2896 // Turn on trace information
  2897 //
  2898     {
  2899 	TInt debugVal=0;
  2900 	if (aSwitches&TShellCommand::ESSwitch)
  2901 		debugVal|=KFSERV;
  2902 	if (aSwitches&TShellCommand::ELSwitch)
  2903 		debugVal|=KFLDR;
  2904 	if (aSwitches&TShellCommand::EFSwitch)
  2905 		debugVal|=KFSYS;
  2906 	if (aSwitches&TShellCommand::ETSwitch)
  2907 		debugVal|=KLFFS;
  2908 	if (aSwitches&TShellCommand::EISwitch)
  2909 		debugVal|=KISO9660;
  2910 	if (aSwitches&TShellCommand::ENSwitch)
  2911 		debugVal|=KNTFS;
  2912 	if (aSwitches&TShellCommand::EMSwitch)
  2913 		debugVal|=KTHRD;
  2914 	if (aSwitches&TShellCommand::EOSwitch)
  2915 		debugVal|=KROFS;
  2916 	if (aSwitches&TShellCommand::ECSwitch)
  2917 		debugVal|=KCOMPFS;
  2918 	if (aSwitches&TShellCommand::EHSwitch)
  2919 		debugVal|=KCACHE;
  2920 	TheShell->TheFs.SetDebugRegister(debugVal);
  2921 
  2922 	aSwitches=0;
  2923 
  2924 	if (aState.Length())
  2925 		{
  2926 		TBuf<KShellMaxCommandLine> indexArg;
  2927 		TWord word(aState);
  2928 
  2929 		TLex lex=aState;
  2930 		TUint val;
  2931 		TInt r2=lex.Val(val,EHex);
  2932 
  2933 		TInt r=word.FindNextWord(aState);
  2934 		TUint index;
  2935 		if (r>0)
  2936 			{
  2937 			indexArg = aState.Right(aState.Length()-r);
  2938 			lex=indexArg;
  2939 			lex.Val(index,EDecimal);
  2940 			}
  2941 		else
  2942 			index = 0;
  2943 
  2944 		if (r2 != KErrNone)
  2945 			{
  2946 			TInt shift = index % 32;
  2947 			index /= 32;
  2948 			val = UserSvr::DebugMask(index);
  2949 			if (aState.Left(2)==_L("on"))
  2950 				val |= 1<<shift;
  2951 			else if (aState.Left(3)==_L("off"))
  2952 				val &= ~(1<<shift);
  2953 			}
  2954 
  2955 		if (index < 256)
  2956 			{
  2957 			User::SetDebugMask(val, index);
  2958 			CShell::TheConsole->Printf(_L("SetDebugMask(0x%x, %d)\n"), val, index);
  2959 			}
  2960 		}
  2961 	else
  2962 		{
  2963 		for (TInt j=0; j<8; j++)
  2964 			CShell::TheConsole->Printf(_L("DebugMask(%d) = 0x%08X\n"), j, UserSvr::DebugMask(j));
  2965 		}
  2966 
  2967     return(KErrNone);
  2968     }
  2969 
  2970 TInt ShellFunction::Tree(TDes& aPath,TUint aSwitches)
  2971 	{
  2972 	ParsePath(aPath);
  2973 	CShell::TheConsole->Printf(_L("\n  %S\n"),&aPath);
  2974 	if (aPath.Right(1)==_L("\\"))
  2975 		aPath.Append('*');
  2976 	else
  2977 		aPath.Append(_L("\\*"));
  2978 	TBuf<256> buf=_L("  ");
  2979 	TInt dirCount=ShowDirectoryTree(aPath,aSwitches,buf);
  2980 	buf.Format(_L("\n    Found %d subdirector"),dirCount);
  2981 	if (dirCount==1)
  2982 		buf.AppendFormat(_L("y\n"));
  2983 	else
  2984 		buf.AppendFormat(_L("ies\n"));
  2985 
  2986 	CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),buf);
  2987 
  2988 	return(KErrNone);
  2989 	}
  2990 
  2991 TInt ShellFunction::ShowDirectoryTree(TDes& aPath,TUint aSwitches,TDes& aTreeGraph)
  2992 //
  2993 // Recursive fn. to draw tree of dir aPath (needs to be suffixed with '*')
  2994 //
  2995 	{
  2996 	TInt dirCount=0;
  2997 	RDir dir;
  2998 	TInt r=dir.Open(TheShell->TheFs,aPath,KEntryAttDir);
  2999 	if (r==KErrNone)
  3000 		{
  3001 		TEntry next,entry;
  3002 		while ((r=dir.Read(next))==KErrNone && !next.IsDir())
  3003 			{
  3004 			}
  3005 		//	lint info 722: Suspicious use of ; in previous line...
  3006 		if (aSwitches&TShellCommand::EFSwitch)
  3007 			{
  3008 			RDir dirFile;
  3009 			if (dirFile.Open(TheShell->TheFs,aPath,0)==KErrNone)
  3010 				{
  3011 				while (dirFile.Read(entry)==KErrNone)
  3012 					CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,(r==KErrNone)?_L("%S\x00B3   %S\n"):_L("%S   %S\n"),&aTreeGraph,&entry.iName);
  3013 
  3014 				dirFile.Close();
  3015 				}
  3016 			}
  3017 		if (r==KErrNone)
  3018 			do
  3019 				{
  3020 				entry=next;
  3021 				while ((r=dir.Read(next))==KErrNone && !next.IsDir())
  3022 					;
  3023 
  3024 				CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,aTreeGraph);
  3025 				if (r==KErrNone)
  3026 					{
  3027 					CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("\x00C0\x00C4\x00C4%S\n"),&entry.iName);
  3028 					aTreeGraph.Append(_L("\x00B3  "));
  3029 					}
  3030 				else
  3031 					{
  3032 					CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("\x00C0\x00C4\x00C4%S\n"),&entry.iName);
  3033 					aTreeGraph.Append(_L("   "));
  3034 					}
  3035 				aPath.Insert(aPath.Length()-1,entry.iName);
  3036 				aPath.Insert(aPath.Length()-1,_L("\\"));
  3037 				dirCount+=1+ShowDirectoryTree(aPath,aSwitches,aTreeGraph);
  3038 				aPath.Delete(aPath.Length()-2-entry.iName.Length(),entry.iName.Length()+1);
  3039 				aTreeGraph.SetLength(aTreeGraph.Length()-3);
  3040 				}
  3041 			while (r==KErrNone);
  3042 		dir.Close();
  3043 		if (r!=KErrEof)
  3044 			CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("Error EOF %d\n"),r);
  3045 
  3046 		}
  3047 	else
  3048 		CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("Error in Open %d\n"),r);
  3049 	return(dirCount);
  3050 	}
  3051 
  3052 void ByteSwap(TDes16& aDes)
  3053 	{
  3054 	TUint8* p=(TUint8*)aDes.Ptr();
  3055 	TUint8* pE=p+aDes.Size();
  3056 	TUint8 c;
  3057 	for (; p<pE; p+=2)
  3058 		c=*p, *p=p[1], p[1]=c;
  3059 	}
  3060 
  3061 _LIT(KLitPercentS, "%S");
  3062 TInt ShellFunction::Type(TDes& aPath,TUint aSwitches)
  3063 	{
  3064 	ParsePath(aPath);
  3065 	RFile file;
  3066 	TInt r=file.Open(TheShell->TheFs,aPath,EFileStreamText|EFileShareReadersOnly);
  3067 	if (r!=KErrNone)
  3068 		return r;
  3069 	TBuf8<0x200> tmpbuf;
  3070 	TBuf<0x200> ubuf;
  3071 	TInt state=0;	// 0=start of file, 1=ASCII, 2=UNICODE little-endian, 3=UNICODE big-endian
  3072     TKeyCode key=EKeyNull;
  3073 
  3074 	TInt nchars=0;
  3075 	TInt l;
  3076 	
  3077 	do
  3078 		{
  3079 		r=file.Read(tmpbuf);
  3080 		if (r!=KErrNone)
  3081 			{
  3082 			file.Close();
  3083 			return r;
  3084 			}
  3085 		
  3086 		l=tmpbuf.Length();
  3087 		if (state==0)
  3088 			{
  3089 			if (l>=2)
  3090 				{
  3091 				TUint c=(tmpbuf[1]<<8)|tmpbuf[0];
  3092 				if (c==0xfeff)
  3093 					state=2;
  3094 				else if (c==0xfffe)
  3095 					state=3;
  3096 				else
  3097 					state=1;
  3098 				}
  3099 			else
  3100 				state=1;
  3101 			}
  3102 		TPtrC buf;
  3103 		if (state>1)
  3104 			{
  3105 			if (l&1)
  3106 				--l, tmpbuf.SetLength(l);
  3107 			buf.Set((TText*)tmpbuf.Ptr(),l/sizeof(TText));
  3108 			if (state==3)
  3109 				{
  3110 				TPtr wbuf( (TText*)buf.Ptr(), buf.Length(), buf.Length() );
  3111 				ByteSwap(wbuf);
  3112 				}
  3113 			}
  3114 		else
  3115 			{
  3116 			ubuf.Copy(tmpbuf);
  3117 			buf.Set(ubuf);
  3118 			}
  3119 		while ((r=buf.Locate('\n'))!=KErrNotFound)
  3120 			{
  3121 			nchars=0;
  3122 			TPtrC bufLeft=buf.Left(r+1);
  3123 			key = CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,KLitPercentS(), &bufLeft);
  3124 			buf.Set(buf.Mid(r+1));
  3125 	
  3126     		if(key == EKeyEscape) 
  3127                 goto exit;
  3128 			}
  3129 
  3130 		nchars=buf.Length();
  3131 		if (nchars)
  3132 			{
  3133             key = CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,KLitPercentS(), &buf);
  3134     		if(key == EKeyEscape) 
  3135                 goto exit;
  3136 
  3137             }
  3138 
  3139 		} while(l==tmpbuf.MaxLength());
  3140 
  3141    exit: 	
  3142     
  3143 	file.Close();
  3144 	CShell::NewLine();
  3145 	return KErrNone;
  3146 	}
  3147 
  3148 void ShellFunction::ParsePath(TDes& aPath)
  3149 	{
  3150 	if (aPath.Length()>0 && aPath[0]==KPathDelimiter)
  3151 		return;
  3152 	TParse pathParse;
  3153 	if (aPath.Length()<2 || aPath[1]!=':')
  3154 		pathParse.SetNoWild(TheShell->currentPath,NULL,NULL);
  3155 	else
  3156 		{
  3157 		if (aPath.Length()>=3 && aPath[2]==KPathDelimiter)
  3158 			return;
  3159 		pathParse.SetNoWild(TheShell->drivePaths[User::UpperCase(aPath[0])-'A'],NULL,NULL);
  3160 		aPath.Delete(0,2);
  3161 		}
  3162 	if (aPath.Length()>=2 && aPath.Left(2).Compare(_L(".."))==0)
  3163 		{
  3164 		aPath.Delete(0,2);
  3165 		pathParse.PopDir();
  3166 		while (aPath.Length()>=3 && aPath.Left(3).Compare(_L("\\.."))==0)
  3167 			{
  3168 			aPath.Delete(0,3);
  3169 			pathParse.PopDir();
  3170 			}
  3171 		if (aPath.Length()!=0 && aPath[0]==KPathDelimiter)
  3172 			aPath.Delete(0,1);
  3173 		}
  3174 	aPath.Insert(0,pathParse.FullName());
  3175 	}
  3176 
  3177 TBool ShellFunction::Certain()
  3178 	{
  3179 	CShell::TheConsole->Printf(_L("Are you sure? Y/N..."));
  3180 	TInt r=User::UpperCase(CShell::TheConsole->Getch());
  3181 	while ((!(r=='Y'))&&(!(r=='N')))
  3182 		{
  3183 		CShell::TheConsole->Printf(_L("%c is invalid\n"),r);
  3184 		CShell::TheConsole->Printf(_L("Are you sure? Y/N..."));
  3185 		r=User::UpperCase(CShell::TheConsole->Getch());
  3186 		}
  3187 	CShell::TheConsole->Printf(_L("%c\n"),r);
  3188 	return(r=='Y');
  3189 	}
  3190 
  3191 TInt ShellFunction::GetFullPath(TDes& aPath,TParse& aParse)
  3192 //
  3193 // Parse a path of the form "[C:][\\]AAA\\..\\.\\BBB\\xxx.yyy" where:
  3194 // .  indicates the current directory
  3195 // .. indicates move to the parent directory
  3196 // An optional "\\" at the start of the path indicates the path is not relative to the current path
  3197 //
  3198 	{
  3199 
  3200 	TInt r;
  3201 	if (aPath.Length()>0 && aPath[aPath.Length()-1]=='.')
  3202 		aPath.Append(KPathDelimiter);
  3203 	if (aPath.Length()==0)
  3204 		r=aParse.Set(TheShell->currentPath,NULL,NULL);
  3205 	else if (aPath[0]==KPathDelimiter)
  3206 		r=aParse.Set(aPath,&TheShell->currentPath,NULL);
  3207 	else if (aPath.Length()>=2 && aPath[1]==KDriveDelimiter)
  3208 		{
  3209 		TInt drvNum;
  3210 		r=RFs::CharToDrive(aPath[0],drvNum);
  3211 		if (r==KErrNone)
  3212 			r=aParse.Set(aPath,&TheShell->drivePaths[drvNum],NULL);
  3213 		}
  3214 	else
  3215 		{
  3216 		if (aPath.LocateReverse(KPathDelimiter)>=0)
  3217 			{
  3218 			if (aPath.Length()+TheShell->currentPath.Length()>aPath.MaxLength())
  3219 				return(KErrBadName);
  3220 			aPath.Insert(0,TheShell->currentPath);
  3221 			}
  3222 		r=aParse.Set(aPath,&TheShell->currentPath,NULL);
  3223 		}
  3224 	if (r!=KErrNone)
  3225 		return(r);
  3226 	if (aParse.Path().Find(_L(".\\"))==KErrNotFound)
  3227 		return(KErrNone);
  3228 	if (aParse.Path().Find(_L("...\\"))!=KErrNotFound)
  3229 		return(KErrBadName);
  3230 	TParse dirParse;
  3231 	TPtrC path(aParse.DriveAndPath());
  3232 	TInt pos=path.Find(_L(".\\"));
  3233 	if (path[pos-1]!='.' && path[pos-1]!='\\')
  3234 		return(KErrNone); // FileName ending in .
  3235 	TInt isParent=(path[pos-1]=='.') ? 1 : 0;
  3236 	r=dirParse.Set(path.Left(pos-isParent),NULL,NULL);
  3237 	while(r==KErrNone)
  3238 		{
  3239 		if (isParent)
  3240 			dirParse.PopDir();
  3241 		path.Set(path.Right(path.Length()-pos-2));
  3242 		pos=path.Find(_L(".\\"));
  3243 		if (pos==0)
  3244 			{
  3245 			isParent=0;
  3246 			continue;
  3247 			}
  3248 		else if (pos!=KErrNotFound)
  3249 			isParent=(path[pos-1]=='.') ? 1 : 0;
  3250 		TInt len=(pos==KErrNotFound) ? path.Length() : pos-isParent;
  3251 		r=AddRelativePath(dirParse,path.Left(len));
  3252 		if (r!=KErrNone || pos==KErrNotFound)
  3253 			break;
  3254 		}
  3255 	if (r!=KErrNone)
  3256 		return(r);
  3257 //	lint -e50
  3258 	TBuf<KMaxFileName> nameAndExt=aParse.NameAndExt();
  3259 	aParse.Set(dirParse.FullName(),&nameAndExt,NULL);
  3260 	return(KErrNone);
  3261 	}
  3262 
  3263 void ShellFunction::StripQuotes(TDes& aVal)
  3264 	{
  3265 	for(TInt idx=0;idx<aVal.Length();idx++)
  3266 		{
  3267 		while((idx < aVal.Length()) && (aVal[idx] == '"'))
  3268 			{
  3269 			aVal.Delete(idx, 1);
  3270 			}
  3271 		}
  3272 	}
  3273 
  3274 TInt ShellFunction::ValidName(TDes& aPath,TUint /*aSwitches*/)
  3275 //
  3276 //	Check whether the name has any invalid characters
  3277 //
  3278 	{
  3279 	TBool tooShort=EFalse;
  3280 
  3281 	TText badChar;
  3282 	TPtr ptr(&badChar,sizeof(TText),sizeof(TText));
  3283 
  3284 	TBool validName=TheShell->TheFs.IsValidName(aPath,badChar);
  3285 	if (validName)
  3286 		CShell::TheConsole->Printf(_L("'%S' is a valid name\n"),&aPath);
  3287 	else
  3288 		{
  3289 		if (!tooShort)
  3290 			CShell::TheConsole->Printf(_L("'%S' is not a valid name.\n"),&aPath);
  3291 
  3292 		CShell::TheConsole->Printf(_L("The '%S' character is not allowed\n"),&ptr);
  3293 		}
  3294 	return (KErrNone);
  3295 	}
  3296 
  3297 LOCAL_C TInt pswd_DrvNbr(TDes &aPath, TInt &aDN)
  3298 //
  3299 // password utility function to extract drive number from cmd string.
  3300 //
  3301 	{
  3302 	TLex l(aPath);
  3303 	return l.Val(aDN);
  3304 	}
  3305 
  3306 LOCAL_C TInt pswd_Password(TDes &aPath, TInt aPWNbr, TMediaPassword &aPW)
  3307 //
  3308 // utility function to extract indexed password from command string.  A
  3309 // dash is interpreted as the null password.
  3310 //
  3311 	{
  3312 	__ASSERT_DEBUG(aPWNbr >= 1, User::Panic(_L("Invalid pswd nbr"), 0));
  3313 
  3314 	TLex l(aPath);
  3315 
  3316 	TPtrC ptScan;
  3317 	for (TInt i = 0; i <= aPWNbr; ++i)
  3318 		{
  3319 		if (l.Eos())
  3320 			return KErrNotFound;
  3321 		else
  3322 			ptScan.Set(l.NextToken());
  3323 		}
  3324 
  3325 	// take remainder of command line and terminate after password
  3326 	TBuf<256> pswd;
  3327 	for (TInt j = 0; j < ptScan.Length() && ! TChar(ptScan[j]).IsSpace(); ++j)
  3328 		{
  3329 		pswd.Append(ptScan[j]);
  3330 		}
  3331 
  3332 	aPW.Zero();
  3333 	if (pswd[0] == '-')
  3334 		return KErrNone;
  3335 
  3336 	// fill aPW with contents of pswd, not converting to ASCII
  3337 	const TInt byteLen = pswd.Length() * 2;
  3338 	if (byteLen > KMaxMediaPassword)
  3339 		return KErrArgument;
  3340 
  3341 	aPW.Copy(reinterpret_cast<const TUint8 *>(pswd.Ptr()), byteLen);
  3342 
  3343 	return KErrNone;
  3344 	}
  3345 
  3346 TInt ShellFunction::Lock(TDes &aPath, TUint aSwitches)
  3347 //
  3348 // Locks a password-enabled media.
  3349 //
  3350 	{
  3351 	TInt r;
  3352 	TInt dn;
  3353 	TMediaPassword curPswd;
  3354 	TMediaPassword newPswd;
  3355 	TBool store = aSwitches & TShellCommand::ESSwitch;
  3356 
  3357 	if ((r = pswd_DrvNbr(aPath, dn)) < 0)
  3358 		return r;
  3359 
  3360 	if ((r = pswd_Password(aPath, 1, curPswd)) < 0)
  3361 		return r;
  3362 
  3363 	if ((r = pswd_Password(aPath, 2, newPswd)) < 0)
  3364 		return r;
  3365 
  3366 	return TheShell->TheFs.LockDrive(dn, curPswd, newPswd, store);
  3367 	}
  3368 
  3369 TInt ShellFunction::Unlock(TDes &aPath, TUint aSwitches)
  3370 //
  3371 // Unlocks a password-enabled media.
  3372 //
  3373 	{
  3374 	TInt r;
  3375 	TInt dn;
  3376 	TMediaPassword curPswd;
  3377 	TBool store = aSwitches & TShellCommand::ESSwitch;
  3378 
  3379 	if ((r = pswd_DrvNbr(aPath, dn)) < 0)
  3380 		return r;
  3381 
  3382 	if ((r = pswd_Password(aPath, 1, curPswd)) < 0)
  3383 		return r;
  3384 
  3385 	return TheShell->TheFs.UnlockDrive(dn, curPswd, store);
  3386 	}
  3387 
  3388 TInt ShellFunction::Clear(TDes &aPath, TUint /* aSwitches */)
  3389 //
  3390 // Clears a password from a password-enabled media.
  3391 //
  3392 	{
  3393 	TInt r;
  3394 	TInt dn;
  3395 	TMediaPassword curPswd;
  3396 
  3397 	if ((r = pswd_DrvNbr(aPath, dn)) < 0)
  3398 		return r;
  3399 
  3400 	if ((r = pswd_Password(aPath, 1, curPswd)) < 0)
  3401 		return r;
  3402 
  3403 	return TheShell->TheFs.ClearPassword(dn, curPswd);
  3404 	}
  3405 
  3406 TInt ShellFunction::SetSize(TDes& aPath,TUint /*aSwitches*/)
  3407 //
  3408 // Set size of a file, create this if it does not exist
  3409 //
  3410 	{
  3411 	TInt fileNameLen=aPath.LocateReverse(' ');
  3412 	if (fileNameLen==KErrNotFound)	//	No spaces implies no filelength specified
  3413 		{
  3414 		CShell::TheConsole->Printf(_L("Please specify a file name and a file length\n"));
  3415 		return (KErrNone);
  3416 		}
  3417 
  3418 
  3419 	TInt fileLength=(aPath.Length()-fileNameLen);
  3420 	if (fileLength>16)
  3421 		return (KErrTooBig);	//	Too many digits - too large!
  3422 	TBuf<16> rightString=aPath.Right(fileLength);
  3423 	aPath.SetLength(fileNameLen);
  3424 
  3425 	TLex size(rightString);
  3426 	size.SkipSpace();
  3427 
  3428 	TRadix radix=ParseHexaPrefixIfAny(size);
  3429 	TUint32 fileSize;
  3430 	TInt r=size.Val(fileSize,radix);
  3431 	if (r!=KErrNone || ! size.Eos())
  3432 		{
  3433 		CShell::TheConsole->Printf(_L("Please specify a file length\n"));
  3434 		return KErrNone;
  3435 		}
  3436 
  3437 	TParse fileName;
  3438 	GetFullPath(aPath,fileName);
  3439 	RFile64 file;
  3440 	r=file.Open(CShell::TheFs,fileName.FullName(),EFileRead|EFileWrite);
  3441 	if(r==KErrNotFound)
  3442 		r=file.Create(CShell::TheFs,fileName.FullName(),EFileRead|EFileWrite);
  3443 	if (r==KErrNone)
  3444 		{
  3445 		r=file.SetSize(fileSize);
  3446 		file.Close();
  3447 		if(r!=KErrNone)
  3448 			CShell::TheConsole->Printf(_L("Error (%d) - could not set size of file\n"),r);
  3449 		}
  3450 	else
  3451 		{
  3452 		CShell::TheConsole->Printf(_L("Error (%d) - could not create or open file\n"),r);
  3453 		CShell::TheFs.Delete(fileName.FullName());
  3454 		}
  3455 	return(r);
  3456 	}
  3457 
  3458 TInt ShellFunction::DebugPort(TDes& aArgs, TUint /*aSwitches*/)
  3459 //
  3460 // Set or get the debug port from the command line (debugport)
  3461 //
  3462 	{
  3463 	_LIT(KGetPortLit, "Debug port is %d (0x%x)\n");
  3464 	_LIT(KSetPortLit, "Debug port set to %d (0x%x)\n");
  3465 
  3466 	TLex s(aArgs);
  3467 	s.SkipSpace();
  3468 	if (s.Eos())
  3469 		{
  3470 		TInt port;
  3471 		TInt r = HAL::Get(HALData::EDebugPort, port);
  3472 		if (r != KErrNone)
  3473 			return r;
  3474 		CShell::TheConsole->Printf(KGetPortLit, (TUint32)port, (TUint32)port);
  3475 		}
  3476 	else
  3477 		{
  3478 		TRadix radix=EDecimal;
  3479 		if (s.Remainder().Length()>2)
  3480 			{
  3481 			s.Mark();
  3482 			s.Inc(2);
  3483 			if (s.MarkedToken().MatchF(_L("0x"))!=KErrNotFound)
  3484 				radix=EHex;
  3485 			else
  3486 				s.UnGetToMark();
  3487 			}
  3488 
  3489         union Port
  3490             {
  3491 		    TUint32 u;
  3492             TInt32 s;
  3493             };
  3494 
  3495         Port port;
  3496         TInt r;
  3497         if (radix == EHex)
  3498             r = s.Val(port.u, radix);
  3499         else
  3500             r = s.Val(port.s);
  3501 		if (r != KErrNone || ! s.Eos())
  3502 			return KErrBadName;
  3503 		r = HAL::Set(HALData::EDebugPort, port.s);
  3504 		if (r != KErrNone)
  3505 			return r;
  3506 		CShell::TheConsole->Printf(KSetPortLit, port.s, port.u);
  3507 		}
  3508 
  3509 	return KErrNone;
  3510 	}
  3511 
  3512 TInt ShellFunction::Plugin(TDes& aName,TUint aSwitches)
  3513 	{
  3514 	TInt err = KErrNone;
  3515 	switch(aSwitches)
  3516 		{
  3517 		case TShellCommand::EASwitch:
  3518 			{
  3519 			err = CShell::TheFs.AddPlugin(aName);
  3520 			CShell::TheConsole->Printf(_L("Add Plugin: %S [r:%d]\n"), &aName, err);
  3521 			break;
  3522 			}
  3523 		case TShellCommand::ERSwitch:
  3524 			{
  3525 			err = CShell::TheFs.RemovePlugin(aName);
  3526 			CShell::TheConsole->Printf(_L("Remove Plugin: %S [r:%d]\n"), &aName, err);
  3527 			break;
  3528 			}
  3529 		case TShellCommand::EMSwitch:
  3530 			{
  3531 			err = CShell::TheFs.MountPlugin(aName);
  3532 			CShell::TheConsole->Printf(_L("Mount Plugin: %S [r:%d]\n"), &aName, err);
  3533 			break;
  3534 			}
  3535 		case TShellCommand::EDSwitch:
  3536 			{
  3537 			err = CShell::TheFs.DismountPlugin(aName);
  3538 			CShell::TheConsole->Printf(_L("Dismount Plugin: %S [r:%d]\n"), &aName, err);
  3539 			break;
  3540 			}
  3541 		default:
  3542 			{
  3543 			break;
  3544 			}
  3545 		}
  3546 	return err;
  3547 	}
  3548 
  3549 _LIT(KCrNl, "\r\n");
  3550 
  3551 void SIPrintf(TRefByValue<const TDesC16> aFmt, ...)
  3552 	{
  3553 	TBuf<256> buf;
  3554 	VA_LIST list;					
  3555 	VA_START(list, aFmt);
  3556 	// coverity[uninit_use_in_call]
  3557 	buf.FormatList(aFmt, list);			
  3558 	buf.Append(KCrNl);					
  3559 	RDebug::RawPrint(buf);
  3560 	CShell::TheConsole->Printf(buf);
  3561 	}
  3562 
  3563 /**
  3564 	Run a specified executable in a loop.
  3565 
  3566 	RUNEXEC <count> <command [args]> [/E] [/S] [/R]
  3567 
  3568 	count	- loop count; zero (0) means: forever
  3569 	command	- the executable to run. Arguments can be supplied.
  3570 			  Limitations:
  3571 			  command arguments cannot contain /? switches as the shell strips these out.
  3572 			  command cannot contain spaces.
  3573 
  3574 	/E	terminates the loop if the program exits with an error
  3575 
  3576 	/S	makes the shell interpret "count" as a number of seconds
  3577 		The shell will not attempt to terminate "command" early if it is still running after
  3578 		"count" seconds. It will terminate the loop only after "command" has exited.
  3579 
  3580 	/R	will make the shell reset debug registers / trace flags after each iteration.
  3581 		This is to be used if the program modifies tracing flags for its own purposes but exits
  3582 		abnormally; if /R is used, later iterations will run the program from the same initial
  3583 		tracing	state each time.
  3584 		Limitation: This flag does not yet affect BTrace / UTrace state.
  3585 
  3586 	Switches can be combined; "RUNEXEC 2000 testprg /E/S/R" keeps running "testprg"	till an error
  3587 	occurs, or more than 2000 seconds have passed, and resets the debug	state after each iteration.
  3588 */
  3589 TInt ShellFunction::RunExec(TDes& aProg, TUint aSwitches)
  3590 	{
  3591 	_LIT(KRunExecFailedProcessCreate, "Failed to spawn command %S: error %d\n");
  3592 	_LIT(KRunExecReportStatusAndTime, "Total elapsed time: %d msecs, Iteration %d: Exit type %d,%d,%S\n");
  3593 	aProg.TrimAll();
  3594 	TBuf<KShellMaxCommandLine> parameters(0);
  3595 	TInt r;
  3596 	TInt count = 0;
  3597 	TTime timeStart, timeCurrent;
  3598 	TTimeIntervalMicroSeconds timeTaken;
  3599 
  3600 	// The first parameter must be a valid decimal integer.
  3601 	for (r=0; r < aProg.Length() && TChar(aProg[r]).IsDigit(); r++)
  3602 		count = count * 10 + (aProg[r] - '0');
  3603 	if (r == 0 || r == aProg.Length() || TChar(aProg[r]).IsSpace() == EFalse)
  3604 		return (KErrArgument);
  3605 	aProg = aProg.Mid(r+1);
  3606 
  3607 	TBool exitOnErr = (aSwitches & TShellCommand::EESwitch);
  3608 	TBool resetDebugRegs = (aSwitches & TShellCommand::ERSwitch);
  3609 	TBool countIsSecs = (aSwitches & TShellCommand::ESSwitch);
  3610 	TBool forever = (count == 0);
  3611 
  3612 	timeStart.HomeTime();
  3613 
  3614 	// copy out the parameters - if any
  3615 	r = aProg.Locate(' ');
  3616 	if(r != KErrNotFound)
  3617 		{
  3618 		parameters = aProg.Mid(r+1);
  3619 		aProg.SetLength(r);
  3620 		}
  3621 
  3622 	// Make sure the executable name qualifies as a pathname.
  3623 	aProg.UpperCase();
  3624 	if (aProg.FindF(_L(".EXE")) == KErrNotFound && (aProg.Length()+4) <= KShellMaxCommandLine)
  3625 		aProg.Append(_L(".EXE"));
  3626 
  3627 #ifdef _DEBUG
  3628 	SIPrintf(_L("RUNEXEC: command %S, parameters %S, count %d, forever %d, issecs %d, exiterr %d"),
  3629 		&aProg, &parameters, count, forever, countIsSecs, exitOnErr); 
  3630 #endif
  3631 	TInt i=0;
  3632 	FOREVER
  3633 		{
  3634 		TInt retcode;
  3635 		RProcess newProcess;
  3636 		TRequestStatus status = KRequestPending;
  3637 		TExitType exitType;
  3638 		TBuf<KMaxExitCategoryName> exitCat(0);
  3639 
  3640 		r = newProcess.Create(aProg, parameters);
  3641 		if (r != KErrNone)
  3642 			{
  3643 			SIPrintf(KRunExecFailedProcessCreate, &aProg, r);
  3644 			return (r);						// this is systematic - must return
  3645 			}
  3646 		newProcess.Logon(status);
  3647 		newProcess.Resume();
  3648 		User::WaitForRequest(status);
  3649 		exitType = newProcess.ExitType();
  3650 		exitCat = newProcess.ExitCategory();
  3651 		retcode = newProcess.ExitReason();
  3652 		newProcess.Close();
  3653 
  3654 		timeCurrent.HomeTime();
  3655 		timeTaken = timeCurrent.MicroSecondsFrom(timeStart);
  3656 		TInt msecs = I64LOW(timeTaken.Int64() / 1000);
  3657 		SIPrintf(KRunExecReportStatusAndTime, msecs, i+1, exitType, retcode, &exitCat);
  3658 
  3659 		if (resetDebugRegs)
  3660 			{
  3661 			TheShell->TheFs.SetDebugRegister(0);
  3662 			User::SetDebugMask(0);
  3663 			}
  3664 
  3665 		i++;
  3666 
  3667 		if ((exitOnErr && (exitType != EExitKill || status != KErrNone)) ||							// err occurred, leave requested ?
  3668 			(countIsSecs && count != 0 && timeTaken.Int64() > (TInt64)1000000 * (TInt64)count) ||	// time elapsed ?
  3669 			(!forever && i >= count))																// loop done ?
  3670 			break;
  3671 		}
  3672 	return(KErrNone);
  3673 	}
  3674 
  3675 //
  3676 // System information command
  3677 //
  3678 
  3679 TBool DebugNum(TInt aBitNum)
  3680 	{
  3681 	__ASSERT_ALWAYS(aBitNum >= 0 && aBitNum <= KMAXTRACE, User::Panic(_L("Bad bit num"), 0));
  3682 	TInt index = aBitNum >> 5;
  3683 	TInt m = UserSvr::DebugMask(index) & (1 << (aBitNum & 31));
  3684 	return m != 0;
  3685 	}
  3686 
  3687 void SIHeading(TRefByValue<const TDesC16> aFmt, ...)
  3688 	{
  3689 	TBuf<256> buf;
  3690 	VA_LIST list;
  3691 	VA_START(list, aFmt);
  3692 	buf.Append(KCrNl);
  3693 	buf.AppendFormatList(aFmt, list);
  3694 	buf.Append(KCrNl);
  3695 	RDebug::RawPrint(buf);
  3696 	CShell::TheConsole->Printf(buf);
  3697 	buf.Fill('=', buf.Length()-4);
  3698 	buf.Append(KCrNl);
  3699 	RDebug::RawPrint(buf);
  3700 	CShell::TheConsole->Printf(buf);
  3701 	}
  3702 
  3703 void SIBoolean(const TDesC& aFmt, TBool aVal)
  3704 	{
  3705 	_LIT(KEnabled, "enabled");
  3706 	_LIT(KDisabled, "disabled");
  3707 	SIPrintf(aFmt, aVal ? &KEnabled : &KDisabled);
  3708 	}
  3709 
  3710 TInt ShellFunction::SysInfo(TDes& /*aArgs*/, TUint /*aSwitches*/)
  3711 	{
  3712 	SIHeading(_L("Kernel Features"));
  3713 	SIBoolean(_L("Crazy scheduler delays are %S."), DebugNum(KCRAZYSCHEDDELAY));
  3714 	SIBoolean(_L("Crazy scheduler priorities and timeslicing are %S."),
  3715 				UserSvr::HalFunction(EHalGroupKernel, EKernelHalConfigFlags, 0, 0) & EKernelConfigCrazyScheduling);
  3716 
  3717 	return KErrNone;
  3718 	}
  3719 
  3720 
  3721 //-------------------------------------------------------------------------
  3722 /**
  3723     Print out the command line to the console and standard debug port.
  3724 */
  3725 TInt ShellFunction::ConsoleEcho(TDes& aArgs, TUint /*aSwitches*/)
  3726 {
  3727     SIPrintf(aArgs);
  3728     return KErrNone;
  3729 }