第七讲 文件系统zz

发信人: gdtyy (gdtyy), 信区: Embedded
标  题: 第七讲 文件系统
发信站: 水木社区 (Mon Jun 25 23:32:53 2007), 站内

*******************
* 第七讲 文件系统 *
*******************
    2007/01/06  asdjf@163.com  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.*]
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值