📄 fdefrag.c
字号:
/*************************************************************
File Name: fdefrag.c *
**************************************************************
Programmer: chilong
Last Modified Date: 2001/6/3
Compiler : Gnu Cross-compiler
Platform : X86 protection mode
Usage :
scanDisk functions for FAT1X_defrag
See defrag.h for usage.
*************************************************************/
#include <pr2k.h>
#include <kernel/linklist.h>
#include <sys/syscall.h>
#include <kernel/malloc.h>
#include <stdio.h>
#ifdef _PROCOMP_
#include "/rtos/driver/FileSys/FileSys.h"
#else
#include "../../FileSys/include/FileSys.h"
#endif
#include "../include/init.h"
#include "../include/cluster.h"
#include "../include/unicode.h"
#include "../include/fat1x.h"
#include "../include/fdefrag.h"
#ifdef FAT_USE_PCMCIA
/**** added by chilong ****/
//#include "../pcm/cf_typedef.h"
/**** added by chilong ****/
//#include "pcmcia/include/pcmcia.h"
#ifdef __WIN32__
#include"../include/ata_emu.h"
#else
#include "pcmcia/include/pcmcia.h"
#endif
#include "../include/ata_pcc.h"
#else
#include "../include/ata_pcc.h"
#endif
#ifdef FAT_ID
/* init.c */
extern unsigned long FAT1Begin[DRIVE_NUM];
extern unsigned long FAT2Begin[DRIVE_NUM];
extern unsigned long FATRootBegin[DRIVE_NUM];
extern unsigned short FATSecPerFAT[DRIVE_NUM];
extern unsigned short FATSecPerROOT[DRIVE_NUM];
extern unsigned short FATTotalCluster[DRIVE_NUM];
extern unsigned long FATBytesPerCluster[DRIVE_NUM];
extern unsigned char FATType[DRIVE_NUM];
extern int FATErrno;
extern int InitFAT;
extern int FATDirSemaphoreID;
// cluster.c
extern unsigned short FATEndOfChain[];
// fscan.c
extern unsigned short *FATBuf;
/**** added by chilong 12/4/2001 ****/
// fat1x.c
extern struct FAT_FILE **FATHandleTable;
/**** added by chilong 12/4/2001 ****/
unsigned short defragClusterNo;
// used to record subdirs that need defragging
struct dLinkList defragDirList;
/**** added by chilong 10/5/2001 ****/
#ifdef FAT_FAT_CACHE_ON
/* FAT cache */
extern struct FAT_fatCache FATFatCache[FAT_FAT_CACHE_BLOCK];
#endif
/**** added by chilong 10/5/2001 ****/
/*************************************************************
Fuction : FAT_defrag
defrag FAT1x disk
// method
introduction:
1. Record all directories in defragDirList
2. Start defragging from root directory.
a) We move all entries upwards by removing all deleted entries
b) We defrag root directory entries, sorting every entry from
cluster number 2.
3. Then according to defragDirList, we go through the same
steps as we do to root directory. Finally, we update the cluster
values of '.' and '..' that might be swapped during defragging
4. Because we keep swapping and modifying fat tables from the above
three steps, we need to update fat tables by writing the fat buffer
back to flash.
ex: (original)
dir/file clusterNo
---------------------------------
\f1.txt 246
\f2.txt 247
\f3.txt 248
\4dos 249
\4dos\fat1x.txt 250
\4dos\abc 2
\4dos\abc\fat1x.txt 3, 4
ex: (after defragging)
dir/file clusterNo
---------------------------------
\f1.txt 2
\f2.txt 3
\f3.txt 4
\4dos 5
\4dos\fat1x.txt 6
\4dos\abc 7
\4dos\abc\fat1x.txt 8, 9
// method
Input:
Output:
0: no error is found
-1: error (see FATError)
**************************************************************/
int FAT_defrag(void)
{
short i;
short status;
short j;
short fileOpened = 0;
/**** added by chilong 12/10/2001 temporarily ****/
return -1;
/**** added by chilong 12/10/2001 temporarily ****/
// check if fat1x file system is on
if (InitFAT != TRUE)
{
FATErrno = ERROR_FILE_SYSTEM_NOT_INIT;
return -1;
}
sc_waitSemaphore(FATDirSemaphoreID);
// check if any file is being opened
for (i = 0; i < MAX_OPEN_FILE; i++)
{
if (FATHandleTable[i] != NULL)
{
if (FATHandleTable[i]->deviceID == FAT_ID)
{
// there are opened files
// have to update the current block field in the file handle when moving blocks
fileOpened = 1;
break;
}
}
}
/**** added by chilong 12/10/2001 ****/
for (i = 0; i < DRIVE_NUM; i++)
{
// defrag from cluster 2
defragClusterNo = 2;
if ((FATBuf = (unsigned short *) ap_malloc(SECTOR_SIZE * FATSecPerFAT[i])) == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
// read FAT1
if (ATA_READ(i, FATSecPerFAT[i], FAT1Begin[i], FATBuf) == ATA_FAILURE)
{
FATErrno = ERROR_ATA_READ;
ap_free(FATBuf);
FAT_free_dirLinkList(&defragDirList);
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
initDLinkList(&defragDirList);
if (FAT_set_defragDirList(i) == -1)
{
ap_free(FATBuf);
FAT_free_dirLinkList(&defragDirList);
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
if (FAT_defrag_root(i) == -1)
{
ap_free(FATBuf);
FAT_free_dirLinkList(&defragDirList);
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
if (FAT_defrag_subdir(i) == -1)
{
ap_free(FATBuf);
FAT_free_dirLinkList(&defragDirList);
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
// write FATBuf back into FAT1
if (ATA_WRITE(i, FATSecPerFAT[i], FAT1Begin[i], FATBuf) == ATA_FAILURE)
{
FATErrno = ERROR_ATA_WRITE;
ap_free(FATBuf);
FAT_free_dirLinkList(&defragDirList);
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
// write FATBuf back into FAT2
if (FAT1Begin[i] != FAT2Begin[i])
{
// write FATBuf back into FAT2
if (ATA_WRITE(i, FATSecPerFAT[i], FAT2Begin[i], FATBuf) == ATA_FAILURE)
{
FATErrno = ERROR_ATA_WRITE;
ap_free(FATBuf);
FAT_free_dirLinkList(&defragDirList);
sc_signalSemaphore(FATDirSemaphoreID);
return -1;
}
}
FAT_free_dirLinkList(&defragDirList);
}
#ifdef FAT_FAT_CACHE_ON /* FAT cache is available */
// update FAT_FAT_CACHE to make data consistent
// The reason why we only update the cache with DirtySec FALSE
// is that the caches sectors with DirtySec TRUE will be
// flushed later.
for (i = 0; i < FAT_FAT_CACHE_BLOCK; i++)
{
if (FATFatCache[i].DirtySec == FALSE)
{
for (j = 0; j < WORDS_PER_SECTOR; j++)
{
*(FATFatCache[i].Entry + j) =
*(FATBuf + WORDS_PER_SECTOR * (FATFatCache[i].sec_num-FAT1Begin[FATFatCache[i].drive]) + j);
}
}
}
#endif
ap_free(FATBuf);
FAT_flushAll();
sc_signalSemaphore(FATDirSemaphoreID);
return 0;
}
/*************************************************************
Fuction : FAT_set_defragDirList
Record all the directories in the global variable "defragDirList"
(from root directory to all its subdirectories sorted in order)
Input:
drive - drive number
Output:
0: no error is found
-1: error (see FATError)
**************************************************************/
int FAT_set_defragDirList(short drive)
{
unsigned long i, j;
unsigned char *rootSecBuffer, *clusterBuffer;
int done = 0;
unsigned short clusterNo, currCluster, parentClusterNo;
struct defrag_dir *tmpDir, *currentDir;
struct dLinkList *pList, *tailNode;
if ((rootSecBuffer = (unsigned char *)ap_malloc(SECTOR_SIZE)) == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
return -1;
}
if ((clusterBuffer = (unsigned char *)ap_malloc(FATBytesPerCluster[drive])) == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
ap_free(rootSecBuffer);
return -1;
}
// search from root directory
tailNode = &defragDirList;
for (i = FATRootBegin[drive]; i < FATRootBegin[drive] + FATSecPerROOT[drive]; i++)
{
if (FAT_read_root_sector(drive, i, (unsigned short *)rootSecBuffer) == ATA_FAILURE)
{
ap_free(rootSecBuffer);
ap_free(clusterBuffer);
return -1;
}
for (j = 0; j < SECTOR_SIZE; j += FAT_DIR_ENTRY_SIZE)
{
// the end
if (rootSecBuffer[j] == '\0')
{
done = 1;
break;
}
// delete entries
if (rootSecBuffer[j] == FAT_DELETED_ENTRY)
{
continue;
}
// if this is a subdir entry, record it in the defragDirList
if ((*(rootSecBuffer + j + 11) & DA_DIR) == DA_DIR)
{
clusterNo = *(rootSecBuffer + j + 27) << 8;
clusterNo |= *(rootSecBuffer + j + 26);
tmpDir = (struct defrag_dir *) ap_malloc(sizeof(struct defrag_dir));
if (tmpDir == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
ap_free(rootSecBuffer);
ap_free(clusterBuffer);
return -1;
}
// we don't record clusterNo because it'll be replayed by defragClusterNo
tmpDir->startCluster = clusterNo;
tmpDir->parentCluster = 0;
tmpDir->block = i;
tmpDir->entry = j;
if(insertTo(tailNode, (void *)tmpDir) == FAIL)
{
FATErrno = ERROR_OPERATING_SYSTEM_ERROR;
ap_free(tmpDir);
ap_free(rootSecBuffer);
ap_free(clusterBuffer);
return -1;
}
tailNode = tailNode->back;
}
}
if (done == 1)
break;
}
// we don't need this buffer anymore
ap_free(rootSecBuffer);
// search sub-directories
pList = &defragDirList;
while(pList->back != NULL)
{
currentDir = (struct defrag_dir *)pList->back->elementPointer;
currCluster = currentDir->startCluster;
for (;;)
{
if (FAT_read_cluster(drive, currCluster, (unsigned short *)clusterBuffer) == -1)
{
ap_free(clusterBuffer);
return -1;
}
done = 0;
for (j = 0; j < FATBytesPerCluster[drive]; j += FAT_DIR_ENTRY_SIZE)
{
if (*(clusterBuffer + j) == '\0')
{
done = 1;
break;
}
else if(*(clusterBuffer + j) == FAT_DELETED_ENTRY)
continue;
#ifdef FAT_LFN
else if ((*(clusterBuffer + j + 11) & DA_VFAT) == DA_VFAT)
continue;
#endif
if(*(clusterBuffer + j) == '.' && *(clusterBuffer + j + 1) == '.')
{
clusterNo = *(clusterBuffer + j + 27) << 8;
clusterNo |= *(clusterBuffer + j + 26);
parentClusterNo = currCluster;
continue;
}
// if this is a subdir entry, record it in the defragDirList
if (*(clusterBuffer + j) != '.' && (*(clusterBuffer + j + 11) & DA_DIR) == DA_DIR)
{
clusterNo = *(clusterBuffer + j + 27) << 8;
clusterNo |= *(clusterBuffer + j + 26);
tmpDir = (struct defrag_dir *) ap_malloc(sizeof(struct defrag_dir));
if (tmpDir == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
ap_free(clusterBuffer);
return -1;
}
tmpDir->startCluster = clusterNo;
tmpDir->parentCluster = parentClusterNo;
tmpDir->block = currCluster;
tmpDir->entry = j;
if(insertTo(tailNode, (void *)tmpDir) == FAIL)
{
FATErrno = ERROR_OPERATING_SYSTEM_ERROR;
ap_free(tmpDir);
ap_free(clusterBuffer);
return -1;
}
tailNode = tailNode->back;
}
}
if (done == 1)
break;
currCluster = read_fat_cluster_from_fatBuffer(drive, currCluster);
if (currCluster >= FATEndOfChain[FATType[drive]])
{
break;
}
}
pList = pList->back;
}
return 0;
}
/*************************************************************
Fuction : FAT_defrag_root
defrag root directory
Input:
drive - drive number
Output:
0: no error is found
-1: error (see FATError)
**************************************************************/
int FAT_defrag_root(short drive)
{
unsigned long i, j, k;
unsigned char *oldRootSecBuffer, *newRootSecBuffer, *clusterBuffer;
int done = 0;
unsigned long updateRootSec;
unsigned short clusterNo;
int dirty;
if ((oldRootSecBuffer = (unsigned char *)ap_malloc(SECTOR_SIZE)) == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
return -1;
}
if ((newRootSecBuffer = (unsigned char *)ap_malloc(SECTOR_SIZE)) == NULL)
{
ap_free(oldRootSecBuffer);
FATErrno = ERROR_ALLOC_MEM;
return -1;
}
myMemSet(newRootSecBuffer, 0, SECTOR_SIZE);
if ((clusterBuffer = (unsigned char *)ap_malloc(FATBytesPerCluster[drive])) == NULL)
{
FATErrno = ERROR_ALLOC_MEM;
ap_free(oldRootSecBuffer);
ap_free(newRootSecBuffer);
return -1;
}
// 1. rearrange root entries, not letting any unused entries be placed
// between two used entries
k = 0;
for (i = updateRootSec = FATRootBegin[drive]; i < FATRootBegin[drive] + FATSecPerROOT[drive]; i++)
{
if (FAT_read_root_sector(drive, i, (unsigned short *)oldRootSecBuffer) == ATA_FAILURE)
{
ap_free(oldRootSecBuffer);
ap_free(newRootSecBuffer);
ap_free(clusterBuffer);
return -1;
}
for (j = 0; j < SECTOR_SIZE; j += FAT_DIR_ENTRY_SIZE)
{
// the end
if (oldRootSecBuffer[j] == '\0')
{
if (FAT_update_root_sector(drive, updateRootSec, (unsigned short *)newRootSecBuffer) != ATA_OK)
{
ap_free(oldRootSecBuffer);
ap_free(newRootSecBuffer);
ap_free(clusterBuffer);
return -1;
}
k = 0;
updateRootSec++;
myMemSet(newRootSecBuffer, 0, SECTOR_SIZE);
done = 1;
break;
}
// delete entries
if (oldRootSecBuffer[j] == FAT_DELETED_ENTRY)
continue;
// copy the entry from the old sector to the new sector
myMemCpy(newRootSecBuffer + k, oldRootSecBuffer + j, FAT_DIR_ENTRY_SIZE);
k += FAT_DIR_ENTRY_SIZE;
if (k > SECTOR_SIZE)
{
if (FAT_update_root_sector(drive, updateRootSec, (unsigned short *)newRootSecBuffer) != ATA_OK)
{
ap_free(oldRootSecBuffer);
ap_free(newRootSecBuffer);
ap_free(clusterBuffer);
return -1;
}
k = 0;
updateRootSec++;
myMemSet(newRootSecBuffer, 0, SECTOR_SIZE);
}
}
if (done == 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -