--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/etshell/ts_com.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,3647 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32\etshell\ts_com.cpp
+// Shell commands
+//
+//
+
+#ifdef __VC32__
+ // Solve compilation problem caused by non-English locale
+ #pragma setlocale("english")
+#endif
+
+#include "ts_std.h"
+
+#include <hal.h>
+#include <d32locd.h>
+#include <e32math.h>
+#include "u32std.h"
+#include <u32hal.h>
+#include <nkern/nk_trace.h>
+#include "filesystem_fat.h"
+
+ TPtrC ptrFormatHelp=_L("Drive:[\\] [fat12|fat16|fat32] [spc:X] [rs:Y] [ft:Z] [/Q] [/S] [/E]\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 ");
+ TPtrC ptrMountHelp=_L("Drive:[\\] <fsy:X> <fs:Y> [pext:Z] [/S][/U][/F]\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 - mout drive as synchronous ");
+
+
+// lint -e40,e30
+const TShellCommand CShell::iCommand[ENoShellCommands]=
+ {
+// TShellCommand(_L("BLANK"),_L("Help"),_L("-?"),TShellCommand::EDSwitch,ShellFunction::BLANK),
+ 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),
+ TShellCommand(_L("CD"),_L("Change the current directory for a drive"),_L("[path] [/d]\n\n /d - Change drive"),TShellCommand::EDSwitch,ShellFunction::Cd),
+ TShellCommand(_L("CHKDEPS"),_L("Check the dependencies of an executable or a Dll (ARM only)"),_L("[Filename.EXE] or [Filename.DLL]"),0,ShellFunction::ChkDeps),
+ 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),
+ TShellCommand(_L("COPY"),_L("Copy one (or more) file(s)"),_L("source [destination]"),TShellCommand::ESSwitch,ShellFunction::Copy),
+ TShellCommand(_L("DEL"),_L("Delete one file"),_L("[drive:][path][filename]"),TShellCommand::ESSwitch,ShellFunction::Del),
+ 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),
+// 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),
+ TShellCommand(_L("FORMAT"),_L("Format a disk"),ptrFormatHelp,TShellCommand::EQSwitch|TShellCommand::ESSwitch|TShellCommand::EESwitch,ShellFunction::Format),
+ 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),
+ 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),
+ TShellCommand(_L("LABEL"),_L("Set or return the volume label"),_L("[newlabel]"),0,ShellFunction::VolumeLabel),
+ TShellCommand(_L("MD"),_L("Make a new directory"),_L("name"),0,ShellFunction::Md),
+ TShellCommand(_L("MOVE"),_L("Move files"),_L("name [destination]"),TShellCommand::ESSwitch,ShellFunction::Move),
+ TShellCommand(_L("PS"),_L("Display information about processes"),_L(""),0,ShellFunction::Ps),
+ TShellCommand(_L("RENAME"),_L("Rename a file"),_L("oldfilename newfilename"),TShellCommand::ESSwitch,ShellFunction::Rename),
+ TShellCommand(_L("RD"),_L("Delete one directory"),_L("[drive:][path]directoryname"),TShellCommand::ESSwitch,ShellFunction::Rd),
+ TShellCommand(_L("START"),_L("Run a program in a separate window"),_L("filename[.exe]"),0,ShellFunction::Start),
+ TShellCommand(_L("TIME"),_L("Display the system time"),_L(""),0,ShellFunction::Time),
+ 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),
+ 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),
+ 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),
+ TShellCommand(_L("VNAME"),_L("Check whether a filename is valid. Return any invalid character"),_L("[drive:][path]filename \n\n "),0,ShellFunction::ValidName),
+ TShellCommand(_L("LOCK"),_L("Lock a password-enabled media"),_L("drive-number cur-pswd new-pswd [/s]"), TShellCommand::ESSwitch, ShellFunction::Lock),
+ TShellCommand(_L("UNLOCK"),_L("Unlock a locked password-enabled media"),_L("drive-number cur-pswd [/s]"), TShellCommand::ESSwitch, ShellFunction::Unlock),
+ TShellCommand(_L("CLEAR"),_L("Clear password from password-enabled media"),_L("drive-number cur-pswd"), 0x00000000, ShellFunction::Clear),
+ TShellCommand(_L("SETSIZE"),_L("Set size of a file"),_L("[filename] size"),0,ShellFunction::SetSize),
+ TShellCommand(_L("DEBUGPORT"),_L("Set or get debug port"),_L("[port]"),0,ShellFunction::DebugPort),
+ TShellCommand(_L("PLUGIN"),_L("Manage Plugins"),_L("[name][/A][/R][/M][/D]"),TShellCommand::EASwitch|TShellCommand::ERSwitch|TShellCommand::EMSwitch|TShellCommand::EDSwitch,ShellFunction::Plugin),
+ 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),
+ TShellCommand(_L("SYSINFO"),_L("Print information about system features and status"),_L(""),0,ShellFunction::SysInfo),
+ TShellCommand(_L("MOUNT"),_L("Mount / dismount file system on specified drive"),ptrMountHelp,TShellCommand::EUSwitch|TShellCommand::ESSwitch|TShellCommand::EFSwitch,ShellFunction::MountFileSystem),
+ TShellCommand(_L("ECHO"),_L("Print out the command line to the console and standard debug port."),_L("[line to print out]"),0,ShellFunction::ConsoleEcho),
+ 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),
+
+ };
+
+
+LOCAL_C TInt pswd_DrvNbr(TDes &aPath, TInt &aDN);
+LOCAL_C TInt pswd_Password(TDes &aPath, TInt aPWNbr, TMediaPassword &aPW);
+
+_LIT(KLitNewLine,"\n");
+void CShell::NewLine()
+ {
+ TheConsole->Printf(KLitNewLine());
+ }
+
+//
+// Skip the hexadecimal prefix if present and return EHex. Return
+// EDecimal otherwise.
+//
+
+static TRadix ParseHexaPrefixIfAny(TLex& aLex)
+ {
+ _LIT(KPrefix, "0x");
+ if (aLex.Remainder().Length() > 2)
+ {
+ aLex.Mark();
+ aLex.Inc(2);
+ if (aLex.MarkedToken().MatchF(KPrefix) != KErrNotFound)
+ return EHex;
+ else
+ aLex.UnGetToMark();
+ }
+
+ return EDecimal;
+ }
+
+
+//
+// TWord class
+// Used to locate spaces in the command line, and return the next word
+//
+
+TWord::TWord(const TDesC& aDes)
+ : iSpace(0),iNextSpace(0)
+//
+// Constructor
+//
+ {
+ Init(aDes);
+ }
+
+
+void TWord::Init(const TDesC& aDes)
+//
+// Resets to the start of the buffer
+//
+ {
+ iDes.Set(aDes);
+ }
+
+TInt TWord::FindNextWord(TDes& aWord)
+//
+// Returns the next word from the buffer
+//
+ {
+ iSpace=aWord.Locate(' ');
+
+ if (iSpace==KErrNotFound) // No spaces in command line
+ {
+ if (aWord.Length()==0) // Command line has zero length:
+ return (KErrNotFound); // User just typed "command"
+ else
+ { // User typed "command aWord"
+ iRightString=aWord;
+ iNextWord=aWord;
+ return (0);
+ }
+ }
+
+ else if (iSpace<aWord.Length()) // Spaces may be command switches or part of the filename
+ {
+ iRightString=(aWord.Right((aWord.Length()-iSpace)-1));
+
+ iNextSpace=iRightString.Locate(' '); // Check for another space
+ if (iNextSpace==KErrNotFound) // No more spaces
+ {
+ iNextWord=iRightString;
+ return((iDes.Length())-(iRightString.Length()));// Position of the (last) word
+ }
+
+ if (iNextSpace<iRightString.Length()) // More spaces - assign iNextWord to be
+ { // the text in between the two spaces
+ iNextWord=(iRightString.Left(iNextSpace));
+ return ((iDes.Length())-(iRightString.Length()));// Position of the word
+ }
+
+ else
+ return(KErrNotFound);
+ }
+
+ else
+ return(KErrNotFound);
+ }
+
+//-------------------------------------------------------------------------
+
+
+TInt ShellFunction::Cd(TDes& aPath,TUint aSwitches)
+//
+// Change directory
+//
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ TBool drvNameOnly=aPath.Length()==2 && aPath[1]==KDriveDelimiter;
+ TBool dSwitchSet=aSwitches&TShellCommand::EDSwitch;
+ if (aPath.Length()==0 || (drvNameOnly && !dSwitchSet))
+ {
+ TInt drvNum=(aPath.Length() ? aPath[0] : TheShell->currentPath[0])-'A';
+ if (drvNum<0 || drvNum>=KMaxDrives)
+ return(KErrBadName);
+ CShell::TheConsole->Printf(_L("%S\n"),&TheShell->drivePaths[drvNum]);
+ return(KErrNone);
+ }
+ if (aPath.Find(_L("*"))!=KErrNotFound)
+ return(KErrBadName);
+ if (aPath[aPath.Length()-1]!=KPathDelimiter && !drvNameOnly)
+ aPath.Append(KPathDelimiter);
+ aPath.Append('*');
+ TChar drvLetter = aPath[0];
+ drvLetter.UpperCase();
+ aPath[0] = (TText) drvLetter;
+ TParse dirParse;
+ TInt r=GetFullPath(aPath,dirParse);
+ if (r!=KErrNone)
+ return(KErrBadName);
+ TPtrC fullName=dirParse.FullName();
+ RDir dir;
+ r=dir.Open(TheShell->TheFs,fullName,KEntryAttMaskSupported);
+ if (r!=KErrNone)
+ return(r);
+ dir.Close();
+ if (dSwitchSet || fullName[0]==TheShell->currentPath[0])
+ r=TheShell->TheFs.SetSessionPath(dirParse.DriveAndPath());
+ if (r==KErrNone)
+ TheShell->SetDrivePath(dirParse.DriveAndPath());
+ return(r);
+ }
+
+TInt ShellFunction::ChkDeps(TDes& aPath,TUint /*aSwitches*/)
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ aPath.Trim();
+ TBool appendedExe=EFalse;
+
+// Determine whether aPath is an executable or a Dll
+
+ TInt r=aPath.FindF(_L(".EXE"));
+ if (r==KErrNotFound)
+ {
+ r=aPath.FindF(_L(".DLL"));
+ if (r==KErrNotFound)// aPath does not include .exe or .dll extensions
+ {
+ aPath.Append(_L(".EXE")); // append a .exe extension
+ appendedExe=ETrue;
+ }
+ }
+
+ if (aPath.Length()>2 && aPath[1]==':' && aPath[2]!='\\')
+ {
+ TInt drive;
+ __ASSERT_ALWAYS(RFs::CharToDrive(aPath[0],drive)==KErrNone,User::Panic(_L("Invalid drive letter"),0));
+ TheShell->currentPath=TheShell->drivePaths[drive];
+ aPath.Delete(0,2);
+ aPath.Insert(0,TheShell->currentPath);
+ }
+ if (aPath.Length()>2 && aPath[1]!=':')
+ {
+ if (aPath[0]!='\\')
+ aPath.Insert(0,TheShell->currentPath);
+ else
+ aPath.Insert(0,TheShell->currentPath.Left(2));
+ }
+
+ RFile file;
+ r=file.Open(CShell::TheFs,aPath,EFileStream);
+ if (r!=KErrNone) // File could not be opened
+ {
+ if (appendedExe) // If .EXE was appended earlier
+ {
+// Remove .EXE and append .DLL instead. Try to open the file again
+// If this fails too, the user entered an invalid filename that is neither
+// an executable or a Dll
+ aPath.Delete(aPath.Length()-4,4);
+ appendedExe=EFalse;
+ aPath.Append(_L(".DLL")); // Try a .DLL extension
+ r=file.Open(CShell::TheFs,aPath,EFileStream);
+ if (r!=KErrNone) // Still could not open file
+ return(r); // Neither an executable or a Dll
+ // Runs to here if the file is opened -> .DLL extension appended
+ }
+ else
+ return(r); // User had typed in an incorrect filename with
+ // a .DLL or .EXE extension
+ }
+
+ file.Close();
+ CDllChecker check;
+ TRAPD(leaveCode,check.ConstructL());// Allocates 4 elements at a time
+ if (leaveCode!=KErrNone) // If function leaves
+ return(leaveCode); // return the leave code
+
+ TRAPD(result,check.GetImportDataL(aPath,NULL));
+ if (result==KErrGeneral)
+ {
+ CShell::TheConsole->Printf(_L(" %S has no import data\n"),&aPath);
+ return(KErrNone);
+ }
+ else
+ check.ListArray(); // Print out the results of DllCheck
+ return(KErrNone);
+ }
+
+//
+// Check disk for corruption
+//
+// Spec:
+//
+// ChkDsk DriveLetter:[\] [/S] [/F] [/U]
+//
+// /S : Starts a ScanDrive instead of CheckDisk
+// /F : Finalise given drive
+// /U : UnFinalise given drive
+
+TInt ShellFunction::ChkDsk(TDes& aPath,TUint aSwitches)
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ const TBool bRunScanDrv = aSwitches & TShellCommand::ESSwitch;
+ const TBool bFinaliseDrv = aSwitches & TShellCommand::EFSwitch;
+ const TBool bUnFinaliseDrv = aSwitches & TShellCommand::EUSwitch;
+
+ TInt nRes;
+ TInt drive=EDriveZ;
+
+ if(aPath.Length() < 1)
+ {
+ nRes = KErrArgument;
+ }
+ else
+ {
+ nRes=CShell::TheFs.CharToDrive(aPath[0], drive);
+ }
+
+ if (nRes != KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("Wrong drive specified!\n"));
+ return nRes;
+ }
+
+ if(bRunScanDrv)
+ {//-- run ScanDrive on the specified drive
+ CShell::TheConsole->Printf(_L("Starting ScanDrive...\n"));
+ nRes=TheShell->TheFs.ScanDrive(aPath);
+ if(nRes == KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("No errors.\n"));
+ }
+ }
+ else if(bFinaliseDrv)
+ {//-- finalise the drive
+ nRes = CShell::TheFs.FinaliseDrive(drive, RFs::EFinal_RW);
+ if(nRes != KErrNone)
+ return nRes;
+
+ CShell::TheConsole->Printf(_L("Drive %c: is finalised RW\n"), 'A'+drive);
+ }
+ else if(bUnFinaliseDrv)
+ {//-- Unfinalise the drive
+ nRes = CShell::TheFs.FinaliseDrive(drive, RFs::EForceUnfinalise);
+ if(nRes != KErrNone)
+ return nRes;
+
+ CShell::TheConsole->Printf(_L("Drive %c: is Unfinalised\n"), 'A'+drive);
+ }
+ else
+ {//-- run CheckDisk on the specified drive
+ nRes=TheShell->TheFs.CheckDisk(aPath);
+ if (nRes<0)
+ return(nRes);
+
+ switch(nRes)
+ {
+ case 0:
+ CShell::TheConsole->Printf(_L("Complete - no errors\n"));
+ break;
+ case 1:
+ CShell::TheConsole->Printf(_L("Error - File cluster chain contains a bad value (<2 or >maxCluster)\n"));
+ break;
+ case 2:
+ CShell::TheConsole->Printf(_L("Error - Two files are linked to the same cluster\n"));
+ break;
+ case 3:
+ CShell::TheConsole->Printf(_L("Error - Unallocated cluster contains a value != 0\n"));
+ break;
+ case 4:
+ CShell::TheConsole->Printf(_L("Error - Size of file != number of clusters in chain\n"));
+ break;
+ default:
+ CShell::TheConsole->Printf(_L("Undefined Error value\n"));
+ }
+ }
+ return nRes;
+ }
+
+TInt ShellFunction::Copy(TDes& aPath,TUint aSwitches)
+//
+// DOS spec:
+//
+// COPY [/A | /B] source [/A | /B] [+ source [/A | /B] [+ ...]] [destination] [/A | /B]] [/V] [/N]
+// source Specifies the file or files to be copied.
+// /A Indicates an ASCII text file.
+// /B Indicates a binary file.
+// destination Specifies the directory and/or filename for the new file(s).
+// /V Verifies that new files are written correctly.
+// /Y Supresses prompting to confirm you want to overwrite existing destination file
+// /N Uses short filename, if available, when copying a file with a non-8dot3 name.
+//
+// To append files, specify a single file for destination, but multiple files
+// for source (using wildcards or file1+file2+file3 format).
+//
+// My spec:
+//
+// COPY source [destination]
+// source Specifies the file or files to be copied to the current directory
+
+// Modified November 1997 to allow spaces in filenames
+
+ {
+ if (aPath.Length() == 0)
+ return KErrNotFound; // no source file
+
+ ShellFunction::StripQuotes(aPath);
+
+ TBuf<KShellMaxCommandLine> destination;
+ TBuf<KShellMaxCommandLine> tempPath;
+ TWord word(aPath);
+
+ TBool endOfCommandLine=EFalse;
+
+// Check if the word returned is a valid filename. If not, scan the next
+// word too in case the filename contains spaces. If, at the end of the
+// the line, the filename is not recognised, it is invalid. If there are no
+// spaces the user has not used the correct format for this command.
+
+ TInt r=word.FindNextWord(aPath);
+ do {
+ TParse dirPath;
+
+ if (r==0) // No destination was specified
+ {
+ // Work out the destination
+ tempPath.SetLength(0);
+ r=GetFullPath(tempPath,dirPath);
+ if (r!=KErrNone)
+ return(r);
+ destination=dirPath.FullName();
+ // Now get the path of the source
+ tempPath=aPath;
+ r=GetFullPath(tempPath,dirPath);
+ if (r!=KErrNone)
+ return(r);
+ endOfCommandLine=ETrue; // So we don't get stuck in an infinite loop
+ }
+ else
+ {
+ // Work out the destination
+ destination=aPath.Right(aPath.Length()-r);
+ if (!destination.Compare(_L(".")))
+ GetFullPath(destination,dirPath);
+ // Now get the path of the source
+ tempPath=aPath;
+ tempPath.SetLength(r);
+ r=GetFullPath(tempPath,dirPath);
+ if (r!=KErrNone)
+ return(r);
+ }
+
+ TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
+ TUint switches=(recursive) ? CFileMan::EOverWrite|CFileMan::ERecurse : CFileMan::EOverWrite;
+ r=CShell::TheFileMan->Copy(dirPath.FullName(),destination,switches);
+ if (r==KErrNone)
+ return(r); // Copy was successful
+
+ else // Not a valid filename - move one word along the command line
+ r=word.FindNextWord(word.iRightString);
+ } while ((r>=0)&&(!endOfCommandLine));
+
+ if (r<0) // Some error
+ return (r);
+ else // End of command line, user typed invalid line, return not found
+ return (KErrNotFound);
+ }
+
+
+TInt ShellFunction::VolumeLabel(TDes& aPath,TUint /*aSwitches*/)
+/**
+Sets or returns the default path
+
+@param aPath The volume label being set or returned
+*/
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ TVolumeInfo vol;
+ TInt drive;
+ TInt r=CShell::TheFs.CharToDrive(CShell::currentPath[0], drive);
+ if (r!=KErrNone)
+ return(r);
+ if (aPath.Length()==0)
+ {
+ r=CShell::TheFs.Volume(vol, drive);
+ if (r==KErrNone)
+ CShell::TheConsole->Printf(_L("Volume = %S\n"),&vol.iName);
+ return(r);
+ }
+ r=CShell::TheFs.SetVolumeLabel(aPath, drive);
+ return(r);
+ }
+
+TInt ShellFunction::Del(TDes& aPath,TUint aSwitches)
+ {
+ TParse filePath;
+ if (aPath.Length()==0)
+ return(KErrNone);
+
+ ShellFunction::StripQuotes(aPath);
+
+ GetFullPath(aPath,filePath);
+ TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
+ TUint switches=(recursive) ? CFileMan::ERecurse : 0;
+ TInt r=CShell::TheFileMan->Delete(filePath.FullName(),switches);
+ return(r);
+ }
+
+
+void ShellFunction::AlignTextIntoColumns(RPointerArray<HBufC>& aText)
+//function which tries to arrange text as a set of columns if console width greater then the longest string
+{
+ TInt ind=0;
+ if (aText.Count()<=0) return;
+ //detect the longest string
+ for (TInt i=0;i<aText.Count();i++)
+ if (aText[i]->Length()>aText[ind]->Length())
+ ind=i;
+ TInt max_string_length=aText[ind]->Length()+2;
+
+ //calculate how many columns fit into the screen
+ TInt number_of_columns=(CShell::TheConsole->ScreenSize().iWidth)/max_string_length;
+
+ //if we cannot fit more than one column into screen when we do nothing
+ if (number_of_columns<2) return;
+
+ //calculate column width
+ TInt column_width=CShell::TheConsole->ScreenSize().iWidth/number_of_columns;
+
+ TInt current_source_string=0;
+ TInt current_destination_string=0;
+
+ TInt count=aText.Count();
+ //join strings together into string which fits in a single line
+ while (current_source_string<count)
+ {
+ TPtr string= aText[current_destination_string++]->Des();
+ TInt to_skip=0;
+
+ for (TInt i=0;i<number_of_columns;i++)
+ {
+ if (current_source_string==count)
+ break;
+ //skip several characters to keep even distance between columns
+ for (TInt j=0;j<to_skip;j++)
+ string.Append(_L(" "));
+
+ if (i==0)
+ string=(*aText[current_source_string]);
+ else
+ string.Append(*aText[current_source_string]);
+ to_skip=column_width-aText[current_source_string]->Length();
+ current_source_string++;
+ }
+ }
+
+ //resize aText array to the new size
+
+ for (TInt j=aText.Count()-1;j>=current_destination_string;j--)
+ {
+ delete aText[j];
+ aText.Remove(j);
+ }
+
+}
+
+
+void ShellFunction::OutputContentsToConsole(RPointerArray<HBufC>& aText,TUint aSwitches)
+//outputs content of the buffer to console according to settings passed in aSwitches
+ {
+ if ((aText.Count()>0)&&((aSwitches&TShellCommand::EWSwitch)!=0))
+ AlignTextIntoColumns(aText);
+
+ for (TInt i=0;i<aText.Count();i++)
+ {
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),*aText[i]);
+ CShell::OutputStringToConsole(EFalse,_L("\n"));
+ delete aText[i];
+ }
+ //empty string array
+ aText.Reset();
+ }
+
+
+void ShellFunction::OutputDirContentL(CDir* aDirList,RPointerArray<HBufC>& aText,TUint aSwitches)
+//outputs content of a directory to console according to settings passed in aSwitches
+ {
+ TInt count=aDirList->Count();
+ TInt fileCount=0, dirCount=0, printCount=0;
+ TInt64 byteCount=0;
+
+ //compose an array of strings describing entries in the directory
+ for (TInt j=0;j<count;j++)
+ {
+ HBufC* buf=NULL;
+ TEntry entry=(*aDirList)[j];
+ TDateTime modTime=entry.iModified.DateTime();
+ if ((aSwitches&TShellCommand::EWSwitch)!=0)//if we are asked to output brief information about directory content
+ {
+ TInt length=(KMaxFileName>CShell::TheConsole->ScreenSize().iWidth)?KMaxFileName:CShell::TheConsole->ScreenSize().iWidth;
+ buf = HBufC::NewL(length);
+
+ CleanupStack::PushL(buf);
+ TPtr name=buf->Des();
+ name=entry.iName;
+
+ if (entry.IsDir())
+ {
+ dirCount++;
+ name.Insert(0,_L("["));
+ name.Append(']');
+ }
+ else
+ {
+ byteCount+=entry.FileSize();
+ fileCount++;
+ }
+ }
+ else//if we are asked to output full information about directory content
+ {
+ buf = HBufC::NewL(KMaxFileName+100);//reserve additional space for the creation time information
+ CleanupStack::PushL(buf);
+ TPtr name=buf->Des();
+ name=entry.iName;
+
+ if (entry.IsDir())
+ {
+ dirCount++;
+ name.Format(_L(" %- 26S <DIR> %+02d/%+02d/%- 4d %02d:%02d:%02d.%06d"),
+ &entry.iName,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
+ }
+ else
+ {
+ TInt64 entrySize = entry.FileSize();
+ byteCount+=entrySize;
+ fileCount++;
+ name.Format(_L(" %- 32S%+ 15Lu %+02d/%+02d/%- 4d %02d:%02d:%02d.%06d"),
+ &entry.iName,entrySize,modTime.Day()+1,modTime.Month()+1,modTime.Year(),modTime.Hour(),modTime.Minute(),modTime.Second(),modTime.MicroSecond());
+ }
+ }
+ User::LeaveIfError(aText.Append(buf ));
+ printCount++;
+ //print the contents if a screen size of data is available. This will prevent huge buffer allocation.
+ if(printCount == CShell::TheConsole->ScreenSize().iHeight)
+ {
+ OutputContentsToConsole(aText,aSwitches);
+ printCount=0;
+ }
+ CleanupStack::Pop();
+
+ }
+ OutputContentsToConsole(aText,aSwitches);
+
+ //output summary information
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L(" %d File%c\n"),fileCount,(fileCount==1)?' ':'s');
+ if (fileCount!=0)
+ {
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L(" %lu byte%c\n"),byteCount,(fileCount==1)?' ':'s');
+ }
+
+ TBuf<50> buf;// allocate string long enough for additional information(number of directories)
+ buf.Format(_L(" %d Director"),dirCount);
+ if (dirCount==1)
+ buf.AppendFormat(_L("y\n"));
+ else
+ buf.AppendFormat(_L("ies\n"));
+
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),buf);
+ }
+
+TInt ShellFunction::Dir(TDes& aPath,TUint aSwitches)
+//
+// Modified December 1997, to sort entries alphabetically
+//
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ RDir dir;
+ RFile64 file;
+ TParse dirParse;
+// Parses the given path to give a full path
+ GetFullPath(aPath,dirParse);
+// Sets aPath to a full path name
+ aPath=dirParse.FullName();
+ if (aPath[aPath.Length()-1]==KPathDelimiter)
+ aPath.Append('*');
+ else if (aPath.Locate(KMatchAny)==KErrNotFound && aPath.Locate(KMatchOne)==KErrNotFound && file.Open(TheShell->TheFs,aPath,KEntryAttMatchExclude|KEntryAttDir)!=KErrNone)
+ aPath.Append(_L("\\*"));
+ else file.Close();
+
+ TInt r=dir.Open(TheShell->TheFs,aPath,KEntryAttMaskSupported);
+ if (r!=KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("File or directory not found\n"));
+ return(KErrNone);
+ }
+
+ CDir* anEntryList;
+ r=TheShell->TheFs.GetDir(aPath,KEntryAttMaskSupported,ESortByName,anEntryList);
+ if (r!=KErrNone)
+ {
+ dir.Close();
+ return(r);
+ }
+ CleanupStack::PushL(anEntryList);
+
+ //Sets the new length of path to the position of the last path delimiter +1
+ aPath.SetLength(aPath.LocateReverse(KPathDelimiter)+1);
+ CShell::TheConsole->Printf(_L("Directory of %S\n"),&aPath);
+
+ //allocate array to be used as an output buffer
+ RPointerArray<HBufC>* text=new(ELeave) RPointerArray<HBufC>();
+ TRAPD(error,OutputDirContentL(anEntryList,*text,aSwitches));
+ //we are not interesed in the error code because we need empty the buffer in any case
+ for (TInt i=0;i<text->Count();i++)
+ delete (*text)[i];
+ delete text;
+ CleanupStack::PopAndDestroy(anEntryList);
+ dir.Close();
+ if (error )
+ return (error);
+ else
+ return(KErrNone);
+ };
+
+
+TInt ShellFunction::Edit(TDes& /*aPath*/,TUint /*aSwitches*/)
+//
+// Dummy, used by edlin (now retired)
+//
+ {
+ return(KErrNone);
+ }
+
+
+TInt ShellFunction::Attrib(TDes& aPath,TUint aSwitches)
+{
+ ShellFunction::StripQuotes(aPath);
+
+// Use TWord::NextWord(aPath) to find any spaces in the command line
+ TWord nextWord(aPath);
+ TInt r=nextWord.FindNextWord(aPath);
+ TInt signal=0;
+ const TPtrC settings[8]={(_L("+R")),(_L("-R")),(_L("+H")),(_L("-H")),(_L("+S")),(_L("-S")),(_L("+A")),(_L("-A"))};
+ TInt numberOfSettings=(sizeof(settings)/sizeof(*settings));
+
+ if (r==KErrNotFound) // User just typed ATTRIB
+ aPath.SetLength(aPath.Length());
+ else if (r==0) // User typed ATTRIB aWord
+ { // Check the word for a valid attributes
+ for (TInt index=0; index<numberOfSettings; index++)
+ {
+ signal=(nextWord.iNextWord).FindF(settings[index]);
+ if (signal!=KErrNotFound)
+ break;
+ }
+ if (signal==KErrNotFound) // No valid attributes settings
+ aPath.SetLength(aPath.Length());
+ else // Valid attributes settings
+ aPath.SetLength(r);
+ }
+ else // User typed ATTRIB aWord1 aWord2
+ { // Check the word for a valid attributes switch
+ while (r!=KErrNotFound)
+ {
+ for (TInt index=0; index<numberOfSettings; index++)
+ {
+ signal=(nextWord.iNextWord).FindF(settings[index]);
+ if (signal!=KErrNotFound)
+ break;
+ }
+ if (signal!=KErrNotFound) // Matched valid switches
+ {
+ // Divide up command line
+ // Include all settings (in case of "ATTRIB aWord +R +S")
+ nextWord.iRightString=aPath.Right(aPath.Length()-r);
+ aPath.SetLength(r);
+ break;
+ }
+ else // No valid switches found in word
+ r=nextWord.FindNextWord(nextWord.iRightString); // Check the next word
+ if (r==0) // Reached the end of a spaced command line without finding settings
+ {
+ nextWord.iRightString=aPath.Right(r);
+ break;
+ }
+ }
+ }
+
+ TParse dirParse;
+ GetFullPath(aPath,dirParse);
+ aPath=dirParse.FullName();
+
+ RFile64 file;
+ if (aPath[aPath.Length()-1]==KPathDelimiter)
+ aPath.Append('*');
+ else if( (aPath.Locate(KMatchAny)==KErrNotFound) && (aPath.Locate(KMatchOne)==KErrNotFound) )
+ {
+ TInt error=file.Open(TheShell->TheFs,aPath,KEntryAttMatchExclude|KEntryAttDir);
+ if (error!=KErrNone)
+ aPath.Append(_L("\\*"));//Path does not end in a valid file
+ else
+ file.Close();// Path ends in a valid file
+ }
+
+// Changes attributes settings (files only) if requested and if necessary
+ if (r!=KErrNotFound)
+ {
+ CDir* entryList;
+ r=CShell::TheFs.GetDir(aPath,KEntryAttMaskSupported,ESortByName,entryList);
+ if (r!=KErrNone)
+ return (r);
+ CleanupStack::PushL(entryList);
+ TInt entryCount=entryList->Count();
+// Save session path
+ TBuf<KShellMaxCommandLine> aSessionPath;
+ r=TheShell->TheFs.SessionPath(aSessionPath);
+// Temporarily assign session path to be the path requested
+// Use the heap as we're running out of stack space
+ HBufC* pTempPath=NULL;
+ TRAP(r,pTempPath=HBufC::NewL(aPath.Length()))
+ if (r!=KErrNone)
+ {
+ CleanupStack::PopAndDestroy(entryList);
+ return (r);
+ }
+ *pTempPath=aPath;
+ pTempPath->Des().SetLength(aPath.LocateReverse(KPathDelimiter)+1);
+ r=TheShell->TheFs.SetSessionPath(pTempPath->Des());
+ User::Free(pTempPath);
+
+// Looks clumsy, but necessary to change attributes of files in higher level directories
+ for (TInt i=0;i<entryCount;i++)
+ {
+ TEntry entry=(*entryList)[i];
+ if (!entry.IsDir())
+ {
+ for (TInt index=0; index<numberOfSettings; index++)
+ {
+ TInt attToSet=0;
+ TInt attToRemove=0;
+ signal=(nextWord.iRightString).FindF(settings[index]);
+ if (signal==KErrNotFound)
+ continue;
+ else
+ switch (index)
+ {
+ case 0:
+ attToSet|=KEntryAttReadOnly;
+ break;
+ case 1:
+ attToRemove|=KEntryAttReadOnly;
+ break;
+ case 2:
+ attToSet|=KEntryAttHidden;
+ break;
+ case 3:
+ attToRemove|=KEntryAttHidden;
+ break;
+ case 4:
+ attToSet|=KEntryAttSystem;
+ break;
+ case 5:
+ attToRemove|=KEntryAttSystem;
+ break;
+ case 6:
+ attToSet|=KEntryAttArchive;
+ break;
+ case 7:
+ attToRemove|=KEntryAttArchive;
+ break;
+ default: // Will never reach here
+ break;
+ }
+ r=TheShell->TheFs.SetAtt((entry.iName),attToSet,attToRemove);
+ continue;
+ }
+ }
+ else continue;
+ }
+// Set session path to previous setting
+ r=TheShell->TheFs.SetSessionPath(aSessionPath);
+ CleanupStack::PopAndDestroy(entryList);
+ }
+
+// Runs to here if no requested attributes changes:
+ CDir* alphaEntryList;
+ r=CShell::TheFs.GetDir(aPath,KEntryAttMaskSupported,ESortByName,alphaEntryList);
+ if (r!=KErrNone)
+ return (r);
+ TInt count=alphaEntryList->Count();
+
+ RDir dir;
+ r=dir.Open(TheShell->TheFs,aPath,KEntryAttMaskSupported);
+ if (r!=KErrNone)
+ {
+ delete alphaEntryList;
+ return(r);
+ }
+
+ aPath.SetLength(aPath.LocateReverse(KPathDelimiter)+1);
+
+
+ TEntry entry;
+ TUint fileCount=0;
+
+// Lists attributes settings (files only)
+ for (TInt j=0;j<count;j++)
+ {
+ entry=alphaEntryList->operator[](j);
+ if (!entry.IsDir())
+ {
+ TBuf<4> attrBuf=entry.IsReadOnly()?_L("R"):_L("");
+ if (entry.IsHidden())
+ attrBuf.Append('H');
+ if (entry.IsSystem())
+ attrBuf.Append('S');
+ if (entry.IsArchive())
+ attrBuf.Append('A');
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L(" %-10S %S%S\n"),&attrBuf, &aPath,&entry.iName);
+ fileCount++;
+ }
+ }
+
+ dir.Close();
+
+ if (fileCount==0)
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),_L("No files found in %S\n"),&aPath);
+
+ delete alphaEntryList;
+ return(KErrNone);
+ }
+
+
+
+
+
+//--------------------------------------------------------
+
+/**
+ Format TMediaType description.
+
+ @param aDrvInfo drive info structure
+ @param aPrintBuf buffer where the information will be printed to.
+*/
+void FormatDrvMediaTypeInfo(const TDriveInfo& aDrvInfo, TDes& aPrintBuf)
+ {
+ aPrintBuf.Format(_L("TMediaType:%d "),aDrvInfo.iType);
+
+ switch(aDrvInfo.iType)
+ {
+ case EMediaNotPresent: aPrintBuf.Append(_L("EMediaNotPresent")); break;
+ case EMediaUnknown: aPrintBuf.Append(_L("EMediaUnknown")); break;
+ case EMediaFloppy: aPrintBuf.Append(_L("EMediaFloppy")); break;
+ case EMediaHardDisk: aPrintBuf.Append(_L("EMediaHardDisk")); break;
+ case EMediaCdRom: aPrintBuf.Append(_L("EMediaCdRom")); break;
+ case EMediaRam: aPrintBuf.Append(_L("EMediaRam")); break;
+ case EMediaFlash: aPrintBuf.Append(_L("EMediaFlash")); break;
+ case EMediaRom: aPrintBuf.Append(_L("EMediaRom")); break;
+ case EMediaRemote: aPrintBuf.Append(_L("EMediaRemote")); break;
+ case EMediaNANDFlash: aPrintBuf.Append(_L("EMediaNANDFlash")); break;
+ case EMediaRotatingMedia: aPrintBuf.Append(_L("EMediaRotatingMedia"));break;
+
+ default: aPrintBuf.Append(_L("??? Unknown Type")); break;
+ };
+
+
+ aPrintBuf.Append(_L("\n"));
+ }
+
+//--------------------------------------------------------
+
+/**
+ Format DriveAtt description.
+
+ @param aDrvInfo drive info structure
+ @param aPrintBuf buffer where the information will be printed to.
+*/
+void FormatDriveAttInfo(const TDriveInfo& aDrvInfo, TDes& aPrintBuf)
+ {
+ aPrintBuf.Format(_L("DriveAtt:0x%x "),aDrvInfo.iDriveAtt);
+
+ if(aDrvInfo.iDriveAtt & KDriveAttLocal) aPrintBuf.Append(_L("KDriveAttLocal,"));
+ if(aDrvInfo.iDriveAtt & KDriveAttRom) aPrintBuf.Append(_L("KDriveAttRom,"));
+ if(aDrvInfo.iDriveAtt & KDriveAttRedirected) aPrintBuf.Append(_L("KDriveAttRedirected,"));
+ if(aDrvInfo.iDriveAtt & KDriveAttSubsted) aPrintBuf.Append(_L("KDriveAttSubsted,"));
+ if(aDrvInfo.iDriveAtt & KDriveAttInternal) aPrintBuf.Append(_L("KDriveAttInternal,"));
+ if(aDrvInfo.iDriveAtt & KDriveAttRemovable) aPrintBuf.Append(_L("KDriveAttRemovable"));
+
+ if(aDrvInfo.iDriveAtt & KDriveAttRemote) aPrintBuf.Append(_L("KDriveAttRemote"));
+ if(aDrvInfo.iDriveAtt & KDriveAttTransaction) aPrintBuf.Append(_L("KDriveAttTransaction"));
+
+ if(aDrvInfo.iDriveAtt & KDriveAttPageable) aPrintBuf.Append(_L("KDriveAttPageable"));
+ if(aDrvInfo.iDriveAtt & KDriveAttLogicallyRemovable) aPrintBuf.Append(_L("KDriveAttLogicallyRemovable"));
+ if(aDrvInfo.iDriveAtt & KDriveAttHidden) aPrintBuf.Append(_L("KDriveAttHidden"));
+
+ aPrintBuf.Append(_L("\n"));
+ }
+
+//--------------------------------------------------------
+
+/**
+ Format MediaAtt description.
+
+ @param aDrvInfo drive info structure
+ @param aPrintBuf buffer where the information will be printed to.
+*/
+void FormatMediaAttInfo(const TDriveInfo& aDrvInfo, TDes& aPrintBuf)
+ {
+ aPrintBuf.Format(_L("MediaAtt:0x%x "),aDrvInfo.iMediaAtt);
+
+ if(aDrvInfo.iMediaAtt & KMediaAttVariableSize) aPrintBuf.Append(_L("KMediaAttVariableSize,"));
+ if(aDrvInfo.iMediaAtt & KMediaAttDualDensity) aPrintBuf.Append(_L("KMediaAttDualDensity,"));
+ if(aDrvInfo.iMediaAtt & KMediaAttFormattable) aPrintBuf.Append(_L("KMediaAttFormattable,"));
+ if(aDrvInfo.iMediaAtt & KMediaAttWriteProtected) aPrintBuf.Append(_L("KMediaAttWriteProtected,"));
+ if(aDrvInfo.iMediaAtt & KMediaAttLockable) aPrintBuf.Append(_L("KMediaAttLockable,"));
+ if(aDrvInfo.iMediaAtt & KMediaAttLocked) aPrintBuf.Append(_L("KMediaAttLocked"));
+
+ if(aDrvInfo.iMediaAtt & KMediaAttHasPassword) aPrintBuf.Append(_L("KMediaAttHasPassword"));
+ if(aDrvInfo.iMediaAtt & KMediaAttReadWhileWrite) aPrintBuf.Append(_L("KMediaAttReadWhileWrite"));
+ if(aDrvInfo.iMediaAtt & KMediaAttDeleteNotify) aPrintBuf.Append(_L("KMediaAttDeleteNotify"));
+ if(aDrvInfo.iMediaAtt & KMediaAttPageable) aPrintBuf.Append(_L("KMediaAttPageable"));
+
+
+ aPrintBuf.Append(_L("\n"));
+ }
+
+//--------------------------------------------------------
+
+/**
+ Format TVolumeInfo description.
+
+ @param volInfo volume information
+ @param aPrintBuf buffer where the information will be printed to.
+*/
+void FormatVolInfo(const TVolumeInfo& volInfo , TDes& aPrintBuf)
+ {
+ aPrintBuf.Format(_L("VolSz:%ld Free:%ld\n"),volInfo.iSize, volInfo.iFree);
+ aPrintBuf.AppendFormat(_L("VolId:0x%x VolName:%S\n"),volInfo.iUniqueID, &volInfo.iName);
+ }
+
+//--------------------------------------------------------
+
+/** Bit flags that specify which information will be printed by PrintDrvInfo() */
+enum TPrintDrvInfoFlags
+{
+ EFSInfo = 0x01, //-- file system information
+ EFSInfoEx = 0x02, //-- extended file system information
+ EMediaTypeInfo = 0x04, //-- media type
+ EMediaAttInfo = 0x08, //-- media attributes etc.
+ EDrvAttInfo = 0x10, //-- drive attributes etc
+ EVolInfo = 0x20, //-- volume information
+
+ EAll = 0xFFFF
+};
+
+//-----------------------------------------------------------------------------------------------------------------------
+/**
+ Prints information about specified drive.
+
+ @param aFs file system object
+ @param aDrvNum drive number
+ @param apConsole pointer to the console to print information into
+ @param aFlags specifies which information to print out, @see TPrintDrvInfoFlags
+
+ @return standard error code
+*/
+TInt PrintDrvInfo(RFs& aFs, TInt aDrvNum, CConsoleBase* apConsole, TUint aFlags = EAll)
+ {
+ TInt nRes;
+ TDriveInfo driveInfo;
+ TVolumeInfo volInfo;
+ TBuf<256> Buf;
+
+ //-- get drive info
+ nRes = aFs.Drive(driveInfo, aDrvNum);
+ if(nRes != KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("Error: %d\n"), nRes);
+ return nRes; //-- can't get information about the drive
+ }
+
+
+ nRes = aFs.Volume(volInfo, aDrvNum);
+ const TBool bVolumeOK = (nRes == KErrNone);
+ if(!bVolumeOK)
+ {//-- can't get information about the volume. It might be just corrupt/unformatted
+ CShell::TheConsole->Printf(_L("Error getting volume info. code: %d\n"), nRes);
+ if(nRes == KErrCorrupt)
+ {
+ CShell::TheConsole->Printf(_L("The volume might be corrupted or not formatted.\n"));
+ }
+ }
+
+
+ //-- Print out information about file system installed
+ if(aFlags & EFSInfo)
+ {
+
+ apConsole->Printf(_L("\nDrive %c: number:%d\n"), 'A'+aDrvNum, aDrvNum);
+
+ //-- print the FS name
+ if(aFs.FileSystemName(Buf, aDrvNum) == KErrNone)
+ {
+ TFSName fsName;
+
+ nRes = aFs.FileSystemSubType(aDrvNum, fsName);
+ if(nRes == KErrNone && Buf.CompareF(fsName) !=KErrNone)
+ {
+ Buf.AppendFormat(_L(" (%S)"), &fsName);
+ }
+
+ //-- try to find out primary extension name if present
+ nRes = aFs.ExtensionName(fsName, aDrvNum, 0);
+ if(nRes == KErrNone)
+ {
+ Buf.AppendFormat(_L(" PExt:%S"), &fsName);
+ }
+
+
+ apConsole->Printf(_L("Mounted FS:%S\n"), &Buf);
+
+ //-- print out the list of supported file systems if there are more than 1
+ nRes = aFs.SupportedFileSystemName(fsName, aDrvNum, 0+1); //-- try to get 2nd child name
+ if(nRes == KErrNone)
+ {
+ Buf.Copy(_L("Supported FS: "));
+ for(TInt i=0; ;++i)
+ {
+ nRes = aFs.SupportedFileSystemName(fsName, aDrvNum, i);
+ if(nRes != KErrNone)
+ break;
+
+ Buf.AppendFormat(_L("%S, "), &fsName);
+ }
+
+ Buf.Append(_L("\n"));
+ apConsole->Printf(Buf);
+ }
+
+
+
+ //-- print out FileSystem volume finalisation info
+ if(bVolumeOK && (aFlags & EFSInfoEx))
+ {
+
+ TPckgBuf<TBool> boolPckg;
+ nRes = aFs.QueryVolumeInfoExt(aDrvNum, EIsDriveFinalised, boolPckg);
+ if(nRes == KErrNone)
+ {
+ if(boolPckg() >0)
+ apConsole->Printf(_L("Volume Finalised\n"));
+ else
+ apConsole->Printf(_L("Volume Not finalised\n"));
+ }
+ }
+ }
+ }//if(aFlags & EFSInfo)
+
+ //-- print media attributes
+ if(aFlags & EMediaTypeInfo)
+ {
+ FormatDrvMediaTypeInfo(driveInfo, Buf);
+ apConsole->Printf(Buf);
+
+ //apConsole->Printf(_L("BatteryState:%d\n"),driveInfo.iBattery);
+ }
+
+ //-- print drive attributes
+ if(aFlags & EDrvAttInfo)
+ {
+ FormatDriveAttInfo(driveInfo, Buf);
+ apConsole->Printf(Buf);
+ }
+
+ //-- print media attributes
+ if(aFlags & EMediaAttInfo)
+ {
+ FormatMediaAttInfo(driveInfo, Buf);
+ apConsole->Printf(Buf);
+ }
+
+
+ //-- print volume information
+ if(bVolumeOK && (aFlags & EVolInfo))
+ {
+ FormatVolInfo(volInfo, Buf);
+ apConsole->Printf(Buf);
+ }
+
+ return KErrNone;
+ }
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+/**
+ Extracts drive specifier from the given string that shall look like 'd:\' or 'd:'
+ And converts it to the drive number.
+
+ @param aStr a string with drive specifier
+ @return Drive number EDriveA..EDriveZ if drive letter is correct
+ negative value (KErrArgument) if drive specifier is incorrect
+*/
+TInt DoExtractDriveLetter(const TDesC& aStr)
+{
+ TLex lex(aStr);
+ TPtrC token;
+
+ lex.SkipSpace();
+ token.Set(lex.NextToken());
+
+ if(token.Length() < 2 || token.Length() > 3 || token[1] != ':')
+ return KErrArgument;
+
+ if(token.Length() == 3 && token[2] != '\\')
+ return KErrArgument;
+
+ const TChar chDrv = token[0];
+ const TInt drvNum = chDrv.GetUpperCase() - (TUint)'A'; //-- drive number
+
+ if(drvNum < 0 || drvNum > EDriveZ)
+ return KErrArgument;
+
+
+ //-- ensure that the only drive token specified
+ token.Set(lex.NextToken());
+ if(token.Length())
+ return KErrArgument;
+
+ return drvNum;
+
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+//
+// Print information about specified drive or about all present drives in the system.
+//
+// DRVINFO [DriveLetter:[\]] [/p]
+//
+// if drive letter is specified print out information about only this one.
+// /P : pause after each drive
+//
+TInt ShellFunction::DrvInfo(TDes& aArgs, TUint aSwitches)
+ {
+
+ TInt nDrv=-1;
+
+ const TInt KCmdLineLen = aArgs.Length();
+ if(KCmdLineLen == 0)
+ {//-- print information about all drives in the system
+ nDrv = -1;
+ }
+ else
+ {//-- print info about specified drive
+ nDrv = DoExtractDriveLetter(aArgs);
+ if(nDrv < 0)
+ {
+ CShell::TheConsole->Printf(_L("Invalid drive specifier!\n"));
+ return KErrNone;
+ }
+ }
+
+ TInt nRes;
+ TDriveList driveList;
+
+ //-- get drives list
+ nRes=TheShell->TheFs.DriveList(driveList);
+ if(nRes != KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("\nError: %d"), nRes);
+ return nRes;
+ }
+
+ if(nDrv >=0)
+ {//-- the drive is specified
+ if(!driveList[nDrv])
+ {
+ CShell::TheConsole->Printf(_L("Invalid drive specification\n"));
+ return KErrNone;
+ }
+
+ PrintDrvInfo(TheShell->TheFs, nDrv, CShell::TheConsole);
+ }
+ else
+ {//-- print information about all drives in the system
+ for (nDrv=0; nDrv < KMaxDrives; nDrv++)
+ {
+ if(!driveList[nDrv])
+ continue; //-- skip unexisting drive
+
+ PrintDrvInfo(TheShell->TheFs, nDrv, CShell::TheConsole);
+
+ if(aSwitches & TShellCommand::EPSwitch)
+ {//-- /p switch, pause after each drive
+ CShell::TheConsole->Printf(_L("\n--- press any key to continue or Esc to exit ---\n"));
+
+ TKeyCode key = CShell::TheConsole->Getch();
+ if (key==EKeyEscape)
+ break;
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("\n----------\n"));
+ }
+ }
+ }
+
+ return KErrNone;
+ }
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+/**
+ Just a helper method. Looks for a given pattern in the given string and returns the rest of the found token.
+ @param aSrc source string
+ @param aPattern pattern to look for
+ @param aToken if the aPattern is found in the string, will contain characters from the pattern end to the next space.
+
+ @return EFalse if the aPattern wasn't found in aSrc
+ ETrue otherwise and the rest of the token in aToken
+*/
+static TBool DoFindToken(const TDesC& aSrc, const TDesC& aPattern, TPtrC& aToken)
+{
+ TLex lex(aSrc);
+ TPtrC token;
+
+ for(;;)
+ {
+ lex.SkipSpace();
+ token.Set(lex.NextToken());
+
+ if(token.Length() == 0)
+ return EFalse;
+
+ if(token.FindF(aPattern) == 0)
+ {//-- found a requires patern, extract substring next to it
+ aToken.Set(token.Right(token.Length() - aPattern.Length()));
+ break;
+ }
+
+
+ }
+
+ return ETrue;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+TInt DoDismountFS(RFs& aFs, TInt aDrvNum)
+{
+ TInt nRes;
+ TBuf<40> fsName;
+
+ nRes = aFs.FileSystemName(fsName, aDrvNum);
+
+ if(nRes != KErrNone)
+ return KErrNotFound;//-- nothing to dismount
+
+ nRes = aFs.DismountFileSystem(fsName, aDrvNum);
+ if(nRes != KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("Can't dismount FS!\n"));
+ return nRes;
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("'%S' filesystem dismounted from drive %c:\n"), &fsName, 'A'+aDrvNum);
+ return KErrNone;
+ }
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+/**
+ Mount or dismount the file system on the specified drive.
+
+ MOUNT <DriveLetter:[\]> <FSY:xxx> <FS:yyy> [PEXT:zzz] [/S] [/U]
+
+ xxx is the *.fsy file system plugin name, like "elocal.fsy" or "elocal"
+ yyy is the file system name that the fsy module exports, like "FAT"
+ zzz is the optional parameter that specifies primary extension name
+
+ /u dismounts a filesystem on the specified drive; e.g. "mount d: /u"
+ /s for mounting FS specifies that the drive will be mounted as synchronous one.
+ /f for forcing mounting the FS; the previous one will be automatically dismounted
+*/
+TInt ShellFunction::MountFileSystem(TDes& aArgs, TUint aSwitches)
+{
+ ShellFunction::StripQuotes(aArgs);
+ aArgs.UpperCase();
+
+ TLex lex(aArgs);
+ TInt nRes;
+ TBuf<40> fsName;
+ RFs& fs = TheShell->TheFs;
+
+
+ //-- extract drive specification; this must be 1st token
+ _LIT(KErrInvalidDrive, "Invalid drive specifier\n");
+ lex.SkipSpace();
+ TPtrC token = lex.NextToken();
+
+ nRes = DoExtractDriveLetter(token);
+ if(nRes < 0)
+ {
+ CShell::TheConsole->Printf(KErrInvalidDrive);
+ return KErrArgument;
+ }
+
+ const TInt drvNum = nRes; //-- this is the drive number;
+
+ //-- check if we dismounting the FS (/U switch)
+ if(aSwitches & TShellCommand::EUSwitch)
+ {
+ nRes = DoDismountFS(fs, drvNum);
+
+ if(nRes == KErrNotFound)
+ {//-- nothing to dismount
+ CShell::TheConsole->Printf(_L("specified drive doesn't have FS mounted\n"));
+ return KErrNone;
+ }
+
+ return nRes;
+ }
+
+ //-- check if we need to forcedly dismount the existing FS (/F switch)
+ if(aSwitches & TShellCommand::EFSwitch)
+ {
+ nRes = DoDismountFS(fs, drvNum);
+
+ if(nRes != KErrNotFound && nRes !=KErrNone)
+ return nRes;
+ }
+
+ //-- request to mount the filesystem
+
+ //-- 1. check that the specified drive doesn't have already mounted file system
+ nRes = fs.FileSystemName(fsName, drvNum);
+ if(nRes == KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("specified drive already has '%S' file system mounted.\n"), &fsName);
+ CShell::TheConsole->Printf(_L("Dismount it first using '/U' switch or use '/F' switch.\n"));
+ return KErrNone;
+ }
+
+ //-- 2. check '/S' switch that specifies synchronous drive
+ const TBool bDrvSynch = aSwitches & TShellCommand::ESSwitch;
+
+ //-- 3. extract FSY name, file system name and optional primary extension name from the command line parameters
+ _LIT(KFSY_Param, "fsy:");
+ _LIT(KFsName_Param, "fs:");
+ _LIT(KPrimExt_Param, "pext:");
+
+ TPtrC ptrFSYName;
+ TPtrC ptrFSName;
+ TPtrC ptrPExtName;
+
+ if(!DoFindToken(aArgs, KFSY_Param, ptrFSYName))
+ {//-- FSY plugin name, like "elocal.fsy"
+ CShell::TheConsole->Printf(_L("'%S' parameter is required!\n"), &KFSY_Param);
+ return KErrNone;
+ }
+
+ if(!DoFindToken(aArgs, KFsName_Param, ptrFSName))
+ {//-- file system name, like "FAT"
+ CShell::TheConsole->Printf(_L("'%S' parameter is required!\n"), &KFsName_Param);
+ return KErrNone;
+ }
+
+ //-- note: it is possible to find out the file system name from loaded .fsy plugin.
+ //-- but it will require some coding. Probably later.
+
+
+ //-- optional primary extension name, like "something.fxt"
+ const TBool bPExtPresent = DoFindToken(aArgs, KPrimExt_Param, ptrPExtName);
+
+
+ //-- add new file system + optional extension
+ nRes = fs.AddFileSystem(ptrFSYName);
+ if(nRes != KErrNone && nRes != KErrAlreadyExists)
+ {
+ CShell::TheConsole->Printf(_L("Can't load '%S' file system plugin!\n"), &ptrFSYName);
+ return nRes;
+ }
+
+ if(bPExtPresent)
+ {
+ nRes = fs.AddExtension(ptrPExtName);
+ if(nRes != KErrNone && nRes != KErrAlreadyExists)
+ {
+ CShell::TheConsole->Printf(_L("Can't load '%S' FS extension plugin!\n"), &ptrPExtName);
+ return nRes;
+ }
+ }
+
+ //-- 4. mount new file system + optional primary extension
+ if(bPExtPresent)
+ {
+ nRes = fs.MountFileSystem(ptrFSName, ptrPExtName, drvNum, bDrvSynch);
+ }
+ else
+ {
+ nRes = fs.MountFileSystem(ptrFSName, drvNum, bDrvSynch);
+ }
+
+ CShell::TheConsole->Printf(_L("Mounting new file system...\n"));
+
+ if(nRes != KErrNone && nRes != KErrCorrupt)
+ {//-- KErrCorrupt might mean that the FS mounted OK onto the drive, but ve volume itself needs formatting
+ CShell::TheConsole->Printf(_L("Error mounting the filesystem! (%d)\n"), nRes);
+ return nRes;
+ }
+
+
+ PrintDrvInfo(fs, drvNum, CShell::TheConsole, EFSInfo | EVolInfo);
+
+ return KErrNone;
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+/**
+ Format the specified disk
+
+ FORMAT DriveLetter:[\] [fat12|fat16|fat32] [spc:X] [rs:Y] [ft:Z] [/Q] [/S] [/E]
+
+ fat12|fat16|fat32 : specifies explicitly FAT type to format drive with (if it is a FAT drive)
+ spc:X "X" specifies FAT sectors per cluster, e.g. spc:16
+ rs:Y "Y" specifies the number of reserved sectors (FAT FS only)
+ ft:Z "Z" specifies the number of FAT tables 1 or 2 (FAT FS only)
+ /Q : Quick Format
+ /S : Special Format
+ /E : Remove Password and Format
+
+*/
+
+TInt ShellFunction::Format(TDes& aPath, TUint aSwitches)
+ {
+ _LIT(KFormatStars,"********************");
+
+ using namespace FileSystem_FAT;
+
+ ShellFunction::StripQuotes(aPath);
+ aPath.UpperCase();
+
+ TUint fmtMode = ESpecialFormat;
+
+ //-- Format /Q - quick format
+ if (aSwitches & TShellCommand::EQSwitch)
+ fmtMode|=EQuickFormat;
+
+ //-- Format /S - special format
+ if (aSwitches & TShellCommand::ESSwitch)
+ fmtMode|=ESpecialFormat;
+
+ //-- Format /E - force erase
+ if (aSwitches & TShellCommand::EESwitch)
+ fmtMode|=EForceErase;
+
+ TInt fmtCnt = 0;
+ RFormat format;
+ TInt nRes;
+ TLex lex(aPath);
+
+ //-- 1st token - drive path; it shall look like "d:"
+ lex.SkipSpace();
+ TPtrC ptrPath = lex.NextToken();
+
+ const TInt nDrv = DoExtractDriveLetter(ptrPath);
+ if(nDrv < 0 )
+ {
+ CShell::TheConsole->Printf(_L("type \"format /?\" for help.\n"));
+ return KErrNone;
+ }
+
+ enum TFmtState
+ {
+ EFsNameNotSpecified,
+ EFormattingFAT,
+ EFormattingOtherFS
+ };
+
+
+ TFmtState formattingState = EFsNameNotSpecified;
+ TName fsName; //-- file system name
+
+
+ TVolFormatParamBuf volFmtParamBuf;
+ TVolFormatParam& volFmtParam = volFmtParamBuf();
+
+
+
+ //-- 2nd token - file system name.
+ //-- FAT fs is a special case, because it has subtypes; FAT FS name can be: FAT, FAT12, FAT16, FAT32
+ //-- everything else is considered as another file system name
+ lex.SkipSpace();
+ TPtrC ptrFsName = lex.NextToken();
+ TFatSubType fatSubType = ENotSpecified;
+
+ if(ptrFsName.Length() > 0)
+ {//-- there is a 2nd token, though it is not guaranteed to be the FS name
+ formattingState = EFormattingOtherFS;
+
+ if(ptrFsName.FindF(KFileSystemName_FAT) == 0)
+ {//-- it looks like "FATxx"
+ fsName.Copy(KFileSystemName_FAT);
+
+ if(ptrFsName.CompareF(KFileSystemName_FAT) == 0)
+ fatSubType = ENotSpecified; //-- generic "FAT", no subtype
+ else if(ptrFsName.CompareF(KFSSubType_FAT12) == 0)
+ fatSubType = EFat12;
+ else if(ptrFsName.CompareF(KFSSubType_FAT16) == 0)
+ fatSubType = EFat16;
+ else if(ptrFsName.CompareF(KFSSubType_FAT32) == 0)
+ fatSubType = EFat32;
+ else
+ fsName.Copy(ptrFsName); //-- none of the FAT types, probably some weird FS name.
+ }
+ else
+ {
+ fsName.Copy(ptrFsName);
+ }
+ }
+
+ if(fsName == KFileSystemName_FAT)
+ formattingState = EFormattingFAT;
+
+ volFmtParam.Init();
+
+ if(formattingState != EFsNameNotSpecified)
+ volFmtParam.SetFileSystemName(fsName);
+
+ //-- process formatting parameters if they are present
+
+ _LIT(KTok_SPC, "spc:"); //-- "sectors per cluster"; valid for: FAT, exFAT
+ _LIT(KTok_RsvdSect, "rs:"); //-- "reserved sectors" ; valid for: FAT
+ _LIT(KTok_NumFATs, "ft:"); //-- "number of FATs" ; valid for: FAT, exFAT
+ _LIT(KFsNameExFat, "exfat");
+
+ TPtrC token;
+ TPtrC ptrParams = lex.Remainder();
+ TLex lexParam;
+ TInt nVal;
+
+
+ //-- if we formatting FAT, process FAT-specific formatting parameters
+ if(formattingState == EFormattingFAT)
+ {
+ //-- Changing base class via derived class interface is OK here, all derived classes has the same layout and size as TVolFormatParam
+ TVolFormatParam_FAT& volFmtParamFAT = (TVolFormatParam_FAT&)volFmtParam;
+
+ volFmtParamFAT.Init();
+
+ //-- FAT sub type
+ if(fatSubType != ENotSpecified)
+ volFmtParamFAT.SetFatSubType(fatSubType);
+
+ //-- process "Sectors per cluster" token
+ if(DoFindToken(ptrParams, KTok_SPC, token))
+ {
+ lexParam.Assign(token);
+ lexParam.SkipSpace();
+ nRes = lexParam.Val(nVal);
+ if(nRes == KErrNone)
+ {
+ volFmtParamFAT.SetSectPerCluster(nVal);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Invalid SectorsPerCluster value!\n"));
+ return KErrNone;
+ }
+ }
+
+ //-- process "reserved sectors" token
+ if(DoFindToken(ptrParams, KTok_RsvdSect, token))
+ {
+ lexParam.Assign(token);
+ lexParam.SkipSpace();
+ nRes = lexParam.Val(nVal);
+ if(nRes == KErrNone && nVal >0 )
+ {
+ volFmtParamFAT.SetReservedSectors(nVal);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Invalid Reserved Sectors value!\n"));
+ return KErrNone;
+ }
+ }
+
+ //-- process "FAT tables" token
+ if(DoFindToken(ptrParams, KTok_NumFATs, token))
+ {
+ lexParam.Assign(token);
+ lexParam.SkipSpace();
+ nRes = lexParam.Val(nVal);
+ if(nRes == KErrNone && nVal >= 1 && nVal <= 2)
+ {
+ volFmtParamFAT.SetNumFATs(nVal);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Invalid FAT tables number value!\n"));
+ return KErrNone;
+ }
+ }
+
+ }//if(formattingState == EFormattingFAT)
+ else if(formattingState == EFormattingOtherFS && fsName.CompareF(KFsNameExFat)==0)
+ {//-- this is actually a h***k. exFAT exported public header file with specific data structures might not be available at all.
+
+ //-- this is more serious hack. The parameters layout (SPC & NumFatTables) in the structure is the same for FAT and exFAT
+ //-- use TVolFormatParam_FAT because this code doesn't know about TVolFormatParam_exFAT
+ TVolFormatParam_FAT& volFmtParamFAT = (TVolFormatParam_FAT&)volFmtParam;
+
+ //-- process "Sectors per cluster" token
+ if(DoFindToken(ptrParams, KTok_SPC, token))
+ {
+ lexParam.Assign(token);
+ lexParam.SkipSpace();
+ nRes = lexParam.Val(nVal);
+ if(nRes == KErrNone)
+ {
+ volFmtParamFAT.SetSectPerCluster(nVal);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Invalid SectorsPerCluster value!\n"));
+ return KErrNone;
+ }
+ }
+
+ //-- process "FAT tables" token
+ if(DoFindToken(ptrParams, KTok_NumFATs, token))
+ {
+ lexParam.Assign(token);
+ lexParam.SkipSpace();
+ nRes = lexParam.Val(nVal);
+ if(nRes == KErrNone && nVal >= 1 && nVal <= 2)
+ {
+ volFmtParamFAT.SetNumFATs(nVal);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Invalid FAT tables number value!\n"));
+ return KErrNone;
+ }
+ }
+
+ }
+
+
+ //-------- actual formatting
+ if(formattingState == EFsNameNotSpecified)
+ {
+ nRes = format.Open(TheShell->TheFs, ptrPath, fmtMode, fmtCnt);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("The new file system is:%S\n"), &fsName);
+ nRes = format.Open(TheShell->TheFs, ptrPath, fmtMode, fmtCnt, volFmtParamBuf);
+ }
+
+ if(nRes == KErrNone)
+ {
+ while(fmtCnt && nRes == KErrNone)
+ {
+ TInt length=(104-fmtCnt)/5;
+ length=Min(length,KFormatStars().Length());
+ TPtrC stars=KFormatStars().Left(length);
+ CShell::TheConsole->Printf(_L("\r%S"),&stars);
+ nRes=format.Next(fmtCnt);
+ }
+
+ format.Close();
+
+ if(nRes == KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("\r%S"),&KFormatStars);
+ CShell::NewLine();
+ }
+
+ }
+
+
+ //-- format errors processing
+ if(nRes != KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("Format failed.\n"));
+ }
+
+ switch(nRes)
+ {
+ case KErrNone:
+ CShell::TheConsole->Printf(_L("Format complete.\n"));
+ break;
+
+
+ case KErrArgument: //-- FORMAT has rejected specified parameters
+ CShell::TheConsole->Printf(_L("Possible reason: Invalid combination of formatting parameters.\n"));
+ nRes = KErrNone;
+ break;
+
+ case KErrNotSupported: //-- trying to format SD card with parameters or not supported FS name specified
+ CShell::TheConsole->Printf(_L("Possible reasons: media does not support special formatting or specified file system is not supported\n"));
+ nRes = KErrNone;
+ break;
+
+ case KErrNotFound: //-- possible reason: unrecognisable media and automounter FS + formatting without specifying the FS name
+ CShell::TheConsole->Printf(_L("Possible reason: Unable to chose appropriate file system (not specified)\n"));
+ nRes = KErrNone;
+ break;
+
+
+ default:
+ break;
+ };
+
+
+ return nRes;
+ }
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+TInt ShellFunction::Hexdump(TDes& aPath,TUint aSwitches)
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ ParsePath(aPath);
+ RFile file;
+ TInt r=file.Open(TheShell->TheFs,aPath,EFileStream);
+ if (r!=KErrNone)
+ return(r);
+
+ TInt offset=0;
+ for (;;)
+ {
+ const TInt KLineLength = 16;
+
+ TBuf8<KLineLength> line;
+ r=file.Read(line);
+ if (r != KErrNone || line.Length() == 0)
+ break;
+
+ TBuf<KLineLength*3+2> hexaRep;
+ TBuf<KLineLength> asciiRep;
+ for (TInt i=0; i<KLineLength; i++)
+ {
+ if (i == KLineLength/2)
+ {
+ hexaRep.Append(' ');
+ hexaRep.Append(i<line.Length() ? '|' : ' ');
+ }
+
+ hexaRep.Append(' ');
+
+ if (i<line.Length())
+ {
+ hexaRep.AppendNumFixedWidth(line[i], EHex, 2);
+ asciiRep.Append(TChar(line[i]).IsPrint() ? line[i] : '.');
+ }
+ else
+ hexaRep.AppendFill(' ', 2);
+ }
+
+ _LIT(KPrompt , " Hit escape to quit hexdump or any other key to continue\n");
+ _LIT(KLineFmt, " %+07x0:%S %S\n");
+ TKeyCode key=CShell::OutputStringToConsole(KPrompt ,(aSwitches&TShellCommand::EPSwitch)!=0,KLineFmt, offset++,&hexaRep, &asciiRep);
+
+ if (key==EKeyEscape)
+ break;
+ }
+
+ if (r == KErrNone)
+ CShell::NewLine();
+
+ file.Close();
+ return r;
+ }
+
+/**
+ Create a file. The file can be empty or filled with random data.
+ The maximal file size depends on the file system of the drive.
+
+ Gobble <file name> <aaaa|0xbbbb> [/E]
+
+ aaaa file size decimal
+ bbbb file size hexadecimal, shall be prefixed with '0x'
+
+ /e for creating an empty file, do not fill it with data
+*/
+TInt ShellFunction::Gobble(TDes& aPath,TUint aSwitches)
+ {
+ ShellFunction::StripQuotes(aPath);
+
+ TInt fileNameLen=aPath.LocateReverse(' ');
+ if (fileNameLen==KErrNotFound) // No spaces implies no filelength specified
+ {
+ CShell::TheConsole->Printf(_L("Please specify a file name and a file length\n"));
+ return (KErrNone);
+ }
+
+ TInt fileLength=(aPath.Length()-fileNameLen);
+ if (fileLength>16)
+ return (KErrTooBig); // Too many digits - too large!
+ TBuf<16> rightString=aPath.Right(fileLength);
+ aPath.SetLength(fileNameLen);
+
+ TLex size(rightString);
+ size.SkipSpace();
+ TRadix radix=ParseHexaPrefixIfAny(size);
+
+ TInt64 fileSize;
+ TInt r=size.Val(fileSize,radix);
+ if (r!=KErrNone || ! size.Eos())
+ {
+ CShell::TheConsole->Printf(_L("Please specify a file length\n"));
+ return (KErrNone);
+ }
+
+ if (aPath.Length()==0)
+ aPath=_L("GOBBLE.DAT");
+
+ TParse fileName;
+ GetFullPath(aPath,fileName);
+ RFile64 file;
+
+ const TInt KBufSize=65536; //-- buffer size for writing data
+ const TUint32 K1Megabyte = 1<<20; //-- 1M, 1048576
+ TInt64 cntBytes = 0;
+ TUint32 cntMegaBytes =0;
+
+ //-- allocate buffer for data
+ RBuf8 buf;
+ r = buf.CreateMax(KBufSize);
+ if(r != KErrNone)
+ return r;
+
+ //-- initialize buffer with random rubbish
+ //Mem::Fill((void*)buf.Ptr(),KBufSize,0xa3);
+ {
+ TInt64 rndSeed = Math::Random();
+ for(TInt i=0; i<KBufSize; ++i)
+ {
+ buf[i] = (TUint8)Math::Rand(rndSeed);
+ }
+ }
+
+
+ TInt64 rem = fileSize;
+ TTime startTime;
+ TTime endTime;
+ TTimeIntervalSeconds timeTaken;
+
+ startTime.UniversalTime(); //-- take start time
+
+ r=file.Create(CShell::TheFs,fileName.FullName(),EFileRead|EFileWrite);
+ if(r != KErrNone)
+ goto fail;
+
+ //-- this can make write faster on rugged fat.
+ if(aSwitches&TShellCommand::EESwitch)
+ {//-- /e switch is specified, create an empty file without writing data
+ CShell::TheConsole->Printf(_L("Creating an empty file, size:%LD bytes\n"), fileSize);
+ }
+
+ r=file.SetSize(fileSize);
+ if(r != KErrNone)
+ goto fail;
+
+
+ if(!(aSwitches&TShellCommand::EESwitch))
+ {//-- fill created file with randomn data
+
+ while(rem)
+ {
+ const TInt s=(TInt)Min((TInt64)KBufSize, rem);
+
+ r=file.Write(buf, s);
+ if(r!=KErrNone)
+ goto fail;
+
+ rem-=s;
+
+ //-- print out number of megabytes written
+ cntBytes+=s;
+ if(cntBytes > 0 && (cntBytes & (K1Megabyte-1))==0)
+ {
+ ++cntMegaBytes;
+ CShell::TheConsole->Printf(_L("%u MB written.\n"),cntMegaBytes);
+ }
+ }//while(rem)
+
+ }
+
+ file.Close();
+ endTime.UniversalTime(); //-- take end time
+ buf.Close();
+
+ endTime.SecondsFrom(startTime, timeTaken);
+
+ CShell::TheConsole->Printf(_L("Total bytes written:%LD\n"), cntBytes);
+ CShell::TheConsole->Printf(_L("Time taken:%d Sec.\n"), timeTaken.Int());
+
+ return r;
+
+ //-- failure.
+ fail:
+ file.Close();
+ buf.Close();
+ if(r!= KErrAlreadyExists) //this is to ensure that an existing file does not get deleted
+ CShell::TheFs.Delete(fileName.FullName());
+
+ CShell::TheConsole->Printf(_L("Error - could not create file, code:%d\n"), r);
+
+ return r;
+ }
+
+TInt ShellFunction::Md(TDes& aPath,TUint /*aSwitches*/)
+ {
+ if (aPath.Length()==0)
+ return(KErrBadName);
+
+ ShellFunction::StripQuotes(aPath);
+
+ if (aPath[aPath.Length()-1]!=KPathDelimiter)
+ aPath.Append(KPathDelimiter);
+
+ TParse dirPath;
+ TInt r = GetFullPath(aPath,dirPath);
+ if(r!=KErrNone)
+ {
+ return(r);
+ }
+ return(TheShell->TheFs.MkDir(dirPath.FullName()));
+ }
+
+TInt ShellFunction::Move(TDes& aPath,TUint aSwitches)
+ {
+
+// Modified to add more helpful error messages and allow spaced filenames
+ ShellFunction::StripQuotes(aPath);
+
+ TBuf<KShellMaxCommandLine> newName;
+ TBuf<KShellMaxCommandLine> tempPath=aPath;
+ RFile64 file;
+ TWord word(aPath);
+
+ TInt r=word.FindNextWord(aPath);
+// Check if the word returned is a valid filename. If not, scan the next
+// word too in case the filename contains spaces. If, at the end of the
+// the line, the filename is not recognised, it is invalid. If there are no
+// spaces the user has not used the correct format for this command.
+
+ while (r>0)
+ {
+ newName=aPath.Right(aPath.Length()-r);
+ tempPath.SetLength(r);
+ TParse oldName;
+ TInt result=GetFullPath(tempPath,oldName);
+ if (result!=KErrNone)
+ return(r);
+
+ TBool validFileOrDir = EFalse;
+
+ result=file.Open(TheShell->TheFs,tempPath,KEntryAttMatchExclude|KEntryAttDir);
+ if (result==KErrNone) // A valid filename
+ {
+ file.Close();
+ validFileOrDir = ETrue;
+ }
+ else // Not a valid filename - move one word along the command line
+ {
+ // Not a valid filename - Could be a directory...
+ RDir directory;
+ result=directory.Open(TheShell->TheFs,tempPath,KEntryAttMatchExclusive|KEntryAttDir);
+ if (result == KErrNone)
+ {
+ directory.Close();
+ validFileOrDir = ETrue;
+ }
+ }
+
+ if(validFileOrDir)
+ {
+ TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
+ TUint switches=(recursive) ? CFileMan::EOverWrite|CFileMan::ERecurse : CFileMan::EOverWrite;
+ r=CShell::TheFileMan->Move(oldName.FullName(),newName,switches);
+ if (r==KErrAccessDenied)
+ {
+ CShell::TheConsole->Printf(_L("Access denied - cannot move %S\n"),&tempPath);
+ CShell::TheConsole->Printf(_L("To move %Sinto directory %S append \\ to the full destination\n"),&tempPath,&newName);
+ return (KErrNone);
+ }
+ return(r);
+ }
+
+ r=word.FindNextWord(word.iRightString);
+ }
+ if (r<0) // r = some error code
+ return (r); // Error in filename or destination
+ else // r = 0
+ return (KErrNotFound);
+ }
+
+TInt GetChunkInfo(TAny* aPtr)
+ {
+
+ TFindChunk findHb;
+ TFullName* namePtr=(TFullName*)aPtr;
+ findHb.Find(*namePtr);
+ TFullName aFN;
+ findHb.Next(aFN);
+ RChunk c;
+ TInt r=c.Open(findHb);
+ if(r==KErrPermissionDenied)
+ {
+ CShell::TheConsole->Printf(_L("...Chunk is protected. No info available.\n"));
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("...Size %dk MaxSize %dk Base 0x%x\n"),c.Size()/1024,c.MaxSize()/1024,c.Base());
+ c.Close();
+ }
+/*
+#if defined (__WINS__)
+ c.Close();
+#else
+ if (aFN.Match(_L("*ESHELL*"))<0)
+ c.Close();
+#endif
+*/
+ return r;
+ };
+
+TInt GetThreadInfo(TAny* aPtr)
+// New function added by WR, November 1997
+ {
+ TBuf<80> detail;
+ TFindThread* findHb = (TFindThread*)aPtr;
+ RThread t;
+ TInt err = t.Open(*findHb);
+ if (err != KErrNone)
+ {
+ detail.Format(_L("... can't open thread, err=%d\n"), err);
+ CShell::TheConsole->Printf(detail);
+ return KErrNone;
+ }
+
+ TExitType exit = t.ExitType();
+ TBuf<KMaxExitCategoryName> exitCat=t.ExitCategory();
+ TThreadId threadId = t.Id();
+ TUint id = *(TUint*)&threadId;
+ RProcess proc;
+ TInt pid = t.Process(proc);
+ if (pid==KErrNone)
+ {
+ TProcessId procId = proc.Id();
+ pid = *(TInt*)&procId;
+ proc.Close();
+ }
+
+ switch (exit)
+ {
+ case EExitPending:
+ detail.Format(_L("... ID %d (Proc %d), running\n"), id, pid);
+ break;
+ case EExitPanic:
+ // lint -e50
+ detail.Format(_L("... ID %d (Proc %d), panic \"%S\" %d\n"), id, pid,
+ &exitCat, t.ExitReason());
+ break;
+ case EExitKill:
+ detail.Format(_L("... ID %d (Proc %d), killed %d\n"), id, pid, t.ExitReason());
+ break;
+ case EExitTerminate:
+ detail.Format(_L("... ID %d (Proc %d), terminated %d\n"), id, pid, t.ExitReason());
+ break;
+ default:
+ detail.Format(_L("... ID %d (Proc %d), ?exit type %d?\n"), id, pid, exit);
+ break;
+ }
+ t.Close();
+ CShell::TheConsole->Printf(detail);
+ return KErrNone;
+ };
+// End of modification
+
+// Class for showing information about processes
+class TShowProcInfo
+ {
+public:
+ TInt DisplayHelp();
+ TInt DisplayMessage(const TFullName& aName);
+ TInt DisplayCmdUnknown();
+ TInt GetAll(const TDes& aName);
+ TInt GetProcesses(const TDes& aName);
+ TInt GetThreads(const TDes& aName);
+ TInt GetChunks(const TDes& aName);
+ TInt GetServers(const TDes& aName);
+// TInt GetSessions(const TDes& aName);
+ TInt GetLibraries(const TDes& aName);
+// TInt GetLogicalChannels(const TDes& aName);
+ TInt GetLogicalDevices(const TDes& aName);
+ TInt GetPhysicalDevices(const TDes& aName);
+ TInt GetSemaphores(const TDes& aName);
+ TInt GetMutexes(const TDes& aName);
+private:
+ void DisplayHelpLine(const TDesC& aCommand, const TDesC& aDescription);
+ TInt Prepare(const TFullName& aName);
+ TInt Prepare(const TFullName& aName,TCallBack& aCallBack);
+ TInt Display(TFullName& aName);
+ TFullName iPrevName;
+ TCallBack iCallBack;
+ TBool useCallBack;
+ };
+
+TInt TShowProcInfo::DisplayHelp()
+ {
+
+ DisplayHelpLine(_L("H or ?"),_L("Show Help"));
+ DisplayHelpLine(_L("Q"),_L("Quit Process Status Mode"));
+ DisplayHelpLine(_L("X<name>"),_L("Switch to a particular Process domain"));
+ DisplayHelpLine(_L("X"),_L("Go Back to standard Process Status Mode"));
+ DisplayHelpLine(_L("A"),_L("Display all container objects"));
+ DisplayHelpLine(_L("P"),_L("List all Processes (irrespective of current domain)"));
+ DisplayHelpLine(_L("T"),_L("List Threads"));
+ DisplayHelpLine(_L("C"),_L("List Chunks, their sizes, maximum sizes and addresses"));
+ DisplayHelpLine(_L("S"),_L("List Servers"));
+// DisplayHelpLine(_L("I"),_L("List Sessions"));
+ DisplayHelpLine(_L("L"),_L("List Libraries"));
+// DisplayHelpLine(_L("G"),_L("List Logical Channels"));
+ DisplayHelpLine(_L("V"),_L("List Logical Devices"));
+ DisplayHelpLine(_L("D"),_L("List Physical Devices"));
+ DisplayHelpLine(_L("E"),_L("List Semaphores"));
+ DisplayHelpLine(_L("M"),_L("List Mutexes"));
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::DisplayMessage(const TFullName& aMessage)
+ {
+ CShell::OutputStringToConsole(ETrue,aMessage);
+ CShell::NewLine();
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::DisplayCmdUnknown()
+ {
+ CShell::OutputStringToConsole(ETrue,_L("Not supported\n"));
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetAll(const TDes& aName)
+ {
+
+ GetProcesses(aName);
+ GetThreads(aName);
+ GetChunks(aName);
+ GetServers(aName);
+// GetSessions(aName);
+ GetLibraries(aName);
+// GetLogicalChannels(aName);
+ GetLogicalDevices(aName);
+ GetPhysicalDevices(aName);
+ GetSemaphores(aName);
+ GetMutexes(aName);
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetProcesses(const TDes& aName)
+ {
+
+ TFindProcess findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("PROCESSES"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetThreads(const TDes& aName)
+ {
+ TInt threads=0;
+ TFindThread findHb;
+ findHb.Find(aName);
+ TFullName name;
+ TAny* findPtr=(TAny*)&findHb;
+
+// Modified by WR, November 1997
+ TCallBack threadCallBack(GetThreadInfo,findPtr);
+ Prepare(_L("THREADS"),threadCallBack);
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ threads += 1;
+ }
+ if (threads==0)
+ {
+ TFullName message;
+ message.Format(_L("? No threads called %S"), &aName);
+ DisplayMessage(message);
+ }
+ return KErrNone;
+// End of modification
+ }
+
+
+TInt TShowProcInfo::GetChunks(const TDes& aName)
+ {
+
+ TFindChunk findHb;
+ findHb.Find(aName);
+ TFullName name;
+ TAny* namePtr=(TAny*)&name;
+ TCallBack chunkCallBack(GetChunkInfo,namePtr);
+ Prepare(_L("CHUNKS & SIZES"),chunkCallBack);
+ TInt totalChunkSize=0;
+ TInt protectedChunks = 0;
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ RChunk c;
+ TInt r=c.Open(findHb);
+ if(r!=KErrNone)
+ ++protectedChunks;
+ else
+ {
+ totalChunkSize+=c.Size()/1024;
+ c.Close();
+ }
+/*
+#if defined(__WINS__)
+ c.Close();
+#else
+ if (name.Match(_L("*ESHELL*"))<0)
+ c.Close();
+#endif
+*/
+ }
+ CShell::OutputStringToConsole(ETrue,_L(" Total Chunk Size = %dk\n"),totalChunkSize);
+ if(protectedChunks)
+ CShell::OutputStringToConsole(ETrue,_L(" %d Protected chunks not counted\n"),protectedChunks);
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetServers(const TDes& aName)
+ {
+
+ TFindServer findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("SERVERS"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+
+/* TInt TShowProcInfo::GetSessions(const TDes& aName)
+ {
+
+ TFindSession findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("SESSIONS"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+*/
+TInt TShowProcInfo::GetLibraries(const TDes& aName)
+ {
+
+ TFindLibrary findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("LIBRARIES"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+/*
+TInt TShowProcInfo::GetLogicalChannels(const TDes& aName)
+ {
+
+ TFindLogicalChannel findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("LOGICAL CHANNELS"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+*/
+
+TInt TShowProcInfo::GetLogicalDevices(const TDes& aName)
+ {
+
+ TFindLogicalDevice findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("LOGICAL DEVICES"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetPhysicalDevices(const TDes& aName)
+ {
+
+ TFindPhysicalDevice findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("PHYSICAL DEVICES"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetSemaphores(const TDes& aName)
+ {
+ TFindSemaphore findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("SEMAPHORES"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::GetMutexes(const TDes& aName)
+ {
+
+ TFindMutex findHb;
+ findHb.Find(aName);
+ TFullName name;
+ Prepare(_L("MUTEXES"));
+ while (findHb.Next(name)==KErrNone)
+ {
+ Display(name);
+ }
+ return KErrNone;
+ }
+
+void TShowProcInfo::DisplayHelpLine(const TDesC& aCommand, const TDesC& aDescription)
+ {
+ CShell::OutputStringToConsole(ETrue,_L("%- *S%S\n"),8,&aCommand,&aDescription);
+ }
+
+
+TInt TShowProcInfo::Prepare(const TFullName& aName)
+ {
+
+ iPrevName=_L("");
+ CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
+ useCallBack=EFalse;
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::Prepare(const TFullName& aName,TCallBack& aCallBack)
+ {
+
+ iPrevName=_L("");
+ CShell::OutputStringToConsole(ETrue,_L("--%S-->\n"),&aName);
+ useCallBack=ETrue;
+ iCallBack=aCallBack;
+ return KErrNone;
+ }
+
+TInt TShowProcInfo::Display(TFullName& aName)
+
+// Modifications by WR, November 1997
+ {
+
+ TFullName prevName=iPrevName;
+ iPrevName=aName;
+ TInt toTab=0;
+ TInt posA=aName.Match(_L("*::*"));
+ if (posA>=0)
+ {
+ TInt posI=prevName.Match(_L("*::*"));
+ while ((posI>=0) && (posA>=0))
+ {
+ TFullName tempAName=(aName.Left(posA));
+ TFullName tempIName=(prevName.Left(posI));
+ if (tempAName.Compare(tempIName)==0)
+ {
+ toTab+=3;
+ aName.Delete(0,posA+2);
+ prevName.Delete(0,posI+2);
+ posA=aName.Match(_L("*::*"));
+ posI=prevName.Match(_L("*::*"));
+ }
+ else
+ break;
+ }
+ while (posA>=0)
+ {
+ TPtrC16 temp_desc=aName.Left(posA);
+ CShell::OutputStringToConsole(ETrue,_L("%+ *S\n"),toTab+temp_desc.Left(posA).Length(),&temp_desc);
+ toTab+=3;
+ aName.Delete(0,posA+2);
+ posA=aName.Match(_L("*::*"));
+ }
+ }
+ CShell::OutputStringToConsole(ETrue,_L("%+ *S\n"),toTab+aName.Length(),&(aName));
+
+
+ if (useCallBack)
+ {
+ toTab+=3;
+ CShell::TheConsole->SetCursorPosRel(TPoint(toTab,0));
+ iCallBack.CallBack();
+ }
+ return KErrNone;
+ }
+// End of modification
+TInt ShellFunction::Ps(TDes& /* aPath */,TUint /* aSwitches */)
+//
+// satisfy information requests about container objects
+//
+ {
+
+ TShowProcInfo showProcInfo;
+ TInt r=KErrNone;
+ TBuf<0x1> asterisk=_L("*");
+ TName processPrefix=asterisk;
+ TBool abort=EFalse;
+ TBool processSelected=EFalse;
+ TBuf<0x16> prompt=_L("ps>");
+ r=showProcInfo.GetProcesses(processPrefix);
+ do
+ {
+ TBuf<0x10> command;
+ CShell::TheEditor->Edit(prompt, &command, ETrue);
+ while (command.Length() && !abort && r==KErrNone)
+ {
+ TInt pos;
+ while ((pos=command.Locate(' '))>=0)
+ command.Delete(pos,1);
+ if (!command.Length())
+ break;
+ command.UpperCase();
+ if (command.CompareF(_L("EXIT"))==0)
+ {
+ abort=ETrue;
+ break;
+ }
+ TText c=command[0];
+ command.Delete(0,1);
+ switch (c)
+ {
+ case 'Q':
+ abort=ETrue;
+ break;
+ case 'H':
+ case '?':
+ {
+ showProcInfo.DisplayHelp();
+ command.Zero();
+ }
+ break;
+ case 'X':
+ {
+ TBuf<0x11> chosenP=command;
+ if (chosenP.Length()<1)
+ {
+ if (processSelected)
+ {
+ r=showProcInfo.DisplayMessage(_L(" -> back to standard Process Status mode"));
+ processPrefix=asterisk;
+ prompt=_L("ps>");
+ processSelected=EFalse;
+ }
+ command.Zero();
+ break;
+ }
+ command.Zero();
+ chosenP.Append(asterisk);
+ TFindProcess findP;
+ findP.Find(chosenP);
+ TFullName findName;
+ if (findP.Next(findName)!=KErrNone)
+ {
+ r=showProcInfo.DisplayMessage(_L("command prefixes no processes"));
+ //r=showProcInfo.GetProcesses(asterisk);
+ }
+ else
+ {
+ if (findP.Next(findName)==KErrNone)
+ {
+ r=showProcInfo.DisplayMessage(_L("command prefixes more than one process"));
+ r=showProcInfo.GetProcesses(chosenP);
+ }
+ else
+ {
+ processSelected=ETrue;
+ processPrefix=chosenP;
+ prompt=processPrefix;
+ prompt.Append(_L(">"));
+ }
+ }
+ }
+ break;
+ case 'A':
+ {
+ r=showProcInfo.GetAll(processPrefix);
+ command.Zero();
+ }
+ break;
+ case 'P':
+ r=showProcInfo.GetProcesses(asterisk);
+ break;
+ case 'T':
+ r=showProcInfo.GetThreads(processPrefix);
+ break;
+ case 'C':
+ r=showProcInfo.GetChunks(processPrefix);
+ break;
+ case 'S':
+ r=showProcInfo.GetServers(processPrefix);
+ break;
+/* case 'I':
+ r=showProcInfo.GetSessions(processPrefix);
+ break;
+*/ case 'L':
+ r=showProcInfo.GetLibraries(processPrefix);
+ break;
+// case 'G':
+// r=showProcInfo.GetLogicalChannels(processPrefix);
+// break;
+ case 'V':
+ r=showProcInfo.GetLogicalDevices(processPrefix);
+ break;
+ case 'D':
+ r=showProcInfo.GetPhysicalDevices(processPrefix);
+ break;
+ case 'E':
+ r=showProcInfo.GetSemaphores(processPrefix);
+ break;
+ case 'M':
+ r=showProcInfo.GetMutexes(processPrefix);
+ break;
+ default:
+ {
+ showProcInfo.DisplayCmdUnknown();
+ command.Zero();
+ }
+ }
+ }
+ }
+ while(!abort && r==KErrNone);
+ return KErrNone;
+ }
+
+TInt ShellFunction::Rename(TDes& aPath,TUint aSwitches)
+ {
+// Modified December 1997 to allow for filenames containing spaces
+
+ TBuf<KShellMaxCommandLine> newName;
+ TBuf<KShellMaxCommandLine> tempPath=aPath;
+ RFile64 file;
+ TWord word(aPath);
+
+ TInt r=word.FindNextWord(aPath);
+// Check if the word returned is a valid filename. If not, scan the next
+// word too in case the filename contains spaces. If, at the end of the
+// the line, the filename is not recognised, it is invalid. If there are no
+// spaces the user has not used the correct format for this command.
+
+ while (r>0)
+ {
+ newName=aPath.Right(aPath.Length()-r);
+ tempPath.SetLength(r);
+ TParse oldName;
+ TInt result=GetFullPath(tempPath,oldName);
+ if (result!=KErrNone)
+ return(r);
+
+ if (tempPath[tempPath.Length()-2]==KPathDelimiter)
+ tempPath.SetLength(tempPath.Length()-2);
+
+ result=file.Open(TheShell->TheFs,tempPath,KEntryAttMatchExclude|KEntryAttDir);
+ if (result==KErrNone) // A valid filename
+ {
+ file.Close();
+ TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
+ TUint switches=(recursive) ? CFileMan::EOverWrite : 0;
+ r=CShell::TheFileMan->Rename(oldName.FullName(),newName,switches);
+ // r=TheShell->TheFs.Rename(oldName.FullName(),newName);
+ return(r);
+ }
+ else
+ {
+ // May be a request to rename a directory
+ RDir dir;
+ result=dir.Open(TheShell->TheFs,tempPath,KEntryAttMatchMask);
+ if (result==KErrNone) // A valid directory name
+ {
+ dir.Close();
+ TBool recursive=((aSwitches&TShellCommand::ESSwitch)!=0);
+ TUint switches=(recursive) ? CFileMan::EOverWrite : 0;
+ r=CShell::TheFileMan->Rename(oldName.FullName(),newName,switches);
+ // r=TheShell->TheFs.Rename(oldName.FullName(),newName);
+ return(r);
+ }
+ else
+ // Not a valid file or directory name - move one word along the command line
+ r=word.FindNextWord(word.iRightString);
+ }
+ }
+
+ if (r<0) // Error in filename or destination
+ return (r);
+ else // End of command line, user typed invalid line
+ return (KErrNotFound);
+
+}
+
+TInt ShellFunction::Rd(TDes& aPath,TUint /*aSwitches*/)
+ {
+ if (aPath.Length()==0)
+ return(KErrBadName);
+ if (aPath[aPath.Length()-1]!=KPathDelimiter)
+ aPath.Append(KPathDelimiter);
+ TParse dirPath;
+ TInt r = GetFullPath(aPath,dirPath);
+ if(r!=KErrNone)
+ return r;
+
+// Check whether the directory actually exists.
+ RDir directory;
+ r=directory.Open(TheShell->TheFs,dirPath.FullName(),KEntryAttMatchExclusive|KEntryAttDir);
+ if (r!=KErrNone)
+ {
+ CShell::TheConsole->Printf(_L("Directory %S was not found\n"),&dirPath.FullName());
+ return (KErrNone);
+ }
+ directory.Close();
+
+ TInt ret=TheShell->TheFs.RmDir(dirPath.FullName());
+
+ if (ret==KErrNone)
+ CShell::TheConsole->Printf(_L("Directory %S was removed\n"),&dirPath.FullName());
+ else if(ret==KErrInUse)
+ {
+ CShell::TheConsole->Printf(_L("Directory %S is in use and cannot be deleted\n"),&dirPath.FullName());
+ return KErrNone;
+ }
+
+ return(ret);
+ }
+
+TInt ShellFunction::Start(TDes& aProg,TUint /*aSwitches*/)
+//
+// Runs a program without waiting for completion
+//
+ {
+
+ TInt bat=aProg.FindF(_L(".BAT"));
+ TInt space=aProg.Locate(' ');
+ TInt r=KErrArgument;
+ if (bat>=0 && (space<0 || space>bat))
+ r=CShell::RunBatch(aProg);
+ else if (aProg.Length()!=0)
+ r=CShell::RunExecutable(aProg,EFalse);
+ return(r);
+ }
+
+TInt ShellFunction::Time(TDes&,TUint /*aSwitches*/)
+ {
+ TTime time;
+ time.HomeTime();
+ TDateTime dateTime(time.DateTime());
+ 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());
+ return(KErrNone);
+ }
+
+TInt ShellFunction::Trace(TDes& aState,TUint aSwitches)
+//
+// Turn on trace information
+//
+ {
+ TInt debugVal=0;
+ if (aSwitches&TShellCommand::ESSwitch)
+ debugVal|=KFSERV;
+ if (aSwitches&TShellCommand::ELSwitch)
+ debugVal|=KFLDR;
+ if (aSwitches&TShellCommand::EFSwitch)
+ debugVal|=KFSYS;
+ if (aSwitches&TShellCommand::ETSwitch)
+ debugVal|=KLFFS;
+ if (aSwitches&TShellCommand::EISwitch)
+ debugVal|=KISO9660;
+ if (aSwitches&TShellCommand::ENSwitch)
+ debugVal|=KNTFS;
+ if (aSwitches&TShellCommand::EMSwitch)
+ debugVal|=KTHRD;
+ if (aSwitches&TShellCommand::EOSwitch)
+ debugVal|=KROFS;
+ if (aSwitches&TShellCommand::ECSwitch)
+ debugVal|=KCOMPFS;
+ if (aSwitches&TShellCommand::EHSwitch)
+ debugVal|=KCACHE;
+ TheShell->TheFs.SetDebugRegister(debugVal);
+
+ aSwitches=0;
+
+ if (aState.Length())
+ {
+ TBuf<KShellMaxCommandLine> indexArg;
+ TWord word(aState);
+
+ TLex lex=aState;
+ TUint val;
+ TInt r2=lex.Val(val,EHex);
+
+ TInt r=word.FindNextWord(aState);
+ TUint index;
+ if (r>0)
+ {
+ indexArg = aState.Right(aState.Length()-r);
+ lex=indexArg;
+ lex.Val(index,EDecimal);
+ }
+ else
+ index = 0;
+
+ if (r2 != KErrNone)
+ {
+ TInt shift = index % 32;
+ index /= 32;
+ val = UserSvr::DebugMask(index);
+ if (aState.Left(2)==_L("on"))
+ val |= 1<<shift;
+ else if (aState.Left(3)==_L("off"))
+ val &= ~(1<<shift);
+ }
+
+ if (index < 256)
+ {
+ User::SetDebugMask(val, index);
+ CShell::TheConsole->Printf(_L("SetDebugMask(0x%x, %d)\n"), val, index);
+ }
+ }
+ else
+ {
+ for (TInt j=0; j<8; j++)
+ CShell::TheConsole->Printf(_L("DebugMask(%d) = 0x%08X\n"), j, UserSvr::DebugMask(j));
+ }
+
+ return(KErrNone);
+ }
+
+TInt ShellFunction::Tree(TDes& aPath,TUint aSwitches)
+ {
+ ParsePath(aPath);
+ CShell::TheConsole->Printf(_L("\n %S\n"),&aPath);
+ if (aPath.Right(1)==_L("\\"))
+ aPath.Append('*');
+ else
+ aPath.Append(_L("\\*"));
+ TBuf<256> buf=_L(" ");
+ TInt dirCount=ShowDirectoryTree(aPath,aSwitches,buf);
+ buf.Format(_L("\n Found %d subdirector"),dirCount);
+ if (dirCount==1)
+ buf.AppendFormat(_L("y\n"));
+ else
+ buf.AppendFormat(_L("ies\n"));
+
+ CShell::OutputStringToConsole(((aSwitches&TShellCommand::EPSwitch)!=0),buf);
+
+ return(KErrNone);
+ }
+
+TInt ShellFunction::ShowDirectoryTree(TDes& aPath,TUint aSwitches,TDes& aTreeGraph)
+//
+// Recursive fn. to draw tree of dir aPath (needs to be suffixed with '*')
+//
+ {
+ TInt dirCount=0;
+ RDir dir;
+ TInt r=dir.Open(TheShell->TheFs,aPath,KEntryAttDir);
+ if (r==KErrNone)
+ {
+ TEntry next,entry;
+ while ((r=dir.Read(next))==KErrNone && !next.IsDir())
+ {
+ }
+ // lint info 722: Suspicious use of ; in previous line...
+ if (aSwitches&TShellCommand::EFSwitch)
+ {
+ RDir dirFile;
+ if (dirFile.Open(TheShell->TheFs,aPath,0)==KErrNone)
+ {
+ while (dirFile.Read(entry)==KErrNone)
+ CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,(r==KErrNone)?_L("%S\x00B3 %S\n"):_L("%S %S\n"),&aTreeGraph,&entry.iName);
+
+ dirFile.Close();
+ }
+ }
+ if (r==KErrNone)
+ do
+ {
+ entry=next;
+ while ((r=dir.Read(next))==KErrNone && !next.IsDir())
+ ;
+
+ CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,aTreeGraph);
+ if (r==KErrNone)
+ {
+ CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("\x00C0\x00C4\x00C4%S\n"),&entry.iName);
+ aTreeGraph.Append(_L("\x00B3 "));
+ }
+ else
+ {
+ CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("\x00C0\x00C4\x00C4%S\n"),&entry.iName);
+ aTreeGraph.Append(_L(" "));
+ }
+ aPath.Insert(aPath.Length()-1,entry.iName);
+ aPath.Insert(aPath.Length()-1,_L("\\"));
+ dirCount+=1+ShowDirectoryTree(aPath,aSwitches,aTreeGraph);
+ aPath.Delete(aPath.Length()-2-entry.iName.Length(),entry.iName.Length()+1);
+ aTreeGraph.SetLength(aTreeGraph.Length()-3);
+ }
+ while (r==KErrNone);
+ dir.Close();
+ if (r!=KErrEof)
+ CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("Error EOF %d\n"),r);
+
+ }
+ else
+ CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,_L("Error in Open %d\n"),r);
+ return(dirCount);
+ }
+
+void ByteSwap(TDes16& aDes)
+ {
+ TUint8* p=(TUint8*)aDes.Ptr();
+ TUint8* pE=p+aDes.Size();
+ TUint8 c;
+ for (; p<pE; p+=2)
+ c=*p, *p=p[1], p[1]=c;
+ }
+
+_LIT(KLitPercentS, "%S");
+TInt ShellFunction::Type(TDes& aPath,TUint aSwitches)
+ {
+ ParsePath(aPath);
+ RFile file;
+ TInt r=file.Open(TheShell->TheFs,aPath,EFileStreamText|EFileShareReadersOnly);
+ if (r!=KErrNone)
+ return r;
+ TBuf8<0x200> tmpbuf;
+ TBuf<0x200> ubuf;
+ TInt state=0; // 0=start of file, 1=ASCII, 2=UNICODE little-endian, 3=UNICODE big-endian
+ TKeyCode key=EKeyNull;
+
+ TInt nchars=0;
+ TInt l;
+
+ do
+ {
+ r=file.Read(tmpbuf);
+ if (r!=KErrNone)
+ {
+ file.Close();
+ return r;
+ }
+
+ l=tmpbuf.Length();
+ if (state==0)
+ {
+ if (l>=2)
+ {
+ TUint c=(tmpbuf[1]<<8)|tmpbuf[0];
+ if (c==0xfeff)
+ state=2;
+ else if (c==0xfffe)
+ state=3;
+ else
+ state=1;
+ }
+ else
+ state=1;
+ }
+ TPtrC buf;
+ if (state>1)
+ {
+ if (l&1)
+ --l, tmpbuf.SetLength(l);
+ buf.Set((TText*)tmpbuf.Ptr(),l/sizeof(TText));
+ if (state==3)
+ {
+ TPtr wbuf( (TText*)buf.Ptr(), buf.Length(), buf.Length() );
+ ByteSwap(wbuf);
+ }
+ }
+ else
+ {
+ ubuf.Copy(tmpbuf);
+ buf.Set(ubuf);
+ }
+ while ((r=buf.Locate('\n'))!=KErrNotFound)
+ {
+ nchars=0;
+ TPtrC bufLeft=buf.Left(r+1);
+ key = CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,KLitPercentS(), &bufLeft);
+ buf.Set(buf.Mid(r+1));
+
+ if(key == EKeyEscape)
+ goto exit;
+ }
+
+ nchars=buf.Length();
+ if (nchars)
+ {
+ key = CShell::OutputStringToConsole((aSwitches&TShellCommand::EPSwitch)!=0,KLitPercentS(), &buf);
+ if(key == EKeyEscape)
+ goto exit;
+
+ }
+
+ } while(l==tmpbuf.MaxLength());
+
+ exit:
+
+ file.Close();
+ CShell::NewLine();
+ return KErrNone;
+ }
+
+void ShellFunction::ParsePath(TDes& aPath)
+ {
+ if (aPath.Length()>0 && aPath[0]==KPathDelimiter)
+ return;
+ TParse pathParse;
+ if (aPath.Length()<2 || aPath[1]!=':')
+ pathParse.SetNoWild(TheShell->currentPath,NULL,NULL);
+ else
+ {
+ if (aPath.Length()>=3 && aPath[2]==KPathDelimiter)
+ return;
+ pathParse.SetNoWild(TheShell->drivePaths[User::UpperCase(aPath[0])-'A'],NULL,NULL);
+ aPath.Delete(0,2);
+ }
+ if (aPath.Length()>=2 && aPath.Left(2).Compare(_L(".."))==0)
+ {
+ aPath.Delete(0,2);
+ pathParse.PopDir();
+ while (aPath.Length()>=3 && aPath.Left(3).Compare(_L("\\.."))==0)
+ {
+ aPath.Delete(0,3);
+ pathParse.PopDir();
+ }
+ if (aPath.Length()!=0 && aPath[0]==KPathDelimiter)
+ aPath.Delete(0,1);
+ }
+ aPath.Insert(0,pathParse.FullName());
+ }
+
+TBool ShellFunction::Certain()
+ {
+ CShell::TheConsole->Printf(_L("Are you sure? Y/N..."));
+ TInt r=User::UpperCase(CShell::TheConsole->Getch());
+ while ((!(r=='Y'))&&(!(r=='N')))
+ {
+ CShell::TheConsole->Printf(_L("%c is invalid\n"),r);
+ CShell::TheConsole->Printf(_L("Are you sure? Y/N..."));
+ r=User::UpperCase(CShell::TheConsole->Getch());
+ }
+ CShell::TheConsole->Printf(_L("%c\n"),r);
+ return(r=='Y');
+ }
+
+TInt ShellFunction::GetFullPath(TDes& aPath,TParse& aParse)
+//
+// Parse a path of the form "[C:][\\]AAA\\..\\.\\BBB\\xxx.yyy" where:
+// . indicates the current directory
+// .. indicates move to the parent directory
+// An optional "\\" at the start of the path indicates the path is not relative to the current path
+//
+ {
+
+ TInt r;
+ if (aPath.Length()>0 && aPath[aPath.Length()-1]=='.')
+ aPath.Append(KPathDelimiter);
+ if (aPath.Length()==0)
+ r=aParse.Set(TheShell->currentPath,NULL,NULL);
+ else if (aPath[0]==KPathDelimiter)
+ r=aParse.Set(aPath,&TheShell->currentPath,NULL);
+ else if (aPath.Length()>=2 && aPath[1]==KDriveDelimiter)
+ {
+ TInt drvNum;
+ r=RFs::CharToDrive(aPath[0],drvNum);
+ if (r==KErrNone)
+ r=aParse.Set(aPath,&TheShell->drivePaths[drvNum],NULL);
+ }
+ else
+ {
+ if (aPath.LocateReverse(KPathDelimiter)>=0)
+ {
+ if (aPath.Length()+TheShell->currentPath.Length()>aPath.MaxLength())
+ return(KErrBadName);
+ aPath.Insert(0,TheShell->currentPath);
+ }
+ r=aParse.Set(aPath,&TheShell->currentPath,NULL);
+ }
+ if (r!=KErrNone)
+ return(r);
+ if (aParse.Path().Find(_L(".\\"))==KErrNotFound)
+ return(KErrNone);
+ if (aParse.Path().Find(_L("...\\"))!=KErrNotFound)
+ return(KErrBadName);
+ TParse dirParse;
+ TPtrC path(aParse.DriveAndPath());
+ TInt pos=path.Find(_L(".\\"));
+ if (path[pos-1]!='.' && path[pos-1]!='\\')
+ return(KErrNone); // FileName ending in .
+ TInt isParent=(path[pos-1]=='.') ? 1 : 0;
+ r=dirParse.Set(path.Left(pos-isParent),NULL,NULL);
+ while(r==KErrNone)
+ {
+ if (isParent)
+ dirParse.PopDir();
+ path.Set(path.Right(path.Length()-pos-2));
+ pos=path.Find(_L(".\\"));
+ if (pos==0)
+ {
+ isParent=0;
+ continue;
+ }
+ else if (pos!=KErrNotFound)
+ isParent=(path[pos-1]=='.') ? 1 : 0;
+ TInt len=(pos==KErrNotFound) ? path.Length() : pos-isParent;
+ r=AddRelativePath(dirParse,path.Left(len));
+ if (r!=KErrNone || pos==KErrNotFound)
+ break;
+ }
+ if (r!=KErrNone)
+ return(r);
+// lint -e50
+ TBuf<KMaxFileName> nameAndExt=aParse.NameAndExt();
+ aParse.Set(dirParse.FullName(),&nameAndExt,NULL);
+ return(KErrNone);
+ }
+
+void ShellFunction::StripQuotes(TDes& aVal)
+ {
+ for(TInt idx=0;idx<aVal.Length();idx++)
+ {
+ while((idx < aVal.Length()) && (aVal[idx] == '"'))
+ {
+ aVal.Delete(idx, 1);
+ }
+ }
+ }
+
+TInt ShellFunction::ValidName(TDes& aPath,TUint /*aSwitches*/)
+//
+// Check whether the name has any invalid characters
+//
+ {
+ TBool tooShort=EFalse;
+
+ TText badChar;
+ TPtr ptr(&badChar,sizeof(TText),sizeof(TText));
+
+ TBool validName=TheShell->TheFs.IsValidName(aPath,badChar);
+ if (validName)
+ CShell::TheConsole->Printf(_L("'%S' is a valid name\n"),&aPath);
+ else
+ {
+ if (!tooShort)
+ CShell::TheConsole->Printf(_L("'%S' is not a valid name.\n"),&aPath);
+
+ CShell::TheConsole->Printf(_L("The '%S' character is not allowed\n"),&ptr);
+ }
+ return (KErrNone);
+ }
+
+LOCAL_C TInt pswd_DrvNbr(TDes &aPath, TInt &aDN)
+//
+// password utility function to extract drive number from cmd string.
+//
+ {
+ TLex l(aPath);
+ return l.Val(aDN);
+ }
+
+LOCAL_C TInt pswd_Password(TDes &aPath, TInt aPWNbr, TMediaPassword &aPW)
+//
+// utility function to extract indexed password from command string. A
+// dash is interpreted as the null password.
+//
+ {
+ __ASSERT_DEBUG(aPWNbr >= 1, User::Panic(_L("Invalid pswd nbr"), 0));
+
+ TLex l(aPath);
+
+ TPtrC ptScan;
+ for (TInt i = 0; i <= aPWNbr; ++i)
+ {
+ if (l.Eos())
+ return KErrNotFound;
+ else
+ ptScan.Set(l.NextToken());
+ }
+
+ // take remainder of command line and terminate after password
+ TBuf<256> pswd;
+ for (TInt j = 0; j < ptScan.Length() && ! TChar(ptScan[j]).IsSpace(); ++j)
+ {
+ pswd.Append(ptScan[j]);
+ }
+
+ aPW.Zero();
+ if (pswd[0] == '-')
+ return KErrNone;
+
+ // fill aPW with contents of pswd, not converting to ASCII
+ const TInt byteLen = pswd.Length() * 2;
+ if (byteLen > KMaxMediaPassword)
+ return KErrArgument;
+
+ aPW.Copy(reinterpret_cast<const TUint8 *>(pswd.Ptr()), byteLen);
+
+ return KErrNone;
+ }
+
+TInt ShellFunction::Lock(TDes &aPath, TUint aSwitches)
+//
+// Locks a password-enabled media.
+//
+ {
+ TInt r;
+ TInt dn;
+ TMediaPassword curPswd;
+ TMediaPassword newPswd;
+ TBool store = aSwitches & TShellCommand::ESSwitch;
+
+ if ((r = pswd_DrvNbr(aPath, dn)) < 0)
+ return r;
+
+ if ((r = pswd_Password(aPath, 1, curPswd)) < 0)
+ return r;
+
+ if ((r = pswd_Password(aPath, 2, newPswd)) < 0)
+ return r;
+
+ return TheShell->TheFs.LockDrive(dn, curPswd, newPswd, store);
+ }
+
+TInt ShellFunction::Unlock(TDes &aPath, TUint aSwitches)
+//
+// Unlocks a password-enabled media.
+//
+ {
+ TInt r;
+ TInt dn;
+ TMediaPassword curPswd;
+ TBool store = aSwitches & TShellCommand::ESSwitch;
+
+ if ((r = pswd_DrvNbr(aPath, dn)) < 0)
+ return r;
+
+ if ((r = pswd_Password(aPath, 1, curPswd)) < 0)
+ return r;
+
+ return TheShell->TheFs.UnlockDrive(dn, curPswd, store);
+ }
+
+TInt ShellFunction::Clear(TDes &aPath, TUint /* aSwitches */)
+//
+// Clears a password from a password-enabled media.
+//
+ {
+ TInt r;
+ TInt dn;
+ TMediaPassword curPswd;
+
+ if ((r = pswd_DrvNbr(aPath, dn)) < 0)
+ return r;
+
+ if ((r = pswd_Password(aPath, 1, curPswd)) < 0)
+ return r;
+
+ return TheShell->TheFs.ClearPassword(dn, curPswd);
+ }
+
+TInt ShellFunction::SetSize(TDes& aPath,TUint /*aSwitches*/)
+//
+// Set size of a file, create this if it does not exist
+//
+ {
+ TInt fileNameLen=aPath.LocateReverse(' ');
+ if (fileNameLen==KErrNotFound) // No spaces implies no filelength specified
+ {
+ CShell::TheConsole->Printf(_L("Please specify a file name and a file length\n"));
+ return (KErrNone);
+ }
+
+
+ TInt fileLength=(aPath.Length()-fileNameLen);
+ if (fileLength>16)
+ return (KErrTooBig); // Too many digits - too large!
+ TBuf<16> rightString=aPath.Right(fileLength);
+ aPath.SetLength(fileNameLen);
+
+ TLex size(rightString);
+ size.SkipSpace();
+
+ TRadix radix=ParseHexaPrefixIfAny(size);
+ TUint32 fileSize;
+ TInt r=size.Val(fileSize,radix);
+ if (r!=KErrNone || ! size.Eos())
+ {
+ CShell::TheConsole->Printf(_L("Please specify a file length\n"));
+ return KErrNone;
+ }
+
+ TParse fileName;
+ GetFullPath(aPath,fileName);
+ RFile64 file;
+ r=file.Open(CShell::TheFs,fileName.FullName(),EFileRead|EFileWrite);
+ if(r==KErrNotFound)
+ r=file.Create(CShell::TheFs,fileName.FullName(),EFileRead|EFileWrite);
+ if (r==KErrNone)
+ {
+ r=file.SetSize(fileSize);
+ file.Close();
+ if(r!=KErrNone)
+ CShell::TheConsole->Printf(_L("Error (%d) - could not set size of file\n"),r);
+ }
+ else
+ {
+ CShell::TheConsole->Printf(_L("Error (%d) - could not create or open file\n"),r);
+ CShell::TheFs.Delete(fileName.FullName());
+ }
+ return(r);
+ }
+
+TInt ShellFunction::DebugPort(TDes& aArgs, TUint /*aSwitches*/)
+//
+// Set or get the debug port from the command line (debugport)
+//
+ {
+ _LIT(KGetPortLit, "Debug port is %d (0x%x)\n");
+ _LIT(KSetPortLit, "Debug port set to %d (0x%x)\n");
+
+ TLex s(aArgs);
+ s.SkipSpace();
+ if (s.Eos())
+ {
+ TInt port;
+ TInt r = HAL::Get(HALData::EDebugPort, port);
+ if (r != KErrNone)
+ return r;
+ CShell::TheConsole->Printf(KGetPortLit, (TUint32)port, (TUint32)port);
+ }
+ else
+ {
+ TRadix radix=EDecimal;
+ if (s.Remainder().Length()>2)
+ {
+ s.Mark();
+ s.Inc(2);
+ if (s.MarkedToken().MatchF(_L("0x"))!=KErrNotFound)
+ radix=EHex;
+ else
+ s.UnGetToMark();
+ }
+
+ union Port
+ {
+ TUint32 u;
+ TInt32 s;
+ };
+
+ Port port;
+ TInt r;
+ if (radix == EHex)
+ r = s.Val(port.u, radix);
+ else
+ r = s.Val(port.s);
+ if (r != KErrNone || ! s.Eos())
+ return KErrBadName;
+ r = HAL::Set(HALData::EDebugPort, port.s);
+ if (r != KErrNone)
+ return r;
+ CShell::TheConsole->Printf(KSetPortLit, port.s, port.u);
+ }
+
+ return KErrNone;
+ }
+
+TInt ShellFunction::Plugin(TDes& aName,TUint aSwitches)
+ {
+ TInt err = KErrNone;
+ switch(aSwitches)
+ {
+ case TShellCommand::EASwitch:
+ {
+ err = CShell::TheFs.AddPlugin(aName);
+ CShell::TheConsole->Printf(_L("Add Plugin: %S [r:%d]\n"), &aName, err);
+ break;
+ }
+ case TShellCommand::ERSwitch:
+ {
+ err = CShell::TheFs.RemovePlugin(aName);
+ CShell::TheConsole->Printf(_L("Remove Plugin: %S [r:%d]\n"), &aName, err);
+ break;
+ }
+ case TShellCommand::EMSwitch:
+ {
+ err = CShell::TheFs.MountPlugin(aName);
+ CShell::TheConsole->Printf(_L("Mount Plugin: %S [r:%d]\n"), &aName, err);
+ break;
+ }
+ case TShellCommand::EDSwitch:
+ {
+ err = CShell::TheFs.DismountPlugin(aName);
+ CShell::TheConsole->Printf(_L("Dismount Plugin: %S [r:%d]\n"), &aName, err);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return err;
+ }
+
+_LIT(KCrNl, "\r\n");
+
+void SIPrintf(TRefByValue<const TDesC16> aFmt, ...)
+ {
+ TBuf<256> buf;
+ VA_LIST list;
+ VA_START(list, aFmt);
+ // coverity[uninit_use_in_call]
+ buf.FormatList(aFmt, list);
+ buf.Append(KCrNl);
+ RDebug::RawPrint(buf);
+ CShell::TheConsole->Printf(buf);
+ }
+
+/**
+ Run a specified executable in a loop.
+
+ RUNEXEC <count> <command [args]> [/E] [/S] [/R]
+
+ count - loop count; zero (0) means: forever
+ command - the executable to run. Arguments can be supplied.
+ Limitations:
+ command arguments cannot contain /? switches as the shell strips these out.
+ command cannot contain spaces.
+
+ /E terminates the loop if the program exits with an error
+
+ /S makes the shell interpret "count" as a number of seconds
+ The shell will not attempt to terminate "command" early if it is still running after
+ "count" seconds. It will terminate the loop only after "command" has exited.
+
+ /R will make the shell reset debug registers / trace flags after each iteration.
+ This is to be used if the program modifies tracing flags for its own purposes but exits
+ abnormally; if /R is used, later iterations will run the program from the same initial
+ tracing state each time.
+ Limitation: This flag does not yet affect BTrace / UTrace state.
+
+ Switches can be combined; "RUNEXEC 2000 testprg /E/S/R" keeps running "testprg" till an error
+ occurs, or more than 2000 seconds have passed, and resets the debug state after each iteration.
+*/
+TInt ShellFunction::RunExec(TDes& aProg, TUint aSwitches)
+ {
+ _LIT(KRunExecFailedProcessCreate, "Failed to spawn command %S: error %d\n");
+ _LIT(KRunExecReportStatusAndTime, "Total elapsed time: %d msecs, Iteration %d: Exit type %d,%d,%S\n");
+ aProg.TrimAll();
+ TBuf<KShellMaxCommandLine> parameters(0);
+ TInt r;
+ TInt count = 0;
+ TTime timeStart, timeCurrent;
+ TTimeIntervalMicroSeconds timeTaken;
+
+ // The first parameter must be a valid decimal integer.
+ for (r=0; r < aProg.Length() && TChar(aProg[r]).IsDigit(); r++)
+ count = count * 10 + (aProg[r] - '0');
+ if (r == 0 || r == aProg.Length() || TChar(aProg[r]).IsSpace() == EFalse)
+ return (KErrArgument);
+ aProg = aProg.Mid(r+1);
+
+ TBool exitOnErr = (aSwitches & TShellCommand::EESwitch);
+ TBool resetDebugRegs = (aSwitches & TShellCommand::ERSwitch);
+ TBool countIsSecs = (aSwitches & TShellCommand::ESSwitch);
+ TBool forever = (count == 0);
+
+ timeStart.HomeTime();
+
+ // copy out the parameters - if any
+ r = aProg.Locate(' ');
+ if(r != KErrNotFound)
+ {
+ parameters = aProg.Mid(r+1);
+ aProg.SetLength(r);
+ }
+
+ // Make sure the executable name qualifies as a pathname.
+ aProg.UpperCase();
+ if (aProg.FindF(_L(".EXE")) == KErrNotFound && (aProg.Length()+4) <= KShellMaxCommandLine)
+ aProg.Append(_L(".EXE"));
+
+#ifdef _DEBUG
+ SIPrintf(_L("RUNEXEC: command %S, parameters %S, count %d, forever %d, issecs %d, exiterr %d"),
+ &aProg, ¶meters, count, forever, countIsSecs, exitOnErr);
+#endif
+ TInt i=0;
+ FOREVER
+ {
+ TInt retcode;
+ RProcess newProcess;
+ TRequestStatus status = KRequestPending;
+ TExitType exitType;
+ TBuf<KMaxExitCategoryName> exitCat(0);
+
+ r = newProcess.Create(aProg, parameters);
+ if (r != KErrNone)
+ {
+ SIPrintf(KRunExecFailedProcessCreate, &aProg, r);
+ return (r); // this is systematic - must return
+ }
+ newProcess.Logon(status);
+ newProcess.Resume();
+ User::WaitForRequest(status);
+ exitType = newProcess.ExitType();
+ exitCat = newProcess.ExitCategory();
+ retcode = newProcess.ExitReason();
+ newProcess.Close();
+
+ timeCurrent.HomeTime();
+ timeTaken = timeCurrent.MicroSecondsFrom(timeStart);
+ TInt msecs = I64LOW(timeTaken.Int64() / 1000);
+ SIPrintf(KRunExecReportStatusAndTime, msecs, i+1, exitType, retcode, &exitCat);
+
+ if (resetDebugRegs)
+ {
+ TheShell->TheFs.SetDebugRegister(0);
+ User::SetDebugMask(0);
+ }
+
+ i++;
+
+ if ((exitOnErr && (exitType != EExitKill || status != KErrNone)) || // err occurred, leave requested ?
+ (countIsSecs && count != 0 && timeTaken.Int64() > (TInt64)1000000 * (TInt64)count) || // time elapsed ?
+ (!forever && i >= count)) // loop done ?
+ break;
+ }
+ return(KErrNone);
+ }
+
+//
+// System information command
+//
+
+TBool DebugNum(TInt aBitNum)
+ {
+ __ASSERT_ALWAYS(aBitNum >= 0 && aBitNum <= KMAXTRACE, User::Panic(_L("Bad bit num"), 0));
+ TInt index = aBitNum >> 5;
+ TInt m = UserSvr::DebugMask(index) & (1 << (aBitNum & 31));
+ return m != 0;
+ }
+
+void SIHeading(TRefByValue<const TDesC16> aFmt, ...)
+ {
+ TBuf<256> buf;
+ VA_LIST list;
+ VA_START(list, aFmt);
+ buf.Append(KCrNl);
+ buf.AppendFormatList(aFmt, list);
+ buf.Append(KCrNl);
+ RDebug::RawPrint(buf);
+ CShell::TheConsole->Printf(buf);
+ buf.Fill('=', buf.Length()-4);
+ buf.Append(KCrNl);
+ RDebug::RawPrint(buf);
+ CShell::TheConsole->Printf(buf);
+ }
+
+void SIBoolean(const TDesC& aFmt, TBool aVal)
+ {
+ _LIT(KEnabled, "enabled");
+ _LIT(KDisabled, "disabled");
+ SIPrintf(aFmt, aVal ? &KEnabled : &KDisabled);
+ }
+
+TInt ShellFunction::SysInfo(TDes& /*aArgs*/, TUint /*aSwitches*/)
+ {
+ SIHeading(_L("Kernel Features"));
+ SIBoolean(_L("Crazy scheduler delays are %S."), DebugNum(KCRAZYSCHEDDELAY));
+ SIBoolean(_L("Crazy scheduler priorities and timeslicing are %S."),
+ UserSvr::HalFunction(EHalGroupKernel, EKernelHalConfigFlags, 0, 0) & EKernelConfigCrazyScheduling);
+
+ return KErrNone;
+ }
+
+
+//-------------------------------------------------------------------------
+/**
+ Print out the command line to the console and standard debug port.
+*/
+TInt ShellFunction::ConsoleEcho(TDes& aArgs, TUint /*aSwitches*/)
+{
+ SIPrintf(aArgs);
+ return KErrNone;
+}