📄 tfs.c
字号:
retval = tfsclean(tdp,0); break; case TFS_DEFRAG: for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) tfsclean(tdp,(int)arg1); retval = 0; break; case TFS_FCOUNT: if (arg1) { tdp = gettfsdev_fromprefix((char *)arg1,0); if (!tdp) retval = TFSERR_BADARG; else retval = tfsftot(tdp); } else { retval = tfsftot(0); } break; case TFS_DEFRAGON: retval = tfsclean_on(); break; case TFS_DEFRAGOFF: retval = tfsclean_off(); break; case TFS_UNOPEN: retval = tfsunopen((int)arg1); break; case TFS_FATOB: retval = tfsflagsatob((char *)arg1,&flag); 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_HEADROOM: retval = tfsheadroom(arg1); 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 = (int(*)(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, *sfp; long bflags; ulong endoftfsflash, nextfileaddr, thisfileaddr; ulong crc_pass1, crc_pass2, state_table_overhead; int ftot, cleanupcount, err, stale, ssize; if (!info) info = ""; if (!flags) flags = ""; if (tfsTrace > 0) printf("tfsadd(%s,%s,%s,0x%lx,%d)\n", name,info,flags,(ulong)src,size); /* Check for valid size and name: */ if ((size <= 0) || (!name)) return(TFSERR_BADARG); /* If name or info field length is too long, abort now... */ 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); /* If incoming flags are illegal, abort now... */ if (*flags == 0) { bflags = 0; } else { err = tfsflagsatob(flags,&bflags); if (err != TFS_OKAY) return(err); } stale = 0; cleanupcount = 0; /* Take snapshot of source crc. */ crc_pass1 = crc32(src, size); /* 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;#if INCLUDE_TFSAUTODEFRAGtryagain:#endif fp = (TFILE *)tdp->start; /* Find end of current storage: */ ftot = 0; while (fp) { if (fp->hdrsize == ERASED16) break; if (TFS_FILEEXISTS(fp)) { ftot++; 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. * Two exceptions to this: * 1. If the current file is stale, then we are here * because of a stale-file fixup at system startup. * 2. If the src file is in-place-modify then source * data is undefined. */ if (!(TFS_STALE(fp))) { if (!(bflags & TFS_IPMOD) && (!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, set a flag to indicate that the * file should be marked stale just prior to * adding the new file. */ stale = 1; } } } 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. */ thisfileaddr = (ulong)(fp+1); nextfileaddr = thisfileaddr + 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) * DEFRAGHDRSIZ) + (tdp->sectorcount * sizeof(struct sectorcrc)); 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) || (nextfileaddr < thisfileaddr) || (!tfsSpaceErased((uchar *)fp,size+TFSHDRSIZ))) {#if INCLUDE_TFSAUTODEFRAG if (!cleanupcount) { err = tfsclean(tdp,0); if (err != TFS_OKAY) { printf("tfsadd autoclean failed: %s\n", (char *)tfsctrl(TFS_ERRMSG,err,0)); return(err); } cleanupcount++; goto tryagain; } else#endif return(TFSERR_FLASHFULL); } memset((char *)&tf,0,TFSHDRSIZ); /* Do another crc on the source data. If crc_pass1 != crc_pass2 then * somehow the source is changing. This is typically caused by the fact * that the source address is within TFS space that was automatically * defragmented above. There is no need to check source data if the * source is in-place-modifiable. */ if (!(bflags & TFS_IPMOD)) { crc_pass2 = crc32(src,size); if (crc_pass1 != crc_pass2) return(TFSERR_FLAKEYSOURCE); } else crc_pass2 = ERASED32; /* Now that we have determined that we have enough space to do the * copy, if the "stale" flag was set (indicating that there is already * a file in TFS with the same name as the incoming file), we must now * mark the file stale... */ if (stale) { sfp = (TFILE *)tdp->start; while (sfp) { if (sfp->hdrsize == ERASED16) break; if (TFS_FILEEXISTS(sfp)) { if (!strcmp(TFS_NAME(sfp),name)) { err = tfsmakeStale(sfp); if (err != TFS_OKAY) return(err); break; } } sfp = nextfp(sfp,tdp); } if (!sfp) return(TFSERR_CORRUPT); } /* Copy name and info data to header. */ strcpy(tf.name, name); strcpy(tf.info, info); tf.hdrsize = TFSHDRSIZ; tf.hdrvrsn = TFSHDRVERSION; tf.filsize = size; tf.flags = bflags; tf.flags |= (TFS_ACTIVE | TFS_NSTALE); tf.filcrc = crc_pass2; tf.modtime = tfsGetLtime();#if TFS_RESERVED { int rsvd; for(rsvd=0;rsvd<TFS_RESERVED;rsvd++) tf.rsvd[rsvd] = 0xffffffff; }#endif 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,0); if (!fp) return(TFSERR_NOFILE); if (TFS_USRLVL(fp) > getUsrLvl()) return(TFSERR_USERDENIED); flags_marked_deleted = fp->flags & ~TFS_ACTIVE; if (tfsflashwrite((ulong *)&fp->flags,&flags_marked_deleted, sizeof(long)) < 0) return(TFSERR_FLASHFAILURE); tfslog(TFSLOG_DEL,name); return (TFS_OKAY);} inttfslink(char *src, char *target){ TFILE *tfp; char linfo[TFSINFOSIZE+1]; tfp = tfsstat(src); if (tfp) { tfp = tfsstat(src); strcpy(linfo,"->"); strncpy(linfo+2,src,TFSINFOSIZE-1); linfo[TFSINFOSIZE] = 0; return(tfsadd(target,linfo,"l",src,strlen(src)+1)); } return(TFSERR_NOFILE);}/* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -