實(shí)驗(yàn)四文件系統(tǒng)實(shí)驗(yàn)報(bào)告.docx
《實(shí)驗(yàn)四文件系統(tǒng)實(shí)驗(yàn)報(bào)告.docx》由會(huì)員分享,可在線閱讀,更多相關(guān)《實(shí)驗(yàn)四文件系統(tǒng)實(shí)驗(yàn)報(bào)告.docx(24頁珍藏版)》請(qǐng)?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ù) 通過對(duì)FAT12文件系統(tǒng)的了解,編寫程序,讀取并列出一個(gè)虛擬軟盤中文件信息(文件名、屬性、修改時(shí)間等),以及讀取其中的文件內(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)分配文件空間的基本單位,簇由若干個(gè)扇區(qū)組成。在FAT12文件系統(tǒng)中,簇號(hào)的有效位是12位,所以這種文件系統(tǒng)就被稱為FAT12。FAT12文件系統(tǒng)中大致可以分成五個(gè)區(qū),這五個(gè)區(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ū)中儲(chǔ)存著一些基本的信息。例如,0x0000000B和0x0000000C兩個(gè)字節(jié)保存著每個(gè)扇區(qū)的大小,0x0000000D保存著每個(gè)簇占用多少個(gè)扇區(qū)。 FAT區(qū)中儲(chǔ)存著簇號(hào)。在0x00000200開始的三個(gè)字節(jié),分別儲(chǔ)存設(shè)備類型標(biāo)記(0xF0為軟盤);第二個(gè)第三個(gè)字節(jié)均為0xFF,是FAT標(biāo)識(shí)符。在FAT12文件系統(tǒng)中,每個(gè)簇占用12位,即1.5個(gè)字節(jié)。簇號(hào)與地址的對(duì)應(yīng)關(guān)系如下表: 地址偏移 000 001 002 003 004 005 簇序號(hào) 000 001 002 003 一個(gè)簇號(hào)跨越兩個(gè)字節(jié),每次讀取簇號(hào)時(shí)讀取兩個(gè)字節(jié),然后對(duì)讀出的兩個(gè)字節(jié)進(jìn)行位運(yùn)算處理,得到下一簇的簇序號(hào)。 注意,這里同樣需要對(duì)高低位進(jìn)行處理,即使用位計(jì)算的方式提取相應(yīng)的簇號(hào)信息。 根據(jù)上述的原理,可以得出一個(gè)函數(shù),以一個(gè)簇號(hào)為參數(shù),返回值為文件下一個(gè)簇號(hào)。代碼如下: 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)前簇號(hào),返回值是下一個(gè)簇號(hào)。 函數(shù)體的第二句代碼,計(jì)算出當(dāng)前簇號(hào)對(duì)應(yīng)的地址,用于文件指針的定位。第三句代碼是根據(jù)第二句計(jì)算得到的地址對(duì)文件指針進(jìn)行定位,定位到當(dāng)前簇號(hào)所對(duì)應(yīng)的信息處。第四句代碼是從文件指針的位置為起始位置讀入兩個(gè)字節(jié)的內(nèi)容(fread會(huì)自動(dòng)對(duì)高低字節(jié)位進(jìn)行處理)。并把這兩個(gè)字節(jié)的信息儲(chǔ)存到tmp變量之中。例如,讀取002簇號(hào)的下一個(gè)簇號(hào),根據(jù)公式,計(jì)算得到的address是0x00000203,讀取到0x00000203和0x00000204兩個(gè)字節(jié)的內(nèi)容。我們需要的是0x00000203整個(gè)字節(jié)的內(nèi)容和0x00000204的高四位,所以需要跟0xFFF0進(jìn)行位與運(yùn)算,并向右移四位,得到下一個(gè)簇號(hào)。 同樣地,讀取003簇號(hào)的下一個(gè)簇號(hào),根據(jù)公式,計(jì)算得到的address是0x00000204,讀取到0x00000204和0x00000205兩個(gè)字節(jié)的內(nèi)容,我們需要的是0x00000205整個(gè)字節(jié)的內(nèi)容和0x00000204第四位的內(nèi)容,所以需要跟0x0FFF進(jìn)行位與運(yùn)算,得到下一個(gè)簇號(hào)。所以代碼中需要對(duì)簇號(hào)的奇偶性進(jìn)行判斷,跟根據(jù)奇偶性的不同返回不同的值。 在根目錄中,保存著根目錄下面的文件或文件夾的信息。每個(gè)文件或者文件夾的信息使用32個(gè)字節(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)容 保留位 時(shí)間 日期 首簇號(hào) 文件大小 這里可以看出點(diǎn)問題,F(xiàn)AT中采用4個(gè)字節(jié)保存文件的大小,也就是說,文件的大小不能超過232字節(jié),也就是4G;文件名和擴(kuò)展名采用了固定長度,分別為8和3,太長的文件名在FAT中是不允許的。 其中,文件名的第一個(gè)字節(jié)還有其他的意義,例如,當(dāng)文件名的第一個(gè)字節(jié)為0x00時(shí),表示這一項(xiàng)沒有文件;為0xE5時(shí),則表示這個(gè)文件已經(jīng)被刪除,在編碼時(shí)應(yīng)該忽略這個(gè)文件。 文件的屬性采用一個(gè)字節(jié),也就是8個(gè)位來表示文件的6種屬性,最高兩位是保留位,沒有實(shí)際意義。這個(gè)字節(jié)的定義為: 位 7 6 5 4 3 2 1 0 屬性 保留 保留 歸檔 目錄 卷標(biāo) 系統(tǒng) 隱藏 只讀 在列出文件列表時(shí),對(duì)各個(gè)位進(jìn)行位與運(yùn)算以后,對(duì)結(jié)果進(jìn)行判斷,從而得出相應(yīng)的屬性值,根據(jù)上表,可以得出一個(gè)函數(shù),參數(shù)是表示文件屬性的那個(gè)字節(jié),返回值是一個(gè)以字符方式顯示文件屬性的一個(gè)字符串 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個(gè)字符分別存放六種屬性,第7位則用于儲(chǔ)存字符串的結(jié)束標(biāo)記’\0’,確保輸出的時(shí)候不會(huì)產(chǎn)生亂碼。 這個(gè)函數(shù)代碼是通過位與運(yùn)算對(duì)文件的各個(gè)屬性進(jìn)行判斷,并在相應(yīng)的字符位用字符或者’-’填充,最后把字符串返回。 時(shí)間和日期都采用的是壓縮儲(chǔ)存,儲(chǔ)存時(shí)間兩個(gè)字節(jié)的各位含義如下: 位 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 時(shí)(0-23) 分(0-59) 兩秒(0-29) 儲(chǔ)存日期兩個(gè)字節(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) 注:日期和時(shí)間都需要對(duì)高低字節(jié)進(jìn)行交換然后再讀取。實(shí)驗(yàn)中使用fread方法會(huì)自動(dòng)進(jìn)行交換。 根據(jù)上面的原理,可以得出這樣的一個(gè)函數(shù),這個(gè)函數(shù)以表示日期和時(shí)間的兩個(gè)原始值作為參數(shù)輸入,返回的是一個(gè)格式形如”xxxx-xx-xx xx:xx:xx”的字符串,這個(gè)函數(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í)儲(chǔ)存的數(shù)據(jù)分配儲(chǔ)存空間,隨后就是根據(jù)上述的原理,進(jìn)行位與運(yùn)算和移位操作,得到各項(xiàng)的時(shí)間屬性。最后通過sprintf函數(shù)對(duì)各個(gè)屬性按照固定的格式輸出到字符串之中并返回。 首簇號(hào),指的是這個(gè)文件儲(chǔ)存在磁盤的第一個(gè)簇的簇號(hào),也就是文件存放的具體地址。同樣地,需要對(duì)簇號(hào)的兩個(gè)字節(jié)進(jìn)行高低位交換。 最后一個(gè)是文件大小,需要對(duì)四個(gè)字節(jié)進(jìn)行高低字節(jié)交換,得到文件大小。 在實(shí)驗(yàn)中,會(huì)通過read函數(shù)每次讀入32個(gè)字節(jié),即讀取FAT表中的每一項(xiàng),在輸出文件信息時(shí)予以分析。 另外,每個(gè)目錄中都包含兩個(gè)虛擬目錄,文件名分別為’.’和’..’,分別表示當(dāng)前目錄和上一級(jí)目錄。在目錄的處理時(shí)需要對(duì)其進(jìn)行判斷,避免在進(jìn)行子目錄迭代顯示時(shí)進(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)體,每個(gè)成員變量對(duì)應(yīng)一個(gè)屬性。 struct file_info_node { int id; struct file_info *info; struct file_info_node *next; }; 這個(gè)文件信息鏈表的結(jié)點(diǎn),相應(yīng)地,在實(shí)驗(yàn)中定義了file_list_new_info方法,將文件信息添加到鏈表之中。 同時(shí),為了避免遞歸調(diào)用,在實(shí)驗(yàn)中,通過一個(gè)隊(duì)列的方式實(shí)現(xiàn)列出所有子目錄文件的功能。 在下面代碼中,content_char是一個(gè)指向儲(chǔ)存上述文件結(jié)構(gòu)的指針,content->size是file_content中表示文件大小的一個(gè)整型變量,用于計(jì)算文件夾中最大文件數(shù)量,newInfo是一個(gè)file_info結(jié)構(gòu)體的指針,用于儲(chǔ)存讀取到的文件信息原始值。 先把一個(gè)文件信息的原始信息從文件內(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; } 通過這個(gè)函數(shù)把文件信息的原始信息復(fù)制到newInfo之中。 上述的文件夾結(jié)構(gòu)不僅僅適用于根目錄,所有的目錄的遵循這種格式,所以這里可以得出一個(gè)初步的結(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); } 這是放在一個(gè)for循環(huán)中的代碼,先通過文件名判斷這個(gè)文件是否存在,如果存在,則把文件信息添加到程序的文件信息鏈表之中。再則判斷是否是目錄,如果是目錄,則把這個(gè)目錄添加到隊(duì)列之中。 2. 文件儲(chǔ)存方式 FAT文件系統(tǒng)對(duì)空間的分配和管理是以簇為基本單位的。所以,一個(gè)邏輯上連續(xù)的文件可能會(huì)被分散地儲(chǔ)存在磁盤的各個(gè)位置。操作系統(tǒng)輸出文件時(shí),遵循下面的步驟: 1. 會(huì)先通過文件夾信息找到文件首簇號(hào)。 2. 根據(jù)文件的首簇號(hào),定位到FAT區(qū)相應(yīng)位置;讀出下一個(gè)簇的簇號(hào)。 3. 如果下一個(gè)簇的簇號(hào)不是結(jié)束標(biāo)記(0xFFF),則會(huì)根據(jù)讀出的下一個(gè)簇號(hào)定位,讀出簇里面的內(nèi)容。如果讀出的是結(jié)束標(biāo)記,則表示文件已經(jīng)讀取完成。 假如一個(gè)文件被分散儲(chǔ)存在0x012,0x022,0x302三個(gè)簇里。從目錄的信息中讀出首簇號(hào)0x012,讀出0x012簇里的內(nèi)容;然后再通過0x012這個(gè)簇號(hào)在FAT區(qū)中找到下一個(gè)簇號(hào)0x022,讀出0x022的內(nèi)容;再通過0x022這個(gè)簇號(hào)找到下一個(gè)簇號(hào)0x302,讀出0x302中的內(nèi)容;再通過0x302讀出下一個(gè)簇號(hào)的內(nèi)容,此時(shí),讀出的簇號(hào)為0xFFF,即表示這個(gè)文件已經(jīng)結(jié)束。 本實(shí)驗(yàn)中,讀取文件的具體實(shí)現(xiàn)方法如下: 1. 通過一個(gè)鏈表,將這個(gè)文件的所有簇號(hào)儲(chǔ)存起來。 2. 遍歷儲(chǔ)存簇號(hào)的鏈表,逐個(gè)逐個(gè)簇讀取出來并儲(chǔ)存到內(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是一個(gè)儲(chǔ)存整型的鏈表,file_content是一個(gè)用于保存讀出文件內(nèi)容和文件信息的結(jié)構(gòu)體。 遍歷鏈表的過程中,通過一個(gè)while循環(huán)實(shí)現(xiàn),把讀取到簇號(hào)添加到鏈表之中。具體實(shí)現(xiàn)代碼如下,tail為保存簇號(hào)鏈表的末尾結(jié)點(diǎn)指針,fp是用于讀取文件的文件指針,curConnt是一個(gè)用于統(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; } 把簇號(hào)讀取完畢以后,開始對(duì)文件內(nèi)容進(jìn)行讀取,下面是文件內(nèi)容讀取的具體實(shí)現(xiàn)代碼,下面代碼中的content是一個(gè)指向用于存放文件內(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)的第一句代碼之中,通過簇號(hào)對(duì)簇所在的地址進(jìn)行計(jì)算,把地址值儲(chǔ)存到address變量之中;第二句代碼則是通過上一步計(jì)算得到的address變量對(duì)文件指針進(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)把每個(gè)文件夾都當(dāng)成是一個(gè)特殊的文件進(jìn)行處理。 3. FAT12文件系統(tǒng)通過簇進(jìn)行空間的管理和分配。 七、 完整實(shí)驗(yàn)代碼 /* * 操作系統(tǒng)課程 實(shí)驗(yàn) * FAT12 文件系統(tǒng) 實(shí)驗(yàn)代碼 * * 雖然這個(gè)程序在 Windows 和 Linux 環(huán)境下都能運(yùn)行。 * 不過,在 Windows 環(huán)境下運(yùn)行的話,顯示文件內(nèi)容的時(shí)候,內(nèi)容的末尾會(huì)有幾個(gè)奇怪的字符。 * Linux 環(huán)境下完全沒問題 * 暫時(shí)推測是 Windows 控制臺(tái)的原因,Windows 控制臺(tái)會(huì)把一些非字符的 ASCII 顯示為奇怪的字符, * 例如,0x0A 會(huì)顯示成一個(gè)笑臉,Linux 的控制臺(tái)下不會(huì)對(duì)這些非字符的 ASCII 進(jìn)行處理 * * 我是今天早上才發(fā)現(xiàn)這個(gè)問題的阿 (╯‵□′)╯︵┻━┻ * * 注意:編譯前,需要把 IMAGE_FILE 那個(gè)宏定義改成公郵上面的那個(gè) IMG 文件; * Linux 下打開這個(gè)源碼文件注釋會(huì)變成亂碼 * */ // 這個(gè)定義只是為了程序能在 VS2013 下面正常編譯而已 #ifdef _WIN32 #define _CRT_SECURE_NO_WARNINGS #endif #include- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來的問題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
9.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國旗、國徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 實(shí)驗(yàn) 文件系統(tǒng) 報(bào)告
鏈接地址:http://m.hcyjhs8.com/p-8844804.html