java開發(fā)系統(tǒng)內(nèi)核:實現(xiàn)基于FAT12文件系統(tǒng)的dir命令

更詳細的講解和代碼調(diào)試演示過程,請參看視頻
Linux kernel Hacker, 從零構建自己的內(nèi)核

如果你對機器學習感興趣薛耻,請參看一下鏈接:
機器學習:神經(jīng)網(wǎng)絡導論

本節(jié)要實現(xiàn)的控制臺命令是dir, 熟悉該命令的同學都了解饼齿,它的作用是列舉出當前目錄下的文件信息蝙搔。問題在于吃型,我們當前的操作系統(tǒng)根本沒有硬盤,更沒有文件系統(tǒng)枉层,那么這個命令列舉的文件從哪里來呢赐写?由于我們的系統(tǒng)內(nèi)核是存儲在軟盤上的挺邀,因此,我們直接把軟盤當做系統(tǒng)硬盤泣矛,該命令列舉的是存儲在虛擬軟盤上的文件沦补。假設我們在虛擬軟盤上存儲了兩個文件夕膀,分別為abc.exe, efg.sys,文件的大小分別為256字節(jié)和128字節(jié),運行該命令后魂奥,控制臺顯示結果如下圖:

這里寫圖片描述

我們先看看FAT12文件系統(tǒng)是如何記錄文件信息的耻煤。每個存儲在FAT12系統(tǒng)上的文件都有一個文件目錄哈蝇,用于存儲文件的基本信息,這個目錄的數(shù)據(jù)結構如下:

struct FILEINFO {
    unsigned char name[8], ext[3], type;
    char  reserve[10];
    unsigned short time, date, clustno;
    unsigned int  size;
};

這個結構體的頭8個字節(jié)對應name,也就是文件名怜跑,也就是說存儲的文件性芬,它的名稱絕不能對于8個字符剧防。接下來三個字節(jié)對應的是文件擴展名峭拘,第12個字節(jié),也就是type, 它對應的是文件的類型棚唆,它的值意義如下:
0x01 只讀文件
0x02 隱藏文件
0x04 系統(tǒng)文件
0x08 非文件信息
0x10 目錄。

接下來的10字節(jié)為保留,這是微軟規(guī)定的瞎惫。跟著的兩個字節(jié)译株,首先是time 和 date 用于表示文件的生成時間歉糜,最后4個字節(jié)就是文件的大小。

當前伞辛,我們的虛擬軟盤所存儲的信息夯缺,其布局是這樣的踊兜,最開始的512字節(jié)是引導扇區(qū)代碼,接下來存儲的就是系統(tǒng)內(nèi)核于游,然后跟著是FAT12文件系統(tǒng)對應的文件目錄贰剥,也就是上面描述的數(shù)據(jù)結構鸠澈,存了幾個文件,就有幾個FILEINFO數(shù)據(jù)結構际度。由此先看看乖菱,我們當前的內(nèi)核到底有多大窒所,這樣我們才能計算出文件目錄在軟盤中的位置吵取,進而確定它加載到內(nèi)存后,所對應的位置皮官。

運行生成虛擬軟盤的java工程捺氢,通過輸出摄乒,我們可以看到残黑,當前系統(tǒng)內(nèi)核的大小總共是71個扇區(qū),每個扇區(qū)大小是512字節(jié)萍摊,因此內(nèi)核的總大小是71*512=0x8E00 字節(jié)冰木。我們的內(nèi)核加載到內(nèi)存時,是從起始地址0x8000開始的歇终,于是內(nèi)核在內(nèi)存中的末尾地址就是 0x10E00 = 0x8000 + 0x8E00, 由于我們把文件的目錄信息直接跟在內(nèi)核末尾的,因此文件目錄信息的起始地址就是0x10E00.

接著我們看看追葡,文件目錄信息是如何寫到虛擬磁盤上的:

import java.nio.ByteBuffer;


public class FileHeader {
    private byte[] header = new byte[32];
    
    public void setFileName(String s) {
        int len = s.length() > 8 ? 8 : s.length();
        for (int i = 0; i < len; i++) {
            header[i] = (byte)s.charAt(i);
        }
    }
    
    public void setFileExt(String s) {
        int len = s.length() > 3 ? 3 : s.length();
        for (int i = 0; i < len; i++) {
            header[8+i] = (byte)s.charAt(i);
        }
    }
    
    public void setFileType(Byte t) {
        header[11] = t;
    }
    
    public void setFileTime(byte[] time) {
        header[22] = time[0];
        header[23] = time[1];
    }
    
