Page 1 of 1
why does del /q "" work like del /q *.* and ruin me
Posted: 12 Aug 2023 20:28
by nnnmmm
SET MA=%~dp0base\flashlight mod.pk4
del /q "%MA%"
renaming and sorting variable names, i only changed MA to X1 in SET, then a disater stoke, being shocked and heartbroken
del /q %MA%", was treated as del /q ""
why does del /q "" work like del /q *.* and delete everything in its current directory
maybe can someone explain it to me in few words and tips but long enough for me never to forget
what about the case of RMDIR /s /q "%YY1%" when YY1 is NOT claimed
now i have to use DEL and RD like this way
if /I exist "%X1%" del /q "%X1%"
if /I exist "%YY1%" RMDIR /s /q "%YY1%"
what other disasters are maybe waiting to happen?
del /q
del /q "
del /q ^
del /q (
del /q ** i dont know i just made up these commands
Re: why does del /q "" work like del /q *.* and ruin me
Posted: 27 Aug 2023 07:14
by dbenham
Ouch! It has been a long while since I have spent much time with batch scripts or Windows command line, but I don't remember ever seeing this abomination.
I ran some additional tests, and all of the following are treated like DEL *
Code: Select all
del ""
del "
del """"""
del .
del "."
del ".
My guess is that all the above are treated like an empty string, and for some unknown reason, DEL treats an empty string like *
The only other command I have seen behave similarly is DIR. I tried with RD/RMDIR, REN/RENAME, COPY, XCOPY, and TYPE, and none of those commands were afflicted with that disastrous design.
But there is a major difference between DIR and DEL - the filename argument is optional for DIR, but required for DEL. So the behavior makes sense for DIR.
I can't imagine how MS could have ended up with this disaster. If you had to have this "feature", DEL is probably the worst command possible - so destructive.
Re: why does del /q "" work like del /q *.* and ruin me
Posted: 27 Aug 2023 08:18
by mataha
I had a quick look at the available source code, but didn't see anything at the first glance:
Code: Select all
int eDelete(struct cmdnode *n) {
return(LastRetCode = DelWork(n->argptr));
}
Code: Select all
int DelWork(TCHAR *pszCmdLine) {
DRP drpCur = {0};
TCHAR szCurDrv[MAX_PATH + 2];
ULONG OldDCount;
STATUS rc;
OldDCount = DCount;
drpCur.rgfAttribs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
drpCur.rgfAttribsOnOff = 0;
drpCur.cpatdsc = 0;
drpCur.dwTimeType = LAST_WRITE_TIME;
if (ParseDelParms(pszCmdLine, &drpCur) == FAILURE) {
return(FAILURE);
}
GetDir((PTCHAR)szCurDrv, GD_DEFAULT);
if (drpCur.cpatdsc == 0) {
PutStdErr(MSG_BAD_SYNTAX, NOARGS);
return(FAILURE);
}
drpCur.rgfSwitches |= DELPROCESSEARLY;
rc = DelPatterns(&drpCur);
mystrcpy(CurDrvDir, szCurDrv);
FreeStack(OldDCount);
return((int)rc);
}
I'd probably look for the culprit in the method that's responsible for parsing parameters to
del:
Code: Select all
STATUS ParseDelParms(IN PTCHAR pszCmdLine, OUT PDRP pdrp) {
PTCHAR pszTok;
TCHAR szT[10];
USHORT irgchTok;
BOOLEAN fToggle;
PPATDSC ppatdscCur;
szT[0] = TEXT('/');
szT[1] = TEXT('\0');
pszTok = TokStr(pszCmdLine, szT, TS_SDTOKENS);
ppatdscCur = &(pdrp->patdscFirst);
if (pdrp->cpatdsc) {
while (ppatdscCur->ppatdscNext) {
ppatdscCur = ppatdscCur->ppatdscNext;
}
}
for (irgchTok = 0; *pszTok; pszTok += mystrlen(pszTok) + 1, irgchTok = 0) {
fToggle = FALSE;
if (pszTok[irgchTok] == (TCHAR) TEXT('/')) {
if (pszTok[irgchTok + 2] == TEXT('-')) {
fToggle = TRUE;
irgchTok++;
}
switch (_totupper(pszTok[irgchTok + 2])) {
case TEXT('P'):
fToggle ? (pdrp->rgfSwitches ^= PROMPTUSERSWITCH)
: (pdrp->rgfSwitches |= PROMPTUSERSWITCH);
if (pszTok[irgchTok + 3]) goto failure;
break;
case TEXT('S'):
fToggle ? (pdrp->rgfSwitches ^= RECURSESWITCH)
: (pdrp->rgfSwitches |= RECURSESWITCH);
if (pszTok[irgchTok + 3]) goto failure;
break;
case TEXT('F'):
fToggle ? (pdrp->rgfSwitches ^= FORCEDELSWITCH)
: (pdrp->rgfSwitches |= FORCEDELSWITCH);
if (pszTok[irgchTok + 3]) goto failure;
break;
case TEXT('?'):
BeginHelpPause();
PutStdOut(MSG_HELP_DEL_ERASE, NOARGS);
EndHelpPause();
return(FAILURE);
break;
case TEXT('Q'):
fToggle ? (pdrp->rgfSwitches ^= QUIETSWITCH)
: (pdrp->rgfSwitches |= QUIETSWITCH);
if (pszTok[irgchTok + 3]) goto failure;
break;
case TEXT('A'):
if (fToggle) {
if (_tcslen(&(pszTok[irgchTok + 2])) > 1) goto failure;
pdrp->rgfAttribs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
pdrp->rgfAttribsOnOff = 0;
break;
}
if (SetAttribs(&(pszTok[irgchTok + 3]), pdrp)) {
return(FAILURE);
}
if (pdrp->rgfAttribsOnOff & FILE_ATTRIBUTE_READONLY) {
pdrp->rgfSwitches |= FORCEDELSWITCH;
}
break;
default:
szT[0] = TEXT('/');
szT[1] = pszTok[2];
szT[2] = TEXT('\0');
PutStdErr(MSG_INVALID_SWITCH, ONEARG, (UINT_PTR)(&(pszTok[irgchTok + 2])));
return(FAILURE);
}
pszTok += 2;
} else {
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, StripQuotes(pszTok));
ppatdscCur->fIsFat = TRUE;
}
}
return(SUCCESS);
failure:
PutStdErr(MSG_PARAMETER_FORMAT_NOT_CORRECT, ONEARG, (UINT_PTR)(&(pszTok[irgchTok + 2])));
return(FAILURE);
}
Or
del's pattern parser:
Code: Select all
STATUS DelPatterns(IN PDRP pdpr) {
PPATDSC ppatdscCur, ppatdscX;
PFS pfsCur, pfsFirst;
ULONG i;
STATUS rc;
ULONG cffTotal = 0;
TCHAR szSearchPath[MAX_PATH + 2];
DosErr = 0;
if (BuildFSFromPatterns(pdpr, TRUE, FALSE, &pfsFirst) == FAILURE) {
return(FAILURE);
}
for (pfsCur = pfsFirst; pfsCur; pfsCur = pfsCur->pfsNext) {
rc = WalkTree(pfsCur,
NULL,
pdpr->rgfAttribs,
pdpr->rgfAttribsOnOff,
(BOOLEAN)(pdpr->rgfSwitches & RECURSESWITCH),
pdpr,
NULL,
NULL,
NewEraseFile,
NULL);
if (rc == FAILURE) {
return rc;
}
if (rc != SUCCESS && rc != ERROR_FILE_NOT_FOUND) {
PutStdErr(rc, NOARGS);
return rc;
}
if (rc == ERROR_FILE_NOT_FOUND) {
rc = AppendPath(szSearchPath,
sizeof(szSearchPath) / sizeof(TCHAR),
pfsCur->pszDir,
pfsCur->ppatdsc->pszPattern);
if (rc == SUCCESS) {
PutStdErr(MSG_NOT_FOUND, ONEARG, szSearchPath);
}
}
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);
}
Re: why does del /q "" work like del /q *.* and ruin me
Posted: 22 Sep 2023 06:28
by nnnmmm
> seeing this abomination.......I can't imagine how MS could have ended up with this disaster. DEL is probably the worst command possible - so destructive.
your statement is gonna make me not forget the damn DEL thing
i didnt get a response for this issue maybe for 2 weeks, so i thought it could just be something that was too obvious to pro's, but not to someone much less. so i moved on... but now
oh yeah!! worst and so destructive abomination, right on!!!