相信大家对Linux的.tar.gz已经不陌生了。这是先tar这个包(.tar后缀),然后用gzip压缩这个tar文件(.tar.gz)后缀名。值得注意的是,tar不是压缩软件,它只是将一堆文件/文件夹打包成一个文件(tar文件),文件关联、文件权限、相对路径等都会为您保存。一开始的设计是tar和gzip只做一件事,各司其职。后来他们觉得太麻烦了,就把压缩功能集成到tar里面了。-Createagzippedarchive:tarczftarget.tar.gzfile1file2file3最近在学习OS的时候写了一个类似tar的项目,所以今天简单说一下如何写一个打包软件。本软件会通过md5比较重复的文件内容,重用旧内容。.基本单位blockblock可以理解为文件系统的最小单位,有以下几种类型:目录块,文件夹块,存放文件夹元信息;文件块,文件块,存储文件元信息;数据块,只用来存放文件内容;目录块,注意entry中必须有一个fileindex,用来存放重复文件名的下标。另外,给项目一个根目录。typedefstruct{charname[SIFS_MAX_NAME_LENGTH];//nameofthedirectorytime_tmodtime;//timelastmodified<-time()uint32_tnentries;//文件夹内的文件/文件夹个数struct{SIFS_BLOCKIDblockID;//blockIDuint32_tfileindexofsubdirectoryorfile;//DifferentduplicatefilesName}entries[SIFS_MAX_ENTRIES];}SIFS_DIRBLOCK;FileBlock,length是文件内容有多少字节,然后用来统计有多少个数据块,firstblockID记录第一个数据块的id,nfiles记录有多少个内容重复的文件number,filenames是重复这个文件块的文件内容的文件名。typedefstruct{time_tmodtime;//timefirstfileadded<-time()size_tlength;//lengthofffiles'contentsinbytesunsignedcharmd5[MD5_BYTELEN];//theMD5cryptographicdigest(asumary)ofthefiles'contentsSIFS_BLOCKIDfirstblockID;//theblocknumber(blockID)ofthefiles'firstdata-blockuint32_tnfiles;//nfileswithidenticalENT_RFScharmd5[icalcontentsIES];][SIFS_MAX_NAME_LENGTH];//每个相同文件的名称及其修改时间的数组。}SIFS_FILEBLOCK;位图数组,记录每个块的类型,有文件、文件夹和数据块三种类型。通用功能,让大家看一下关键功能:读取tar后文件的元头记录了块的大小(blocksize)和多少块。voidread_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文件都要读取。voidread_bitmap(FILE*vol,SIFS_BIT*bitmap,intnblocks){intsize=nblocks*sizeof(SIFS_BIT);fread(bitmap,size,1,vol);}root_block同理,从根块开始读写,根目录离开。voidread_root_block(FILE*vol,SIFS_DIRBLOCK*dirblock){fread(dirblock,sizeof(SIFS_DIRBLOCK),1,vol);printf("read_root_blockfinish,dirblock.name:%s,dirblock.entrieds:%d,dirblock.modtime%ld\n",dirblock->name,dirblock->nentries,dirblock->modtime);}路径,你懂的,./sifs_putvolume~/res.txt/dirB/subdirB/subsubdir/newfileB,要读取的内容即可是靠读取函数解决的,但是写入tar文件必须手动解析递归搜索路径。voidread_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的例子作为代表。intrecursive_dirinfo(SIFS_DIRBLOCK*cur_dir_block,char**route_names,introute_name_p,introute_cnt);实现:intrecursive_dirinfo(SIFS_DIRBLOCK*cur_dir_block,char**route_names,introute_name_p,introute_cnt){for(inti=0;i
