tfsclean1.c

来自「umon bootloader source code, support mip」· C语言 代码 · 共 2,107 行 · 第 1/5 页

C
2,107
字号
		sbase += ssize;
	}
	if (isnum == lastsnum) {
		ssize -= (tdp->sectorcount * sizeof(struct sectorcrc));	
		ssize -= (ftot * DEFRAGHDRSIZ);
		ssize -= 4;
	}
	if (crctbl[i].postcrc == crc32(sbase,ssize))
		return(1);
	else
		return(0);
}

/* defragGetStateStr():
 * Return a string that corresponds to the incoming state value.
 */
static char *
defragGetStateStr(int state)
{
	char *str;

	switch(state) {
	case SECTOR_DEFRAG_INACTIVE:
		str = "SectorDefragInactive";
		break;
	case SECTOR_DEFRAG_ABORT_RESTART:
		str = "DefragRestartAborted";
		break;
	case SCANNING_ACTIVE_SECTOR_1:
		str = "ScanningActiveSector1";
		break;
	case SCANNING_ACTIVE_SECTOR_2:
		str = "ScanningActiveSector2";
		break;
	case SCANNING_ACTIVE_SECTOR_3:
		str = "ScanningActiveSector3";
		break;
	case SCANNING_ACTIVE_SECTOR_4:
		str = "ScanningActiveSector4";
		break;
	case SCANNING_ACTIVE_SECTOR_5:
		str = "ScanningActiveSector5";
		break;
	case SECTOR_DEFRAG_ALMOST_DONE:
		str = "DefragAlmostDone";
		break;
	default:
		str = "???";
		break;
	}
	return(str);
}

/* defragRestart():
 * Poll the console allowing the user to abort the auto-restart of
 * the defragmentation.  If a character is received on the console,
 * then return 0 indicating that the defrag should not be restarted;
 * else return 1.
 */
int
defragRestart(int state,int snum)
{
	printf("TFS defrag restart state: %s sector %d\n",
		defragGetStateStr(state),snum);
	if (pollConsole("Hit any key to abort..."))
		return(0);
	return(1);
}

/* defragGetState():
 * Step through the files in the specified device and check for
 * sanity.  Return 1 if the conclusion is that we are in the middle
 * of a defragmentation; else 0.
 */
static int
defragGetState(TDEV *tdp, int *activesnum)
{
	TFILE	*tfp;
	struct	defraghdr	*dhp;
	struct	sectorcrc *crctbl;
	int		snum_in_spare, firstsnum;
	int		first_touched_snum, last_touched_snum;
	int		break_cause, break1_cause, spare_is_erased, ftot, ftot1, errstate;

	/* Establish state of spare sector:
	 */
	spare_is_erased = flasherased((uchar *)tdp->spare,
		(uchar *)tdp->spare+tdp->sparesize-1);

	ftot = 0;
	break_cause = break1_cause = 0;
	for(tfp=(TFILE *)tdp->start; tfp < (TFILE *)tdp->end; tfp=tfp->next) {
		/* If we are legally at the end of file storage space, then we
		 * will hit a header size that is ERASED16.  If we reach this
		 * point and the remaining space dedicated to file storage is
		 * erased and the spare is erased, it is safe to assume that we
		 * were not in the middle of a defrag.
		 */
		if (tfp->hdrsize == ERASED16) {
			/* Is space from last file to end of TFS space erased? */
			if (!flasherased((uchar *)tfp,(uchar *)tdp->end)) {
				break_cause = 1;
				break;
			}
			if (!spare_is_erased) {
				break_cause = 2;
				break;
			}
#if DEFRAG_TEST_ENABLED
			printf("\ndefragGetState: inactive_1\n");
#endif
			return(SECTOR_DEFRAG_INACTIVE);
		}

		/* If the crc32 of the header is corrupt, or if the next pointer
		 * doesn't make any sense, then we must assume that a defrag
		 * was in progress...
		 */
		if (tfshdrcrc(tfp) != tfp->hdrcrc) {
			break;
		}

		if (!(tfp->next) || (tfp->next <= (TFILE *)tdp->start) ||
			 (tfp->next >= (TFILE *)tdp->end)) {
			break;
		}
		if (TFS_FILEEXISTS(tfp))
			ftot++;
	}
	/* If we are here, then something is not "perfect" with the flash
	 * space used by TFS.  If break_cause is non-zero, there is a chance
	 * that the only problem is that a file-write was interrupted and
	 * we did not actually interrupt an in-progress-defrag.  An interrupted
	 * file write would place some incomplete data after the last file.
	 */
	ftot1 = defragValidDSI(tdp,&crctbl);

	/* If we don't have valid defrag state info (DSI), then we can assume
	 * that the files in TFS have not yet been touched (since if we had
	 * touched them, we would have already successfully created the DSI).
	 * This being the case, then we will not continue with any defrag,
	 * let TFS clean things up when the space is needed.
	 */
	if (!ftot1) {
		if (break_cause) {
			/* Hmmm... Should something be done here? */
		}
#if DEFRAG_TEST_ENABLED
		printf("\ndefragGetState: inactive_2\n");
#endif
		return(SECTOR_DEFRAG_INACTIVE);
	}

	/* If we get here, then we have a valid defrag header table, so we
	 * can use it and the state of each of the sectors to figure out
	 * where we are in the defragmentation process.  We need to determine
	 * which sector was being worked on at the point in time when the
	 * defragmentation was interrupted.  A sector is in the "touched"
	 * state if a crc32 on its content does not match the crc32 stored
	 * in the crc table above the defrag header table.
	 * 
	 * Here we step through the defrag header table and see if each file
	 * in the header table exists in TFS.  If all files exist, then we
	 * must have been very close to completion of the defrag process.
	 */
	printf("TFS: scanning DSI space... ");
	dhp = (struct defraghdr *)crctbl - ftot1;
	while(dhp < (struct defraghdr *)crctbl) {
		tfp = (TFILE *)dhp->nda;
		if (tfp->hdrcrc != dhp->ohdrcrc)
			break;
		
		if (tfshdrcrc(tfp) != tfp->hdrcrc) {
			break1_cause = 1;
			break;
		}
		if (crc32((uchar *)(tfp+1),tfp->filsize) != tfp->filcrc) {
			break1_cause = 2;
			break;
		}
		dhp++;
		defragTick(0);
	}
	printf("done\n");

	/* If we stepped through the entire table, then we've completed the
	 * file relocation process, but we still have to clean up...
	 */
	if (dhp >= (struct defraghdr *)crctbl) {
		if (defragRestart(SECTOR_DEFRAG_ALMOST_DONE,0)) {
			return(SECTOR_DEFRAG_ALMOST_DONE);
		}
		else {
			return(SECTOR_DEFRAG_ABORT_RESTART);
		}
	}
	
	if (addrtosector((char *)tdp->start,&firstsnum,0,0) < 0) {
		errstate = 50;
		goto state_error;
	}
	defragTouchedSectors(tdp,&first_touched_snum,&last_touched_snum);

	/* If there are no touched sectors, then we will not continue with
	 * the defrag because we didn't start relocation of any of the files
	 * yet.
	 */
	if (first_touched_snum == -1) {
#if DEFRAG_TEST_ENABLED
		printf("\ndefragGetState: inactive_3\n");
#endif
		return(SECTOR_DEFRAG_INACTIVE);
	}

	if (spare_is_erased)
		snum_in_spare = -1;
	else
		snum_in_spare = defragSectorInSpare(tdp,crctbl);

#if DEFRAG_TEST_ENABLED
	printf("\ndefragGetState info: %d %d %d\n",
		first_touched_snum, last_touched_snum, snum_in_spare);
#endif

	/* At this point we know what sector was the last to be touched. 
	 * What we don't know is whether or not the "touch" was completed.
	 * So we don't know if the active sector is last_touched_snum or
	 * last_touched_snum+1.
	 * The only useful piece of data we 'might' have is the fact that
	 * the spare may contain the content of the last touched sector.
	 */

	/* If the spare is erased, it may be because defrag was just getting
	 * ready to start working on the next sector (meaning that the active
	 * sector is last_touched_snum+1) or the sector was in the process of
	 * being modified.  We use the post-crc in the DHT to determine what
	 * the active sector is...
	 */
	if (spare_is_erased) {
		if (last_touched_snum >= 0) {
			if (defragPostCrcCheck(tdp,last_touched_snum)) {
				*activesnum = last_touched_snum + 1;

				if (defragRestart(SCANNING_ACTIVE_SECTOR_1,*activesnum))
					return(SCANNING_ACTIVE_SECTOR_1);
				else
					return(SECTOR_DEFRAG_ABORT_RESTART);
			}
			else {
				if (defragSerase(2,last_touched_snum) < 0) {
					errstate = 51;
					goto state_error;
				}
				*activesnum = last_touched_snum;

				if (defragRestart(SCANNING_ACTIVE_SECTOR_2,*activesnum))
					return(SCANNING_ACTIVE_SECTOR_2);
				else
					return(SECTOR_DEFRAG_ABORT_RESTART);
			}

		}
		else {
			errstate = 52;
			goto state_error;
		}
	}

	/* If the sector copied to spare is one greater than the last touched
	 * sector, then the active sector is last_touched_snum+1 and it was
	 * just copied to the spare.  In this case we erase the spare and
	 * return indicating the active sector.
	 */
	if (snum_in_spare == last_touched_snum+1) {
		if (defragEraseSpare(tdp) < 0) {
			errstate = 53;
			goto state_error;
		}
		*activesnum = snum_in_spare;

		if (defragRestart(SCANNING_ACTIVE_SECTOR_3,*activesnum))
			return(SCANNING_ACTIVE_SECTOR_3);
		else
			return(SECTOR_DEFRAG_ABORT_RESTART);
	}

	/* If the spare is not erased, but it does not match any of the 
	 * sector CRCs, then we must have been in the process of copying
	 * the active sector to the spare, so we can erase it and return
	 * to the SCANNING_ACTIVE_SECTOR state.
	 */
	if (snum_in_spare == -1) {
		if (last_touched_snum >= 0) {
			*activesnum = last_touched_snum + 1;

			if (!defragRestart(SCANNING_ACTIVE_SECTOR_4,*activesnum))
				return(SECTOR_DEFRAG_ABORT_RESTART);

			if (defragEraseSpare(tdp) < 0) {
				errstate = 54;
				goto state_error;
			}
			return(SCANNING_ACTIVE_SECTOR_4);
		}
		else {
			errstate = 55;
			goto state_error;
		}
	}

	/* If the sector copied to spare is the number of the last touched
	 * sector, then we were in the middle of modifying the sector, so
	 * we have to erase that sector, copy the spare to it and return
	 * to the scanning state.
	 */
	if (snum_in_spare == last_touched_snum) {
		int	ssize;
		uchar *sbase;

		*activesnum = snum_in_spare;

		if (!defragRestart(SCANNING_ACTIVE_SECTOR_5,*activesnum))
			return(SECTOR_DEFRAG_ABORT_RESTART);

		if (defragSerase(3,snum_in_spare) < 0) {
			errstate = 56;
			goto state_error;
		}
		if (sectortoaddr(snum_in_spare,&ssize,&sbase) < 0) {
			errstate = 57;
			goto state_error;
		}
		if (defragFwrite(1,sbase,(uchar *)tdp->spare,ssize) < 0) {
			errstate = 58;
			goto state_error;
		}
		if (defragEraseSpare(tdp) < 0) {
			errstate = 59;
			goto state_error;
		}
		return(SCANNING_ACTIVE_SECTOR_5);
	}

	/* If we got here, then we are confused, so don't do any defrag
	 * continuation...
	 */
	errstate = 90;

state_error:
	printf("DEFRAG_STATE_ERROR: #%d.\n",errstate);
	return(SECTOR_DEFRAG_INACTIVE);
}

