Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1318 lines
34 KiB

#include "cmd.h"
#define Wild(spec) ((spec)->flags & (CI_NAMEWILD))
VOID ResetCtrlC();
extern unsigned msglen;
extern jmp_buf CmdJBuf2 ;
extern TCHAR Fmt11[], Fmt19[], Fmt17[], Fmt14[];
extern TCHAR CurDrvDir[] ;
extern TCHAR *SaveDir ;
extern TCHAR SwitChar;
extern unsigned DosErr ;
extern BOOL CtrlCSeen;
extern ULONG DCount ;
STATUS BuildFSFromPatterns ( PDRP, BOOLEAN, PFS * );
STATUS DirWalkAndProcess( STATUS (* ) ( PSCREEN, PULONG, PULONG, ULONG, ULONG, PFS ),
STATUS (* ) (PFS, PULONG),
PSCREEN,
PULONG,
PLARGE_INTEGER,
PFS,
PDRP,
BOOLEAN,
BOOLEAN (*) (STATUS, PTCHAR));
VOID FreeStr( PTCHAR );
STATUS ParseDelParms ( PTCHAR, PDRP );
STATUS ParseRmDirParms ( PTCHAR, PDRP );
STATUS DelPatterns (BOOLEAN,
BOOLEAN (*) (STATUS, PTCHAR),
PDRP );
PTCHAR GetWildPattern( ULONG, PPATDSC );
STATUS SetSearchPath ( PFS, PPATDSC, PTCHAR, ULONG);
BOOLEAN
PrintFNFErr(
IN STATUS rc,
IN PTCHAR pszFile
)
{
UNREFERENCED_PARAMETER(rc);
if (pszFile) {
PutStdErr(MSG_NOT_FOUND, ONEARG, pszFile);
} else {
PutStdErr(MSG_FILE_NOT_FOUND, NOARGS);
}
//
// BUGBUG later may want to return FALSE to indicate not to continue
// process
//
return( TRUE );
}
int
DelWork (
TCHAR *pszCmdLine
) {
//
// drp - structure holding current set of parameters. It is initialized
// in ParseDelParms function. It is also modified later when
// parameters are examined to determine if some turn others on.
//
DRP drpCur = {0, 0, 0, 0,0, {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, NULL} ;
//
// szCurDrv - Hold current drive letter
//
TCHAR szCurDrv[MAX_PATH + 2];
//
// OldDCount - Holds the level number of the heap. It is used to
// free entries off the stack that might not have been
// freed due to error processing (ctrl-c etc.)
ULONG OldDCount;
STATUS rc;
OldDCount = DCount;
//
// Setup defaults
//
//
// Display everything but system and hidden files
// rgfAttribs set the attribute bits to that are of interest and
// rgfAttribsOnOff says wither the attributs should be present
// or not (i.e. On or Off)
//
drpCur.rgfAttribs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
drpCur.rgfAttribsOnOff = 0;
//
// Number of patterns present. A pattern is a string that may have
// wild cards. It is used to match against files present in the directory
// 0 patterns will show all files (i.e. mapped to *.*)
//
drpCur.cpatdsc = 0;
//
// default time is LAST_WRITE_TIME.
//
drpCur.dwTimeType = LAST_WRITE_TIME;
//
//
//
if (ParseDelParms(pszCmdLine, &drpCur) == FAILURE) {
return( FAILURE );
}
//
// Must have some pattern on command line
//
//
GetDir((PTCHAR)szCurDrv, GD_DEFAULT);
if (drpCur.cpatdsc == 0) {
PutStdErr(MSG_BAD_SYNTAX, NOARGS);
return(FAILURE);
}
//
// Print out this particular pattern. If the recursion switch
// is set then this will desend down the tree.
//
drpCur.rgfSwitchs |= DELPROCESSEARLY;
rc = DelPatterns(FALSE,
fEnableExtensions && (drpCur.rgfSwitchs & RECURSESWITCH) ? NULL : PrintFNFErr,
&drpCur
);
mystrcpy(CurDrvDir, szCurDrv);
//
// Free unneeded memory
//
FreeStack( OldDCount );
#ifdef _CRTHEAP_
//
// Force the crt to release heap we may have taken on recursion
//
if (drpCur.rgfSwitchs & RECURSESWITCH) {
_heapmin();
}
#endif
return( (int)rc );
}
STATUS
SetDelAttribs(
IN PTCHAR pszTok,
OUT PDRP pdrp
)
/*++
Routine Description:
Parses the 'attribute' string
Arguments:
pszTok - list of attributes
Return Value:
pdrp - where to place the attributes recognized.
this is the parameter structure.
Return: TRUE - recognized all parameters
FALSE - syntax error.
An error is printed if incountered.
--*/
{
ULONG irgch;
BOOLEAN fOff;
ULONG rgfAttribs, rgfAttribsOnOff;
// rgfAttributes hold 1 bit per recognized attribute. If the bit is
// on then do something with this attribute. Either select the file
// with this attribute or select the file without this attribute.
//
// rgfAttribsOnOff controls wither to select for the attribute or
// select without the attribute.
//
// /a triggers selection of all files by default
// so override the default
//
pdrp->rgfAttribs = rgfAttribs = 0;
pdrp->rgfAttribsOnOff = rgfAttribsOnOff = 0;
//
// Move over optional ':'
//
if (*pszTok == COLON) {
pszTok++;
}
//
// rgfAttribs and rgfAttribsOnOff must be maintained in the
// same bit order.
//
for( irgch = 0, fOff = FALSE; pszTok[irgch]; irgch++ ) {
switch (_totupper(pszTok[irgch])) {
case TEXT('H'):
rgfAttribs |= FILE_ATTRIBUTE_HIDDEN;
if (fOff) {
rgfAttribsOnOff &= ~FILE_ATTRIBUTE_HIDDEN;
fOff = FALSE;
} else {
rgfAttribsOnOff |= FILE_ATTRIBUTE_HIDDEN;
}
break;
case TEXT('S'):
rgfAttribs |= FILE_ATTRIBUTE_SYSTEM;
if (fOff) {
rgfAttribsOnOff &= ~FILE_ATTRIBUTE_SYSTEM;
fOff = FALSE;
} else {
rgfAttribsOnOff |= FILE_ATTRIBUTE_SYSTEM;
}
break;
case TEXT('A'):
rgfAttribs |= FILE_ATTRIBUTE_ARCHIVE;
if (fOff) {
rgfAttribsOnOff &= ~FILE_ATTRIBUTE_ARCHIVE;
fOff = FALSE;
} else {
rgfAttribsOnOff |= FILE_ATTRIBUTE_ARCHIVE;
}
break;
case TEXT('R'):
rgfAttribs |= FILE_ATTRIBUTE_READONLY;
if (fOff) {
rgfAttribsOnOff &= ~FILE_ATTRIBUTE_READONLY;
fOff = FALSE;
} else {
rgfAttribsOnOff |= FILE_ATTRIBUTE_READONLY;
//
// If selecting on read only make sure we implicitly
// force removing file.
//
pdrp->rgfSwitchs |= FORCEDELSWITCH;
}
break;
case MINUS:
if (fOff) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
argstr1(Fmt14,(unsigned long)((int)(pszTok+2))));
return( FAILURE );
}
fOff = TRUE;
break;
default:
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
argstr1(Fmt14,(unsigned long)((int)(pszTok+2))));
return( FAILURE );
} // switch
} // for
pdrp->rgfAttribs = rgfAttribs;
pdrp->rgfAttribsOnOff = rgfAttribsOnOff;
return( SUCCESS );
}
STATUS
ParseDelParms (
IN PTCHAR pszCmdLine,
OUT PDRP pdrp
)
/*++
Routine Description:
Parse the command line translating the tokens into values
placed in the parameter structure. The values are or'd into
the parameter structure since this routine is called repeatedly
to build up values (once for the environment variable DIRCMD
and once for the actual command line).
Arguments:
pszCmdLine - pointer to command line user typed
Return Value:
pdrp - parameter data structure
Return: TRUE - if valid command line.
FALSE - if not.
--*/
{
PTCHAR pszTok;
TCHAR szT[10] ;
USHORT irgchTok;
BOOLEAN fToggle;
PPATDSC ppatdscCur;
//
// Tokensize the command line (special delimeters are tokens)
//
szT[0] = SwitChar ;
szT[1] = NULLC ;
pszTok = TokStr(pszCmdLine, szT, TS_SDTOKENS) ;
ppatdscCur = &(pdrp->patdscFirst);
//
// If there was a pattern put in place from the environment.
// just add any new patterns on. So move to the end of the
// current list.
//
if (pdrp->cpatdsc) {
while (ppatdscCur->ppatdscNext) {
ppatdscCur = ppatdscCur->ppatdscNext;
}
}
//
// At this state pszTok will be a series of zero terminated strings.
// "/o foo" wil be /0o0foo0
//
for ( irgchTok = 0; *pszTok ; pszTok += mystrlen(pszTok)+1, irgchTok = 0) {
DEBUG((ICGRP, DILVL, "PRIVSW: pszTok = %ws", (ULONG)pszTok)) ;
//
// fToggle control wither to turn off a switch that was set
// in the DIRCMD environment variable.
//
fToggle = FALSE;
if (pszTok[irgchTok] == (TCHAR)SwitChar) {
if (pszTok[irgchTok + 2] == MINUS) {
//
// disable the previously enabled the switch
//
fToggle = TRUE;
irgchTok++;
}
switch (_totupper(pszTok[irgchTok + 2])) {
case TEXT('P'):
fToggle ? (pdrp->rgfSwitchs ^= PROMPTUSERSWITCH) : (pdrp->rgfSwitchs |= PROMPTUSERSWITCH);
if (pszTok[irgchTok + 3]) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
break;
case TEXT('S'):
fToggle ? (pdrp->rgfSwitchs ^= RECURSESWITCH) : (pdrp->rgfSwitchs |= RECURSESWITCH);
if (pszTok[irgchTok + 3]) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
break;
case TEXT('F'):
fToggle ? (pdrp->rgfSwitchs ^= FORCEDELSWITCH) : (pdrp->rgfSwitchs |= FORCEDELSWITCH);
if (pszTok[irgchTok + 3]) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
break;
case QMARK:
PutStdOut(MSG_HELP_DEL_ERASE, NOARGS);
return( FAILURE );
break;
case QUIETCH:
fToggle ? (pdrp->rgfSwitchs ^= QUITESWITCH) : (pdrp->rgfSwitchs |= QUITESWITCH);
if (pszTok[irgchTok + 3]) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
break;
case TEXT('A'):
if (fToggle) {
if ( _tcslen( &(pszTok[irgchTok + 2]) ) > 1) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
pdrp->rgfAttribs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
pdrp->rgfAttribsOnOff = 0;
break;
}
if (SetDelAttribs(&(pszTok[irgchTok + 3]), pdrp) ) {
return( FAILURE );
}
break;
default:
szT[0] = SwitChar;
szT[1] = pszTok[2];
szT[2] = NULLC;
PutStdErr(MSG_INVALID_SWITCH,
ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
} // switch
//
// TokStr parses /N as /0N0 so we need to move over the
// switchar in or to move past the actual switch value
// in for loop.
//
pszTok += 2;
} else {
//
// If there already is a list then extend it else put info
// directly into structure.
//
if (pdrp->cpatdsc) {
ppatdscCur->ppatdscNext = (PPATDSC)gmkstr(sizeof(PATDSC));
ppatdscCur = ppatdscCur->ppatdscNext;
ppatdscCur->ppatdscNext = NULL;
}
pdrp->cpatdsc++;
ppatdscCur->pszPattern = (PTCHAR)gmkstr(_tcslen(pszTok)*sizeof(TCHAR) + sizeof(TCHAR));
mystrcpy(ppatdscCur->pszPattern, stripit(pszTok));
ppatdscCur->fIsFat = TRUE;
}
} // for
return( SUCCESS );
}
STATUS
DelPatterns (
IN BOOLEAN fMustExist,
IN BOOLEAN (*pfctPrint) (STATUS, PTCHAR),
IN PDRP pdpr
)
{
PPATDSC ppatdscCur;
PPATDSC ppatdscX;
PFS pfsFirst;
PFS pfsCur;
ULONG i;
STATUS rc;
BOOLEAN fRecurse;
ULONG cffTotal = 0;
TCHAR szSearchPath[MAX_PATH+2];
BOOLEAN bPrintedErr;
DosErr = 0;
if (BuildFSFromPatterns(pdpr, FALSE, &pfsFirst ) == FAILURE) {
return( FAILURE );
}
fRecurse = (BOOLEAN)(pdpr->rgfSwitchs & RECURSESWITCH);
for( pfsCur = pfsFirst; pfsCur; pfsCur = pfsCur->pfsNext) {
//DbgPrint("DelPatterns: searching for %s in %s\n",pfsCur->ppatdsc->pszPattern, pfsCur->ppatdsc->pszDir);
rc = DirWalkAndProcess(NULL,
NULL,
NULL,
&cffTotal,
NULL,
pfsCur,
pdpr,
fMustExist,
pfctPrint );
bPrintedErr=FALSE;
if (rc != SUCCESS) {
if (rc == FAILURE) {
return( rc );
}
if ((rc != ERROR_FILE_NOT_FOUND) && (rc != ERROR_NO_MORE_FILES)) {
PutStdErr(rc, NOARGS);
return( rc );
}
if (!fRecurse &&
rc == ERROR_FILE_NOT_FOUND &&
cffTotal == 0
) {
rc = SetSearchPath(pfsCur, pfsCur->ppatdsc, szSearchPath, MAX_PATH+2);
if (rc == SUCCESS) {
// PutStdErr(MSG_NOT_FOUND, ONEARG, szSearchPath);
bPrintedErr=TRUE;
}
}
}
//
// If recursing then will not have printed
// This means that cffTotal will be 0 for the single dir
// case (no subs in directory)
//
if ((cffTotal == 0) && (!bPrintedErr) &&
(!(pdpr->rgfSwitchs & PROMPTUSERSWITCH) || rc != SUCCESS)) {
if (DosErr == ERROR_ACCESS_DENIED) {
PutStdErr(DosErr, NOARGS);
} else if (DosErr == ERROR_SHARING_VIOLATION) {
PutStdErr(DosErr, NOARGS);
} else if (DosErr == ERROR_NO_MORE_FILES) {
// in this case, there were files in the directory. they weren't
// deleted for some reason, but the error has already been
// displayed.
if ((cffTotal == 0) && fEnableExtensions && (pdpr->rgfSwitchs & RECURSESWITCH)) {
PutStdErr(MSG_NOT_FOUND, ONEARG, pfsCur->ppatdsc->pszPattern);
}
//return (rc);
} else {
PutStdErr(MSG_FILE_NOT_FOUND, NOARGS);
}
}
//
//
// Have walked down and back up the tree, but in the case of
// deleting directories we have not deleted the top most directory
// do so now.
//
FreeStr(pfsCur->pszDir);
for(i = 1, ppatdscCur = pfsCur->ppatdsc;
i <= pfsCur->cpatdsc;
i++, ppatdscCur = ppatdscX) {
ppatdscX = ppatdscCur->ppatdscNext;
FreeStr(ppatdscCur->pszPattern);
FreeStr(ppatdscCur->pszDir);
FreeStr((PTCHAR)ppatdscCur);
}
}
return(rc);
}
STATUS
EraseFile (
IN PSCREEN pscr,
IN ULONG rgfSwitchs,
IN ULONG dwTimeType,
OUT PLARGE_INTEGER pcbFileTotal,
IN PFS pfs,
IN PFF pff
)
{
PWIN32_FIND_DATA pdata;
TCHAR szFile[MAX_PATH + 2];
BOOLEAN fPrompt;
BOOLEAN fQuite;
STATUS rc;
PTCHAR LastComponent;
USHORT cb;
USHORT obAlternate;
PTCHAR pszPattern;
TCHAR szFilePrompt[MAX_PATH + 2];
int incr;
pdata = &pff->data;
cb = pff->cb;
obAlternate = pff->obAlternate;
fPrompt = fQuite = FALSE;
if (rgfSwitchs & PROMPTUSERSWITCH) {
fPrompt = TRUE;
}
if (rgfSwitchs & QUITESWITCH) {
fQuite = TRUE;
}
//
// Only prompt for global delete if user didn't specify /P
//
if ((pfs->cffDisplayed == 0 &&
!fPrompt) &&
!pfs->fDelPrompted &&
(!fQuite) &&
(pszPattern = GetWildPattern(pfs->cpatdsc, pfs->ppatdsc))) {
if ((mystrlen(pfs->pszDir) + mystrlen(pszPattern) + 2) > MAX_PATH) {
PutStdErr(MSG_FILE_NOT_FOUND, NOARGS);
return( FAILURE );
}
mystrcpy(szFile,pfs->pszDir);
//
// check if it needs a trailing path char
//
if (*lastc(szFile) != BSLASH) {
mystrcat(szFile, TEXT("\\"));
}
mystrcat(szFile,pszPattern);
pfs->fDelPrompted = TRUE;
if (!PromptUser(szFile, MSG_ARE_YOU_SURE)) {
return( FAILURE+1 );
}
}
if (!(pdata->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (*lastc(pfs->pszDir) != BSLASH) {
incr = 1;
} else {
incr = 0;
}
//
// If name is too big then blow it all away
//
if ((_tcslen(pfs->pszDir) + _tcslen(pdata->cFileName) + incr) > MAX_PATH) {
PutStdErr(MSG_FILE_NOT_FOUND, NOARGS);
return( FAILURE );
}
mystrcpy(szFile, pfs->pszDir);
//
// check if it needs a trailing path char
//
if (*lastc(szFile) != BSLASH) {
mystrcat(szFile, TEXT("\\"));
}
LastComponent = lastc(szFile)+1;
// prompt should not be based on the alternat. name
mystrcpy(szFilePrompt, szFile);
mystrcat(szFilePrompt, pdata->cFileName);
if (obAlternate) {
mystrcat(szFile, &pdata->cFileName[obAlternate]);
} else {
mystrcat(szFile, pdata->cFileName);
}
if (fPrompt) {
if (!PromptUser(szFilePrompt,MSG_CMD_DELETE)) {
if (CtrlCSeen) {
return( FAILURE+1 );
}
return( SUCCESS );
}
}
if (rgfSwitchs & FORCEDELSWITCH) {
if (pdata->dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
if (!SetFileAttributes(szFile,
pdata->dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) {
PutStdErr(GetLastError(), NOARGS);
return( FAILURE );
}
}
}
if (!DeleteFile(szFile)) {
if ( (rc = GetLastError() ) == ERROR_REQUEST_ABORTED )
return (FAILURE);
if (obAlternate) {
mystrcpy(LastComponent, pdata->cFileName);
}
cmd_printf(Fmt17, szFile);
PutStdErr(rc, NOARGS);
return FAILURE;
} else {
pfs->cffDisplayed++;
if (fEnableExtensions && (rgfSwitchs & RECURSESWITCH)) {
PutStdOut(MSG_FILE_DELETED, ONEARG, szFile);
}
}
}
return SUCCESS;
}
STATUS
RemoveDirectoryForce(
PTCHAR pszDirectory
)
/*++
Routine Description:
Removes a directory, even if it is read-only.
Arguments:
pszDirectory - Supplies the name of the directory to delete.
Return Value:
SUCCESS - Success.
other - Windows error code.
--*/
{
STATUS Status = SUCCESS;
BOOL Ok;
DWORD Attr;
TCHAR szRootPath[ 4 ];
TCHAR *pFilePart;
if (GetFullPathName(pszDirectory, 4, szRootPath, &pFilePart) == 3 &&
szRootPath[1] == COLON &&
szRootPath[2] == BSLASH
) {
//
// Don't waste time trying to delete the root directory.
//
return SUCCESS;
}
if ( !RemoveDirectory( pszDirectory ) ) {
Status = (STATUS)GetLastError();
if ( Status == ERROR_ACCESS_DENIED ) {
Attr = GetFileAttributes( pszDirectory );
if ( Attr != 0xFFFFFFFF &&
Attr & FILE_ATTRIBUTE_READONLY ) {
Attr &= ~FILE_ATTRIBUTE_READONLY;
if ( SetFileAttributes( pszDirectory, Attr ) ) {
if ( RemoveDirectory( pszDirectory ) ) {
Status = SUCCESS;
} else {
Status = GetLastError();
}
}
}
}
}
return Status;
}
STATUS
RmDirSlashS(
IN PTCHAR pszDirectory,
OUT PBOOL AllEntriesDeleted
)
/*++
Routine Description:
This routine deletes the given directory including all
of its files and subdirectories.
Arguments:
pszDirectory - Supplies the name of the directory to delete.
AllEntriesDeleted - Returns whether or not all files were deleted.
Return Value:
SUCCESS - Success.
other - Windows error code.
--*/
{
HANDLE find_handle;
DWORD attr;
STATUS s;
BOOL all_deleted;
int dir_len, new_len;
TCHAR *new_str;
WIN32_FIND_DATA find_data;
TCHAR pszFileBuffer[MAX_PATH];
*AllEntriesDeleted = TRUE;
dir_len = _tcslen(pszDirectory);
// If this path is so long that we can't append \* to it then
// it can't have any subdirectories.
if (dir_len + 3 > MAX_PATH) {
return RemoveDirectoryForce(pszDirectory);
}
// Compute the findfirst pattern for enumerating the files
// in the given directory.
_tcscpy(pszFileBuffer, pszDirectory);
if (dir_len && pszDirectory[dir_len - 1] != COLON &&
pszDirectory[dir_len - 1] != BSLASH) {
_tcscat(pszFileBuffer, TEXT("\\"));
dir_len++;
}
_tcscat(pszFileBuffer, TEXT("*"));
// Initiate findfirst loop.
find_handle = FindFirstFile(pszFileBuffer, &find_data);
if (find_handle == INVALID_HANDLE_VALUE) {
return RemoveDirectoryForce(pszDirectory);
}
for (;;) {
// Check for control-C.
if (CtrlCSeen) {
break;
}
//
// Replace previous file name with new one, checking against MAX_PATH
// Using the short name where possible lets us go deeper before we hit
// the MAX_PATH limit.
//
new_len = _tcslen(new_str = find_data.cAlternateFileName);
if (!new_len)
new_len = _tcslen(new_str = find_data.cFileName);
if (dir_len + new_len >= MAX_PATH) {
*AllEntriesDeleted = FALSE;
PutStdErr(MSG_MAX_PATH_EXCEEDED, 1, pszFileBuffer);
break;
}
_tcscpy(&pszFileBuffer[dir_len], new_str);
// If the file is a directory then recurse,
// otherwise delete the file.
attr = find_data.dwFileAttributes;
if (attr&FILE_ATTRIBUTE_DIRECTORY) {
if (_tcscmp(find_data.cFileName, TEXT(".")) &&
_tcscmp(find_data.cFileName, TEXT(".."))) {
s = RmDirSlashS(pszFileBuffer, &all_deleted);
// Don't report error if control-C
if (CtrlCSeen) {
break;
}
if (s != ESUCCESS) {
*AllEntriesDeleted = FALSE;
if (s != ERROR_DIR_NOT_EMPTY || all_deleted) {
PutStdErr(MSG_FILE_NAME_PRECEEDING_ERROR, 1, pszFileBuffer);
PutStdErr(GetLastError(), NOARGS);
}
}
}
} else {
if (attr&FILE_ATTRIBUTE_READONLY) {
SetFileAttributes(pszFileBuffer,
attr&(~FILE_ATTRIBUTE_READONLY));
}
if (!DeleteFile(pszFileBuffer)) {
s = GetLastError();
if ( s == ERROR_REQUEST_ABORTED )
break;
if (_tcslen(find_data.cAlternateFileName)) {
pszFileBuffer[dir_len] = 0;
if (dir_len + _tcslen(find_data.cFileName) >= MAX_PATH) {
_tcscat(pszFileBuffer, find_data.cAlternateFileName);
PutStdErr(MSG_FILE_NAME_PRECEEDING_ERROR, 1, pszFileBuffer);
}
else {
_tcscat(pszFileBuffer, find_data.cFileName);
PutStdErr(MSG_FILE_NAME_PRECEEDING_ERROR, 1, pszFileBuffer);
pszFileBuffer[dir_len] = 0;
_tcscat(pszFileBuffer, find_data.cAlternateFileName);
}
} else {
PutStdErr(MSG_FILE_NAME_PRECEEDING_ERROR, 1, pszFileBuffer);
}
PutStdErr(GetLastError(), NOARGS);
SetFileAttributes(pszFileBuffer, attr);
*AllEntriesDeleted = FALSE;
}
}
if (!FindNextFile(find_handle, &find_data)) {
break;
}
}
FindClose(find_handle);
// If control-C was hit then don't bother trying to remove the
// directory.
if (CtrlCSeen) {
return SUCCESS;
}
return RemoveDirectoryForce(pszDirectory);
}
int
RdWork (
TCHAR *pszCmdLine
) {
//
// drp - structure holding current set of parameters. It is initialized
// in ParseDelParms function. It is also modified later when
// parameters are examined to determine if some turn others on.
//
DRP drpCur = {0, 0, 0, 0,0, {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}, NULL} ;
//
// szCurDrv - Hold current drive letter
//
TCHAR szCurDrv[MAX_PATH + 2];
//
// OldDCount - Holds the level number of the heap. It is used to
// free entries off the stack that might not have been
// freed due to error processing (ctrl-c etc.)
ULONG OldDCount;
PPATDSC ppatdscCur;
ULONG cpatdsc;
STATUS rc, s;
BOOL all_deleted;
rc = SUCCESS;
OldDCount = DCount;
//
// Setup defaults
//
//
// Display everything but system and hidden files
// rgfAttribs set the attribute bits to that are of interest and
// rgfAttribsOnOff says wither the attributs should be present
// or not (i.e. On or Off)
//
//
// BUGBUG change this to only find directories
//
drpCur.rgfAttribs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
drpCur.rgfAttribsOnOff = 0;
//
// Number of patterns present. A pattern is a string that may have
// wild cards. It is used to match against files present in the directory
// 0 patterns will show all files (i.e. mapped to *.*)
//
drpCur.cpatdsc = 0;
//
// default time is LAST_WRITE_TIME.
//
drpCur.dwTimeType = LAST_WRITE_TIME;
//
//
//
if (ParseRmDirParms(pszCmdLine, &drpCur) == FAILURE) {
return( FAILURE );
}
GetDir((PTCHAR)szCurDrv, GD_DEFAULT);
//
// If no patterns on the command line then syntax error out
//
if (drpCur.cpatdsc == 0) {
PutStdErr(MSG_BAD_SYNTAX, NOARGS);
return( FAILURE );
}
for (ppatdscCur = &(drpCur.patdscFirst),cpatdsc = drpCur.cpatdsc;
cpatdsc;
ppatdscCur = ppatdscCur->ppatdscNext, cpatdsc--) {
if (drpCur.rgfSwitchs & RECURSESWITCH) {
if (!(drpCur.rgfSwitchs & QUITESWITCH) &&
!PromptUser(ppatdscCur->pszPattern, MSG_ARE_YOU_SURE)
) {
rc = FAILURE;
} else {
s = RmDirSlashS(ppatdscCur->pszPattern, &all_deleted);
if (s != SUCCESS && (s != ERROR_DIR_NOT_EMPTY || all_deleted)) {
PutStdErr(rc = s, NOARGS);
}
}
} else {
if (!RemoveDirectory(ppatdscCur->pszPattern)) {
PutStdErr(rc = GetLastError(), NOARGS);
}
}
}
mystrcpy(CurDrvDir, szCurDrv);
//
// Free unneeded memory
//
FreeStack( OldDCount );
#ifdef _CRTHEAP_
//
// Force the crt to release heap we may have taken on recursion
//
if (drpCur.rgfSwitchs & RECURSESWITCH) {
_heapmin();
}
#endif
return( (int)rc );
}
STATUS
ParseRmDirParms (
IN PTCHAR pszCmdLine,
OUT PDRP pdrp
)
/*++
Routine Description:
Parse the command line translating the tokens into values
placed in the parameter structure. The values are or'd into
the parameter structure since this routine is called repeatedly
to build up values (once for the environment variable DIRCMD
and once for the actual command line).
Arguments:
pszCmdLine - pointer to command line user typed
Return Value:
pdrp - parameter data structure
Return: TRUE - if valid command line.
FALSE - if not.
--*/
{
PTCHAR pszTok;
TCHAR szT[10] ;
USHORT irgchTok;
BOOLEAN fToggle;
PPATDSC ppatdscCur;
int tlen;
//
// Tokensize the command line (special delimeters are tokens)
//
szT[0] = SwitChar ;
szT[1] = NULLC ;
pszTok = TokStr(pszCmdLine, szT, TS_SDTOKENS) ;
ppatdscCur = &(pdrp->patdscFirst);
//
// If there was a pattern put in place from the environment.
// just add any new patterns on. So move to the end of the
// current list.
//
if (pdrp->cpatdsc) {
while (ppatdscCur->ppatdscNext) {
ppatdscCur = ppatdscCur->ppatdscNext;
}
}
//
// At this state pszTok will be a series of zero terminated strings.
// "/o foo" wil be /0o0foo0
//
for ( irgchTok = 0; *pszTok ; pszTok += tlen+1, irgchTok = 0) {
tlen = mystrlen(pszTok);
DEBUG((ICGRP, DILVL, "PRIVSW: pszTok = %ws", (ULONG)pszTok)) ;
//
// fToggle control wither to turn off a switch that was set
// in the DIRCMD environment variable.
//
fToggle = FALSE;
if (pszTok[irgchTok] == (TCHAR)SwitChar) {
if (pszTok[irgchTok + 2] == MINUS) {
//
// disable the previously enabled the switch
//
fToggle = TRUE;
irgchTok++;
}
switch (_totupper(pszTok[irgchTok + 2])) {
case QUIETCH:
fToggle ? (pdrp->rgfSwitchs ^= QUITESWITCH) : (pdrp->rgfSwitchs |= QUITESWITCH);
if (pszTok[irgchTok + 3]) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
break;
case TEXT('S'):
fToggle ? (pdrp->rgfSwitchs ^= RECURSESWITCH) : (pdrp->rgfSwitchs |= RECURSESWITCH);
if (pszTok[irgchTok + 3]) {
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
}
break;
case QMARK:
PutStdOut(MSG_HELP_DIR, NOARGS);
return( FAILURE );
break;
default:
szT[0] = SwitChar;
szT[1] = pszTok[2];
szT[2] = NULLC;
PutStdErr(MSG_INVALID_SWITCH,
ONEARG,
(ULONG)(&(pszTok[irgchTok + 2])) );
return( FAILURE );
} // switch
//
// TokStr parses /N as /0N0 so we need to move over the
// switchar in or to move past the actual switch value
// in for loop.
//
pszTok += 2;
} else {
mystrcpy( pszTok, stripit( pszTok ) );
//
// If there already is a list the extend it else put info
// directly into structure.
//
if (pdrp->cpatdsc) {
ppatdscCur->ppatdscNext = (PPATDSC)gmkstr(sizeof(PATDSC));
ppatdscCur = ppatdscCur->ppatdscNext;
ppatdscCur->ppatdscNext = NULL;
}
pdrp->cpatdsc++;
ppatdscCur->pszPattern = (PTCHAR)gmkstr(_tcslen(pszTok)*sizeof(TCHAR) + sizeof(TCHAR));
mystrcpy(ppatdscCur->pszPattern, pszTok);
ppatdscCur->fIsFat = TRUE;
}
} // for
return( SUCCESS );
}
PTCHAR
GetWildPattern(
IN ULONG cpatdsc,
IN PPATDSC ppatdsc
)
/*
return pointer to a pattern if it contains only a wild card
*/
{
ULONG i;
PTCHAR pszT;
for(i = 1; i <= cpatdsc; i++, ppatdsc = ppatdsc->ppatdscNext) {
pszT = ppatdsc->pszPattern;
if (!_tcscmp(pszT, TEXT("*")) ||
!_tcscmp(pszT, TEXT("*.*")) ||
!_tcscmp(pszT, TEXT("????????.???")) ) {
return( pszT );
}
}
return( NULL );
}