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

📄 tfs.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* 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);

		/* If we're adding a link, then the size better be zero...
		 */
		if ((bflags & TFS_SYMLINK) && (size != 0))
			return(TFSERR_LINKERROR);
	}

	/* If size is zero, but the request is not a link, then
	 * error...
	 */
	if ((size == 0) && ((bflags & TFS_SYMLINK) != TFS_SYMLINK))
		return(TFSERR_BADARG);

	stale = 0;
	cleanupcount = 0;

	/* Take snapshot of source crc.  Note that we only run the CRC
	 * if the IPMOD flag is not set.  If this flag is set, then the
	 * CRC is invalid...
	 */
	if (!(bflags & TFS_IPMOD))
		crc_pass1 = crc32(src, size);
	else
		crc_pass1 = 0;

	/* Establish the device that is to be used for the incoming file
	 * addition request...
	 */
	tdp = tfsNameToDevice(name);

#ifndef TFS_DISABLE_AUTODEFRAG
tryagain:
#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 (!(TFS_STALE(fp))) {
					/* If destination file exists, but we do not meet the
					 * user level requirements, return error now.
					 */
					if (TFS_USRLVL(fp) > getUsrLvl()) 
						return(TFSERR_USERDENIED);

					/* 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 (!(bflags & TFS_IPMOD) && 
						(!tfscompare(fp,name,info,flags,src,size))) {
						return(TFS_OKAY);
					}
				
#ifdef TFS_DISABLE_MAKE_BEFORE_BREAK
					err = _tfsunlink(name);
					if (err != TFS_OKAY)
						printf("%s: %s\n",name,tfserrmsg(err));
#else
					/* 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;
#endif
				}
			}
		}
		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.  
	 */
	if (TFS_DEVTYPE_ISRAM(tdp)) {
		endoftfsflash = tdp->end;
	}
	else {
		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))) {
#ifndef TFS_DISABLE_AUTODEFRAG
		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)) {
					if (TFS_DEVTYPE_ISRAM(tdp)) {
						TFS_FLAGS(sfp) &= ~TFS_NSTALE;
					}
					else {
						if ((err = tfsmakeStale(sfp)) != 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 (TFS_DEVTYPE_ISRAM(tdp))
			memcpy((char *)(fp+1),src,size);
		else {
			rc = tfsflashwrite((uchar *)(fp+1),(uchar *)src,size);
			if (rc != TFS_OKAY)
				return(rc);
		}
	}

	/* Write the file header to flash:
	 */
	if (TFS_DEVTYPE_ISRAM(tdp))
		memcpy((char *)fp,(char *)&tf,TFSHDRSIZ);
	else {
		rc = tfsflashwrite((uchar *)fp,(uchar *)(&tf),TFSHDRSIZ);
		if (rc != TFS_OKAY)
			return(rc);
	}

	/* 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)
{
	int		rc;
	TFILE	*fp;
	TDEV	*tdp;
	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;

	tdp = tfsNameToDevice(name);
	if (TFS_DEVTYPE_ISRAM(tdp))
		memcpy((char *)&fp->flags,(char *)&flags_marked_deleted,sizeof(long));
	else {
		rc = tfsflashwrite((uchar *)&fp->flags,
			(uchar *)&flags_marked_deleted, sizeof(long));
		if (rc != TFS_OKAY)
			return(rc);
	}

	tfslog(TFSLOG_DEL,name);
	return (TFS_OKAY);
}
			
int
tfslink(char *src, char *target)
{
	TFILE	*tfp;
	char	linfo[TFSINFOSIZE+1];
	char	flags[16];

	tfp = tfsstat(src);
	if (tfp) {
		if (TFS_ISLINK(tfp))
			return(TFSERR_LINKERROR);

		strncpy(linfo,src,TFSINFOSIZE-1);
		linfo[TFSINFOSIZE] = 0;
		flags[0] = 'l';
		tfsflagsbtoa(tfp->flags,flags+1);
		return(tfsadd(target,linfo,flags,0,0));
	}
	return(TFSERR_NOFILE);
}

/*
 * tfsrun_abortableautoboot():
 *
 * Aborting execution of the monrc & non-query-autoboot files:
 * The code wrapped within the #ifdef TFS_AUTOBOOT_ABORTABLE definition
 * is an implementation of an idea from Jason DiDonato (Jan 2004).
 * These files can be aborted by an escape character under two
 * circumstances:
 *
 *		1. There is no password file installed
 *		2. The user correctly enters the level-three password when
 *		   prompted by the abort interaction below.
 *
 * This mechanism maintains security, but only when security is desired.
 * A system that needs security will have a password file installed;
 * hence, if no password file is found, the escape character
 * (AUTOBOOT_ABORT_CHAR) is all that is needed at startup to abort an
 * otherwise non-abortable file.
 * If a password file is found, then the user must know the level-3 password
 * to abort the execution; otherwise, after a few seconds, the interaction
 * will terminate and the file will be executed.
 *
 * Prior to this implementation, autobootables were not abortable in any
 * way.  This is still the default, which is overridden by the definition
 * of TFS_AUTOBOOT_ABORTABLE in config.h
 */


#define AUTOBOOT_ABORT_NULL		0
#define AUTOBOOT_ABORT_NO		1
#define AUTOBOOT_ABORT_YES		2
#define AUTOBOOT_ABORT_FAILED	3

#ifndef AUTOBOOT_ABORT_CHAR
#ifdef TFS_AUTOBOOT_CANCEL_CHAR
#define AUTOBOOT_ABORT_CHAR		TFS_AUTOBOOT_CANCEL_CHAR
#else
#define AUTOBOOT_ABORT_CHAR		0x03	/* CTRL-C */
#endif
#endif

int
tfsrun_abortableautoboot(char **arglist,int verbose)
{
#ifdef TFS_AUTOBOOT_ABORTABLE
	int	err;
	static int	autoboot_abort;

	/* If a character has been detected at the console, and the
	 * character is AUTOBOOT_ABORT_CHAR, then, if a password file
	 * exists, require that the user enter the level-3 password
	 * to abort the autoboot file...
	 * Note that this is only done on the first pass through this
	 * function.  All subsequent passes use the result of the initial
	 * pass.
	 */
	if (autoboot_abort == AUTOBOOT_ABORT_NULL) {
		autoboot_abort = AUTOBOOT_ABORT_NO;

		if (gotachar() && (getchar() == AUTOBOOT_ABORT_CHAR)) {
			if (passwordFileExists()) {
				char passwd[16];
	
				/* To allow the user to simply hold down on the abort
				 * character during a target, reset, this loop will
				 * absorb a burst of incoming characters.  Then, when
				 * the burst halts, the user will be queried for the
				 * password.
				 */
				monDelay(500);
				while(gotachar()) {
					getchar();
					monDelay(500);
				}

				getpass("autoboot-abort password: ",passwd,sizeof(passwd)-1,50);
				if (validPassword(passwd,3))
					autoboot_abort = AUTOBOOT_ABORT_YES;
				else
					autoboot_abort = AUTOBOOT_ABORT_FAILED;
			}
			else
				autoboot_abort = AUTOBOOT_ABORT_YES;
		}
	}

	err = TFS_OKAY;

	switch(autoboot_abort) {
		case AUTOBOOT_ABORT_NO:
			err = tfsrun(arglist,verbose);
			break;
		case AUTOBOOT_ABORT_YES:
			printf("%s aborted\n",arglist[0]);
			break;
		case AUTOBOOT_ABORT_FAILED:
			printf("%s abort attempt failed\n",arglist[0]);
			err = tfsrun(arglist,verbose);
			break;
	}
	return(err);
#else
	return(tfsrun(arglist,verbose));
#endif	/* TFS_AUTOBOOT_ABORTABLE */
}


/* tfsrun():
 *	Run the named file.  Based on the file flags, the file is either
 *	executed as 

⌨️ 快捷键说明

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