    public void setFileDate(byte[] date) {
        header[24] = date[0];
        header[25] = date[1];
    }
    
    public void setFileClusterNo(byte[] no) {
        header[26] = no[0];
        header[27] = no[1];
    }
    
    public void setFileSize(int size) {
        byte[] buf = ByteBuffer.allocate(4).putInt(size).array();
        for (int i = 0; i < 4; i++) {
            header[28+i] = buf[3 - i];
        }
        
        
    }
    
    public byte[] getHeaderBuffer() {
        return header;
    }
    
    
}

一個FileHeader 類用來表示一個文件目錄,它對應前頭提到的FILEINFO數(shù)據(jù)結構谬返,它提供了幾個接口遣铝,用來設置文件名酿炸,擴展名等相關信息涨冀。


public class DiskFileSystem {
    private Floppy floppyWriter;
    private int beginSec;
    private int fileHeaderCount = 0;
    private byte[] buffer = new byte[512];
    private int cylinder = 0;
    
    public DiskFileSystem(Floppy disk, int  cylinder, int sec) {
        this.floppyWriter = disk;
        this.beginSec = sec;
        this.cylinder = cylinder;
    }
    
    public void addHeader(FileHeader header) {
        if (fileHeaderCount >= 16) {
            flashFileHeaders();
            fileHeaderCount = 0;
            buffer = new byte[512];
            beginSec++;
        }
        
        byte[] headerBuf = header.getHeaderBuffer();
        for (int i = 0; i < 32; i++) {
            buffer[fileHeaderCount * 32 + i] = headerBuf[i];
        }
        
        fileHeaderCount++;
    }
    
    public void flashFileHeaders() {
        floppyWriter.writeFloppy(Floppy.MAGNETIC_HEAD.MAGNETIC_HEAD_0 , cylinder, beginSec, buffer);
    }
}

DiskFileSystem 用于把文件目錄結構寫入到磁盤的指定地方廷支。該類的初始函數(shù)需要傳入幾個參數(shù),disk 表示虛擬磁盤栓辜,cylinder 表示文件目錄所要寫入的柱面,sec 表示所在柱面的起始扇區(qū)垛孔。

這里寫圖片描述

上圖表示的是內(nèi)核寫入到磁盤的情況藕甩,可以看到,內(nèi)核最后寫入到虛擬軟盤的第4柱面周荐,第17扇區(qū)狭莱。由于我們的文件目錄緊跟著內(nèi)核存儲,因此概作,我們的文件目錄要寫入到第4柱面腋妙,第18扇區(qū),于是我們在生成虛擬軟盤時讯榕,在指定位置寫下文件目錄:

 public void makeFllopy()   {
        writeFileToFloppy("kernel.bat", false, 1, 1);
        
        //test file system
        
        DiskFileSystem fileSys = new DiskFileSystem(floppyDisk, 4, 18);
        FileHeader header = new FileHeader();
        header.setFileName("abc");
        header.setFileExt("exe");
        byte[] date = new byte[2];
        date[0] = 0x11;
        date[1] = 0x12;
        header.setFileTime(date);
        header.setFileDate(date);
        header.setFileSize(256);
        fileSys.addHeader(header);
        
        header = new FileHeader();
        header.setFileName("efg");
        header.setFileExt("sys");
        header.setFileSize(128);
        fileSys.addHeader(header);
        
        fileSys.flashFileHeaders();
        
        //test file system
        
        floppyDisk.makeFloppy("system.img");
    }

上面代碼先創(chuàng)建了兩個文件目錄骤素,這兩個文件名分別為abc.exe 和 efg.sys, 這兩個文件是虛擬的痕檬,我們只在磁盤上構造它們的目錄,在磁盤上并沒有這兩個文件的實際數(shù)據(jù)。磁盤上有了文件目錄后荒澡,我們要編寫內(nèi)核代碼,讓內(nèi)核能夠讀取顯示相關信息饥侵。

首先在global_define.h添加如下代碼:

#define  ADR_DISKIMG  0x10E00

struct FILEINFO {
    unsigned char name[8], ext[3], type;
    char  reserve[10];
    unsigned short time, date, clustno;
    unsigned int  size;
};

其中ADR_DISKIMG 就是文件目錄在內(nèi)存中的起始地址狼忱,F(xiàn)ILEINFO對應的就是我們前頭提到過的FAT12文件系統(tǒng)對應的文件目錄信息佃却。當我們在控制臺輸入命令dir 后,控制臺從指定位置,把FILEINFO結構數(shù)據(jù)讀取出來赦邻,并把對應的文件名和文件大小顯示出來按声,代碼如下,在write_vga_desktop.c中:

void console_task(struct SHEET *sheet, int memtotal) {
....
struct FILEINFO* finfo = (struct FILEINFO*)(ADR_DISKIMG);

    for(;;) {
    ....
    else if (strcmp(cmdline, "dir") == 1) {
                       while (finfo->name[0] != 0) {

                       char s[13];
                       s[12] = 0;
                       int k;
                       for (k = 0; k < 8; k++) {
                           if (finfo->name[k] != 0) {
                               s[k] = finfo->name[k]; 
                           }else {
                               break;
                           }
                       }

                       int t = 0;
                       s[k] = '.';
                       k++;
                       for (t = 0; t < 3; t++) {
                           s[k] = finfo->ext[t];
                           k++;
                       }
                       
                       showString(shtctl, sheet, 16, cursor_y, COL8_FFFFFF, s);
                       int offset = 16 + 8*15;
                       char* p = intToHexStr(finfo->size);
                       showString(shtctl, sheet, offset, cursor_y, COL8_FFFFFF, p);
                       cursor_y = cons_newline(cursor_y, sheet);
                       finfo++;

                      }
    ....
    }
....
}

當控制臺收到dir命令時,它先從地址ADR_DISKIMG開始扛拨,讀取第一個文件目錄信息,如果文件名的起始第一個字符不是0计盒,那么表明接下來的32字節(jié)表示有效的文件目錄信息拔第,于是代碼先獲取文件名懈涛,然后獲取文件擴展名,最后得到文件大小,然后依次把這些信息顯示到控制臺上。接著越過32字節(jié)晨横,再判斷接下來的32個字節(jié)是否表示有效的文件目錄信息,如果是伙狐,再按照原有邏輯,繼續(xù)顯示相關信息唉侄。

我們在虛擬軟盤中寫入了兩個文件目錄信息候生,因此運行該命令后,控制臺正確顯示了相關文件的目錄信息唠粥。

本節(jié)內(nèi)容稍微有點燒腦,請參看視頻官份,以便獲得更詳細的講解和代碼調(diào)試演示。

歡迎關注公眾號,讓我們一起學習搁凸,交流,成長:


文章公眾號.jpg
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锨亏,更是在濱河造成了極大的恐慌乾翔,老刑警劉巖雷则,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遵岩,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匪傍。 經(jīng)常有香客問我薪棒,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任锐极,我火速辦了婚禮翎迁,結果婚禮上肃拜,老公的妹妹穿的比我還像新娘士聪。我一直安慰自己略板,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般瞬测。 火紅的嫁衣襯著肌膚如雪穷躁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天竖螃,我揣著相機與錄音,去河邊找鬼旗闽。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的绳匀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼脚乡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了劈猪?” 一聲冷哼從身側響起庸推,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后养葵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佃蚜,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡腮考,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了现喳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片球凰。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腿宰,靈堂內(nèi)的尸體忽然破棺而出呕诉,到底是詐尸還是另有隱情,我是刑警寧澤吃度,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布甩挫,位于F島的核電站,受9級特大地震影響椿每,放射性物質(zhì)發(fā)生泄漏伊者。R本人自食惡果不足惜英遭,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亦渗。 院中可真熱鬧挖诸,春花似錦、人聲如沸法精。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搂蜓。三九已至狼荞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帮碰,已是汗流浹背相味。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留殉挽,地道東北人丰涉。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像斯碌,于是被迫代替她去往敵國和親昔搂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 21.1文件系統(tǒng)的概念 21.1.1文件系統(tǒng)和文件 ■文件系統(tǒng)是操作系統(tǒng)中管理持久性數(shù)據(jù)的子系統(tǒng)输拇,提供數(shù)據(jù)存儲和訪...
    龜龜51閱讀 721評論 0 4
  • Ubuntu的發(fā)音 Ubuntu瘩绒,源于非洲祖魯人和科薩人的語言猴抹,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢閱讀 99,202評論 9 467
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,146評論 2 34
  • 早上我想起來背書锁荔,但是不需要掃地蟀给,需要做飯,需要上廁所需要把孩子叫醒阳堕,需要陪著孩子一起背書跋理,也需要背自己的書。我需...
    105d45b91b02閱讀 734評論 0 1
  • 學會用git了恬总,記錄一下前普,以后好參考。 創(chuàng)建項目文件夾壹堰,然后git init生成倉庫 添加文件拭卿,git add增加...
    銀河星海閱讀 194評論 0 0