• 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"

        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

  • 相关阅读:
    Teamplate Workflow Architecture(Teamplate工作流架构)
    Las Vegas拉斯维加斯(赌城)游记
    初步尝试Teamplate Workflow Web Part for SharePoint Portal Server
    灵活管理Remote Objects生存期(lifetime)
    Wincv.exe类查看器工具(Class Viewer)
    重构(Refactoring)技巧读书笔记 之二
    重构(Refactoring)技巧读书笔记 之一
    尝试RemotingSqlHelper的若干问题
    关于ADO.Net连接池(Connection Pool)的一些个人见解
    SQL Server 最佳实践分析器使用小结
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/4823913.html
Copyright © 2020-2023  润新知