?? tfs.c
字號(hào):
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.
*/
int
tfsadd(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.
*/
int
tfsunlink(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.
*/
int
tfsrun(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.
*/
int
tfsfstat(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);
}
int
showTfsError(int errno, char *msg)
{
if (msg)
printf("%s: %s\n",msg,tfserrmsg(errno));
else
printf("%s\n",tfserrmsg(errno));
return(errno);
}
void
exitscript(char *ignored)
{
ScriptExitFlag = EXIT_SCRIPT;
}
char *ExitHelp[] = {
"Exit a script",
"-[r]",
"Options:",
" -r remove script after exit",
0,
};
int
Exit(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);
}
int
tfsinit(void)
{
return(TFSERR_NOTAVAILABLE);
}
int
tfsfstat(char *name, TFILE *apptfp)
{
return(TFSERR_NOTAVAILABLE);
}
TFILE *
tfsstat(char *name)
{
return ((TFILE *) 0);
}
TFILE *
tfsnext(TFILE *fp)
{
return ((TFILE *) 0);
}
int
tfsrun(char **arglist,int verbose)
{
return(TFSERR_NOTAVAILABLE);
}
int
tfsunlink(char *name)
{
return(TFSERR_NOTAVAILABLE);
}
int
tfsadd(char *name, char *info, char *flags, uchar *src, int size)
{
return(TFSERR_NOTAVAILABLE);
}
long
tfsctrl(int rqst,long arg1,long arg2)
{
return(TFSERR_NOTAVAILABLE);
}
#endif /* INCLUDE_TFS else */
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -