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.
 
 
 
 
 
 

991 lines
23 KiB

/* sadmin utilities */
#include "precomp.h"
#pragma hdrstop
EnableAssert
/*** RENAME ***
*
* Rename a *file* to a new name.
*
* Effect on status file:
* Insert a new entry for the new name.
* Copy the information to the new entry; with fpiNew->fv = pfiOld->fv + 1.
* Delete the existing entry.
*
* Effect on the log file:
* An entry "rename;old v4;;;new;comment" is written to the log.
*
* Effect on the file itself:
* It is copied to the new name, then removed from the old name.
*
* Effect on catsrc (so that you can catsrc old versions of a file at a
* new name).
* It must check for these "rename" entries and shift attention from
* new to old.
*
* What happens if we have "foo@v2; bar@v3; rename bar baz; rename foo bar"?
* Doesn't that mean there are now two "bar@v3" records in the log?
* Yes, but it doesn't matter. In retrieving "baz@v2", we skip over
* the later "bar@v3" entry (because we're looking for baz entries), then
* find the "rename;baz v4;;;bar;" entry, and *then* start looking for
* bar entries; we find entries for bar@v3 and then bar@v2 and then stop.
* It seems complicated, but it *does* work.
* (We use different rules for catsrc -x.)
*/
/* Check that we have two arguments, "old-file-path new-name" */
F FRenInit(
AD *pad)
{
NE *pneOld;
NE *pneNew;
char *szNew;
/* pad->pneArgs should contain two entries, the path to the file to be
* renamed, and its new name. Neither should contain wildcards, and
* the latter must be a simple path.
*/
if (Cne(pad->pneArgs) != 2)
Usage(pad);
pneOld = pad->pneArgs;
pneNew = pneOld->pneNext;
szNew = SzOfNe(pneNew);
if (FWildSz(SzOfNe(pneOld)) || FWildSz(szNew))
{
Error("can't wildcard rename arguments\n");
Usage(pad);
}
if (index(szNew, '/') != 0)
{
Error("new name must be a simple file name, not a path\n");
Usage(pad);
}
ValidateFileName(szNew, TRUE);
/* Save the new name, then munge pneArgs so that it contains only
* the source file path. Not exactly "a gem of algoristic precision".
* REVIEW.
*/
pad->sz = szNew;
pneOld->pneNext = 0;
return fTrue;
}
/* Rename the file in pad->pneFiles to the name in pad->sz. Return fTrue
* if successful.
*/
F FRenDir(
AD *pad)
{
char *szOld;
char *szNew;
FI far *pfiOld;
FI far *pfiNew;
char szBuf[cchLineMax];
F fExists;
F fOk;
AssertF(Cne(pad->pneFiles) == 1);
szOld = SzOfNe(pad->pneFiles);
szNew = pad->sz;
if (!FLoadStatus(pad, lckAll, FlsFromCfiAdd(1)))
return fFalse;
/* Check that the old file exists, and that the new file doesn't. */
if (!FLookupSz(pad, szOld, &pfiOld, &fExists))
{
Error("%s doesn't exist\n", szOld);
goto fail;
}
if (FLookupSz(pad, szNew, &pfiNew, &fExists))
{
Error("%s is already in the project\n", szNew);
goto fail;
}
/* Too hard to rename directories. REVIEW. */
if (pfiOld->fk == fkDir)
{
Error("can't rename a directory\n");
goto fail;
}
/* Can't rename a file which is checked out. */
SzPrint(szBuf, "can't rename %&C/F, checked out to ", pad, pfiOld);
if (FOutUsers(szBuf, sizeof szBuf, pad, pfiOld))
{
Error("%s\n", szBuf);
goto fail;
}
/* Rename it. */
if (!FRenameFile(pad, pfiOld, szNew))
{
fail: AbortStatus();
return fFalse;
}
ProjectChanged(pad);
/* If enlisted, sync the two files. */
fOk = fTrue;
if (pad->iedCur != iedNil)
{
SyncVerH(pad, NULL);
/* Lookup these fi again, FRenameFile may have moved them.
*
* PfiOld should be deleted, but *must* exist. It can not be
* reused for pfiNew, because there is still an enlisted user
* who has not yet sync'd to it (pad->iedCur).
*/
if (FLookupSz(pad, szOld, &pfiOld, &fExists) || !fExists ||
!FLookupSz(pad, szNew, &pfiNew, &fExists))
AssertF(fFalse);
UnMarkAll(pad);
pfiOld->fMarked = fTrue;
pfiNew->fMarked = fTrue;
fOk = FSyncMarked(pad, NULL);
}
FlushStatus(pad);
return fOk;
}
/*** ROBUST ***/
/* Check that we have an argument and that it's either "on" or "off" */
F FRobustInit(
AD *pad)
{
AssertF(pad->sz != 0);
if (SzCmp(pad->sz, "on") != 0 && SzCmp(pad->sz, "off") != 0)
{
Error("must specify either \"on\" or \"off\"\n");
return fFalse;
}
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
CreatePeekThread(pad);
return fTrue;
}
/* Turn on/off fRobust for this dir. */
F FRobustDir(
AD *pad)
{
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
if (pad->psh->version < 3)
{
Error("robust checking cannot be turned on for %&P/C;\n"
"\tit is available only for version 3 and above status files\n",
pad);
return (fFalse);
}
pad->psh->fRobust = (SzCmp(pad->sz, "on") == 0);
if (fVerbose)
PrErr("robust checking turned %s for %&P/C\n",
pad->psh->fRobust ? "on" : "off", pad);
FlushStatus(pad);
return fTrue;
}
/*** LSSRC ***/
F FLssInit(
AD *pad)
{
Unreferenced(pad);
return fTrue;
}
F FLssDir(
AD *pad)
{
FI far *pfi;
FI far *pfiMac;
PTH pth[cchPthMax];
if (!FLoadStatus(pad, lckNil, flsNone))
return fFalse;
if (pad->pneFiles != 0)
MarkList(pad, pad->pneFiles, fFalse);
else
/* mark only the non-deleted files */
MarkNonDel(pad);
for (pfi=pad->rgfi, pfiMac=pfi+pad->psh->ifiMac; pfi < pfiMac; pfi++)
{
if (pfi->fMarked)
{
if (pad->flags&flagLssL)
PrOut("%&F\n", pad, pfi);
else
{
PthForSFile(pad, pfi, pth);
if (pad->szComment)
PrOut("%s %!s\n", pad->szComment, pth);
else
PrOut("%!s\n", pth);
}
}
}
FlushStatus(pad);
return fTrue;
}
/*** SETTYPE ***/
/* settype argument checking. Make sure fk is valid and the user isn't trying
* to set files to a version type.
*/
F FSetTInit(
AD *pad)
{
if (pad->fk == fkNil)
Usage(pad);
if (pad->fk == fkVersion)
FatalError("can't set files to version type\n");
return fTrue;
}
/* set type of files in pad->pneFiles */
F FSetTDir(
AD *pad)
{
FI far *pfi;
FI far *pfiMac;
char szBuf[cbLogPage];
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
OpenLog(pad, fTrue);
MarkList(pad, pad->pneFiles, fFalse);
for (pfi=pad->rgfi, pfiMac=pfi+pad->psh->ifiMac; pfi < pfiMac; pfi++)
{
char sz[cchLineMax];
IED ied;
IED iedMac = pad->psh->iedMac;
if (!pfi->fMarked)
continue;
SzPrint(sz, "can't set type of %&C/F, checked out to ",pad,pfi);
if (FOutUsers(sz, cchLineMax, pad, pfi))
{
Error("%s\n", sz);
continue;
}
if (pfi->fk == fkVersion)
{
Error("can't set the type of version file %&F\n",pad,pfi);
continue;
}
if (pfi->fk == fkText && pad->fk == fkUnicode)
{
Error("can't set the type of text file to unicode\n");
continue;
}
if (pfi->fk == fkUnicode && pad->fk == fkText)
{
Error("can't set the type of unicode file to text\n");
continue;
}
pfi->fk = pad->fk;
++pfi->fv;
/* Make others copy-in. If we're in sync, update our local fv*/
for (ied = 0; ied < iedMac; ied++)
{
if (!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) {
FS far *pfs = PfsForPfi(pad, ied, pfi);
switch(pfs->fm)
{
default:
case fmOut:
case fmMerge:
case fmVerify:
case fmConflict:
case fmDelOut:
AssertF(fFalse);
case fmNonExistent:
case fmDelIn:
case fmGhost:
case fmAdd:
case fmCopyIn:
break;
case fmIn:
if (ied == pad->iedCur)
pfs->fv = pfi->fv;
else
pfs->fm = fmCopyIn;
break;
}
}
}
AppendLog(pad, pfi, (char *)0,
SzPrint(szBuf, "%s;%s", mpfksz[pfi->fk],
pad->szComment ? pad->szComment : ""));
if (fVerbose)
PrErr("settype %&C/F %s\n", pad, pfi, mpfksz[pfi->fk]);
}
CloseLog();
FlushStatus(pad);
return fTrue;
}
/*** LISTED ***/
F FListInit(
AD *pad)
{
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
CreatePeekThread(pad);
return fTrue;
}
F FListDir(
AD *pad)
{
IED ied;
if (!FLoadStatus(pad, lckNil, flsNone))
return fFalse;
PrOut("IED\tOwner \tPath\t(Directory %&P/C)\n", pad);
for (ied = 0; ied < pad->psh->iedMac; ied++)
if ((!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd))
PrOut("%d\t%&O \t%&E\n", ied, pad, ied, pad, ied);
FlushStatus(pad);
return fTrue;
}
/*** DELED ***/
F FDelEdInit(
AD *pad)
{
unsigned iedToGo; /* need sizeof(int) for PchGetW */
AssertF(pad->sz != 0);
if (PchGetW(pad->sz, (int *)&iedToGo) > pad->sz &&
(pad->flags & (flagAll|flagRecursive)) != 0)
{
Error("cannot specify -r or -a with numeric ED\n");
Usage(pad);
}
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
CreatePeekThread(pad);
return fTrue;
}
private F FDelEd(
AD *pad,
IED iedToGo);
/* Remove the specified ED from the project. This function is similar to
* RemoveEd, but allows the deletion of any ed.
*/
F FDelEdDir(
AD *pad)
{
unsigned iedToGo; // need sizeof(int) to pass to PchGetW
SH far *psh;
ED far *rged;
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
psh = pad->psh;
rged = pad->rged;
/* If user specified an ied, use it, else look up pad->sz in
* rged[].nmUser or rged[].pthEd.
*/
if (PchGetW(pad->sz, (int *)&iedToGo) > pad->sz)
{
if (iedToGo >= psh->iedMac)
{
Error("%&P/C ied %d out of range [0..%d]\n",
pad, iedToGo, psh->iedMac - 1);
}
else
FDelEd(pad, (IED)iedToGo);
}
else if (index(pad->sz, '/') == 0 && index(pad->sz, '\\') == 0)
{
/* Assume pad->sz is a user name. Count number of matches.
* Warn if none, do it if one, prompt if more than one.
*/
int cMatch;
IED ied;
cMatch = 0;
iedToGo = iedNil;
for (ied = 0; ied < psh->iedMac; ied++)
{
if ((!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) &&
NmCmpSz(rged[ied].nmOwner, pad->sz, cchUserMax) ==0)
{
cMatch++;
iedToGo = ied;
}
}
if (cMatch == 0)
Warn("%&P/C no eds owned by %s\n", pad, pad->sz);
else if (cMatch == 1)
FDelEd(pad, (IED)iedToGo);
else
{
for (ied = 0; ied < psh->iedMac; )
if ((!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) &&
NmCmpSz(rged[ied].nmOwner, pad->sz, cchUserMax) == 0 &&
FCanQuery("%&P/C ED %&E not deleted\n", pad, pad, ied) &&
FQueryUser("%&P/C delete ED %&E owner %s? ",
pad, pad, ied, pad->sz))
{
if (!FDelEd(pad, ied))
break;
}
else
ied++;
}
}
else
{
/* Assume pad->sz is a path, search for matching rged[].pthEd */
F fFound = fFalse;
ConvToSlash(pad->sz);
for (iedToGo = 0; iedToGo < psh->iedMac; iedToGo++)
if ((!FIsFreeEdValid(pad->psh) || !pad->rged[iedToGo].fFreeEd) &&
PthCmp(pad->sz, rged[iedToGo].pthEd) == 0)
{
FDelEd(pad, (IED)iedToGo);
fFound = fTrue;
break;
}
if (!fFound)
{
Error("%&P/C ed %s not found\n", pad, pad->sz);
/* continue anyway */
}
}
FlushStatus(pad);
return fTrue;
}
/* Delete the specified ied. Return fTrue if successful and further deletions
* are possible.
*/
private F FDelEd(
AD *pad,
IED iedToGo)
{
SH far *psh = pad->psh;
ED far *rged = pad->rged;
FS far * far *mpiedrgfs = pad->mpiedrgfs;
FS *rgfs;
FI far *pfiMac = pad->rgfi + psh->ifiMac;
FI far *pfi;
FS far *pfs;
IED ied;
IFS ifs;
F fQueried = fFalse;
char szComment[150];
AssertF(iedToGo < psh->iedMac);
for (pfi = pad->rgfi; pfi < pfiMac; pfi++) {
pfs = PfsForPfi(pad, iedToGo, pfi);
switch(pfs->fm)
{
default: AssertF(fFalse);
case fmIn:
case fmCopyIn:
case fmGhost:
case fmAdd:
case fmNonExistent:
case fmDelIn:
break;
case fmOut:
case fmVerify:
case fmConflict:
case fmMerge:
case fmDelOut:
if (!fQueried &&
!FQueryApp("Files are still checked out to %&E",
"remove ED anyway", pad, iedToGo))
return fFalse;
fQueried = fTrue;
pfs->fm = fmDelIn;
break;
}
}
SzPrint(szComment, "Removed ED %&E", pad, iedToGo);
if (fVerbose)
PrErr("%s from %&P/C\n", szComment, pad);
if (FIsFreeEdValid(pad->psh)) {
rged[iedToGo].fFreeEd = fTrue;
rged[iedToGo].wSpare = 0;
memset(rged[iedToGo].pthEd, 0, sizeof(rged[iedToGo].pthEd));
memset(rged[iedToGo].nmOwner, 0, sizeof(rged[iedToGo].nmOwner));
rgfs = mpiedrgfs[iedToGo];
for (ifs = 0; ifs < pad->psh->ifiMac; ifs++) {
pfs = &rgfs[ifs];
pfs->fm = fmNonExistent;
pfs->bi = biNil;
pfs->fv = 0;
}
} else {
psh->iedMac--;
for (ied = iedToGo; ied < psh->iedMac; ied++)
{
rged[ied] = rged[ied+1];
mpiedrgfs[ied] = mpiedrgfs[ied+1];
}
}
/* write out to log */
OpenLog(pad, fTrue);
AppendLog(pad, (FI far *)0, (char *)0, szComment);
CloseLog();
return fTrue;
}
/*** EXFILE ***/
F FExFiInit(
AD *pad)
{
/* Force ScanLog to use whole log file. */
pad->ileMin = 1;
pad->ileMac = ileMax;
pad->tdMin.tdt = tdtNone;
return fTrue;
}
private F FExFi(
AD *,
FI far *);
private F FDelLeDiff(
AD *,
LE *,
F,
F);
/* Expunge a file and all associated diffs. This removes the source file and
* all diffs which have ever been associated with that file, and then compacts
* the rgfi and rgfs' to obliterate any record of the file. Also removes all
* log entries associated with that file.
*/
F FExFiDir(
AD *pad)
{
FI far *pfi;
F fExists;
NE *pne;
NE *pneToDelete = 0;
NE **ppneLast;
F fOk;
InitAppendNe(&ppneLast, &pneToDelete);
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
/* Build a linked list of pnes to delete from log. */
ForEachNe(pne, pad->pneFiles)
{
if (!(FLookupSz(pad, SzOfNe(pne), &pfi, &fExists) || fExists) ||
FExFi(pad, pfi))
AppendNe(&ppneLast, PneCopy(pne));
}
fOk = pneToDelete != 0 ? FCopyLog(pad, pneToDelete, FDelLeDiff, fsmUseAll|fsmInOnly) : fTrue;
FreeNe(pneToDelete);
FlushStatus(pad);
return fOk;
}
/* If the file has not been deleted, forces it to be so after obtaining user's
* approval.
*/
private F FExFi(
AD *pad,
FI far *pfi)
{
register IED ied;
register IED iedMac;
FS far *pfs;
PTH pth[cchPthMax];
PTH pthDA[cchPthMax];
MF *pmfDA;
AssertF(pfi != 0);
if (!pfi->fDeleted)
{
if (pfi->fk == fkDir)
{
PrErr("%&C/F is a directory; not deleting\n", pad, pfi);
return fFalse;
}
if (!FQueryApp("%&C/F has not been deleted","delete anyway", pad, pfi))
return fFalse;
/* check the fm for all ed */
for (ied=0, iedMac=pad->psh->iedMac; ied < iedMac; ied++) {
if (!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) {
pfs = PfsForPfi(pad, ied, pfi);
switch(pfs->fm)
{
default: AssertF(fFalse);
case fmGhost:
case fmIn:
case fmCopyIn:
case fmAdd:
case fmNonExistent:
case fmDelIn:
break;
case fmOut:
case fmVerify:
case fmMerge:
case fmConflict:
case fmDelOut:
if (!FCanQuery("%&/C/F is still checked out to %&O; not deleting\n", pad, pfi, pad, ied) ||
!FQueryUser("%&/C/F is still checked out to %&O; delete anyway ? ", pad, pfi, pad, ied))
return fFalse;
break;
}
}
}
UnlinkPth(PthForSFile(pad, pfi, pth), fxGlobal);
pfi->fDeleted = fTrue;
}
/* delete diff file if it exists */
PthForDA(pad, pfi, pthDA);
if ((pmfDA = PmfOpen(pthDA, omReadOnly, fxNil)) != (MF *)0)
{
CloseMf(pmfDA);
UnlinkPth(pthDA, fxGlobal);
}
PurgeFi(pad, (IFI)(pfi - pad->rgfi));
return fTrue;
}
/*** DELDIFF ***/
F FDlDfInit(
AD *pad)
{
if (pad->tdMin.tdt == tdtNone)
{
if (!pad->pneArgs)
{
Error("specify file(s)\n");
return fFalse;
}
/* Force ScanLog to use whole log file. */
pad->ileMin = 1;
pad->ileMac = ileMax;
}
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
CreatePeekThread(pad);
return fTrue;
}
static char szDelDiff[] = "Warning: Deleting the diff file for %s will make old versions\nof %s permanently unavailable";
F FDlDfDir(
AD *pad)
{
NE *pne;
MF *pmfDA;
PTH pthDA[cchPthMax];
F fExists;
FI *pfi;
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
ForEachNe(pne, pad->pneFiles)
{
FLookupSz(pad, SzOfNe(pne), &pfi, &fExists);
if (fExists && (pfi->fk == fkText))
{
if (!FQueryApp(szDelDiff, "continue", SzOfNe(pne), SzOfNe(pne)))
continue;
PthForDA(pad, pfi, pthDA);
/* make sure diff file already exists */
if ((pmfDA = PmfOpen(pthDA, omReadOnly, fxNil)) != (MF *)0)
{
CloseMf(pmfDA);
/* create temp file to hold the last diff entry */
pmfDA = PmfCreate(pthDA, permRW, fFalse /* fPrVerbose */, fxGlobal);
if (FCopyLastDiff(pad, SzOfNe(pne), pmfDA))
{
OpenLog(pad, fTrue);
AppendLog(pad, pfi, (char *)0, pad->szComment);
CloseLog();
CloseMf(pmfDA);
}
}
}
}
FlushStatus(pad);
return fTrue;
}
/*** TRUNCLOG ***/
F FTrLogInit(
AD *pad)
{
if (pad->tdMin.tdt == tdtNone)
Usage(pad);
if (pad->flags&flagAll || pad->pecmd->gl&fglAll)
CreatePeekThread(pad);
return fTrue;
}
private F FDelLe(
AD *,
LE *,
F,
F);
F FTrLogDir(
AD *pad)
{
F fOk;
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
fOk = FCopyLog(pad, pad->pneFiles, FDelLe, fsmUseAll);
FlushStatus(pad);
return fOk;
}
/*** COMMENT ***/
F FComInit(pad)
AD *pad;
{
if ((pad->tdMin.tdt != tdtNone) ^ (pad->ileMac != 0) != 1)
{
Error("must specify one of -t or -#\n");
Usage(pad);
}
else if (pad->ileMac != 0 && pad->ileMin == 0)
pad->ileMin = 1;
if (!pad->szComment)
{
if (!FCanQuery("no comment specified\n"))
Usage(pad);
pad->szComment = SzDup(SzQuery("Comment for selected entries: "));
}
return fTrue;
}
private F FIncCommLog(
AD *,
LE *,
F,
F);
F FComDir(
AD *pad)
{
F fOk;
if (!FLoadStatus(pad, lckAll, flsNone))
return fFalse;
fOk = FCopyLog(pad, pad->pneFiles, FIncCommLog, fsmUseAll|fsmInOnly);
FlushStatus(pad);
return fOk;
}
/* Include the given le in the new version of the log file. We have to use
* the static global pmfNewLog, since ScanLog can't pass the pmf.
* If fAddComm is fTrue (i.e. the le is in the specified date or count range
* and refers to one of the selected files), use pad->szComment as the new
* comment. Otherwise, write out the le as is.
* Called indirectly from ScanLog().
*/
private F FIncCommLog(
AD *pad,
LE *ple,
F fFirst, /* not used */
F fAddComm) /* use pad->szComment instead of ple->szComLog */
{
Unreferenced(fFirst);
if (fVerbose && fAddComm)
PrErr("comment %&C/%s v%d \"%s\"\n", pad, ple->szFile, ple->fv, pad->szComment);
PrMf(pmfNewLog, szFileLog,
ple->timeLog, ple->szUser, ple->szLogOp, ple->szURoot,
ple->szSubDir, ple->szFile, ple->fv, ple->szDiFile,
fAddComm ? pad->szComment : ple->szComLog);
return fTrue;
}
private F FDelDiff(
AD *,
LE *,
F,
F);
/* If fRemove, remove the diff file assciated with the le if it exists, and
* don't include the log entry in the new version of the log file.
* Otherwise, include the entry as is.
*/
private F FDelLeDiff(
AD *pad,
LE *ple,
F fFirst,
F fRemove)
{
return FDelLe(pad, ple, fFirst, fRemove) &&
FDelDiff(pad, ple, fFirst, fRemove);
}
/* If fRemove, don't copy the log entry to the new log file. */
private F FDelLe(
AD *pad,
LE *ple,
F fFirst,
F fRemove)
{
MF *pmf = fRemove ? &mfStderr : pmfNewLog;
Unreferenced(pad);
Unreferenced(fFirst);
if (fVerbose && fRemove)
PrErr("delete log entry ");
if (fVerbose || !fRemove)
PrMf(pmf, szFileLog, ple->timeLog, ple->szUser, ple->szLogOp,
ple->szURoot, ple->szSubDir, ple->szFile, ple->fv,
ple->szDiFile, ple->szComLog);
return fTrue;
}
/* If fRemove, remove the diff file assciated with the le if it exists. */
private F FDelDiff(
AD *pad,
LE *ple,
F fFirst,
F fRemove)
{
PTH pthDiff[cchPthMax];
TDFF tdff;
int idae;
Unreferenced(fFirst);
if (fRemove && ple->szDiFile[0])
{
GetTdffIdaeFromSzDiFile(pad, ple->szDiFile, &tdff, &idae);
if (tdff == tdffDiffFile)
{
PthForDiffSz(pad, ple->szDiFile, pthDiff);
if (FPthExists(pthDiff, fFalse))
UnlinkPth(pthDiff, fxGlobal);
}
}
return fTrue;
}