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"

sun@ubuntu:/tmp/mkyaffs/utils/test$ tree
    .
    └── fs_test
        └── 222.txt

1 directory, 1 file
    sun@ubuntu:/tmp/mkyaffs/utils/test$ cat fs_test/222.txt
    bbbccc

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

sun@ubuntu:/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
    sun@ubuntu:/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

mkyaffs2image编译的更多相关文章

  1. jffs2和yaffs2文件系统制作工具的编译与使用

    一 . 先准备文件 mtd-utils-1.4.5.tar.bz2 ftp://ftp.infradead.org/pub/mtd-utils/ zlib-1.2.5.tar.bz2 http://z ...

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

    前言:      因为工作需要,经常要编译安卓下的动态库,公司有已经搭建好环境的服务器,但是第一自己想自己搭建一下了解一个整个过程,另外,公司的服务器也经常出现问 题,导致编译不了,所以就想自己搭建环 ...

  3. 【转】Android 4.3源码的下载和编译环境的安装及编译

    原文网址:http://jingyan.baidu.com/article/c85b7a641200e0003bac95a3.html  告诉windows用户一个不好的消息,windows环境下没法 ...

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

    原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

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

    昨晚在编译源码,make一段时间之后报错如下: # A fatal error has been detected by the Java Runtime Environment: # # SIGSE ...

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

    一, 安装SDK 1.Hi3531 SDK包位置 在"Hi3531_V100R001***/01.software/board"目录下,您可以看到一个 Hi3531_SDK_Vx. ...

  7. 01.ubuntu16.06编译安装Hi3518EV200 SDK

    转载,侵删 HI3518EV200 SDK安装并编译osdr. 1.开发环境 windows10电脑 + 虚拟机14 Pro + Ubuntu16.0.4 2.拷贝并解压.将 Hi3518E_SDK_ ...

  8. Android OTA在线升级二(升级包编译原理分析) 【转】

    本文转载自:http://blog.csdn.net/huryjiang/article/details/7590015 1 升级包的制作 基本命令: Ø  makeMtk [project[flav ...

  9. linux根文件系统制作之busybox编译和系统构建【转】

    转自:http://blog.chinaunix.net/uid-29401328-id-5019660.html 介绍完相关文件后我们开始构建文件系统,涉及到的文件等到具体用到的时候再讲. 一.编译 ...

随机推荐

  1. java测试Unicode编码以及数组的运用(初学篇)

    /*第二章第四小题*/ /* * (1)编写一个应用程序,给出汉字“你” ,“我”,“他”在Unicode 表中的位置 * (2)编写一个java应用程序,输出全部的希腊字母 */ public cl ...

  2. HDUOJ---2112HDU Today

    HDU Today Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  3. nyoj-----前缀式计算

    前缀式计算 时间限制:1000 ms  |           内存限制:65535 KB 难度:3   描述 先说明一下什么是中缀式: 如2+(3+4)*5这种我们最常见的式子就是中缀式. 而把中缀 ...

  4. 理解ROC和AUC

    分类器各种各样,如何评价这些分类器的性能呢?(这里只考虑二元分类器,分类器的输出为概率值) 方法一:概率定义法 从正样本中随机选取元素记为x,从负样本中随机选取元素记为y,x的置信度大于y的概率 计算 ...

  5. 【LeetCode】150. Evaluate Reverse Polish Notation

    Evaluate Reverse Polish Notation Evaluate the value of an arithmetic expression in Reverse Polish No ...

  6. Android开发学习之SQLite数据存取浅析

    一.SQLite的介绍 1.SQLite简介 SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入 式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低 ...

  7. 【jQuery】jquery-ui autocomplete智能提示

    jQuery UI,简而言之,它是一个基于jQuery的前端UI框架.我们可以使用jQuery + jQuery UI非常简单方便地制作出界面美观.功能强大.跨浏览器兼容的前端html界面. Auto ...

  8. Linux时间子系统(一) 基本概念

    本文使用Q & A的方式来和大家以前探讨一下时间的基本概念 一.什么是时间? 这个问题实在是太复杂了,我都不知道这是一个物理学.宇宙学.还是热力学异或是哲学问题,我只是想从几个侧面来了解一下时 ...

  9. spring 多线程

    http://blog.csdn.net/chszs/article/details/8219189 一.ThreadPoolTaskExecutor ThreadPoolTaskExecutor的配 ...

  10. 零基础学python》(第二版)

    ---恢复内容开始--- 零基础学python>(第二版) python学习手册 可以离线下载,  .chn格式, 插入小幽默笑话,在学习累的时候看看笑话 放松一下 欢迎下载转载,请注明出处,谢 ...