第七講 文件系統zz

發信人: gdtyy (gdtyy), 信區: Embedded
標  題: 第七講 文件系統
發信站: 水木社區 (Mon Jun 25 23:32:53 2007), 站內

*******************
* 第七講 文件系統 *
*******************
    2007/01/06  [email protected]  www.armecos.com

    文件系統的本質是“按名存取”,把文件名字和數據對應起來,比如webserver裏需要
按文件名提取文件數據(各種圖片gif/bmp等,html,cgi等)。你可以用各種方法實現這個目
的,只要能夠“按名存取”就叫文件系統,比如:用數組保存文件,用鏈表結構體,用比較
複雜完備的FAT等。完成名字映射,可以給應用編程帶來極大的便利,你不必親自管理數據
存儲,所有細節操作交由文件系統處理,只需要統一地用名字訪問即可。文件系統屏蔽底層
細節,用戶可以在ROM、RAM、網絡、硬盤、SD卡、CF卡、USB等很多種介質上實現“按名存
取”。算法根據需要可以簡單也可以複雜,核心思想就是一個------“按名存取”。
    前面講過ecos將串口抽象爲串口設備文件,將中斷抽象爲一個通用的虛擬中斷系統,而
這裏講的文件系統就是特指對存儲設備的抽象。存儲設備利用半導體、磁性、光學等物理介
質材料,把所有信息(視頻、音頻、圖像、數據等)以“0”或“1”編碼的形式存儲起來。用
戶通過將(文件)名字掛裝到物理介質上,並在其上使用某個文件系統(即數據結構),實現名
字映射。
    常見的存儲介質有:ROM、RAM、硬盤、SD卡、CF卡、USB、網絡.....
    常見的文件系統有:RAMFS、ROMFS、FAT、NTFS、NFS、EXT3......
    有的文件系統適用於多種介質,比較通用,而有的則是專門爲某種介質設計。文件系統
可以看成是某種數據組織結構,不同的數據結構用在不同的介質上可靠性、效率不同,一般
有最佳匹配。
    文件系統的核心思想很簡單,不過,考慮到速度、效率、容量、簡單性、安全性、可靠
性、擴展性、併發訪問、存儲介質多樣等,“按名存取”的實現有一定的挑戰性。
    ecos實現了POSIX標準的文件和目錄函數,主要包括文件系統的安裝和卸載、目錄操作
、文件操作等幾個方面。文件系統根據安裝點(mount point)的名字,將具有根的文件名(以
“/”開始的文件名)指向正確的文件系統。當使用以“/”開始的文件名時,系統將其與安
裝表中所有有效的表項名字進行比較,表項名字在字符“/”出現之前或字符串結束之前與
文件名具有最長匹配的表項即爲該文件所屬的文件系統安裝表表項。文件名的剩餘部分、該
安裝表表項的指針以及作爲目錄指針的root值一起被當作參數傳送到文件系統表表項中的相
應函數。
    例如,假設一個安裝表具有如下的表項內容:
    { "/" , "msdos" , "/dev/hd0" , ... }
    { "/fd" , "msdos" , "/dev/fd0" , ... }
    { "/rom" , "romfs" , "" , ... }
    { "/rom/tmp" , "ramfs" , "" , ... }
    { "/tmp" , "ramfs" , "" , ... }
    { "/dev" , "devfs" , "" , ... }
    其中順序爲:{ 目錄名(掛裝點),文件系統,物理設備... }
    當試圖打開“/rom/yy”時,該文件被定向到ROM文件系統(romfs),而“/rom/tmp”卻
被定向到RAM文件系統(ramfs)。打開“/bar/bundy”將被定向到硬盤MSDOS文件系統
(msdos),打開“/dev/tty0”的操作將被定向到設備管理文件系統(devfs)的設備表中的
lookup函數。不帶根的文件名(不以“/”開始的文件名)將直接定向到包含當前目錄的文件
系統。當前目錄是由一個安裝表表項和一個目錄指針組合起來表示的。

    下面我們以ROMFS文件系統爲例來說明文件系統的用法,ROMFS文件系統是最簡單的,對
文件系統設計感興趣的讀者可以閱讀其源碼,如果想移植FAT操作系統,只要以ROMFS爲藍本
,修改對應的接口函數實現體即可。
    我們的例子程序是一個通用的靜態頁面發佈服務器,可以發佈任意目錄下的靜態頁面(
支持長文件名)、pdf文件、圖片(jpg/bmp/gif等)......ZLG原來的例子程序只能發佈一個簡
單頁面,也不能更換髮布目錄,下面給出的程序可以任意更換髮布目錄,可以做爲靜態web
server使用。範例程序將發佈“Linux From Scratch”,LFS安裝指導書將講解如何通過編
譯從網上下載的源碼包,來建立一個LINUX系統。當然,你也可以發佈自己的靜態個人主頁
,或者GNU的資料,或者英語學習資料等等,把這個web server掛在局域網上,就可以從這
個服務器上查找常用資料了,比PC機省電,速度足夠了。如果嫌2M flash太小,可以考慮把
發佈目錄掛接在2G SD卡/CF卡上,或者300G硬盤上。只要更改mount掛裝點即可,其餘部分
不用改動。如果想發佈在互聯網上,那麼實現了PPPOE和動態域名以後就可以了。在發佈目
錄下還增加了a.pdf和b.jpg文件,以便測試pdf和jpg的發佈。
    Let's go!
    web server的工作原理是:每當點擊鏈接時,IE瀏覽器會發出GET請求“GET 文件名(從
根開始) HTTP/1.0”,我們只要發回請求的文件數據即可完成服務,IE瀏覽器會自動將頁面
中的圖片分別請求,每個請求對應一個TCP連接,傳送完畢不保留該次TCP連接。GET請求中
的文件名是絕對路徑,即使在頁面中使用相對路徑,IE瀏覽器也會翻譯成絕對路徑發給服務
器,目錄由瀏覽器自己維護,服務器只負責應答請求,不記憶連接信息。可以在程序中增加
打印語句輸出請求信息,對於深入理解HTTP協議是個很好的方法。由此可見ecos增值包用於
學習各種TCP/IP協議非常方便有效!該程序還利用了一個合理的調試技巧,完全漏掉了
HTTP頭,這種大多數(並非全部)情況下瀏覽器仍正確工作。雖然不提倡這種違背協議的行爲
,但它在起初的開發和調試中確實有用。文件擴展名和HTTP數據類型之間的關係更爲複雜。
當文件從磁盤裝入時,瀏覽器必須判斷文檔類型,它判斷的依據僅僅是文件擴展名,操作系
統文件關聯,或兩者都作爲依據。從網上下載時,文件通常帶有文件擴展名和數據類型,後
者優先。不過並不強制WEB服務器提供HTTP數據類型,雖然缺少它容易引起混淆,於是一些
瀏覽器根據文件擴展名派生類型,其他的則假定默認值(HTML)。
    下面分析程序,大部分與ZLG程序相同,只分析不同部分。
    讀到瀏覽器請求後,提取帶根的文件名,如果是“/”,那麼就用缺省文件index.htm替
換(或者你可以缺省選擇default.htm)。打開此文件,如果返回-1,說明文件不存在,就關
閉TCP連接準備下一次應答,否則,讀取文件併發送,一次讀不完就反覆這個過程,直至讀
完發完。這樣,不管多大的文件,也能用有限的緩衝發送。由此可見,改動的地方並不大,
而且看起來更簡潔明瞭,文件大小和類型也沒有限制了。使用文件系統並不會使應用變複雜
,而是變得更容易了。

    ROMFS文件系統有兩種實現方法:1、用程序頭文件實現;2、用ROM映像實現。
    我要發佈的目錄是lfs,其結構如下:

    aboutdebug.htm
    .
    .
    index.htm
    .
    .
    zlib.htm
    zlib-1.htm
    a.pdf
    b.jpg

    在cygwin中使用$ mk_romfs -v ./lfs romfs.img將lfs目錄製作成ROMFS文件系統映像
romfs.img,
    在redboot中用lo -b 0x81010000 -r -h 192.168.0.1 romfs.img下載映像到RAM中,
    在redboot中用fis create -b 0x81010000 -l 0x40000 romfs將RAM中的映像燒寫到
flash中,
    用fis list查看到redboot把此映像自動分配到了0x80080000地址。
    在程序中定義CYGNUM_FS_ROM_BASE_ADDRESS爲0x80080000,就可以使用這個ROMFS了。
如果你要發佈別的目錄,只要製作新的映像並替換這個位置的ROMFS文件即可,不用改動程
序。

    如果想用頭文件的方式實現,只要用file2c.tcl就可以轉換爲C頭文件,如下:
    sh file2c.tcl romfs.img romfs.h
    把這個頭文件包含在C應用程序裏,並將ROMFS掛裝在這個數組上即可。不過這樣每次更
改發佈目錄/文件都要重新編譯程序。

    redboot可以引導程序自動運行,用fconfig配置啓動文件,5秒鐘不按鍵自動執行應用
程序(這裏指web server),如果按鍵就進入redboot,此時可以寫入ROMFS文件系統。這樣,
這個靜態頁面服務器就比較實用了,上電5秒後自動發佈頁面,可以更換髮布目錄,可以掛
裝不同存儲設備,便攜省電。

    使用192.168.0.6/a.pdf可以看pdf文件,使用192.168.0.6/b.jpg可以看圖片。其實支
持ASP、JavaScript、數據庫、公網動態發佈也是可以的,以後再說吧。

 

//此程序配合IE瀏覽器

#include <network.h>

#include <pkgconf/system.h>
#include <pkgconf/net.h>

#include <cyg/fileio/fileio.h>

#include <cyg/infra/testcase.h>

#define CYGNUM_FS_ROM_BASE_ADDRESS 0x80080000

MTAB_ENTRY( romfs_mte1,
                   "/",
                   "romfs",
                   "",
                   (CYG_ADDRWORD) CYGNUM_FS_ROM_BASE_ADDRESS );

#ifdef CYGBLD_DEVS_ETH_DEVICE_H    // Get the device config if it exists
#include CYGBLD_DEVS_ETH_DEVICE_H  // May provide
CYGTST_DEVS_ETH_TEST_NET_REALTIME
#endif

#ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test?
# ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists
#  include CYGTST_DEVS_ETH_TEST_NET_REALTIME
# endif
#endif

#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
static char stack[STACK_SIZE],stack1[STACK_SIZE];
static cyg_thread thread_data,thread_data1;
static cyg_handle_t thread_handle,thread_handle1;

#define BUF_LEN 10000
void
pexit(char *s)
{
    CYG_TEST_FAIL_FINISH(s);
}

void
webserver_test(struct bootp *bp)
{
    //struct protoent *p;
    //struct timeval tv;
    struct sockaddr_in host,client;
    int s,sa,e_source,len;
    unsigned char buf[BUF_LEN];
    unsigned char * p;

    int err,fd;

    err = mount("","/","romfs");

    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) {
        pexit("socket");
        return;
    }

    // Set up host address
    host.sin_family = AF_INET;
    host.sin_len = sizeof(host);
    host.sin_addr.s_addr = INADDR_ANY;
    host.sin_port = ntohs(80);

    if(bind(s, (struct sockaddr *) &host, sizeof(host)) < 0) {
        pexit("bind /source/ error");
    }

    listen(s, SOMAXCONN);

    while(true){
        //memset(buf, 0, sizeof(buf));

        if ((sa = accept(s, (struct sockaddr *)&client, &len)) < 0) {
            printf("Accept ERROR!/n");
            continue;
        }

        printf("SERVER : HTTP request arrived from %s:%d/n",
inet_ntoa(client.sin_addr),ntohs(client.sin_port));

        len = read(sa, buf, sizeof(buf));

        p = &buf[4];
        while(*p++ != ' ');
        *(p-1) = '/0';
        p = &buf[4];

        printf("/n%s/n/n",p);

        if(strcmp(p,"/") == 0)
            {
                strcpy(p,"/index.htm");
            }

        fd = open(p,O_RDONLY);

        if(fd == -1)
            {
                close(fd);
                close(sa);
                printf("File open error!/n");
                continue;
            }

        len = read(fd,buf,BUF_LEN);
        while(len != 0){
            len = write(sa, buf, len);
            len = read(fd,buf,BUF_LEN);
        }

        close(fd);

        close(sa);
    }
}

void
net_test(cyg_addrword_t p)
{
    diag_printf("Start Networking Test.../n");

    init_all_network_interfaces();

#ifdef CYGHWR_NET_DRIVER_ETH0
    if (eth0_up) {
        cyg_thread_create(10,                // Priority - just a number
                      webserver_test,        // entry
                      (cyg_addrword_t)&eth0_bootp_data,      // entry parameter
                      "Network tcp test",    // Name
                      &stack1[0],            // Stack
                      STACK_SIZE,            // Size
                      &thread_handle1,       // Handle
                      &thread_data1          // Thread data structure
            );
        cyg_thread_resume(thread_handle1);  // Start it
    }
#endif

}

void
cyg_start(void)
{
    // Create a main thread, so we can run the scheduler and have time 'pass'
    cyg_thread_create(10,                // Priority - just a number
                      net_test,          // entry
                      0,                 // entry parameter
                      "Network test",    // Name
                      &stack[0],         // Stack
                      STACK_SIZE,        // Size
                      &thread_handle,    // Handle
                      &thread_data       // Thread data structure
            );

    cyg_thread_resume(thread_handle);  // Start it
    cyg_scheduler_start();
}

--

※ 來源:·水木社區 http://newsmth.net·[FROM: 61.149.56.*]
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章