/* inSector():
 * We are trying to figure out if the address space that we want to copy
 * from is within the active sector.  If it is, then we need to adjust
 * our pointers so that we retrieve the at least some of data from the
 * spare. 
 * If the range specified by 'i_base' and 'i_size' overlays (in any way)
 * the address space used by the sector specified by 'snum', 
 * then return the address in the spare and the size of the overlay.
 */
static int
inSector(TDEV *tdp,int snum,uchar *i_base,int i_size,uchar **saddr,int *ovlysz)
{
	int		s_size;
	uchar	*s_base, *s_end, *i_end;

	/* Retrieve information about the sector: */
	if (sectortoaddr(snum,&s_size,&s_base) == -1)
		return(TFSERR_MEMFAIL);

	i_end = i_base + i_size;
	s_end = s_base + s_size;

	if ((i_end < s_base) || (i_base > s_end)) {
		*ovlysz = 0;
		return(0);
	}

	if (i_base < s_base) {
		if (i_end > s_end) {
			*ovlysz = s_size;
		}
		else {
			*ovlysz = (i_size - (s_base - i_base));
		}
		*saddr = (uchar *)tdp->spare;
	}
	else {
		if (i_end > s_end) {
			*ovlysz = (i_size - (i_end - s_end));
		}
		else {
			*ovlysz = i_size;
		}
		*saddr = (uchar *)tdp->spare + (i_base - s_base);
	}
	return(0);
}

/* struct fillinfo & FILLMODE definitions:
 * Structure used by the "Fill" functions below.
 */
#define FILLMODE_FWRITE			1	/* Do the flash write */
#define FILLMODE_SPAREOVERLAP	2	/* Determine if there is SPARE overlap */
#define FILLMODE_CRCONLY		3	/* Calculate a 32-bit crc on the data */

struct fillinfo {
	struct defraghdr *dhp;	/* pointer to defrag header table */
	TDEV	*tdp;			/* pointer to TFS device */
	ulong	crc;			/* used in FILLMODE_CRCONLY mode */
	int		crcsz;			/* size of crc calculation */
	int		fhdr;			/* set if we're working on a file header */
	int		asnum;			/* the active sector */
	int		mode;			/* see FILLMODE_xxx definitions */
};

/* defragFillFlash():
 * This function is called by the defragFillActiveSector() function
 * below.  It covers the four different cases of a file spanning over
 * the active sector, plus it deals with the possibility that the source

⌨️ 快捷键说明

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