📄 tfs.c
字号:
if (!tfp->flag)
return(TFSERR_BADFLAG);
fstr++;
}
return(TFS_OKAY);
}
/* hdrcrc():
* The crc of the file header was originally calculated (in tfsadd())
* with the header crc and next pointer nulled out; so a copy must
* be made and these two fields cleared. Also, note that the
* TFS_NSTALE and TFS_ACTIVE flags are forced to be set in the copy.
* This is done because it is possible that either of these bits may
* have been cleared due to other TFS interaction; hence, they need
* to be set prior to crc calculation.
* Note also that earlier versions of TFS deleted a file by clearing
* the entire flags field. This made it impossible to do a header crc
* check on a deleted file; deletion has been changed to simply clear
* the TFS_ACTIVE bit in the flags, so now a deleted file's header can
* can be crc tested by simply forcing the TFS_ACTIVE bit high as was
* mentioned above.
*/
ulong
tfshdrcrc(TFILE *hdr)
{
TFILE hdrcpy;
hdrcpy = *hdr;
hdrcpy.next = 0;
hdrcpy.hdrcrc = 0;
hdrcpy.flags |= (TFS_NSTALE | TFS_ACTIVE);
return(crc32((uchar *)&hdrcpy,TFSHDRSIZ));
}
/* validtfshdr():
* Return 1 if the header pointed to by the incoming header pointer is valid.
* Else return 0. The header crc is calculated based on the hdrcrc
* and next members of the structure being zero.
* Note that if the file is deleted, then just ignore the crc and return 1.
*/
int
validtfshdr(TFILE *hdr)
{
/* A few quick checks... */
if (!hdr || hdr->hdrsize == ERASED16)
return(0);
if (tfshdrcrc(hdr) == hdr->hdrcrc) {
return(1);
}
else {
/* Support transition to new deletion flag method...
*/
if ((hdr->flags == 0) && tfsOldDelFlagCheckActive)
return(1);
printf("Bad TFS hdr crc @ 0x%lx\n",(ulong)hdr);
return(0);
}
}
/* nextfp():
* Used as a common means of retrieving the next file header pointer. It
* does some sanity checks based on the fact that all pointers must fall
* within the TFSSTART<->TFSEND memory range and since each file is placed
* just after the previous one in linear memory space, fp->next should
* always be greater than fp.
*/
TFILE *
nextfp(TFILE *fp, TDEV *tdp)
{
if (!tdp)
tdp = gettfsdev(fp);
/* Make some basic in-range checks...
*/
if ((!tdp) || (fp < (TFILE *)tdp->start) || (fp > (TFILE *)tdp->end) ||
(fp->next < (TFILE *)tdp->start) || (fp->next > (TFILE *)tdp->end) ||
(fp->next <= fp)) {
printf("Bad TFS hdr ptr @ 0x%lx\n",(ulong)fp);
return(0);
}
return(fp->next);
}
/* tfsflasherased():
* Jump to the point in flash after the last file in TFS, then verify
* that all remaining flash that is dedicated to TFS is erased (0xff).
* If erased, return 1; else return 0.
*/
int
tfsflasherased(TDEV *tdp, int verbose)
{
ulong *lp;
TFILE *tfp;
tfp = (TFILE *)tdp->start;
while(validtfshdr(tfp))
tfp = nextfp(tfp,tdp);
lp = (ulong *)tfp;
while (lp < (ulong *)tdp->end) {
if (*lp != ERASED32) {
if (verbose)
printf("End of TFS on %s not erased at 0x%lx\n",
tdp->prefix,(ulong)lp);
return(0);
}
#ifdef WATCHDOG_ENABLED
if (((ulong)lp & 0x3f) == 0)
WATCHDOG_MACRO;
#endif
lp++;
}
return(1);
}
static int
tfsftot(TDEV *tdpin)
{
int ftot;
TFILE *tfp;
TDEV *tdp;
ftot = 0;
for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
if (!tdpin || (tdpin == tdp)) {
tfp = (TFILE *)tdp->start;
while(validtfshdr(tfp)) {
if (TFS_FILEEXISTS(tfp))
ftot++;
tfp = nextfp(tfp,tdp);
}
}
}
return(ftot);
}
/* tfsmemuse():
* Step through one (or all) TFS devices and tally up various memory usage
* totals. See definition of tfsmem structure for more details.
* If incoming tdpin pointer is NULL, then tally up for all TFS devices;
* otherwise, tally up for only the one device pointed to by tdpin.
*/
int
tfsmemuse(TDEV *tdpin, TINFO *tinfo, int verbose)
{
int devtot;
char *cfgerr;
TFILE *tfp;
TDEV *tdp;
/* Start by clearing incoming structure...
*/
tinfo->pso = 0;
tinfo->sos = 0;
tinfo->memtot = 0;
tinfo->liveftot = 0;
tinfo->deadftot = 0;
tinfo->livedata = 0;
tinfo->deaddata = 0;
tinfo->liveovrhd = 0;
tinfo->deadovrhd = 0;
if (verbose) {
printf("TFS Memory Usage...\n ");
printf(" name start end spare spsize scnt type\n");
}
devtot = 0;
for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) {
if (!tdpin || (tdpin == tdp)) {
devtot++;
tfp = (TFILE *)tdp->start;
cfgerr = (char *)0;
/* Do some sanity checks on the configuration...
*/
if ((tdp->spare >= tdp->start) && (tdp->spare <= tdp->end)) {
cfgerr = "spare within storage space";
}
if (cfgerr) {
printf("Bad %s TFS config: %s.\n",tdp->prefix,cfgerr);
}
if (verbose) {
printf("%10s: 0x%08lx|0x%08lx|",
tdp->prefix,(ulong)(tdp->start),(ulong)(tdp->end));
if (TFS_DEVTYPE_ISRAM(tdp))
printf(" - NA - | - NA - | NA ");
else
printf("0x%08lx|0x%06lx|%4ld",(ulong)(tdp->spare),
tdp->sparesize,tdp->sectorcount);
printf("|0x%lx\n",(ulong)(tdp->devinfo));
}
tinfo->memtot += ((tdp->end - tdp->start) + 1) + tdp->sparesize;
tinfo->pso += (tdp->sectorcount * 4) + 16;
tinfo->sos += tdp->sparesize;
while(validtfshdr(tfp)) {
if (TFS_FILEEXISTS(tfp)) {
tinfo->liveftot++;
tinfo->livedata += TFS_SIZE(tfp);
tinfo->liveovrhd += (TFSHDRSIZ + DEFRAGHDRSIZ);
}
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 + DEFRAGHDRSIZ));
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)
{
int tfscorrupt, filtot;
TFILE *fp, *fp1;
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;
break;
}
}
if (!(tfscorrupt & HDR_CORRUPT))
break;
else
goto nextfile;
}
/* Run a crc check on the header even if file is deleted...
*/
if (tfshdrcrc(fp) != fp->hdrcrc) {
if (verbose)
printf(" CRC error in hdr @ 0x%lx\n",(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;
}
tfsflasherased(tdp,verbose);
if (tfscorrupt)
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().
*
* Note that this function may be called as a result of the monitor
* doing an application exit. In that case, the heap is not
* re-initialized; hence, tfsAlist may already be allocated.
* If it is, then just leave it alone...
*/
if (tfsAlist == 0) {
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -