⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tfs.c

📁 可移到ucos上的文件系统
💻 C
📖 第 1 页 / 共 4 页
字号:
			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 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -