mirror of https://github.com/lianthony/NT4.0
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.
990 lines
25 KiB
990 lines
25 KiB
#include "precomp.h"
|
|
#pragma hdrstop
|
|
EnableAssert
|
|
|
|
private FI far *PfiAdd(P6(AD *pad, FI far *pfi, F fExists, char *sz, FK fk, FV fv));
|
|
private void DelFi(P2(AD *pad, FI far *pfi));
|
|
|
|
extern short wStart; // start time
|
|
|
|
#define szRes "reserved"
|
|
#define szUser "user defined"
|
|
#define szA "a"
|
|
#define szAn "an"
|
|
|
|
char const * mpfmsz[] = {
|
|
" deleted",
|
|
" in",
|
|
" out",
|
|
"*add",
|
|
"*del(in)",
|
|
"*del(out)",
|
|
"*update",
|
|
"*merge",
|
|
" ERROR1",
|
|
" ERROR2",
|
|
"*verify",
|
|
"*conflict",
|
|
" ghost"
|
|
};
|
|
|
|
char const * mpfksz[] = {
|
|
"???",
|
|
"dir",
|
|
"text",
|
|
"ascii",
|
|
"word",
|
|
"binary",
|
|
"unrecoverable",
|
|
"version",
|
|
"object",
|
|
"unicode",
|
|
szRes, szRes, szRes, szRes, szRes, szRes,
|
|
szUser, szUser, szUser, szUser, szUser,
|
|
szUser, szUser, szUser, szUser, szUser
|
|
};
|
|
|
|
char const * rgszA[] = {
|
|
szA,
|
|
szA,
|
|
szA,
|
|
szAn,
|
|
szA,
|
|
szA,
|
|
szAn,
|
|
szA,
|
|
szAn,
|
|
szAn,
|
|
szA, szA, szA, szA, szA, szA,
|
|
szAn, szAn, szAn, szAn, szAn,
|
|
szAn, szAn, szAn, szAn, szAn
|
|
};
|
|
|
|
FK
|
|
FkForCh(
|
|
char ch)
|
|
{
|
|
static char rgch[] = ".dtawbuvo.......0123456789";
|
|
char *pch;
|
|
|
|
pch = index(rgch, ch);
|
|
return pch ? (FK)(pch - rgch) : fkNil;
|
|
}
|
|
|
|
|
|
/* return pfs for pfi and ied combination */
|
|
FS far *
|
|
PfsForPfi(
|
|
register AD *pad,
|
|
IED ied,
|
|
register FI far *pfi)
|
|
{
|
|
unsigned long ifi = ((unsigned long)pfi - (unsigned long)pad->rgfi)
|
|
/sizeof(FI) ;
|
|
FS far *fsTemp;
|
|
|
|
if (pad->fQuickIO)
|
|
fsTemp = pad->rgfs;
|
|
else
|
|
fsTemp = pad->mpiedrgfs[ied];
|
|
|
|
return fsTemp + ifi;
|
|
}
|
|
|
|
|
|
/* insert a new fi (and appropriate fs) for sz; print a an error message
|
|
if the name already exists. MUST have write permission to directory in
|
|
which file is located.
|
|
|
|
We return fTrue and log the addition if successful.
|
|
|
|
NOTE: the current directory does not have to be enlisted.
|
|
*/
|
|
F
|
|
FAddFile(
|
|
register AD *pad,
|
|
char *sz,
|
|
FK fk)
|
|
{
|
|
F fDir, fExists;
|
|
FI far *pfi;
|
|
IED ied;
|
|
int cchURoot, cchURootMax;
|
|
char *szComment;
|
|
struct _stat st;
|
|
PTH pthDir[cchPthMax];
|
|
char szDiff[cchFileMax + 1];
|
|
|
|
AssertF(pad->cfiAdd != 0);
|
|
|
|
/* see if name already exists; pfi points to place to insert which
|
|
may point to a deleted name. Only compares cchFileMax chars from
|
|
name.
|
|
*/
|
|
if (FLookupSz(pad, sz, &pfi, &fExists)) {
|
|
Warn("%s has already been added to %&P/C\n", sz, pad);
|
|
return fTrue; /* not a serious error */
|
|
}
|
|
|
|
SzPrint(pthDir, "%&/U/Q/Z", pad, sz);
|
|
if (fk == fkVersion && pad->iedCur != iedNil) {
|
|
if (FStatPth(pthDir, &st)) {
|
|
Error("would destroy %s, you must remove it first\n", pthDir);
|
|
return fFalse;
|
|
}
|
|
}
|
|
else if (fk != fkVersion) {
|
|
if (!FStatPth(pthDir, &st)) {
|
|
Error("cannot access %s\n", sz);
|
|
return fFalse;
|
|
}
|
|
}
|
|
|
|
fDir = (fk != fkVersion) && (st.st_mode&S_IFDIR) != 0;
|
|
|
|
if (fDir) {
|
|
if ((strlen(pad->pthSRoot)+
|
|
strlen(pad->pthSSubDir)+
|
|
strlen(pad->nmProj) + 31 ) >= cchPthMax-1) {
|
|
Error("ADDFILE of DIRECTORY exceeds MAXPATH on server\n%&C\n", pad);
|
|
return fFalse;
|
|
}
|
|
|
|
cchURootMax = strlen(pad->pthURoot);
|
|
for (ied=0; ied<pad->psh->iedMac; ied++) {
|
|
cchURoot = strlen(pad->rged[ied].pthEd);
|
|
if (cchURoot > cchURootMax)
|
|
cchURootMax = cchURoot;
|
|
}
|
|
|
|
if ((cchURootMax+strlen(pad->pthUSubDir)+cchFileMax+4) >= cchPthMax-1) {
|
|
Error("ADDFILE of DIRECTORY exceeds MAXPATH on for some enlistment\n%&C\n", pad);
|
|
return fFalse;
|
|
}
|
|
|
|
if (fk != fkDir && fk != fkNil)
|
|
Warn("%s is a directory\n", sz);
|
|
fk = fkDir;
|
|
}
|
|
else if (fk == fkNil) {
|
|
switch (FBinaryPth(pthDir)) {
|
|
case fTrue:
|
|
fk = fkUnrec;
|
|
break;
|
|
case fText:
|
|
fk = fkText;
|
|
break;
|
|
case fUnicode:
|
|
fk = fkUnicode;
|
|
break;
|
|
}
|
|
Warn("adding %s as %s %s file\n", sz, rgszA[fk], mpfksz[fk]);
|
|
}
|
|
else if (fk == fkText) {
|
|
if (FBinaryPth(pthDir) == fTrue &&
|
|
FQueryApp("%s appears to be an unrecoverable file", "add as unrecoverable",sz))
|
|
fk = fkUnrec;
|
|
else if (FBinaryPth(pthDir) == fUnicode &&
|
|
FQueryApp("%s appears to be an Unicode text file", "add as Unicode text",sz))
|
|
fk = fkUnicode;
|
|
}
|
|
else if (fk == fkBinary) {
|
|
if (FBinaryPth(pthDir) == fText &&
|
|
FQueryApp("%s appears to be a text file", "add as text",sz))
|
|
fk = fkText;
|
|
else if (FBinaryPth(pthDir) == fUnicode &&
|
|
FQueryApp("%s appears to be an unicode file", "add as unicode",sz))
|
|
fk = fkUnicode;
|
|
}
|
|
else if (fk == fkUnicode) {
|
|
if (FBinaryPth(pthDir) == fTrue &&
|
|
FQueryApp("%s appears to be an unrecoverable file", "add as unrecoverable",sz))
|
|
fk = fkUnrec;
|
|
if (FBinaryPth(pthDir) == fText &&
|
|
FQueryApp("%s appears to be a text file", "add as text",sz))
|
|
fk = fkText;
|
|
}
|
|
|
|
if (fVerbose) {
|
|
if (fDir)
|
|
PrErr("Adding directory %s to %&P/C\n", sz, pad);
|
|
else
|
|
PrErr("Adding %s file %s to %&P/C\n", mpfksz[fk], sz, pad);
|
|
}
|
|
|
|
if ((szComment = pad->szComment) == 0) {
|
|
if (FCanQuery("no comment given for %&C/Z\n", pad, sz))
|
|
szComment = SzQuery("Comment for %&C/Z: ", pad, sz);
|
|
}
|
|
|
|
/* Add the file to the status file. */
|
|
if ((pfi = PfiAdd(pad, pfi, fExists, sz, fk, (FV)1)) == 0)
|
|
return fFalse;
|
|
|
|
strcpy(szDiff, "");
|
|
if (!fDir) {
|
|
if (fk == fkVersion) {
|
|
PTH pth[cchPthMax];
|
|
|
|
PthForSFile(pad, pfi, pth);
|
|
WritePvFile(pad, iedNil, pth, fxGlobal);
|
|
/* The user (if enlisted) is set to fmAdd and will
|
|
* get his copy when FAddFile calls SyncVerH().
|
|
*/
|
|
}
|
|
else
|
|
InstallNewSrc(pad, pfi, fTrue);
|
|
|
|
/* Create a diff file, which may prove valuable some day. */
|
|
if (pfi->fk == fkText || pfi->fk == fkUnicode)
|
|
FMkDae(pad, pfi, FMkSimDiff, /*fAdd*/fTrue, szDiff, szComment);
|
|
else if (pfi->fk == fkBinary)
|
|
FMkDae(pad, pfi, FMkCkptFile, /*fLocal*/fTrue, szDiff, szComment);
|
|
}
|
|
else {
|
|
AD ad;
|
|
|
|
/* this simplifies the calls to FMkPth, CreateStatus and
|
|
CreateLog().
|
|
*/
|
|
CopyAd(pad, &ad);
|
|
ChngDir(&ad, sz);
|
|
|
|
/* create system directories; earlier ????? */
|
|
/* create the longest one (diff) first because it might
|
|
* fail where the others wouldn't (under LanMan 2.1)
|
|
*/
|
|
FMkPth(SzPrint(pthDir, szDifPZ, &ad, (char *)NULL), (void *)0, fFalse);
|
|
FMkPth(SzPrint(pthDir, szEtcPZ, &ad, (char *)NULL), (void *)0, fFalse);
|
|
FMkPth(SzPrint(pthDir, szSrcPZ, &ad, (char *)NULL), (void *)0, fFalse);
|
|
|
|
/* create log and a copy of the status in sub-directory sz */
|
|
CreateStatus(pad, &ad);
|
|
CreateLog(&ad); /* already in sub dir */
|
|
|
|
if (pad->iedCur != iedNil && !FPthExists(PthForRc(pad, pfi, pthDir), fFalse))
|
|
/* create rc file */
|
|
CreateRc(pad, pfi);
|
|
}
|
|
AppendLog(pad, pfi, szDiff, szComment);
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* Add (sz, fk, fv) to the project. May reuse a deleted slot in the rgfi.
|
|
* Return the position of the new fi or 0 if it can't be added.
|
|
*/
|
|
FI far *
|
|
PfiAdd(
|
|
AD *pad,
|
|
FI far *pfi,
|
|
F fExists,
|
|
char *sz,
|
|
FK fk,
|
|
FV fv)
|
|
{
|
|
PTH pthDir[cchPthMax];
|
|
F fDir = (fk == fkDir); /* new file is dir? */
|
|
|
|
if (fExists && fDir != (pfi->fk == fkDir) && !FAllFsDel(pad, pfi)) {
|
|
/* Trying to add a deleted file/dir back, but as a dir/file,
|
|
* and not all users have sync'd to it yet.
|
|
*/
|
|
Error("%&C/F was deleted and some users have yet to sync\n",
|
|
pad, pfi);
|
|
return (FI far *)0;
|
|
}
|
|
|
|
if (fExists) {
|
|
/* Overwrite existing name; keep same pointer. */
|
|
|
|
// First, make sure the slot we're adding this entry into isn't a subdir.
|
|
// If so, delete it before continuing.
|
|
|
|
if (pfi->fk == fkDir) {
|
|
/* Remove now-obsolete system directories. */
|
|
RmPth(SzPrint(pthDir, szEtcPZ, pad, pfi->nmFile));
|
|
RmPth(SzPrint(pthDir, szSrcPZ, pad, pfi->nmFile));
|
|
RmPth(SzPrint(pthDir, szDifPZ, pad, pfi->nmFile));
|
|
}
|
|
|
|
SetupFi(pad, pfi, sz, fk, fv);
|
|
return pfi;
|
|
}
|
|
|
|
/* Insert fi and fs, shifting if necc; all fields initialized;
|
|
* returns a pointer to the exact fi used for the new name.
|
|
*/
|
|
pfi = PfiInsert(pad, pfi, sz, fk, fv);
|
|
|
|
return pfi;
|
|
}
|
|
|
|
|
|
/* inserts a new fi and fs before pfiNew. If the name at pfiNew is completly
|
|
deleted, use that one. If the name before pfiNew is completely deleted,
|
|
use that one. Otherwise, add one on to end or insert into middle.
|
|
This routine returns the actual pfi used.
|
|
|
|
The name and fk are installed in the fi. All of the fs for the new file
|
|
are set to fmAdd except for the current directory which is fmIn. Increments
|
|
ifiMac in the sh if neccessary. Must be in a critical section.
|
|
*/
|
|
FI far *
|
|
PfiInsert(
|
|
AD *pad,
|
|
FI far *pfiNew,
|
|
char *sz,
|
|
FK fk,
|
|
FV fv)
|
|
{
|
|
SH far *psh;
|
|
FS far *rgfs, far * far *mpiedrgfs;
|
|
IED ied;
|
|
FI far *rgfi;
|
|
IFI ifi, ifiNew;
|
|
PTH pthDir[cchPthMax];
|
|
|
|
rgfi = pad->rgfi;
|
|
psh = pad->psh;
|
|
mpiedrgfs = pad->mpiedrgfs;
|
|
|
|
AssertLoaded(pad);
|
|
AssertF(pad->cfiAdd != 0);
|
|
pad->cfiAdd--;
|
|
|
|
ifiNew = (IFI)(pfiNew - rgfi); /* NOTE: ifiNew may change below */
|
|
|
|
//ifiNew = pfiNew - rgfi; /* NOTE: ifiNew may change below */
|
|
|
|
AssertF(ifiNew <= psh->ifiMac);
|
|
|
|
if (ifiNew < psh->ifiMac && FAllFsDel(pad, pfiNew)) {
|
|
/* overwrite fi with all fm == fmNonExistent */
|
|
//*pfOWDir = (pfiNew->fk == fkDir);
|
|
|
|
// First, make sure the slot we're adding this entry into isn't a subdir.
|
|
// If so, delete it before continuing.
|
|
|
|
if (pfiNew->fk == fkDir) {
|
|
/* Remove now-obsolete system directories. */
|
|
RmPth(SzPrint(pthDir, szEtcPZ, pad, pfiNew->nmFile));
|
|
RmPth(SzPrint(pthDir, szSrcPZ, pad, pfiNew->nmFile));
|
|
RmPth(SzPrint(pthDir, szDifPZ, pad, pfiNew->nmFile));
|
|
}
|
|
}
|
|
else if (ifiNew > 0 && FAllFsDel(pad, pfiNew-1)) {
|
|
/* overwrite previous fi with all fm == fmNonExistent */
|
|
pfiNew--, ifiNew--;
|
|
//*pfOWDir = (pfiNew->fk == fkDir);
|
|
|
|
// First, make sure the slot we're adding this entry into isn't a subdir.
|
|
// If so, delete it before continuing.
|
|
|
|
if (pfiNew->fk == fkDir) {
|
|
/* Remove now-obsolete system directories. */
|
|
RmPth(SzPrint(pthDir, szEtcPZ, pad, pfiNew->nmFile));
|
|
RmPth(SzPrint(pthDir, szSrcPZ, pad, pfiNew->nmFile));
|
|
RmPth(SzPrint(pthDir, szDifPZ, pad, pfiNew->nmFile));
|
|
}
|
|
}
|
|
else {
|
|
/* inserting in middle (may be at Mac); make room for a new fi
|
|
at ifiNew; pfiNew will not change.
|
|
*/
|
|
for (ifi = psh->ifiMac; ifi > ifiNew; ifi--)
|
|
rgfi[ifi] = rgfi[ifi-1];
|
|
|
|
/* for each dir... */
|
|
for (ied = 0; ied < psh->iedMac; ied++) {
|
|
register FS far *pfs;
|
|
|
|
rgfs = mpiedrgfs[ied];
|
|
|
|
/* shift fs */
|
|
for (ifi = psh->ifiMac; ifi > ifiNew; ifi--)
|
|
rgfs[ifi] = rgfs[ifi-1];
|
|
|
|
/* init the new fs */
|
|
pfs = &rgfs[ifiNew];
|
|
ClearLpbCb((char far *)pfs, sizeof(FS));
|
|
pfs->fm = fmNonExistent;
|
|
pfs->fv = 0;
|
|
pfs->bi = biNil;
|
|
}
|
|
psh->ifiMac++;
|
|
|
|
//*pfOWDir = fFalse; /* not overwriting anything */
|
|
}
|
|
|
|
SetupFi(pad, pfiNew, sz, fk, fv);
|
|
|
|
return pfiNew;
|
|
}
|
|
|
|
|
|
/* setup fi with new name and set status of associated fs */
|
|
void
|
|
SetupFi(
|
|
AD *pad,
|
|
FI far *pfiNew,
|
|
char *sz,
|
|
FK fk,
|
|
FV fv)
|
|
{
|
|
IED ied, iedMac;
|
|
|
|
AssertLoaded(pad);
|
|
|
|
/* set the new fi */
|
|
ClearLpbCb((char far *)pfiNew, sizeof(FI));
|
|
NmCopySz(pfiNew->nmFile, sz, cchFileMax);
|
|
pfiNew->fv = fv;
|
|
pfiNew->fk = fk;
|
|
pfiNew->fMarked = fTrue;
|
|
|
|
/* for each ed, set the rgfs[ifiNew] for the new file */
|
|
iedMac = pad->psh->iedMac;
|
|
for (ied = 0; ied < iedMac; ied++) {
|
|
register FS far *pfs;
|
|
|
|
pfs = PfsForPfi(pad, ied, pfiNew);
|
|
if (ied == pad->iedCur && pfiNew->fk != fkVersion) {
|
|
/* current directory; in by definition */
|
|
pfs->fm = fmIn;
|
|
pfs->fv = fv;
|
|
}
|
|
else if (pfs->fm == fmDelIn) {
|
|
/* had most recent copy; add new */
|
|
if (pfiNew->fk == fkDir) {
|
|
pfs->fm = fmIn;
|
|
pfs->fv = pfiNew->fv;
|
|
}
|
|
else {
|
|
pfs->fm = fmCopyIn;
|
|
pfs->fv = 0;
|
|
}
|
|
}
|
|
else
|
|
if (!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) {
|
|
/* some other status; add */
|
|
pfs->fm = fmAdd;
|
|
pfs->fv = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Set all marked file's fm to deleted.
|
|
* Return fTrue if delfile should continue.
|
|
*/
|
|
F
|
|
FDelFMarked(
|
|
AD *pad,
|
|
F *pfAny)
|
|
{
|
|
IED ied;
|
|
IED iedMac = pad->psh->iedMac;
|
|
FI far *pfi;
|
|
FI far *pfiMac = pad->rgfi + pad->psh->ifiMac;
|
|
char *szComment;
|
|
char szDiff[cchFileMax + 1];
|
|
|
|
*pfAny = fFalse;
|
|
|
|
for (pfi=pad->rgfi; pfi < pfiMac; pfi++) {
|
|
if (!pfi->fMarked)
|
|
continue;
|
|
|
|
/* check the fm for all ed */
|
|
for (ied = 0; ied < iedMac; ied++) {
|
|
if ((!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) &&
|
|
FCheckedOut(pad, ied, pfi)) {
|
|
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)) {
|
|
if (!FQContinue())
|
|
return fFalse;
|
|
|
|
pfi->fMarked = fFalse;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* at this point we are committed to delete all marked files */
|
|
for (pfi=pad->rgfi; pfi < pfiMac; pfi++) {
|
|
if (!pfi->fMarked)
|
|
continue;
|
|
|
|
DelFi(pad, pfi);
|
|
|
|
if ((szComment = pad->szComment) == 0) {
|
|
if (FCanQuery("no comment given for %&C/F\n", pad, pfi))
|
|
szComment = SzQuery("Comment for %&C/F: ", pad, pfi);
|
|
}
|
|
|
|
*szDiff = '\0';
|
|
if (pfi->fk == fkText || pfi->fk == fkUnicode)
|
|
FMkDae(pad, pfi, FMkSimDiff, /*fAdd*/fFalse, szDiff, szComment);
|
|
else if (pfi->fk == fkBinary)
|
|
FMkDae(pad, pfi, FMkCkptFile, /*fLocal*/fFalse, szDiff, szComment);
|
|
|
|
AppendLog(pad, pfi, szDiff, szComment);
|
|
|
|
*pfAny = fTrue;
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* Delete the specified file from the project. Change all users' fm to a
|
|
* deleted mode.
|
|
*/
|
|
private void
|
|
DelFi(
|
|
AD *pad,
|
|
FI far *pfi)
|
|
{
|
|
IED ied;
|
|
IED iedMac = pad->psh->iedMac;
|
|
FS far *pfs;
|
|
|
|
pfi->fv++;
|
|
|
|
/* change the fm for all ed */
|
|
for (ied = 0; ied < iedMac; ied++) {
|
|
if (!FIsFreeEdValid(pad->psh) || !pad->rged[ied].fFreeEd) {
|
|
pfs = PfsForPfi(pad, ied, pfi);
|
|
pfs->fm = FmMapFm(pfs->fm, mpNonDelToDel);
|
|
}
|
|
}
|
|
|
|
/* we leave the system files because we want the other
|
|
directories to be able to continue work.
|
|
*/
|
|
if (pfi->fk != fkDir)
|
|
RmSFile(pad, pfi);
|
|
|
|
pfi->fDeleted = fTrue;
|
|
}
|
|
|
|
|
|
F
|
|
FRenameFile(
|
|
AD *pad,
|
|
FI far *pfiOld,
|
|
char *szNew)
|
|
{
|
|
FI far *pfiNew;
|
|
PTH pthOld[cchPthMax];
|
|
PTH pthNew[cchPthMax];
|
|
char szBuf[cchLineMax];
|
|
char szDiff[cchFileMax + 1];
|
|
char szLogComment[cbLogPage];
|
|
char *szComment;
|
|
F fNewExists;
|
|
|
|
AssertLoaded(pad);
|
|
AssertF(pad->cfiAdd == 1);
|
|
AssertF(pfiOld->fk != fkDir);
|
|
AssertF(!FOutUsers(szBuf, sizeof szBuf, pad, pfiOld));
|
|
|
|
if (fVerbose)
|
|
PrErr("Rename %s file %&C/F to %s\n", mpfksz[pfiOld->fk], pad, pfiOld, szNew);
|
|
|
|
if (FLookupSz(pad, szNew, &pfiNew, &fNewExists)) {
|
|
/* New file must not already exist. */
|
|
AssertF(fFalse);
|
|
}
|
|
|
|
if ((szComment = pad->szComment) == NULL) {
|
|
if (FCanQuery("no comment given for %&C/F\n", pad, pfiOld))
|
|
szComment = SzQuery("Comment for %&C/F: ", pad, pfiOld);
|
|
else
|
|
szComment = "";
|
|
}
|
|
|
|
/* Create a checkpoint file for catsrc, unless it's a version file */
|
|
/* or a unrecoverable file kind. */
|
|
strcpy(szDiff, "");
|
|
if (pfiOld->fk != fkVersion && pfiOld->fk != fkUnrec)
|
|
FMkDae(pad, pfiOld, FMkCkptFile, /*fLocal*/fFalse, szDiff, szComment);
|
|
|
|
/* Copy the old src file to the new name. We have to copy "now"
|
|
* because calling routines may also sync to the new file.
|
|
*/
|
|
PthForSFile(pad, pfiOld, pthOld);
|
|
SzPrint(pthNew, szSrcPZ, pad, szNew);
|
|
CopyNow(pthNew, pthOld, permRO, fxGlobal);
|
|
|
|
/* Delete the old file from the project. Doesn't compact, so
|
|
* pfiOld and pfiNew are still valid.
|
|
*/
|
|
DelFi(pad, pfiOld);
|
|
|
|
/* Write the rename log entry, now that DelFi has incremented
|
|
* pfiOld->fv.
|
|
*/
|
|
OpenLog(pad, fTrue);
|
|
AppendLog(pad, pfiOld, szDiff, SzPrint(szLogComment, "%s;%s", szNew, szComment));
|
|
CloseLog();
|
|
|
|
/* Add the new file to the project. */
|
|
if (PfiAdd(pad, pfiNew, fNewExists, szNew, pfiOld->fk, pfiOld->fv) == 0)
|
|
return fFalse;
|
|
|
|
/* Now pfiOld and pfiNew are invalid. */
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/* init Ed and rgfs for new ed (always at end). If fGhost, fm are set to
|
|
* fmGhost, else fmAdd.
|
|
*/
|
|
void
|
|
SetupEd(
|
|
AD *pad,
|
|
PTH pthURoot[],
|
|
NM nmUser[],
|
|
int fGhost)
|
|
{
|
|
IED ied;
|
|
IFI ifi;
|
|
SH far *psh;
|
|
ED far *ped;
|
|
FI far *rgfi;
|
|
FS far *rgfs;
|
|
FM fmDefault;
|
|
|
|
AssertLoaded(pad);
|
|
AssertF(pad->fExtraEd);
|
|
|
|
psh = pad->psh;
|
|
|
|
/* init ed; assume zeroed when allocated */
|
|
|
|
//
|
|
// Look for free ED first, from a previous defect. If
|
|
// none found, we will use the extra one already allocated
|
|
// by FLoadStatus(..., flsExtraEd)
|
|
//
|
|
|
|
if (FIsFreeEdValid(pad->psh))
|
|
for (ied = 0, ped = &pad->rged[ied]; ied < psh->iedMac; ied++, ped++) {
|
|
if (ped->fFreeEd) {
|
|
ped->fFreeEd = fFalse;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
ied = psh->iedMac;
|
|
ped = &pad->rged[ied];
|
|
}
|
|
|
|
if (fSetTime) {
|
|
if (fVerbose)
|
|
printf("Setting enlistment timestamp...\n");
|
|
ped->wSpare = wStart;
|
|
} else
|
|
if (fVerbose)
|
|
printf("Not Setting enlistment timestamp...\n");
|
|
PthCopy(ped->pthEd, pthURoot);
|
|
NmCopy(ped->nmOwner, nmUser, cchUserMax);
|
|
|
|
rgfi = pad->rgfi;
|
|
rgfs = pad->mpiedrgfs[ied];
|
|
fmDefault = fGhost ? fmGhost : fmAdd;
|
|
|
|
for (ifi = 0; ifi < psh->ifiMac; ifi++) {
|
|
rgfs[ifi].fm = rgfi[ifi].fDeleted
|
|
? fmNonExistent
|
|
: ((rgfi[ifi].fk == fkDir) ? fmAdd : fmDefault);
|
|
/* spare already zero */
|
|
rgfs[ifi].fv = 0;
|
|
rgfs[ifi].bi = biNil;
|
|
}
|
|
|
|
if (ied == psh->iedMac) {
|
|
psh->iedMac++;
|
|
}
|
|
pad->iedCur = ied;
|
|
pad->fExtraEd = fFalse;
|
|
}
|
|
|
|
|
|
/* add ed for current directory; adds .slmrc if top level dir.
|
|
Logs the action.
|
|
*/
|
|
void
|
|
AddCurEd(
|
|
AD *pad,
|
|
int fGhost)
|
|
{
|
|
PTH pth[cchPthMax];
|
|
|
|
AssertLoaded(pad);
|
|
AssertF(pad->fExtraEd);
|
|
AssertF(pad->cfiAdd == 0);
|
|
AssertF(pad->iedCur == iedNil);
|
|
|
|
if (fVerbose)
|
|
PrErr("Enlisting %!&/U/Q in %&P/C\n", pad, pad);
|
|
|
|
SetupEd(pad, pad->pthURoot, pad->nmInvoker, fGhost);
|
|
|
|
if (FTopUDir(pad) && !FPthExists(PthForRc(pad, (FI far *)0, pth), fFalse))
|
|
/* create top level rc file; others created in sync */
|
|
CreateRc(pad, (FI far *)0);
|
|
|
|
AppendLog(pad, (FI far *)0, (char *)0, (char *)0);
|
|
}
|
|
|
|
|
|
/* remove ed for current directory and deletes the rc file if top dir.
|
|
Logs the removal
|
|
*/
|
|
void
|
|
RemoveEd(
|
|
AD *pad)
|
|
{
|
|
IED ied, iedCur = pad->iedCur;
|
|
IFS ifs;
|
|
SH far *psh = pad->psh;
|
|
ED far *rged = pad->rged;
|
|
FS far * far *mpiedrgfs = pad->mpiedrgfs;
|
|
FS *rgfs;
|
|
FS *pfs;
|
|
|
|
AssertLoaded(pad);
|
|
AssertF(!pad->fExtraEd);
|
|
AssertF(iedCur != iedNil);
|
|
AssertF(mpiedrgfs[iedCur] != 0);
|
|
|
|
if (fVerbose)
|
|
PrErr("Defecting %!&/U/Q from %&P\n", pad, pad);
|
|
|
|
if (FIsFreeEdValid(pad->psh)) {
|
|
rged[iedCur].fFreeEd = fTrue;
|
|
rged[iedCur].wSpare = 0;
|
|
memset(rged[iedCur].pthEd, 0, sizeof(rged[iedCur].pthEd));
|
|
memset(rged[iedCur].nmOwner, 0, sizeof(rged[iedCur].nmOwner));
|
|
|
|
rgfs = mpiedrgfs[iedCur];
|
|
for (ifs = 0; ifs < pad->psh->ifiMac; ifs++) {
|
|
pfs = &rgfs[ifs];
|
|
pfs->fm = fmNonExistent;
|
|
pfs->bi = biNil;
|
|
pfs->fv = 0;
|
|
}
|
|
} else {
|
|
psh->iedMac--;
|
|
pad->iedCur = iedNil;
|
|
for (ied = iedCur; ied < psh->iedMac; ied++) {
|
|
rged[ied] = rged[ied+1];
|
|
mpiedrgfs[ied] = mpiedrgfs[ied+1];
|
|
}
|
|
}
|
|
|
|
if (FTopUDir(pad) && FCmpRcPfi(pad, (FI far *)0) ) {
|
|
DeleteRc(pad, (FI far *)0);
|
|
RemoveIedCache(pad);
|
|
}
|
|
|
|
AppendLog(pad, (FI far *)0, (char *)0, (char *)0);
|
|
}
|
|
|
|
|
|
/* clear ad and initialize the elements for which the default is non-zero */
|
|
void
|
|
InitAd(
|
|
AD *pad)
|
|
{
|
|
ClearPbCb((char *)pad, sizeof(AD));
|
|
|
|
PthCopySz(pad->pthSRoot, "/");
|
|
PthCopySz(pad->pthURoot, "/<unknown>");
|
|
PthCopySz(pad->pthSSubDir, "/");
|
|
PthCopySz(pad->pthUSubDir, "/");
|
|
pad->iedCur = iedNil;
|
|
pad->tdMin.tdt = pad->tdMac.tdt = tdtNone;
|
|
}
|
|
|
|
|
|
/* copys the ad and sets the fields which have allocated memory attached to
|
|
them to zero (except szComment).
|
|
*/
|
|
void
|
|
CopyAd(
|
|
AD *pad1,
|
|
AD *pad2)
|
|
{
|
|
*pad2 = *pad1;
|
|
|
|
pad2->fWLock = fFalse;
|
|
pad2->psh = 0;
|
|
pad2->rgfi = 0;
|
|
pad2->cfiAdd = 0;
|
|
pad2->rged = 0;
|
|
pad2->rged1 = 0;
|
|
pad2->mpiedrgfs = 0;
|
|
pad2->rgfs = 0;
|
|
pad2->fExtraEd = fFalse;
|
|
pad2->fMappedIO = fFalse;
|
|
pad2->fQuickIO = fFalse;
|
|
pad2->iedCur = iedNil;
|
|
pad2->pneFiles = 0;
|
|
}
|
|
|
|
|
|
/* aborts if not loaded */
|
|
void
|
|
AssertLoaded(
|
|
AD *pad)
|
|
{
|
|
AssertF(pad->psh != 0);
|
|
AssertF(pad->rgfi != 0);
|
|
if (pad->fQuickIO) {
|
|
AssertF(pad->rged1 != 0);
|
|
AssertF(pad->rgfs != 0);
|
|
}
|
|
else {
|
|
AssertF(pad->rged != 0);
|
|
AssertF(pad->mpiedrgfs != 0);
|
|
}
|
|
}
|
|
|
|
|
|
/* Return fTrue if the file is checked out. */
|
|
F
|
|
FCheckedOut(
|
|
AD *pad,
|
|
IED ied,
|
|
FI far *pfi)
|
|
{
|
|
AssertLoaded(pad);
|
|
AssertF(ied != iedNil);
|
|
|
|
return FMapFm(PfsForPfi(pad, ied, pfi)->fm, mpfmfOut);
|
|
}
|
|
|
|
|
|
F
|
|
FMapFm(
|
|
FM fm,
|
|
F mpfmf[])
|
|
{
|
|
AssertF(FValidFm(fm));
|
|
|
|
return mpfmf[fm];
|
|
}
|
|
|
|
|
|
FM
|
|
FmMapFm(
|
|
FM fm,
|
|
FM mpfmfm[])
|
|
{
|
|
AssertF(FValidFm(fm));
|
|
|
|
fm = mpfmfm[fm];
|
|
|
|
AssertF(FValidFm(fm));
|
|
return fm;
|
|
}
|
|
|
|
|
|
/* Mapping tables. Note that "non-identity" mappings are marked with a "*". */
|
|
|
|
/* Map from a non-deleted fm to a deleted one. */
|
|
FM mpNonDelToDel[] =
|
|
{
|
|
/* fmNonExistent */ fmNonExistent,
|
|
/* fmIn **/ fmDelIn,
|
|
/* fmOut **/ fmDelOut,
|
|
/* fmAdd **/ fmNonExistent,
|
|
/* fmDelIn */ fmDelIn,
|
|
/* fmDelOut */ fmDelOut,
|
|
/* fmCopyIn **/ fmDelIn,
|
|
/* fmMerge **/ fmDelOut,
|
|
/* obsolete */ fmNil,
|
|
/* obsolete */ fmNil,
|
|
/* fmVerify **/ fmDelOut,
|
|
/* fmConflict **/ fmDelOut,
|
|
/* fmGhost **/ fmNonExistent
|
|
};
|
|
|
|
/* Map from a deleted fm to a non-deleted one. */
|
|
FM mpDelToNonDel[] =
|
|
{
|
|
/* fmNonExistent**/ fmAdd,
|
|
/* fmIn */ fmIn,
|
|
/* fmOut */ fmOut,
|
|
/* fmAdd */ fmAdd,
|
|
/* fmDelIn **/ fmIn,
|
|
/* fmDelOut **/ fmOut,
|
|
/* fmCopyIn */ fmCopyIn,
|
|
/* fmMerge */ fmMerge,
|
|
/* obsolete */ fmNil,
|
|
/* obsolete */ fmNil,
|
|
/* fmVerify */ fmVerify,
|
|
/* fmConflict */ fmConflict,
|
|
/* fmGhost */ fmGhost
|
|
};
|
|
|
|
/* Map from non-dir modes to dir */
|
|
FM mpNonDirToDir[] =
|
|
{
|
|
/* fmNonExistent */ fmNonExistent,
|
|
/* fmIn */ fmIn,
|
|
/* fmOut **/ fmIn,
|
|
/* fmAdd */ fmAdd,
|
|
/* fmDelIn */ fmDelIn,
|
|
/* fmDelOut **/ fmDelIn,
|
|
/* fmCopyIn **/ fmAdd,
|
|
/* fmMerge **/ fmIn,
|
|
/* obsolete */ fmNil,
|
|
/* obsolete */ fmNil,
|
|
/* fmVerify **/ fmIn,
|
|
/* fmConflict **/ fmIn,
|
|
/* fmGhost **/ fmIn
|
|
};
|
|
|
|
|
|
/* fTrue if the fm is a candidate for ghosting */
|
|
F mpfmfCanGhost[] =
|
|
{
|
|
/* fmNonExistent */ fFalse,
|
|
/* fmIn **/ fTrue,
|
|
/* fmOut */ fFalse,
|
|
/* fmAdd **/ fTrue,
|
|
/* fmDelIn **/ fTrue,
|
|
/* fmDelOut */ fFalse,
|
|
/* fmCopyIn **/ fTrue,
|
|
/* fmMerge */ fFalse,
|
|
/* obsolete */ fFalse,
|
|
/* obsolete */ fFalse,
|
|
/* fmVerify */ fFalse,
|
|
/* fmConflict */ fFalse,
|
|
/* fmGhost */ fFalse
|
|
};
|
|
|
|
/* fTrue if the fm is a in a checked out state. */
|
|
F mpfmfOut[] =
|
|
{
|
|
/* fmNonExistent */ fFalse,
|
|
/* fmIn */ fFalse,
|
|
/* fmOut **/ fTrue,
|
|
/* fmAdd */ fFalse,
|
|
/* fmDelIn */ fFalse,
|
|
/* fmDelOut **/ fTrue,
|
|
/* fmCopyIn */ fFalse,
|
|
/* fmMerge **/ fTrue,
|
|
/* obsolete */ fFalse,
|
|
/* obsolete */ fFalse,
|
|
/* fmVerify **/ fTrue,
|
|
/* fmConflict **/ fTrue,
|
|
/* fmGhost */ fFalse,
|
|
};
|