📄 tfs.c
字号:
if (retval == TFS_OKAY) retval = flag; break; case TFS_FBTOA: retval = (long)tfsflagsbtoa(arg1,(char *)arg2); if (retval == 0) retval = TFSERR_BADARG; break; case TFS_TELL: retval = tfstell(arg1); break; case TFS_TIMEFUNCS: tfsGetLtime = (long(*)(void))arg1; tfsGetAtime = (char *(*)(long,char *,int))arg2; retval = TFS_OKAY; break; case TFS_DOCOMMAND: if (arg2) *(long *)arg2 = (long)tfsDocommand; if (arg1) tfsDocommand = (void(*)(char *,int))arg1; else tfsDocommand = docommand; retval = TFS_OKAY; break; default: retval = TFSERR_BADARG; break; } return(retval);}/* tfsadd(): * Add a file to the current list. * If the file already exists AND everything is identical between the * old and the new (flags, info and data), then return and do nothing; * else remove the old file prior to adding the new one. * * Note: * At the point when tfsadd is called for a file that currently exists, * the old file must be removed and a new one is put in its place. This * opens up the possibility of losing the file if a power-hit or reset was * to occur between the point at which the old file was removed and the new * one was put in its place. To overcome this problem, TFS files have a * flag called TFS_NSTALE. It is a bit that is normally 1, but cleared * if it becomes stale (hence the name TFS_NSTALE). A file is * in this mode only for a short time... the time it takes to write the * new file that replaces the file that was made stale. * Now, if a reset occurs after the file is stale, depending on * whether or not the new file was written, it will either be removed or * used to recreate the original file because the write of the new file * was chopped off by the power hit. Refer to the function tfsstalecheck() * for details on the recovery after a reset or powerhit. * MONLIB NOTICE: this function is accessible through monlib.c. */inttfsadd(char *name, char *info, char *flags, uchar *src, int size){ TDEV *tdp; TFILE *fp, tf; ulong endoftfsflash, nextfileaddr, state_table_overhead; int ftot, cleanupcount, err, stale, ssize; if (tfsTrace > 0) printf("tfsadd(%s,%s,%s,0x%lx,%d)\n", name,info,flags,(ulong)src,size); if ((size <= 0) || (!name)) return(TFSERR_BADARG); if ((strlen(name) > TFSNAMESIZE) || ((info) && (strlen(info) > TFSINFOSIZE))) return(TFSERR_NAMETOOBIG); /* If the file is currently opened, then don't allow the add... */ if (tfsFileIsOpened(name)) return(TFSERR_FILEINUSE); stale = 0; cleanupcount = 0; /* Establish the device that is to be used for the incoming file * addition request... The device used depends on the prefix of * the incoming file name. If the incoming prefix doesn't match * any of the devices in the table, then place the file in the * first device in the table (assumed to be the default). */ for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { if (!strncmp(name,tdp->prefix,strlen(tdp->prefix))) break; } if (tdp->start == TFSEOT) tdp = tfsDeviceTbl;tryagain: fp = (TFILE *)tdp->start; /* Find end of current storage: */ ftot = 0; while (fp) { if (fp->hdrsize == ERASED16) break; if (TFS_FILEEXISTS(fp)) { ftot++; if (fp->flags & TFS_NSTALE) { if (!strcmp(TFS_NAME(fp),name)) { /* If file of the same name exists AND it is identical to * the new file to be added, then return TFS_OKAY and be * done; otherwise, remove the old one and continue. */ if (!tfscompare(fp,name,info,flags,src,size)) return(TFS_OKAY); /* If a file of the same name exists but is different than * the new file, make the current file stale, then after * the new file is added we will delete the stale one. */ stale = 1; err = tfsmakeStale(fp); if (err == TFS_OKAY) goto tryagain; else return(err); } } } fp = nextfp(fp,tdp); } if (!fp) /* If fp is 0, then nextfp() (above) detected corruption. */ return(TFSERR_CORRUPT); /* Calculate location of next file (on mod16 address). This will be * initially used to see if we have enough space left in flash to store * the current request; then, if yes, it will become part of the new * file's header. */ nextfileaddr = ((ulong)(fp+1)) + size; if (nextfileaddr & 0xf) nextfileaddr = (nextfileaddr | 0xf) + 1; /* Make sure that the space is available for writing to flash... * Remember that the end of useable flash space must take into * account the fact that some space must be left over for the * defragmentation state tables. Also, the total space needed for * state tables cannot exceed the size of the sector that will contain * those tables. */ state_table_overhead = ((ftot+1) * sizeof(struct defraghdr)) + (tdp->sectorcount * sizeof(long)); if (addrtosector((uchar *)(tdp->end),0,&ssize,0) < 0) return(TFSERR_MEMFAIL); if (state_table_overhead >= (ulong)ssize) return(TFSERR_FLASHFULL); endoftfsflash = (tdp->end + 1) - state_table_overhead; if ((nextfileaddr >= endoftfsflash) || (!tfsSpaceErased((uchar *)fp,size+TFSHDRSIZ))) { if (!cleanupcount) { err = tfsautoclean(0,0,0,0,tdp,0,0); if (err != TFS_OKAY) { printf("tfsadd autoclean failed: %s\n", (char *)tfsctrl(TFS_ERRMSG,err,0)); return(err); } cleanupcount++; goto tryagain; } else return(TFSERR_FLASHFULL); } memset((char *)&tf,0,TFSHDRSIZ); /* Copy name and info data to header. */ strcpy(tf.name, name); if (info) strcpy(tf.info, info); tf.hdrsize = TFSHDRSIZ; tf.hdrvrsn = TFSHDRVERSION; tf.filsize = size; if ((flags == (char *)0) || (*flags == 0)) tf.flags = 0; else { err = tfsflagsatob(flags,&tf.flags); if (err != TFS_OKAY) return(err); } tf.flags |= (TFS_ACTIVE | TFS_NSTALE); if (!(tf.flags & TFS_IPMOD)) tf.filcrc = crc32(src, size); else tf.filcrc = ERASED32; tf.modtime = tfsGetLtime(); tf.next = 0; tf.hdrcrc = 0; tf.hdrcrc = crc32((uchar *)&tf,TFSHDRSIZ); tf.next = (TFILE *)nextfileaddr; /* Now copy the file and header to flash. * Note1: the header is copied AFTER the file has been * successfully copied. If the header was written successfully, * then the data write failed, the header would be incorrectly * pointing to an invalid file. To avoid this, simply write the * data first. * Note2: if the file is in-place-modifiable, then there is no * file data to be written to the flash. It will be left as all FFs * so that the flash can be modified by tfsipmod() later. */ /* Write the file to flash if not TFS_IPMOD: */ if (!(tf.flags & TFS_IPMOD)) { if (tfsflashwrite((ulong *)(fp+1),(ulong *)src,size) == -1) return(TFSERR_FLASHFAILURE); } /* Write the file header to flash: */ if (tfsflashwrite((ulong *)fp,(ulong *)(&tf),TFSHDRSIZ) == -1) return(TFSERR_FLASHFAILURE); /* Double check the CRC now that it is in flash. */ if (!(tf.flags & TFS_IPMOD)) { if (crc32((uchar *)(fp+1), size) != tf.filcrc) return(TFSERR_BADCRC); } /* If the add was a file that previously existed, then the stale flag * will be set and the old file needs to be deleted... */ if (stale) { err = _tfsunlink(name); if (err != TFS_OKAY) printf("%s: %s\n",name,tfserrmsg(err)); } tfslog(TFSLOG_ADD,name); return(TFS_OKAY);}/* tfsunlink(): * Delete a file from the current list of files. Note that there * is no attempt to de-fragment the flash; it simply nulls out the flags * field of the file. If successful return 0; else return error number. * MONLIB NOTICE: this function is accessible through monlib.c. */inttfsunlink(char *name){ if (tfsTrace > 0) printf("tfsunlink(%s)\n",name); /* If the file is currently opened, then don't allow the deletion... */ if (tfsFileIsOpened(name)) return(TFSERR_FILEINUSE); return(_tfsunlink(name));}int_tfsunlink(char *name){ TFILE *fp; ulong flags_marked_deleted; if (tfsTrace > 0) printf("_tfsunlink(%s)\n",name); fp = tfsstat(name); if (!fp) return(TFSERR_NOFILE); if (TFS_USRLVL(fp) > getUsrLvl()) return(TFSERR_USERDENIED); flags_marked_deleted = fp->flags & ~TFS_ACTIVE; if (tfsflashwrite(&fp->flags,&flags_marked_deleted,sizeof(long)) < 0) return(TFSERR_FLASHFAILURE); tfslog(TFSLOG_DEL,name); return (TFS_OKAY);}/* tfsrun(): * Run the named file. Based on the file flags, the file is either * executed as a COFF/ELF file with all relocation data in the file * or run as a simple script of monitor commands. * MONLIB NOTICE: this function is accessible through monlib.c. */inttfsrun(char **arglist,int verbose){ int i; TFILE *fp; char namebak[TFSNAMESIZE+8], *name; name = arglist[0]; fp = tfsstat(name); if (!fp) return(TFSERR_NOFILE); if (TFS_USRLVL(fp) > getUsrLvl()) return(TFSERR_USERDENIED); /* Store away the argument list so that it is accessible by the script * or executable application about to be run: */ for(i=0;arglist[i];i++) putargv(i,arglist[i]); putargv(i,(char *)0); /* If the incoming named file doesn't exist, and that incoming name is * the TFS_RCFILE string, then try TFS_RCFILE.bak as an alternative. * This allows the user to copy TFS_RCFILE to TFS_RCFILE.bak, then * delete/reload TFS_RCFILE. Note that usually TFS_RCFILE is "monrc". */ if (!fp) { if (!strcmp(name,TFS_RCFILE)) { sprintf(namebak,"%s.bak",TFS_RCFILE); fp = tfsstat(namebak); if (!fp) return(TFSERR_NOFILE); name = namebak; printf("Running %s...\n",namebak); } else return (TFSERR_NOFILE); } /* Executable file can be script or binary... */ if (!(fp->flags & (TFS_EXEC|TFS_EBIN))) return(TFSERR_NOTEXEC); if (!(fp->flags & TFS_IPMOD)) { if (crc32(TFS_BASE(fp), fp->filsize) != fp->filcrc) return(TFSERR_BADCRC); } /* Machine code or script... */ if (fp->flags & TFS_EBIN) return(tfsexec(fp,verbose)); else return(tfsscript(fp,verbose));}/* tfsnext(): * Called to retrieve the "next" file in the tfs list. If * incoming argument is NULL then return the first file in the list. If no * more files, return NULL; else return the tfshdr structure pointer to the * next (or first) file in the tfs. * MONLIB NOTICE: this function is accessible through monlib.c. */TFILE *tfsnext(TFILE *fp){ TDEV *tdp; TFILE *fpnext; if (!fp) { tdp = tfsDeviceTbl; fpnext = (TFILE *) tfsDeviceTbl[0].start; } else { tdp = gettfsdev(fp); fpnext = nextfp(fp,0); } while(tdp->start != TFSEOT) { while(validtfshdr(fpnext)) { if (TFS_FILEEXISTS(fpnext)) return (fpnext); fpnext = nextfp(fpnext,0); } tdp++; fpnext = (TFILE *)tdp->start; } return ((TFILE *) 0);}/* tfsstat(): * Steps through the list of files until it finds the specified * filename or reaches the end of the list. If found, a pointer to that * file's structure is returned; else return 0. * MONLIB NOTICE: this function is accessible through monlib.c. */TFILE *tfsstat(char *name){ TDEV *tdp; TFILE *fp; if (tfsTrace > 0) printf("tfsstat(%s)\n",name); for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { fp = (TFILE *) tdp->start; while(validtfshdr(fp)) { if (TFS_FILEEXISTS(fp) && (strcmp(name, fp->name) == 0)) return(fp); fp = nextfp(fp,tdp); } } return ((TFILE *) 0);}/* tfsfstat(): * Very similar in purpose to tfsstat(). This version is provided to the * API as a "defrag-safe" version of tfsstat()... * If tfsstat() is called (returning a pointer into TFS memory space), then * a defragmentation occurs, that pointer is stale; hence, the need for * an alternative that will load the content of the TFILE structure into * an application-supplied block of memory (usually a pointer to a local * TFILE structure). Using tfsfstat avoids this because if a defrag occurs, * it does not affect the content of the locally stored TFILE structure. * NOTE: * addition of this function to the TFS API was due to the fact that * I did not consider the above described condition when first adding * tfsstat() to the TFS API. In general, tfsfstat() should be considered * a replacement for all tfsstat() situations that will dereference the * pointer. * NOTE1: * The return value is similar to standard "stat"... Return 0 if * successful, else -1. */inttfsfstat(char *name, TFILE *apptfp){ TFILE *tfp; int otrace; otrace = tfsTrace; if (tfsTrace > 0) { tfsTrace = 0; printf("tfsfstat(%s)\n",name); } tfp = tfsstat(name); tfsTrace = otrace; if (!tfp) return(-1); *apptfp = *tfp; return(0);}intshowTfsError(int errno, char *msg){ if (msg) printf("%s: %s\n",msg,tfserrmsg(errno)); else printf("%s\n",tfserrmsg(errno)); return(errno);}voidexitscript(char *ignored){ ScriptExitFlag = EXIT_SCRIPT;}char *ExitHelp[] = { "Exit a script", "-[r]", "Options:", " -r remove script after exit", 0,};intExit(int argc, char *argv[]){ ScriptExitFlag = EXIT_SCRIPT; if ((argc == 2) && (!strcmp(argv[1],"-r"))) ScriptExitFlag |= REMOVE_SCRIPT; return(0);}#else /* INCLUDE_TFS */char *tfserrmsg(int errno){ return(0);}inttfsinit(void){ return(TFSERR_NOTAVAILABLE);}inttfsfstat(char *name, TFILE *apptfp){ return(TFSERR_NOTAVAILABLE);}TFILE *tfsstat(char *name){ return ((TFILE *) 0);}TFILE *tfsnext(TFILE *fp){ return ((TFILE *) 0);}inttfsrun(char **arglist,int verbose){ return(TFSERR_NOTAVAILABLE);}inttfsunlink(char *name){ return(TFSERR_NOTAVAILABLE);}inttfsadd(char *name, char *info, char *flags, uchar *src, int size){ return(TFSERR_NOTAVAILABLE);}longtfsctrl(int rqst,long arg1,long arg2){ return(TFSERR_NOTAVAILABLE);}#endif /* INCLUDE_TFS else */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -