📄 tfs.c
字号:
}
else {
tinfo->deadftot++;
tinfo->deaddata += TFS_SIZE(tfp);
tinfo->deadovrhd += TFSHDRSIZ;
}
tfp = nextfp(tfp,tdp);
}
}
}
tinfo->memused = tinfo->livedata + tinfo->liveovrhd +
tinfo->deaddata + tinfo->deadovrhd + tinfo->pso + tinfo->sos;
tinfo->memfree = tinfo->memtot - tinfo->memused;
/* Remaining space may not even be big enough to contain the
* file overhead, if this is the case, show a remaining space
* of zero rather than a negative number...
*/
tinfo->memfordata =
tinfo->memfree - (devtot * (TFSHDRSIZ + sizeof(struct defraghdr)));
if (tinfo->memfordata < 0)
tinfo->memfordata = 0;
if (verbose) {
printf("\n Total memory: %d bytes (used=%d, avail=%d (%d for data)).\n",
tinfo->memtot,tinfo->memused,tinfo->memfree, tinfo->memfordata);
printf(" Per-device overhead: %d bytes ",tinfo->pso+tinfo->sos);
printf("(defrag-state=%d spare-sector=%d).\n",tinfo->pso,tinfo->sos);
printf(" File data space: %d bytes (live=%d, dead=%d).\n",
tinfo->livedata+tinfo->deaddata,
tinfo->livedata,tinfo->deaddata);
printf(" File overhead space: %d bytes (live=%d, dead=%d).\n",
tinfo->liveovrhd+tinfo->deadovrhd,
tinfo->liveovrhd,tinfo->deadovrhd);
printf(" File count: %d (live=%d, dead=%d).\n",
tinfo->liveftot+tinfo->deadftot,tinfo->liveftot,tinfo->deadftot);
printf(" Defrag will release %d bytes\n",
tinfo->deadovrhd+tinfo->deaddata);
printf("\n");
}
return(tinfo->liveftot + tinfo->deadftot);
}
/* tfscheck():
* Step through each file in a particular device making a few checks...
* - First look at the header. If hdrsize is erased, it "should" indicate
* the end of the linear list of files. To be anal about it, verify that
* the entire header is erased. If it is, we truly are at the end of the
* list; otherwise, header error.
* - Second, do a crc32 on the header.
* - Third, if the file is not deleted, then do a crc32 on the data portion
* of the file (if the file is deleted, then it really doesn't matter if
* there is a crc32 error on that data).
* - Finally, if the header is not corrupted, index to the next pointer and
* continue. If the header is corrupt, see if enough information
* in the header is valid to allow us to step to the next file. Do this
* by calculating where the next pointer should be (using current pointer,
* file+header size and mod16 adjustment) and then see if that matches the
* value stored in the actual "next" pointer. If yes, go to next file;
* else break out of the loop.
*
* The purpose is to do more sophisticated file system checks than are
* done in normal TFS operations.
*/
#define TFS_CORRUPT 1
#define HDR_CORRUPT 2
#define DATA_CORRUPT 4
int
tfscheck(TDEV *tdp, int verbose)
{
ulong hdrcrc;
int tfscorrupt, filtot;
TFILE *fp, *fp1, hdrcpy;
if (!tdp)
return(TFSERR_BADARG);
if (verbose)
printf("TFS device %s check:\n",tdp->prefix);
filtot = tfscorrupt = 0;
fp = (TFILE *)tdp->start;
while(1) {
tfscorrupt &= ~(HDR_CORRUPT | DATA_CORRUPT);
/* If hdrsize is ERASED16, then verify that the whole header is
* also ERASED16, if yes, we're at the end of the linear list of
* files; otherwise, we have a corrupt header.
*/
if (fp->hdrsize == ERASED16) {
int i;
ushort *sp;
/* If this is right at the edge of the end of the TFS device,
* then break with no further checks to this header.
*/
if ((fp+1) > (TFILE *)tdp->end)
break;
/* Make sure the entire header is erased... */
sp = (ushort *)fp;
for(i=0;i<TFSHDRSIZ;i+=2,sp++) {
if (*sp != ERASED16) {
if (verbose)
printf(" Corrupt hdr @ 0x%lx",(ulong)fp);
tfscorrupt = HDR_CORRUPT | TFS_CORRUPT;
}
}
if (!(tfscorrupt & HDR_CORRUPT))
break;
else
goto nextfile;
}
/* Run a crc check on the header even if file is deleted... */
hdrcpy = *fp;
hdrcrc = fp->hdrcrc;
hdrcpy.next = 0;
hdrcpy.hdrcrc = 0;
hdrcpy.flags |= (TFS_NSTALE | TFS_ACTIVE);
if (crc32((uchar *)&hdrcpy,TFSHDRSIZ) != hdrcrc) {
if (verbose)
printf(" CRC error in hdr @ 0x%lx",(ulong)fp);
tfscorrupt = HDR_CORRUPT | TFS_CORRUPT;
goto nextfile;
}
/* If file exists, and it's not IPMOD, run a crc check on data... */
if (TFS_FILEEXISTS(fp) && !(fp->flags & TFS_IPMOD)) {
filtot++;
if (verbose)
printf(" %s...",fp->name);
if ((!(fp->flags & TFS_IPMOD)) &&
(crc32(TFS_BASE(fp),fp->filsize) != fp->filcrc)) {
if (verbose)
printf(" CRC error in data");
tfscorrupt = DATA_CORRUPT | TFS_CORRUPT;
}
else {
if (verbose)
printf(" ok");
}
}
/* Prior to incrementing to the next file pointer, if the header
* is corrupted, attempt to salvage the next pointer...
* If the value of the next pointer matches what is calculated
* from the file size and header size, then assume it is ok
* and allow the tfscheck() loop to continue; otherwise break.
*/
nextfile:
if (tfscorrupt & HDR_CORRUPT) {
if (fp->next) {
ulong modnext;
modnext = (ulong)((int)(fp+1) + fp->filsize);
if (modnext & 0xf) {
modnext += 16;
modnext &= ~0xf;
}
if (verbose)
printf(" (next ptr ");
if (fp->next != (TFILE *)modnext) {
if (verbose)
printf("damaged)\n");
break;
}
else {
if (verbose)
printf("salvaged)");
}
}
}
fp1 = nextfp(fp,tdp);
if (!fp1) {
tfscorrupt = HDR_CORRUPT | TFS_CORRUPT;
break;
}
if ((verbose) && (TFS_FILEEXISTS(fp) || tfscorrupt))
putchar('\n');
fp = fp1;
}
if (tfscorrupt || !tfsflasherased(tdp,verbose))
return(TFSERR_CORRUPT);
if (verbose)
printf(" PASSED\n");
return (TFS_OKAY);
}
void
tfsclear(TDEV *tdp)
{
int i;
/* Clear the fileslot[] table indicating that no files are opened.
* Only clear the slots applicable to the incoming TDEV pointer.
*/
for (i = 0; i < TFS_MAXOPEN; i++) {
ulong offset;
offset = tfsSlots[i].offset;
if (offset != (ulong)-1) {
if ((tdp == (TDEV *)0) ||
((offset >= tdp->start) && (offset <= tdp->end)))
tfsSlots[i].offset = -1;
}
}
/* If the incoming TDEV pointer is NULL, then we can assume a global
* clear and go ahead and cleanup everything; otherwise, we just return
* here.
*/
if (tdp != (TDEV *)0)
return;
/* Turn off tracing. */
tfsTrace = 0;
/* Init the time retrieval function pointers to their dummy values. */
tfsGetAtime = dummyAtime;
tfsGetLtime = dummyLtime;
/* Default to using standard docommand() within scripts. */
tfsDocommand = docommand;
/* Start off with a buffer for 16 files. This is probably more than
* will be used, so it avoids reallocations in tfsreorder().
*/
tfsAlistSize = 16;
tfsAlist = (TFILE **)malloc((tfsAlistSize+1) * sizeof(TFILE **));
if (!tfsAlist) {
printf("tfsclear(): tfsAlist allocation failed\n");
tfsAlistSize = 0;
}
}
/* tfsstalecheck():
* Called at startup to clean up any file that may be in STALE mode.
* A file is stale if it was in the process of being modified
* and a power hit occurred. Refer to notes in tfsadd() for details.
* There are a few cases to be covered here...
* 1. there is no stale file; so there is nothing to do.
* 2. there is a stale file, but no other file with the same name...
* In this case, the stale file must be copied to another file (with the
* TFS_NSTALE flag set) and the stale file is deleted.
* 3. there is stale file and another file with the same name...
* In this case, the stale file is simply deleted because the other file
* with the same name is newer.
*/
static void
tfsstalecheck()
{
int err;
ulong flags;
TDEV *tdp;
TFILE *tfp, *tfpa;
char buf[16];
tfpa = (TFILE *)0;
for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
tfp = (TFILE *)tdp->start;
tfpa = (TFILE *)0;
while(validtfshdr(tfp)) {
if (TFS_FILEEXISTS(tfp)) {
if (tfpa) {
if (!strcmp(TFS_NAME(tfp),TFS_NAME(tfpa))) {
_tfsunlink(TFS_NAME(tfpa));
return;
}
}
else if (TFS_STALE(tfp)) {
tfpa = tfp;
}
}
tfp = nextfp(tfp,tdp);
}
}
if (tfpa) {
flags = TFS_FLAGS(tfpa) | TFS_NSTALE;
err = tfsadd(TFS_NAME(tfpa),TFS_INFO(tfpa),tfsflagsbtoa(flags,buf),
(char *)(TFS_BASE(tfpa)),TFS_SIZE(tfpa));
if (err != TFS_OKAY)
printf("%s: %s\n",TFS_NAME(tfpa),tfserrmsg(err));
_tfsunlink(TFS_NAME(tfpa));
}
}
/* tfsoldstyleflagcheck():
* This function is called once at startup to make a clean transition
* to a version of TFS that deletes a file by ONLY clearing the TFS_ACTIVE
* bit in the flags field (older method cleared the whole flag).
* This new deletion method makes it possible to run a crc32 check on the
* header of a deleted file; this change was made around Sept 1999.
*/
void
tfsoldstyleflagcheck(void)
{
#ifdef INCLUDE_OLDSTYLE_FLAGCHECK
static int alreadyran;
int printonce;
TDEV *tdp;
TFILE *tfp;
/* This should only occur once at startup. */
if (alreadyran)
return;
printonce = 1;
tfsOldDelFlagCheckActive = 1;
for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
tfp = (TFILE *)tdp->start;
while(validtfshdr(tfp)) {
/* If old-style deletion flag is detected, just run tfsclean */
/* (with tfsOldDelFlagCheckActive set) on the device to */
/* eliminate the delted file. */
if (tfp->flags == 0) {
if (printonce) {
printf("Cleaning up old style deletion flags...\n");
printonce = 0;
}
tfsautoclean(0,0,0,0,tdp,0,1);
break;
}
tfp = nextfp(tfp,tdp);
}
}
tfsOldDelFlagCheckActive = 0;
alreadyran = 1;
#endif
}
/* tfsdevtblinit():
* Transfer the information in tfsdevtbl (in tfsdev.h) to tfsDeviceTbl[].
* In most cases, this will be a simple copy. If the device flag is set
* to indicate that the initalization is dynamic, then use the flash
* ops to retrieve the information from the specified bank.
*
* For dynamic configuration, the "start" member of the tfsdev structure
* must be set in tfsdev.h and the "devinfo & TFS_DEVINFO_BANKMASK" area
* must contain the number of the last flash bank that is to be part of
* the TFS device. Typically this value is the same bank number as the
* starting bank, but it could span across multiple contiguous banks
* if the hardware is set up that way.
*
* To support the use of top-boot devices, plus the TFS requirement that
* the SPARE sector be at-least as large as any other sector in the device,
* this code will automatically step down the sector list until it finds
* the first large sector below all the small ones usually at the top of
* a top-boot device. The call to lastlargesector() takes care of this.
*
* NOTE:
* This dynamic configuration assumes that the end of the TFS space is
* just below the beginning of the spare space.
*
*/
void
tfsdevtblinit(void)
{
int i, startsector, endsector, bank;
TDEV *tDp, *tdp;
for(i=0;i<TFSDEVTOT;i++) {
tdp = &tfsdevtbl[i];
tDp = &tfsDeviceTbl[i];
*tDp = *tdp;
if (i == TFSDEVTOT-1)
break;
if (tdp->devinfo & TFS_DEVINFO_DYNAMIC) {
bank = tDp->devinfo & TFS_DEVINFO_BANKMASK;
/* The spare sector may not be the last sector in the device...
* device. Especially if the device is TopBoot type.
*/
if (lastlargesector(bank,&endsector,
(int *)&tDp->sparesize,(uchar **)&tDp->spare) == -1)
break;
tDp->end = tDp->spare - 1;
if (addrtosector((uchar *)tDp->start,&startsector,0,0) == -1)
break;
tDp->sectorcount = endsector - startsector;
}
}
}
/* tfsstartup():
* Called at system startup to get things properly initialized.
*/
void
tfsstartup()
{
tfsdevtblinit();
tfsclear((TDEV *)0);
tfsfixup(3,0);
tfsstalecheck();
tfsoldstyleflagcheck();
}
/* tfsexec: Treat the file as machine code that is COFF or ELF. */
static int
tfsexec(fp,verbose)
int verbose;
TFILE *fp;
{
extern int ctxMON(), ctxAPP();
int err, (*entry)(), octx;
long address;
err = tfsloadebin(fp,verbose,&address,0);
if (err != TFS_OKAY)
return(err);
entry = (int(*)())address;
octx = ctxAPP(); /* Change context to APPLICATION. */
entry(); /* Call entrypoint (may not return). */
ctxMON(octx); /* Change context to APPLICATION. */
return(TFS_OKAY);
}
/* tfsmemset():
* Superset of memset(). Includes verbose option plus verification after
* set.
*/
int
tfsmemset(uchar *to,uchar val,int count,int verbose,int verifyonly)
{
int failed;
uchar *end;
failed = 0;
if (verbose) {
printf("%s %7d bytes at 0x%08lx to 0x%02x",
verifyonly ? "vrfy" : "set ",count,(ulong)to,val);
}
if (count == 0)
goto done;
end = to+count;
if (verifyonly) {
while(to < end) {
if (*to++ != val) {
failed = 1;
break;
}
}
}
else {
while(to < end) {
*to = val;
if (*to++ != val) {
failed = 1;
break;
}
}
}
done:
if (verbose) {
if (failed)
printf(" failed");
else if (verifyonly)
printf(" OK");
printf("\n");
}
if (failed)
return(TFSERR_MEMFAIL);
else
return(TFS_OKAY);
}
/* tfsmemcpy():
* Superset of memcpy(). Includes verbose option plus verification after
* copy. Takes advantage of address alignment when possible.
*/
int
tfsmemcpy(uchar *to,uchar *from,int count,int verbose,int verifyonly)
{
int err;
register uchar *end;
if (verbose)
printf("%s %7d bytes from 0x%08lx to 0x%08lx",
verifyonly ? "vrfy" : "copy", count,(ulong)from,(ulong)to);
if (verifyonly) {
while(count) {
if (*to != *from)
break;
to++;
from++;
count--;
}
if (count) {
if (verbose) {
printf(" FAILED\n");
printf(" (0x%02x @ 0x%08lx should be 0x%02x)\n",
*to,(ulong)to,*from);
}
return(TFSERR_MEMFAIL);
}
else
if (verbose)
printf(" OK\n");
return(TFS_OKAY);
}
if (count == 0)
goto done;
if (to != from) {
err = 0;
if (!((int)to & 3) && !((int)from & 3) && !(count & 3)) {
register ulong *lto, *lfrom, *lend;
count >>= 2;
lto = (ulong *)to;
lfrom = (ulong *)from;
lend = lto + count;
while(lto < lend) {
*lto = *lfrom;
if (*lto != *lfrom) {
err = 1;
break;
}
lto++;
lfrom++;
}
}
else if (!((int)to & 1) && !((int)from & 1) && !(count & 1)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -