mkyaffs2image编译

http://blog.chinaunix.net/uid-26009923-id-3760474.html
http://blog.csdn.net/xingtian19880101/article/details/17504529

一. mkyaffs2image 是如何生成的
我们往往用 mkyaffs2image把文件系统打包成yaffs.bin格式,然后在u-boot 中用 nand.write.yaffs2 把文件系统烧到nand flash的指定位置上
但是mkyaffs2image是如何编译出来的呢? 其实mkyaffs2image是在yaffs文件系统的utils目录下,
只把其中的chunkSize  spareSize  与 pagesPerBlock几个变量,按照nand_flash中的改一下就可以用

// Adjust these to match your NAND LAYOUT:
    //#define chunkSize 8192
    //#define spareSize 232
    #define chunkSize 4096
    //#define spareSize 218
    #define spareSize 128
    #define pagesPerBlock 128

我这儿只是改了 chunkSize 与 spareSize.但是貌似datasheet上的spareSize=218. 莫非datasheet也可以骗人。
二. mkyaffs2image分析
2. 下面是mkyaffs2image的main, 很简单的一个函数吧
其中, argc必须大于3     
     argv[1] = dir                  //文件系统的path
     argv[2] = image_file      //打包后生成yaffs.bin的路径

int main(int argc, char *argv[])   
    {
        struct stat stats;
        stat(argv[1],&stats);  
        if(!S_ISDIR(stats.st_mode))              //保证argv[1]必须是一个目录  
            exit(1);   
        outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);  //写入到镜像yaffs.bin的fd保存在一个全局变量outFile中
        process_directory(YAFFS_OBJECTID_ROOT,argv[1]);                            //1. 依次读取目录中的文件,写到yaffs.bin中
        pad_image();                                                               //2. 将yaffs.bin扩充到block对齐                       
        close(outFile);
    }

2.1 对目录的处理过程

static int process_directory(int parent, const char *path)
    {
        DIR *dir;
        char full_name[500];
        struct stat stats;
        int equivalentObj;
        int newObj;
        struct dirent *entry;
        nDirectories++;
        dir = opendir(path);                      //打开目录
        while((entry = readdir(dir)) != NULL)     //遍历目录中的所有文件
        {
            if(strcmp(entry->d_name,".") || strcmp(entry->d_name,".."))         //如果是 . 或者 .. 则直接跳过
                continue;
            snprintf(full_name,sizeof(full_name),"%s/%s",path,entry->d_name);    //构造文件的路径,存于full_name中        
            lstat(full_name,&stats);                                             //获取目录下该文件的stat信息

if(!S_ISLNK(stats.st_mode) && !S_ISREG(stats.st_mode) && ! S_ISDIR(stats.st_mode) &&
             !S_ISFIFO(stats.st_mode) && !S_ISBLK(stats.st_mode) && ! S_ISCHR(stats.st_mode) &&
             !S_ISSOCK(stats.st_mode))
                continue ;                                                        //不知道这TMD是什么类型的文件则跳过

newObj = obj_id++;
            n_obj++;                
            if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
            {
                write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
            }
            else
            {
                add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
                if(S_ISLNK(stats.st_mode))
                {
                    char symname[500];
                    memset(symname,0, sizeof(symname));
                    readlink(full_name,symname,sizeof(symname) -1);
                    write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);

}
                else if(S_ISREG(stats.st_mode))             //如果是普通文件
                {                        
                    if(write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL) == 0)  //1.先写入文件头
                    {
                        int h;
                        u8 bytes[chunkSize];
                        int n_bytes;
                        int chunk = 0;

h = open(full_name,O_RDONLY);                            
                        memset(bytes,0xff,sizeof(bytes));
                        while((n_bytes = read(h,bytes,sizeof(bytes))) > 0)
                        {
                            chunk++;
                            write_chunk(bytes,newObj,chunk,n_bytes);                                            //2.再写入文件内容
                            memset(bytes,0xff,sizeof(bytes));
                        }
                        close(h);
                    }
                }
                else if(S_ISSOCK(stats.st_mode))                                    //如果是socket文件                   
                    write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);  //只写入文件头                  
                else if(S_ISFIFO(stats.st_mode))                                    //如果是FIFO文件                   
                    write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头                   
                else if(S_ISCHR(stats.st_mode))                                     //如果是字符设备文件                  
                    write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);  //只写入文件头                  
                else if(S_ISBLK(stats.st_mode))                                     //如果是块设备文件                  
                    write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头                   
                else if(S_ISDIR(stats.st_mode))                                     //如果是目录文件                   
                    if (write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL) == 0) //只写入文件头
                        process_directory(newObj,full_name);                       //并把这次的newObj作为parent,继续             
            }    
        }
        closedir(dir);
        return 0;
    }

2.1.1

static int write_object_header(int id, enum yaffs_obj_type t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
    {
        u8 bytes[chunkSize];

struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)bytes;

memset(bytes,0xff,sizeof(bytes));

oh->type = t;

oh->parent_obj_id = parent;

if (strlen(name)+1 > sizeof(oh->name))
        {
            errno = ENAMETOOLONG;
            return warn("object name");
        }
        memset(oh->name,0,sizeof(oh->name));
        strcpy(oh->name,name);

if(t != YAFFS_OBJECT_TYPE_HARDLINK)
        {
            oh->yst_mode = s->st_mode;
            oh->yst_uid = s->st_uid;
            oh->yst_gid = s->st_gid;
            oh->yst_atime = s->st_atime;
            oh->yst_mtime = s->st_mtime;
            oh->yst_ctime = s->st_ctime;
            oh->yst_rdev = s->st_rdev;
        }

if(t == YAFFS_OBJECT_TYPE_FILE)
        {
            oh->file_size = s->st_size;
        }

if(t == YAFFS_OBJECT_TYPE_HARDLINK)
        {
            oh->equiv_id = equivalentObj;
        }

if(t == YAFFS_OBJECT_TYPE_SYMLINK)
        {
            if (strlen(alias)+1 > sizeof(oh->alias))
            {
                errno = ENAMETOOLONG;
                return warn("object alias");
            }
            memset(oh->alias,0,sizeof(oh->alias));
            strcpy(oh->alias,alias);
        }
        return write_chunk(bytes,id,0,0xffff);

}

static int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes)
    {
        struct yaffs_ext_tags t;
        struct yaffs_packed_tags2 pt;
        char spareData[spareSize];

if (write(outFile,data,chunkSize) != chunkSize)                //写4K
            fatal("write");

memset(&t, 0, sizeof(t));

t.chunk_id = chunk_id;
        t.serial_number = 1;    // **CHECK**
        t.n_bytes = n_bytes;
        t.obj_id = id;
        t.seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
        t.chunk_used = 1;

nPages++;

memset(&pt, 0, sizeof(pt));                        //函数将 yaffs_ext_tags转为yaffs_packed_tags2,并生成校验信息,
        yaffs_pack_tags2(&pt,&t,0);                        //但最后一个函数是0,所以只转化保存校验信息
        memset(spareData, 0xff, sizeof(spareData));             
        shuffle_oob(spareData, &pt);

if (write(outFile,spareData,sizeof(spareData)) != sizeof(spareData))  //写oob
            fatal("write");

return 0;
    }

注:
struct yaffs_packed_tags2 {
    struct yaffs_packed_tags2_tags_only t;     //数据
    struct yaffs_ecc_other ecc;                       //校验信息
};
yaffs_packed_tags2是由数据和校难信息两部分组成的,但是这儿只用了数据不进行校验,所以内核里面也只是读出数据不校验
2.2 扩充yaffs.bin到一个block

static void pad_image(void)
    {
        u8 data[chunkSize + spareSize];
        int padPages = (nPages % pagesPerBlock);

if (padPages)
        {
            memset(data, 0xff, sizeof(data));
            for (padPages = pagesPerBlock-padPages; padPages; padPages--)
            {
                if (write(outFile, data, sizeof(data)) != sizeof(data))
                    fatal("write");
            }
        }
    }

d 三. 实验一下
3.1 实验
a.新建目录fs_test,在fs_test新建一文件222.txt, 内空是"bbbcc"

[email protected]:/tmp/mkyaffs/utils/test$ tree
    .
    └── fs_test
        └── 222.txt

1 directory, 1 file
    [email protected]:/tmp/mkyaffs/utils/test$ cat fs_test/222.txt
    bbbccc

b. 利用mkyaffs2image生成yaffs的打包文件fs.yaffs

[email protected]:/tmp/mkyaffs/utils/test$ ../mkyaffs2image fs_test/ fs.yaffs
        main[432]: mkyaffs2image: image building tool for YAFFS2 built Jul 3 2013
        main[464]: Processing directory fs_test/ into image file fs.yaffs
        Object 257, fs_test//222.txt is a
        file,
        1 data chunks written
        pad_image[255]: nPages=2
        main[480]: Operation complete.
        2 objects in 1 directories
        2 NAND pages
    [email protected]:/tmp/mkyaffs/utils/test$ ll
    total 540
    drwxrwxr-x 3 sun sun 4096 Jul 3 16:36 ./
    drwxrwxr-x 5 sun sun 4096 Jul 3 15:36 ../
    drwxrwxr-x 2 sun sun 4096 Jul 3 15:06 fs_test/
    -rw------- 1 sun sun 540672 Jul 3 16:36 fs.yaffs

可以看出fs.yaffs的大小是540672=128×(4096+128)
c. 分析一下fs.yaffs
按page的记录内容,可以分为两种,一个是oh_page另一个是data_page
其中普通文件,需要一个oh_page,如果有内容还需要一个或多个data_page
其它的文件,则只需要一个oh_page就够了.
   oh_page:

data_page:

sizeof(yaffs_obj_hdr)=0x200=512B
28B的信息就是结构体 yaffs_packed_tags2

struct yaffs_packed_tags2_tags_only {
        unsigned seq_number;
        unsigned obj_id;
        unsigned chunk_id;
        unsigned n_bytes;
    };
    struct yaffs_ecc_other {
        unsigned char col_parity;
        unsigned line_parity;
        unsigned line_parity_prime;
    };
    struct yaffs_packed_tags2 {
        struct yaffs_packed_tags2_tags_only t;
        struct yaffs_ecc_other ecc;
    };

3.2 oh_page与data_page的根本区别
int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes);
write_chunk(bytes,id,0,0xffff);                         //写oh_page    chunk_id=0,写入oob
write_chunk(bytes,newObj,chunk,n_bytes);     //写data_page  chunk_id!=0,写入oob

其中 write_chunk的第2个参数id, oh_page与data_page相等的话说明这是同一个文件的头与数据区
其中 write_chunk的第3个参数chunk_id, 区分oh_page与data_page,  oh_page的chunk_id=0

时间: 2024-08-24 04:35:27

mkyaffs2image编译的相关文章

yaffs2文件系统

yaffs2文件系统是针对nandflash的文件系统.其制作工具为mkyaffs2image.1. mkyaffs2image编译完成后,复制到/usr/bin下即可. 验证是否成功可直接在终端下输入:mkyaffs2image输出:mkyaffs2image: image building tool for YAFFS2 built Jul  9 2009usage: mkyaffs2image dir image_file [convert]           dir        th

Android编译篇

Android的编译系统涉及面极广,包含编译工具.印像文件编译.SDK编译.NDK编译.目标系统配置等多个方面.尽管这些方面的内容烦琐而晦涩,能够參考的资料不多,可是系统设计尤其是系统架构人员必须熟悉它们. 1.源码编译 基于源码的方式进行开发,一般会依据目标环境的不同,对系统配置进行调整,如採用不同的引导器.特定的驱动.不同的文件系统.特定的属性配置等,这就要求开发人员必须熟练掌握源码的编译方法和配置. (1)映像文件 在编译完源码后.须要将生成的文件等打包成对应的文件系统.然后烧写到移动终端

【转】高通平台android 环境配置编译及开发经验总结

原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流程分析 qcril 流程分析,设置sim卡锁 python scons 语法学习 Python 语言之 scons 工具流程分析: 1.2 搭建高通平台环境开发环境 高通and

ubuntu12.04下安卓编译环境搭建总结

前言: 因为工作需要,经常要编译安卓下的动态库,公司有已经搭建好环境的服务器,但是第一自己想自己搭建一下了解一个整个过程,另外,公司的服务器也经常出现问 题,导致编译不了,所以就想自己搭建环境.开始是在公司自己的电脑上装了一个unbuntu的虚拟机,然后在网上找了一个攻略,开始搭建环境.但是一直卡 在源码下载那一块,每次源码下载都出错,如后面问题1所描述.断断续续,都是工作之余抽空弄一弄,但是始终下载不成功,我以为是公司网络的问题,网络不稳 定,所以下载老失败.本来想多试几次,想想总有一次会下载

Ubuntu12.04编译Android4.0.1源码全过程-----附wubi安装ubuntu编译android源码硬盘空间不够的问题解决

本文转至  http://blog.csdn.net/yanzi1225627/article/details/9263097 昨晚在编译源码,make一段时间之后报错如下: [html] view plaincopyprint? # A fatal error has been detected by the Java Runtime Environment: # #  SIGSEGV (0xb) at pc=0x40362d33, pid=12195, tid=2835454784 # # 

hi3531 SDK已编译文件系统制作jffs2文件系统镜像并解决问题 .

一, 安装SDK 1.Hi3531 SDK包位置 在"Hi3531_V100R001***/01.software/board"目录下,您可以看到一个 Hi3531_SDK_Vx.x.x.x.tgz 的文件, 该文件就是Hi3531的软件开发包. 2.解压缩SDK包 在linux服务器上(或者一台装有linux的PC上,主流的linux发行版本均可以),使用命令:tar -zxf Hi3531_SDK_Vx.x.x.x.tgz , 解压缩该文件,可以得到一个Hi3531_SDK_Vx.

旧文-编译make2yaffsimage-2010年01月11日 19:19

最近弄yaffs,但是CVS上下的无法编译make2yaffsimage,提示yaffs_PackTags2()函数传入的参数不对,看源代码发现,传入的参数少一个,google了一下,解决了问题,详见以下patch: diff --git a/utils/mkyaffs2image.c b/utils/mkyaffs2image.c index 9939658..5b6c0c6 100644 --- a/utils/mkyaffs2image.c +++ b/utils/mkyaffs2imag

Ubuntu12.04 制作Smart210的编译环境

去年一月份做的笔记,一直没有发表,现在在找工作,才发觉自己的工作习惯不太好,笔记的话最好还是能够发出来,大家一起阅读,交流这样才能提升的快些,在这里很是感谢那些在CSDN,51CTO,和cnblog里分享自己成果的大牛们.学习的很多东西都是在这些大牛的启发下学习,并掌握的.我也会陆陆续续地把自己工作中用到的知识点分门别类地整理出来,给后来者提供一些方便.关键点都已标出,若还有不解之处,欢迎留言,大家讨论. 1)将光盘 Linux 目录中的 arm-linux-gcc-4.5.1-v6-vfp-2

Android源代码的下载和编译

Android源码包括应用程序源码.SDK工具集以及NDK工具集等等,如何下载?请看: 配置Android源代码下载环境: 创建一个用于存放下载脚本文件(repo)的目录 # mkdir ~/bin # PATH=~/bin:$PATH 下载rope脚本文件 # curl https://dl-ssl.google.com/dl/googlesource/git-repo > ~/bin/repo # chmod a+x ~/bin/repo 创建用于存放Android源代码的目录 # mkdi