带你写一个Linux 下的打包软件 Tar

您所在的位置:网站首页 linux文件打包成tar包 带你写一个Linux 下的打包软件 Tar

带你写一个Linux 下的打包软件 Tar

#带你写一个Linux 下的打包软件 Tar| 来源: 网络整理| 查看: 265

相信你对 linux 的 .tar.gz 有点熟悉,这就是先 tar 打包(.tar 后缀),再对此 tar 文件用 gzip 压缩(.tar.gz)的后缀名。

值得注意的是, tar 不是压缩软件,它只做把一堆文件/文件夹打包到一个文件(tar 文件)里的事情,而文件联系,文件权限,相对的路径等都会给你保存好。

一开始设计是 tar 跟 gzip 只做一件事情,各司其事,后来发现太麻烦了,于是就把压缩功能整合到 tar 里了。

- Create a gzipped archive:     tar czf target.tar.gz file1 file2 file3 

最近学习 OS 时写了一个类似 tar 的项目,那么今天就趁热打铁简单说一下如何写一个打包软件,这个软件会将重复的文件内容通过 md5 比较,复用旧的内容。

基本单位 block

block 可以理解为文件系统的最小单位,分别有以下类型:

directory block,文件夹 block,存储文件夹 meta 信息; file block,文件 block,存储文件 meta 信息; data block,只用来存文件内容;

Directory block,注意的是 entry 里要有 fileindex 来存储重复文件的 name 的下标。

同时,给 项目一个 root dir。

typedef struct {     char        name[SIFS_MAX_NAME_LENGTH]; // name of the directory     time_t        modtime;    // time last modified blocksize , header->nblocks); } 

bitmap,每次操作 tar 文件都要读的。

void read_bitmap(FILE *vol, SIFS_BIT *bitmap, int nblocks) {     int size = nblocks * sizeof(SIFS_BIT);     fread(bitmap, size, 1, vol); } 

root_block 同理,读和写啥东西都要从 root block、root dir 出发。

void read_root_block(FILE *vol, SIFS_DIRBLOCK *dirblock){     fread(dirblock, sizeof(SIFS_DIRBLOCK), 1, vol);     printf("read_root_block finish, dirblock.name: %s, dirblock.entrieds: %d, dirblock.modtime %ld\n", dirblock->name, dirblock->nentries,dirblock->modtime); } 

路径嘛,你懂的,./sifs_put volumn ~/res.txt /dirB/subdirB/subsubdir/newfileB,要读的内容可以靠 read 函数解决,但是写到 tar 文件里的就要手动解析递归查路径了。

void read_route_names(char* pathname, char** route_names, int *route_cnt) {     char *dir;     char *pathname_to_split = copyStr(pathname);     strcpy(pathname_to_split, pathname);     while ((dir = strsep(&pathname_to_split, "/")) != NULL) {         route_names[*route_cnt] = copyStr(dir);         (*route_cnt)++;     } } 

以上几乎是 mkdir,rmdir,writefile,readfile,putfile 等等操作都要做的。

实现

然后,应该举一个 readfile 的例子就可以做代表了。

int recursive_dirinfo(SIFS_DIRBLOCK *cur_dir_block, char **route_names, int route_name_p, int route_cnt); 

实现:

int recursive_dirinfo(SIFS_DIRBLOCK *cur_dir_block, char **route_names, int route_name_p, int route_cnt) {     for(int i=0; inentries ; i++) {         int blockid = cur_dir_block->entries[i].blockID;         if(bitmap[blockid]==SIFS_DIR) {             SIFS_DIRBLOCK dirblock;             int start = sizeof(SIFS_VOLUME_HEADER) + header.nblocks*sizeof(SIFS_BIT);             read_dir_block(vol, &dirblock, blockid * blocksize, start);             if(strcmp(dirblock.name, route_names[route_name_p]) == 0) {                 if(route_name_p+2 == route_cnt) {                     return do_read_file(cur_dir_block, route_names[route_name_p+1], blockid);                 }                 return recursive_dirinfo(&dirblock, route_names, route_name_p+1, route_cnt);             }         }     }     return 1; } 

以``./sifs_put volumn ~/res.txt /dirB/subdirB/subsubdir/newfileB 为例子,如果递归找到 subsubdir`这个文件夹 block,进行相应操作:

写文件就往 bitmap 一直找没有用过的 block,够写文件就写进去,文件夹更新一下信息。 读文件就是根据此文件夹 block,找里面的 newfileB int do_read_file(SIFS_DIRBLOCK *parent_dir, char *filename,  int parent_dir_block) {     printf("do_find_file_info, filename %s\n", filename);     for(int i=1; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3