Linux打包软件版本带时间,带你写一个 linux 下的打包软件 tar

相信你对 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 

uint32_t        nentries;// 文件夹内的文件/文件夹数量

struct {

SIFS_BLOCKID    blockID;    // subdirectory 或者 file 的 blockID

uint32_t    fileindex;    // 重复文件的不同名字

} entries[SIFS_MAX_ENTRIES];

} SIFS_DIRBLOCK;

文件 Block,length 就是有多少 bytes 的文件内容,之后用来算有多少个 data block,firstblockID 记录第一个数据 block 的 id,nfiles 记录有多少重复内容的文件数量了,filenames 就是重复此文件 block 的文件内容的文件名字。

typedef struct {

time_t        modtime;    // time first file added 

size_t        length;        // length of files' contents in bytes

unsigned char    md5[MD5_BYTELEN];//the MD5 cryptographic digest (a summary) of the files' contents

SIFS_BLOCKID    firstblockID;// the block number (blockID) of the files' first data-block

uint32_t        nfiles;        // n files with identical contents

char        filenames[SIFS_MAX_ENTRIES][SIFS_MAX_NAME_LENGTH];// an array of each same file's name and its modification time.

} SIFS_FILEBLOCK;

bitmaps数组,记录了每个 block 的类型,有:文件、文件夹以及data block 三种类型。

通用函数

就让大家看看关键函数好了:

读 tar 后的文件的 meta 头,记录了 block 的大小( blocksize) 以及多少个 blocks。

void read_vol_header(FILE *vol, SIFS_VOLUME_HEADER *header){

fread(header, sizeof(SIFS_VOLUME_HEADER), 1, vol);

printf("header->blocksize %zu, header->nblocks %u\n", header->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

SIFS_FILEBLOCK fileblock;

if(bitmap[i]==SIFS_FILE) {

int start = sizeof(SIFS_VOLUME_HEADER) + header.nblocks*sizeof(SIFS_BIT);

read_file_block(vol, &fileblock, i * blocksize, start);

*nbytes = fileblock.length;

int need_data_blocks = *nbytes / header.blocksize;

if(strcmp(fileblock.filenames[0],  filename) == 0) {

for(int d_block_id = fileblock.firstblockID; d_block_id - i -1 

read_data_block(vol, (char*)(*data)+(d_block_id - i -1), blocksize, d_block_id * header.blocksize, start);

}

return 0;

}

}

}

return 1;

}

而真实的 tar 自然更复杂,还要记录用户权限、用户、group文件等等:

struct posix_header

{                       /* byte offset */

char name[100];       /*   0 */   文件名

char mode[8];         /* 100 */   用户权限

char uid[8];          /* 108 */   user id

char gid[8];          /* 116 */   group id

char size[12];        /* 124 */   文件大小

char mtime[12];       /* 136 */   修改时间

char chksum[8];       /* 148 */   校验值

char typeflag;        /* 156 */   文件类型标志

char linkname[100];   /* 157 */   符号链接指向

char magic[6];        /* 257 */

char version[2];      /* 263 */

char uname[32];       /* 265 */   user name

char gname[32];       /* 297 */   group name

char devmajor[8];     /* 329 */   设备文件 major

char devminor[8];     /* 337 */   设备文件 minor

char prefix[155];     /* 345 */

/* 500 */

};

文件类型标志定义,包含了所有 Unix 系统中的文件类型

#define REGTYPE  '0'            /* regular file */

#define LNKTYPE  '1'            /* link */

#define SYMTYPE  '2'            /* reserved */

#define CHRTYPE  '3'            /* character special */

#define BLKTYPE  '4'            /* block special */

#define DIRTYPE  '5'            /* directory */

#define FIFOTYPE '6'            /* FIFO special */

#define CONTTYPE '7'            /* reserved */

概览如此,写起来其实有点烦 - = -,有兴趣的读者可以写写。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/533813.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优先队列默认是小顶堆吗_一分钟带你读懂什么是堆?

堆其实就是一种特殊的队列——优先队列。 普通的队列游戏规则很简单:就是先进先出;但这种优先队列搞特殊,不是按照进队列的时间顺序,而是按照每个元素的优先级来比拼,优先级高的在堆顶。 这也很容易理解吧,…

螺旋测微器b类不确定度_物理实验直测量不确定度评估.ppt

物理实验直测量不确定度评估直接测量不确定度评估 Gauss分布 测量列的平均值、标准差 A类不确定度 t分布 B类不确定度 直接测量的合成不确定度 Gauss分布 也称正态分布。 δ的平均值等于0、方差为σ。 特征: 对称性——大于平均值与小于平均值的概率相等&#xff1b…

python 执行shell_python执行shell命令的方法

python执行shell命令的方法 os模块 os.system方式: import os os.system(top) os.system(cat /proc/cpuinfo) 说明 这个调用相当直接,且是同步进行的,程序需要阻塞并等待返回。 返回值是依赖于系统的,直接返回系统的调用返回值&am…

linux下c语言读取roed文件,如何在Linux系统上安装Android4.4.docx

Android (x86)项目致力于移植 Android系统到X86处理器上,使用户可以更容易的在任何电脑上安装Android。他们通过使用android源码,增加补丁来使 Android能够在X86处理器,笔记本电脑和平板 电脑下工作。前一段时间,项目组发布了最新…

微信小程序setinterval_简单谈谈setTimeout与setInterval

感谢踩过的坑sf社区的第一篇文章。最近在做一个拍卖的微信小程序,用到了定时器setTimout和setInterval,简单谈谈这两个api。setTimeout最常见的用法就是第二种(第三种mdn文档不推荐),如:var timeoutId setTimeout(function() {console.log(hello world!…

python 注释一段话_Python快速入门(一)

引言Python作为一个,目前最火的编程语言之一,已经渗透到了各行各业。它易学好懂,拥有着丰富的库,功能齐全。人生苦短,就用Python。这个快速入门系列分为六篇,包含了Python大部分基础知识,每篇阅…

linux ibus获取窗体位置,Ubuntu 12.04 显示ibus 的输入框

在虚拟机中安装了Ubuntu 12.04,系统是英文版本的,我能接受,但是苦于没有中文输入法。起先,我是安装SCIM,结果我折腾了半天,发现其只能在lib-office下使用。firefox,文字编辑器中都不能调出SCIM。无奈将其卸…

transporter上传卡正在交付_【iOS】Xcode11使用Transporter将APP上传到App Store,卡在正在验证APP...

问题:在使用Transporter时,会卡主,一直显示正在验证APP在这里插入图片描述解决方案一:利用V-P-N在这里插入图片描述使用安全上网(V-P-N),双击打开iTMSTransporter,等待几分钟lichuangMacBook-Pro-3 ~ % /Ap…

python练手经典100例微盘_20个Python练手经典案例,能全做对的人确实很少!

100个Python练手小程序,学习python的很好的资料,覆盖了python中的每一部分,可以边学习边练习,更容易掌握python。 如果你感觉学不会?莫慌,小编推荐大家加入群, 前面548中间377后面875&#xff0…

小红帽linux各功能中英,英文短剧《小红帽》剧本台词完整版---中英对照文本版...

大灰狼和小红帽的故事红帽第一场:小红帽家 妈妈: (妈妈拿着一个篮子,把桌子上的水果放在篮子里) 小红帽唱着歌,欢快地跑进来)Hi,mummy, what are you doing? 嘿,妈妈 你在什么? 妈妈: (一边把水…

uipath循环datatable_UiPath之DataTable转换为List和Array

今天给大家分享一下,如何将DataTable转为List和Array,为此小U也花了不少时间研究,最后发现没有那么复杂。先来说说List和Array的区别:List:就像一个链条,存储数据的空间可以不连续。Array:就像一…

python批量下载文件教程_Python抓包菜鸟教程:批量下载图片的方法,电脑和手机都能用...

笔者看上了一组图集,然后准备一张一张下载时,瞄了一眼,这组图集还有100,好吧,我酸了。 笔者就是试试工具,你们别像我这样用,这么好的工具,做自媒体,那绝对了那如何批量下…

esxi挂载Linux的nfs盘,ESXi安装centos7挂载群晖NFS

前段时间折腾了ESXi,然后无尽的折腾接踵而来,今天要说的是如何安装centos7并挂载群晖虚拟机的NFS共享文件夹直接步入正题!先是下载centos7镜像,因为我是用来当服务器的,所以只需要minimal版即可【centos下载链接】自己…

python使用的编辑器_我用过的最好的python编辑器PyScripter

用了IDLE, PythonWin等几个python编辑器,在代码补全、参数提示等功能上都非常不满意。 终于找到PyScripter并且试用了一下,代码补全、参数提示等功能非常强大。这个功能其实非常重要,可以大大提高开发效率,减少出错。很满意.PyScr…

linux is not unix由来,一些奇怪的 unix 指令名字的由来(转)

一些奇怪的 unix 指令名字的由来(转)[more]一些奇怪的 unix 指令名字的由来awk "Aho Weinberger and Kernighan"这个语言以作者 Al Aho, Peter Weinberger 和 Brian Kernighan 的姓来命名。grep "Global Regular Expression Print"grep 来自 ed 的列印所…

python discuz_pythonDiscuz发帖器的实现

网络技术需要大家共同分享,不能闭门造车,下面是bj-dnsCom提示:首先要清楚discuz论坛发帖的流程,简单地说就是以下流程:进入登录页 ->登录 -> 进入版面 ->发帖 首先要清楚discuz论坛发帖的流程,简单地说就是以…

基于linux的业设计课题,基于linux下智能手机的设计与制作 毕业设计.doc

本科生毕业论文(设计)题 目: 基于linux下智能手机的设计与制作目录1. 绪论11.1 嵌入式系统的应用前景11.2linux操作系统21.2.1Linux介绍22.硬件、软件介绍32.1S3c2440知识32.1.1S3c2440系统结构介绍32.1.2arm实验仪介绍72.2 GPRS无线模组92.2.1 GPRS概述及工作原理9…

excel文件导入hive乱码_将excel中的数据导入hive

步骤一:将excel另存为txt文档(文本文件(制表符分割))假设名字为CompanyCode.txt步骤二,将该txt文件导入Linux指定目录中步骤三,转换编码格式,在指定目录下执行如下命令:piconv -f gb2312 -t UTF-8 CompanyCode.txt &g…

传统的6d位姿估计fangfa1_李飞飞团队最新论文:基于anchor关键点的类别级物体6D位姿跟踪...

点击上方“3D视觉工坊”,选择“星标”干货第一时间送达简介作者提出了一种基于RGB-D的深度学习方法6PACK,能够实时的跟踪已知类别物体。通过学习用少量的3D关键点来简洁地表示一个物体,基于这些关键点,通过关键点匹配来估计物体在…

c语言的程序结构语序,第3章 C语序结构.doc

第3章 C语序结构第三章 基本语句本章要求:1.表达式语句,空语句,复合语句2.数据的输入与输出,输入,输出函数的调用C语句概述C程序的执行部分是由语句组成的。 程序的功能也是由执行语句实现的。3.1 赋值语句赋值语句: 是由赋值表达式再加上分号构成的表达…