韩国做 mp4下载网站,邵阳做网站公司,成都p2p网站建设,325建筑网站相信你对 linux 的 .tar.gz 有点熟悉#xff0c;这就是先 tar 打包(.tar 后缀)#xff0c;再对此 tar 文件用 gzip 压缩(.tar.gz)的后缀名。值得注意的是#xff0c; tar 不是压缩软件#xff0c;它只做把一堆文件/文件夹打包到一个文件(tar 文件)里的事情#xff0c;而文…相信你对 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 比较复用旧的内容。基本单位 blockblock 可以理解为文件系统的最小单位分别有以下类型•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 directorytime_t modtime; // time last modified uint32_t nentries;// 文件夹内的文件/文件夹数量struct {SIFS_BLOCKID blockID; // subdirectory 或者 file 的 blockIDuint32_t fileindex; // 重复文件的不同名字} entries[SIFS_MAX_ENTRIES];} SIFS_DIRBLOCK;文件 Blocklength 就是有多少 bytes 的文件内容之后用来算有多少个 data blockfirstblockID 记录第一个数据 block 的 idnfiles 记录有多少重复内容的文件数量了filenames 就是重复此文件 block 的文件内容的文件名字。typedef struct {time_t modtime; // time first file added size_t length; // length of files contents in bytesunsigned char md5[MD5_BYTELEN];//the MD5 cryptographic digest (a summary) of the files contentsSIFS_BLOCKID firstblockID;// the block number (blockID) of the files first data-blockuint32_t nfiles; // n files with identical contentschar filenames[SIFS_MAX_ENTRIES][SIFS_MAX_NAME_LENGTH];// an array of each same files 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);}}以上几乎是 mkdirrmdirwritefilereadfileputfile 等等操作都要做的。实现然后应该举一个 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 i0; 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_p2 route_cnt) {return do_read_file(cur_dir_block, route_names[route_name_p1], blockid);}return recursive_dirinfo(dirblock, route_names, route_name_p1, route_cnt);}}}return 1;}以./sifs_put volumn ~/res.txt /dirB/subdirB/subsubdir/newfileB 为例子如果递归找到 subsubdir这个文件夹 block进行相应操作•写文件就往 bitmap 一直找没有用过的 block够写文件就写进去文件夹更新一下信息。•读文件就是根据此文件夹 block找里面的 newfileBint do_read_file(SIFS_DIRBLOCK *parent_dir, char *filename, int parent_dir_block){printf(do_find_file_info, filename %s\n, filename);for(int i1; iSIFS_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 idchar gid[8]; /* 116 */ group idchar 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 namechar gname[32]; /* 297 */ group namechar devmajor[8]; /* 329 */ 设备文件 majorchar devminor[8]; /* 337 */ 设备文件 minorchar 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 */概览如此写起来其实有点烦 - -有兴趣的读者可以写写。