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 + -
显示快捷键?