《實(shí)驗(yàn)四文件系統(tǒng)實(shí)驗(yàn)報(bào)告.docx》由會員分享,可在線閱讀,更多相關(guān)《實(shí)驗(yàn)四文件系統(tǒng)實(shí)驗(yàn)報(bào)告.docx(24頁珍藏版)》請?jiān)谘b配圖網(wǎng)上搜索。
文件系統(tǒng) 實(shí)驗(yàn)報(bào)告
一、 實(shí)驗(yàn)?zāi)康?
了解操作系統(tǒng)中文件系統(tǒng)的原理以及實(shí)現(xiàn)方法。
二、 實(shí)驗(yàn)方法
通過FAT12文件系統(tǒng)的解讀,了解文件系統(tǒng)的原理和實(shí)現(xiàn)。
三、 實(shí)驗(yàn)任務(wù)
通過對FAT12文件系統(tǒng)的了解,編寫程序,讀取并列出一個虛擬軟盤中文件信息(文件名、屬性、修改時間等),以及讀取其中的文件內(nèi)容
四、 實(shí)驗(yàn)要點(diǎn)
FAT12文件系統(tǒng)的了解,Linux系統(tǒng)下文件讀寫相關(guān)系統(tǒng)調(diào)用。
五、 實(shí)驗(yàn)過程
1. FAT12 文件系統(tǒng)分析
簇是操作系統(tǒng)分配文件空間的基本單位,簇由若干個扇區(qū)組成。在FAT12文件系統(tǒng)中,簇號的有效位是12位,所以這種文件系統(tǒng)就被稱為FAT12。FAT12文件系統(tǒng)中大致可以分成五個區(qū),這五個區(qū)為:
起始扇區(qū)
占用扇區(qū)
起始地址
結(jié)束地址
分區(qū)
0
1
0x00000000
0x000001FF
引導(dǎo)區(qū)
1
9
0x00000200
0x000013FF
FAT區(qū)
10
9
0x00001400
0x000025FF
FAT備份區(qū)
19
12
0x00002600
0x00003DFF
根目錄區(qū)
31
-
0x00003E00
-
文件數(shù)據(jù)區(qū)
其中,引導(dǎo)區(qū)中儲存著一些基本的信息。例如,0x0000000B和0x0000000C兩個字節(jié)保存著每個扇區(qū)的大小,0x0000000D保存著每個簇占用多少個扇區(qū)。
FAT區(qū)中儲存著簇號。在0x00000200開始的三個字節(jié),分別儲存設(shè)備類型標(biāo)記(0xF0為軟盤);第二個第三個字節(jié)均為0xFF,是FAT標(biāo)識符。在FAT12文件系統(tǒng)中,每個簇占用12位,即1.5個字節(jié)。簇號與地址的對應(yīng)關(guān)系如下表:
地址偏移
000
001
002
003
004
005
簇序號
000
001
002
003
一個簇號跨越兩個字節(jié),每次讀取簇號時讀取兩個字節(jié),然后對讀出的兩個字節(jié)進(jìn)行位運(yùn)算處理,得到下一簇的簇序號。
注意,這里同樣需要對高低位進(jìn)行處理,即使用位計(jì)算的方式提取相應(yīng)的簇號信息。
根據(jù)上述的原理,可以得出一個函數(shù),以一個簇號為參數(shù),返回值為文件下一個簇號。代碼如下:
int getNextClutserId(FILE *fp, short clusterId)
{
unsigned short tmp, low = 0, high = 0;;
int address = (clusterId * 3 / 2) + 0x0000200;
fseek(fp, address, SEEK_SET);
fread((void *)(&tmp), 1, sizeof(unsigned short), fp);
low = ((tmp & 0xFFF0) >> 4);
high = tmp & 0x0FFF;
return (clusterId % 2 == 0 ? high : low);
}
其中,fp 是用于讀取文件系統(tǒng)的文件流,clusterID是當(dāng)前簇號,返回值是下一個簇號。
函數(shù)體的第二句代碼,計(jì)算出當(dāng)前簇號對應(yīng)的地址,用于文件指針的定位。第三句代碼是根據(jù)第二句計(jì)算得到的地址對文件指針進(jìn)行定位,定位到當(dāng)前簇號所對應(yīng)的信息處。第四句代碼是從文件指針的位置為起始位置讀入兩個字節(jié)的內(nèi)容(fread會自動對高低字節(jié)位進(jìn)行處理)。并把這兩個字節(jié)的信息儲存到tmp變量之中。例如,讀取002簇號的下一個簇號,根據(jù)公式,計(jì)算得到的address是0x00000203,讀取到0x00000203和0x00000204兩個字節(jié)的內(nèi)容。我們需要的是0x00000203整個字節(jié)的內(nèi)容和0x00000204的高四位,所以需要跟0xFFF0進(jìn)行位與運(yùn)算,并向右移四位,得到下一個簇號。
同樣地,讀取003簇號的下一個簇號,根據(jù)公式,計(jì)算得到的address是0x00000204,讀取到0x00000204和0x00000205兩個字節(jié)的內(nèi)容,我們需要的是0x00000205整個字節(jié)的內(nèi)容和0x00000204第四位的內(nèi)容,所以需要跟0x0FFF進(jìn)行位與運(yùn)算,得到下一個簇號。所以代碼中需要對簇號的奇偶性進(jìn)行判斷,跟根據(jù)奇偶性的不同返回不同的值。
在根目錄中,保存著根目錄下面的文件或文件夾的信息。每個文件或者文件夾的信息使用32個字節(jié)保存。這些內(nèi)容的含義如下表:
地址
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
內(nèi)容
文件名
擴(kuò)展名
屬性
保留位
地址
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
內(nèi)容
保留位
時間
日期
首簇號
文件大小
這里可以看出點(diǎn)問題,F(xiàn)AT中采用4個字節(jié)保存文件的大小,也就是說,文件的大小不能超過232字節(jié),也就是4G;文件名和擴(kuò)展名采用了固定長度,分別為8和3,太長的文件名在FAT中是不允許的。
其中,文件名的第一個字節(jié)還有其他的意義,例如,當(dāng)文件名的第一個字節(jié)為0x00時,表示這一項(xiàng)沒有文件;為0xE5時,則表示這個文件已經(jīng)被刪除,在編碼時應(yīng)該忽略這個文件。
文件的屬性采用一個字節(jié),也就是8個位來表示文件的6種屬性,最高兩位是保留位,沒有實(shí)際意義。這個字節(jié)的定義為:
位
7
6
5
4
3
2
1
0
屬性
保留
保留
歸檔
目錄
卷標(biāo)
系統(tǒng)
隱藏
只讀
在列出文件列表時,對各個位進(jìn)行位與運(yùn)算以后,對結(jié)果進(jìn)行判斷,從而得出相應(yīng)的屬性值,根據(jù)上表,可以得出一個函數(shù),參數(shù)是表示文件屬性的那個字節(jié),返回值是一個以字符方式顯示文件屬性的一個字符串
char *formatAttribute(char attribute)
{
char *result = (char *)malloc(sizeof(char)* 7);
result[0] = ((attribute & 0x01) == 0x01) ? r : -;
result[1] = ((attribute & 0x02) == 0x02) ? h : -;
result[2] = ((attribute & 0x04) == 0x04) ? s : -;
result[3] = ((attribute & 0x08) == 0x08) ? l : -;
result[4] = ((attribute & 0x10) == 0x10) ? d : -;
result[5] = ((attribute & 0x20) == 0x20) ? f : -;
result[6] = \0;
return result;
}
因?yàn)槲募傩杂?種,需要6個字符分別存放六種屬性,第7位則用于儲存字符串的結(jié)束標(biāo)記’\0’,確保輸出的時候不會產(chǎn)生亂碼。
這個函數(shù)代碼是通過位與運(yùn)算對文件的各個屬性進(jìn)行判斷,并在相應(yīng)的字符位用字符或者’-’填充,最后把字符串返回。
時間和日期都采用的是壓縮儲存,儲存時間兩個字節(jié)的各位含義如下:
位
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
時(0-23)
分(0-59)
兩秒(0-29)
儲存日期兩個字節(jié)的各位含義如下:
位
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
距離1980年的年數(shù)(0-119)
月(1-12)
日(1-31)
注:日期和時間都需要對高低字節(jié)進(jìn)行交換然后再讀取。實(shí)驗(yàn)中使用fread方法會自動進(jìn)行交換。
根據(jù)上面的原理,可以得出這樣的一個函數(shù),這個函數(shù)以表示日期和時間的兩個原始值作為參數(shù)輸入,返回的是一個格式形如”xxxx-xx-xx xx:xx:xx”的字符串,這個函數(shù)的代碼如下:
char *formatDatetime(short date, short time)
{
int year, month, day, hour, minute, second;
char *result = (char *)malloc(sizeof(char)* 20);
year = 1980 + ((date & 0xE000) >> 9);
month = ((date & 0x01E0) >> 5);
day = (date & 0x001F);
hour = ((time & 0xF800) >> 11);
minute = ((time & 0x07E0) >> 5);
second = ((time & 0x001F) << 1);
sprintf(result, "%d-%d%d-%d%d %d%d:%d%d:%d%d",
year, month / 10, month % 10, day / 10, day % 10,
hour / 10, hour % 10, minute / 10, minute % 10,
second / 10, second % 10);
return result;
}
函數(shù)的第一句,第二句是為函數(shù)運(yùn)行過程中需要臨時儲存的數(shù)據(jù)分配儲存空間,隨后就是根據(jù)上述的原理,進(jìn)行位與運(yùn)算和移位操作,得到各項(xiàng)的時間屬性。最后通過sprintf函數(shù)對各個屬性按照固定的格式輸出到字符串之中并返回。
首簇號,指的是這個文件儲存在磁盤的第一個簇的簇號,也就是文件存放的具體地址。同樣地,需要對簇號的兩個字節(jié)進(jìn)行高低位交換。
最后一個是文件大小,需要對四個字節(jié)進(jìn)行高低字節(jié)交換,得到文件大小。
在實(shí)驗(yàn)中,會通過read函數(shù)每次讀入32個字節(jié),即讀取FAT表中的每一項(xiàng),在輸出文件信息時予以分析。
另外,每個目錄中都包含兩個虛擬目錄,文件名分別為’.’和’..’,分別表示當(dāng)前目錄和上一級目錄。在目錄的處理時需要對其進(jìn)行判斷,避免在進(jìn)行子目錄迭代顯示時進(jìn)入死循環(huán)。綜上所述,可以得出從文件段中讀出文件信息的源碼。下面的是一些在讀取過程中所使用的一些數(shù)據(jù)結(jié)構(gòu):
struct file_info {
char filename[8];
char extname[3];
char attributes;
char reserved[10];
short time;
short date;
short pos;
int size;
};
上面是表示文件信息原始信息的結(jié)構(gòu)體,每個成員變量對應(yīng)一個屬性。
struct file_info_node {
int id;
struct file_info *info;
struct file_info_node *next;
};
這個文件信息鏈表的結(jié)點(diǎn),相應(yīng)地,在實(shí)驗(yàn)中定義了file_list_new_info方法,將文件信息添加到鏈表之中。
同時,為了避免遞歸調(diào)用,在實(shí)驗(yàn)中,通過一個隊(duì)列的方式實(shí)現(xiàn)列出所有子目錄文件的功能。
在下面代碼中,content_char是一個指向儲存上述文件結(jié)構(gòu)的指針,content->size是file_content中表示文件大小的一個整型變量,用于計(jì)算文件夾中最大文件數(shù)量,newInfo是一個file_info結(jié)構(gòu)體的指針,用于儲存讀取到的文件信息原始值。
先把一個文件信息的原始信息從文件內(nèi)容中提取出來,為此,可以實(shí)現(xiàn)內(nèi)存復(fù)制的函數(shù),代碼如下:
int copyTo(void *desc, void *src, int size)
{
int counter = 0, i;
for (i = 0; i < size; i++, counter++)
*(char *)(((char *)desc) + i) = *(char *)(((char *)src) + i);
return counter;
}
通過這個函數(shù)把文件信息的原始信息復(fù)制到newInfo之中。
上述的文件夾結(jié)構(gòu)不僅僅適用于根目錄,所有的目錄的遵循這種格式,所以這里可以得出一個初步的結(jié)論:文件夾是一種特殊的文件。
if (newInfo->filename[0] != (char)0xE5 && newInfo->filename[0] != (char)0x00) {
file_list_new_info(newInfo, &newId, &newInfoNode);
if ((newInfo->attributes & 0x10) == 0x10)
{
if (newInfo->filename[0] == .) continue;
char *buffer = (char *)malloc(sizeof(char)* 9);
int j;
for (j = 0; j < 8 && newInfo->filename[j] != (char)0x20; j++)
{
buffer[j] = newInfo->filename[j];
}
buffer[j] = \0;
queue_new_task(buffer, 0, 0, newInfo->pos);
}
這是放在一個for循環(huán)中的代碼,先通過文件名判斷這個文件是否存在,如果存在,則把文件信息添加到程序的文件信息鏈表之中。再則判斷是否是目錄,如果是目錄,則把這個目錄添加到隊(duì)列之中。
2. 文件儲存方式
FAT文件系統(tǒng)對空間的分配和管理是以簇為基本單位的。所以,一個邏輯上連續(xù)的文件可能會被分散地儲存在磁盤的各個位置。操作系統(tǒng)輸出文件時,遵循下面的步驟:
1. 會先通過文件夾信息找到文件首簇號。
2. 根據(jù)文件的首簇號,定位到FAT區(qū)相應(yīng)位置;讀出下一個簇的簇號。
3. 如果下一個簇的簇號不是結(jié)束標(biāo)記(0xFFF),則會根據(jù)讀出的下一個簇號定位,讀出簇里面的內(nèi)容。如果讀出的是結(jié)束標(biāo)記,則表示文件已經(jīng)讀取完成。
假如一個文件被分散儲存在0x012,0x022,0x302三個簇里。從目錄的信息中讀出首簇號0x012,讀出0x012簇里的內(nèi)容;然后再通過0x012這個簇號在FAT區(qū)中找到下一個簇號0x022,讀出0x022的內(nèi)容;再通過0x022這個簇號找到下一個簇號0x302,讀出0x302中的內(nèi)容;再通過0x302讀出下一個簇號的內(nèi)容,此時,讀出的簇號為0xFFF,即表示這個文件已經(jīng)結(jié)束。
本實(shí)驗(yàn)中,讀取文件的具體實(shí)現(xiàn)方法如下:
1. 通過一個鏈表,將這個文件的所有簇號儲存起來。
2. 遍歷儲存簇號的鏈表,逐個逐個簇讀取出來并儲存到內(nèi)存之中,返回之。
下面是讀取文件的實(shí)現(xiàn)所需要的一些數(shù)據(jù)結(jié)構(gòu):
struct int_linked_list {
int data;
struct int_linked_list *next;
};
struct file_content {
struct int_linked_list *curList;
void *content;
int size;
char *filename;
};
其中,int_linked_list是一個儲存整型的鏈表,file_content是一個用于保存讀出文件內(nèi)容和文件信息的結(jié)構(gòu)體。
遍歷鏈表的過程中,通過一個while循環(huán)實(shí)現(xiàn),把讀取到簇號添加到鏈表之中。具體實(shí)現(xiàn)代碼如下,tail為保存簇號鏈表的末尾結(jié)點(diǎn)指針,fp是用于讀取文件的文件指針,curConnt是一個用于統(tǒng)計(jì)文件簇?cái)?shù)的變量,便于后續(xù)步驟分配內(nèi)存空間使用,下文同:
while ((clusterId = getNextClutserId(fp, clusterId)) != 0x00000FFF)
{
curCount++;
tail->next = (struct int_linked_list *)malloc(sizeof(struct int_linked_list));
tail->next->data = clusterId;
tail->next->next = NULL;
tail = tail->next;
}
把簇號讀取完畢以后,開始對文件內(nèi)容進(jìn)行讀取,下面是文件內(nèi)容讀取的具體實(shí)現(xiàn)代碼,下面代碼中的content是一個指向用于存放文件內(nèi)容的內(nèi)存空間的指針變量:
content->size = curCount * 512;
content->content = malloc(content->size);
struct int_linked_list *ptr = head;
int i = 0, address = 0xFFFFFFF;
for (ptr = head; ptr != NULL; ptr = ptr->next, i++)
{
address = 0x00003E00 + (512 * ptr->data);
fseek(fp, address, SEEK_SET);
fread((void *)(((char *)(content->content)) + (512 * i)), 512, 1, fp);
}
在for循環(huán)的第一句代碼之中,通過簇號對簇所在的地址進(jìn)行計(jì)算,把地址值儲存到address變量之中;第二句代碼則是通過上一步計(jì)算得到的address變量對文件指針進(jìn)行定位,第三句是通過fread方法把文件內(nèi)容讀入到內(nèi)存之中。
六、 實(shí)驗(yàn)結(jié)論
1. FAT12文件系統(tǒng)中,把磁盤劃分成引導(dǎo)區(qū)、FAT區(qū)、FAT備份區(qū)、根目錄區(qū)和文件數(shù)據(jù)區(qū)。
2. 除了根目錄以外,文件系統(tǒng)把每個文件夾都當(dāng)成是一個特殊的文件進(jìn)行處理。
3. FAT12文件系統(tǒng)通過簇進(jìn)行空間的管理和分配。
七、 完整實(shí)驗(yàn)代碼
/*
* 操作系統(tǒng)課程 實(shí)驗(yàn)
* FAT12 文件系統(tǒng) 實(shí)驗(yàn)代碼
*
* 雖然這個程序在 Windows 和 Linux 環(huán)境下都能運(yùn)行。
* 不過,在 Windows 環(huán)境下運(yùn)行的話,顯示文件內(nèi)容的時候,內(nèi)容的末尾會有幾個奇怪的字符。
* Linux 環(huán)境下完全沒問題
* 暫時推測是 Windows 控制臺的原因,Windows 控制臺會把一些非字符的 ASCII 顯示為奇怪的字符,
* 例如,0x0A 會顯示成一個笑臉,Linux 的控制臺下不會對這些非字符的 ASCII 進(jìn)行處理
*
* 我是今天早上才發(fā)現(xiàn)這個問題的阿 (╯‵□′)╯︵┻━┻
*
* 注意:編譯前,需要把 IMAGE_FILE 那個宏定義改成公郵上面的那個 IMG 文件;
* Linux 下打開這個源碼文件注釋會變成亂碼
*
*/
// 這個定義只是為了程序能在 VS2013 下面正常編譯而已
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include
#include
#include
#ifdef _WIN32
#include
#endif
#define OK 0x00000000
#define MESSAGE_FILE_NOT_FOUND 0xE0000404
#define ERROR_MALLOC_FAILED 0xF0000001
#define ERROR_IO_ERROR 0xF0000002
// ↓ 這里改路徑 ↓
#define IMAGE_FILE "/home/user/DOS622.IMG"
// ↑ 這里改路徑 ↑
/******************** 這里是結(jié)構(gòu)體的定義 **************************/
// 這里是文件信息
struct file_info {
char filename[8];
char extname[3];
char attributes;
char reserved[10];
short time;
short date;
short pos;
int size;
};
struct file_info_node {
int id;
struct file_info *info;
struct file_info_node *next;
};
// 這里是儲存文件夾信息
struct folder_info {
char *filename;
int fileBeginIndex, fileEndIndex;
struct file_info_node *beginFile, *endFile;
struct folder_info *next;
};
// 這里是一個隊(duì)列,用于迭代方式遍歷文件系統(tǒng)的一個中間變量
struct queue_info {
char *filename;
int offset, size, cluster;
struct queue_info *next;
};
// 一個整數(shù)鏈表結(jié)構(gòu)
struct int_linked_list {
int data;
struct int_linked_list *next;
};
// 這里是一個文件結(jié)構(gòu),表示內(nèi)容,可以讀取文件的其中一段,也可以通過簇的方式完整讀入整個文件
struct file_content {
struct int_linked_list *curList;
void *content;
int size;
char *filename;
};
/******************** 這里是全局變量的定義 **************************/
struct file_info_node *file_list_head, *file_list_tail;
struct folder_info *folder_info_head, *folder_info_tail;
struct queue_info *queue_head, *queue_tail;
char decToHex[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F };
/******************** 這里是函數(shù)的定義 **************************/
int file_list_init();
int file_list_new_info(struct file_info *info, int *id, struct file_info_node **newInfoNode);
int folder_info_init();
int folder_info_new_info(struct folder_info *info);
int queue_init();
int queue_new_task(char *filename, int offset, int size, int cluster);
struct queue_info *queue_get_task();
int process_task(struct queue_info* info);
struct file_content* readContentFromFixedSection(FILE *fp, int offset, int size);
struct file_content* readContentFromCluster(FILE *fp, short clusterId, int isFolder, int *size);
struct file_content* find_file_by_id(FILE *fp, int id, int *errCode);
int process_file_content(struct file_content* content, struct queue_info *info);
int getNextClutserId(FILE *fp, short clusterId);
int copyTo(void *desc, void *src, int size);
void print_all_list();
void print_file_content(struct file_content *content);
char *formatIndex(int i);
char *formatClustNo(int i);
char *formatFileName(char *filename, char *ext);
char *formatAttribute(char attribute);
char *formatDatetime(short date, short time);
char *formatSize(int size, int rightAlign);
/******************** 主函數(shù) **************************/
int main(int argc, char **args)
{
struct queue_info *task = NULL;
int choose, status;
FILE *fp = fopen(IMAGE_FILE, "r");
struct file_content *content;
char tmp;
if (fp == NULL)
{
return 1;
}
getNextClutserId(fopen(IMAGE_FILE, "r"), 2);
queue_init();
queue_new_task("Root", 0x00002600, 6144, 0);
while ((task = queue_get_task()) != NULL)
{
process_task(task);
}
print_all_list();
fflush(stdin);
printf("\nThe Number of File you want to view (enter -1 to exit): ");
scanf("%d", &choose);
content = find_file_by_id(fp, choose, &status);
if (status == MESSAGE_FILE_NOT_FOUND)
{
printf("Invaild Number, please input again!\n");
return 0;
}
else
{
if (content != NULL)
{
print_file_content(content);
}
}
return 0;
}
int process_task(struct queue_info* info)
{
FILE *fp;
struct file_content* content = NULL;
int size = 0;
fp = fopen(IMAGE_FILE, "r");
if (fp == NULL)
{
return ERROR_IO_ERROR;
}
// 判斷是否對根目錄進(jìn)行讀取
if (info->offset == 0x00002600)
{
content = readContentFromFixedSection(fp, info->offset, info->size);
}
else
{
content = readContentFromCluster(fp, info->cluster, 1, &size);
info->size = size;
}
process_file_content(content, info);
fclose(fp);
return OK;
}
int process_file_content(struct file_content* content, struct queue_info *info)
{
struct folder_info *node = (struct folder_info *)malloc(sizeof(struct folder_info));
struct file_info *newInfo = NULL;
struct file_info_node *newInfoNode = NULL;
char *content_char = (char *)content->content;
int newId = -1, fileCount = 0;
if (node == NULL)
{
return ERROR_MALLOC_FAILED;
}
node->filename = info->filename;
// 根據(jù)大小計(jì)算目錄中的文件數(shù)量
int maxFile = content->size / 32, i;
for (i = 0; i < maxFile; i++)
{
newInfo = (struct file_info *)malloc(sizeof(struct file_info));
if (newInfo == NULL)
{
printf("malloc failed!\n");
return ERROR_MALLOC_FAILED;
}
copyTo((void *)newInfo, (void *)(content_char + (32 * i)), 32);
if (newInfo->filename[0] != (char)0xE5 && newInfo->filename[0] != (char)0x00) {
file_list_new_info(newInfo, &newId, &newInfoNode);
if ((newInfo->attributes & 0x10) == 0x10)
{
if (newInfo->filename[0] == .)
{
continue;
}
char *buffer = (char *)malloc(sizeof(char)* 9);
int j;
for (j = 0; j < 8 && newInfo->filename[j] != (char)0x20; j++)
{
buffer[j] = newInfo->filename[j];
}
buffer[j] = \0;
queue_new_task(buffer, 0, 0, newInfo->pos);
}
if (0 == fileCount)
{
node->fileBeginIndex = newId;
node->beginFile = newInfoNode;
}
fileCount++;
}
}
node->fileEndIndex = file_list_tail->id;
node->endFile = file_list_tail;
folder_info_new_info(node);
return OK;
}
int copyTo(void *desc, void *src, int size)
{
int counter = 0, i;
for (i = 0; i < size; i++, counter++)
{
*(char *)(((char *)desc) + i) = *(char *)(((char *)src) + i);
}
return counter;
}
int file_list_init()
{
file_list_head = NULL;
file_list_tail = NULL;
return OK;
}
int file_list_new_info(struct file_info *info, int *id, struct file_info_node **newInfoNode)
{
struct file_info_node *newNode = (struct file_info_node*)malloc(sizeof(struct file_info_node));
if (newNode == NULL)
{
return ERROR_MALLOC_FAILED;
}
newNode->info = info;
newNode->next = NULL;
if (file_list_head == NULL)
{
newNode->id = 1;
file_list_head = newNode;
file_list_tail = newNode;
}
else
{
newNode->id = file_list_tail->id + 1;
file_list_tail->next = newNode;
file_list_tail = newNode;
}
*newInfoNode = newNode;
*id = newNode->id;
return OK;
}
int folder_info_init()
{
folder_info_head = folder_info_tail = NULL;
return OK;
}
int folder_info_new_info(struct folder_info *info)
{
if (info == NULL)
{
return OK;
}
if (folder_info_head == NULL)
{
info->next = NULL;
folder_info_head = info;
folder_info_tail = info;
}
else
{
info->next = NULL;
folder_info_tail->next = info;
folder_info_tail = info;
}
return OK;
}
int queue_init()
{
queue_head = queue_tail = NULL;
return OK;
}
int queue_new_task(char *filename, int offset, int size, int cluster)
{
struct queue_info *newNode = (struct queue_info *)malloc(sizeof(struct queue_info));
if (newNode == NULL)
{
return ERROR_MALLOC_FAILED;
}
newNode->filename = filename;
newNode->offset = offset;
newNode->size = size;
newNode->cluster = cluster;
newNode->next = NULL;
if (queue_head == NULL)
{
queue_head = queue_tail = newNode;
}
else
{
queue_tail->next = newNode;
queue_tail = newNode;
}
return OK;
}
struct queue_info *queue_get_task()
{
struct queue_info *retValue = queue_head;
if (queue_head == NULL)
{
return NULL;
}
if (queue_head == queue_tail)
{
queue_tail = NULL;
}
queue_head = queue_head->next;
retValue->next = NULL;
return retValue;
}
struct file_content* readContentFromFixedSection(FILE *fp, int offset, int size)
{
if (fp == NULL)
{
return NULL;
}
struct file_content *retValue = (struct file_content *)malloc(sizeof(struct file_content));
if (retValue == NULL)
{
return NULL;
}
retValue->curList = NULL;
retValue->size = size;
retValue->content = malloc(size);
if (retValue->content == NULL)
{
free(retValue);
return NULL;
}
fseek(fp, offset, SEEK_SET);
fread(retValue->content, size, 1, fp);
return retValue;
}
struct file_content* readContentFromCluster(FILE *fp, short clusterId, int isFolder, int *size)
{
int curCount = 1;
struct file_content *content = (struct file_content *)malloc(sizeof(struct file_content));
if (content == NULL)
{
return NULL;
}
// 第一步:迭代尋找所有簇號
content->curList = (struct int_linked_list *)malloc(sizeof(struct int_linked_list));
if (content->curList == NULL)
{
return NULL;
}
struct int_linked_list *head = content->curList, *tail = head;
head->data = clusterId;
head->next = NULL;
while ((clusterId = getNextClutserId(fp, clusterId)) != 0x00000FFF)
{
curCount++;
tail->next = (struct int_linked_list *)malloc(sizeof(struct int_linked_list));
tail->next->data = clusterId;
tail->next->next = NULL;
tail = tail->next;
}
// 第二步:開始根據(jù)簇號讀取
content->size = curCount * 512;
content->content = malloc(content->size);
struct int_linked_list *ptr = head;
int i = 0, address = 0xFFFFFFF;
for (ptr = head; ptr != NULL; ptr = ptr->next, i++)
{
address = 0x00003E00 + (512 * ptr->data);
fseek(fp, address, SEEK_SET);
fread((void *)(((char *)(content->content)) + (512 * i)), 512, 1, fp);
}
if (size != NULL)
{
*size = content->size;
}
return content;
}
struct file_content* find_file_by_id(FILE *fp, int id, int *errCode)
{
if (id < 1)
{
*errCode = MESSAGE_FILE_NOT_FOUND;
return NULL;
}
// 先遍歷目錄尋找這個文件
struct folder_info *ptr = folder_info_head;
struct file_info_node *node = NULL, *tmp = NULL;
struct file_content *content = NULL;
while (ptr != NULL)
{
if (ptr->fileBeginIndex <= id && id <= ptr->fileEndIndex)
{
for (tmp = ptr->beginFile; tmp->id != id && id <= ptr->fileEndIndex; tmp = tmp->next);
if (tmp->id == id)
{
node = tmp;
break;
}
}
else
{
ptr = ptr->next;
}
}
*errCode = (node == NULL ? MESSAGE_FILE_NOT_FOUND : OK);
if (node != NULL)
{
content = readContentFromCluster(fp, node->info->pos, 0, NULL);
content->size = node->info->size;
content->filename = formatFileName(node->info->filename, node->info->extname);
}
return (node == NULL ? NULL : content);
}
int getNextClutserId(FILE *fp, short clusterId)
{
if (clusterId == 0x000000A0)
{
printf("");
}
unsigned short tmp;
int address = (clusterId * 3 / 2) + 0x0000200;
unsigned short low = 0, high = 0;
fseek(fp, address, SEEK_SET);
fread((void *)(&tmp), 1, sizeof(unsigned short), fp);
low = ((tmp & 0xFFF0) >> 4);
high = tmp & 0x0FFF;
return (clusterId % 2 == 0 ? high : low);
}
void print_all_list() {
struct folder_info *ptr = folder_info_head;
struct file_info_node *node;
int index;
#ifdef _WIN32
system("cls");
#else
printf("\033[2J");
#endif
for (; ptr != NULL; ptr = ptr->next)
{
int count = 0, totalSize = 0;
printf("--------------------------------------------------------------------------\n");
printf(" Folder : %s\n", ptr->filename);
printf("--------------------------------------------------------------------------\n");
printf(" Num | File Name | Type | CLUSTNO | File Change Time | Size \n");
printf("--------------------------------------------------------------------------\n");
index = ptr->fileBeginIndex;
node = ptr->beginFile;
while (node != NULL && node->id <= ptr->fileEndIndex)
{
// 只是實(shí)現(xiàn)不同平臺下的變色操作
#ifdef _WIN32
HANDLE
鏈接地址:http://www.szxfmmzy.com/p-8844804.html