相信你對(duì) linux 的 .tar.gz 有點(diǎn)熟悉,這就是先 tar 打包(.tar 后綴),再對(duì)此 tar 文件用 gzip 壓縮(.tar.gz)的后綴名。
值得注意的是, tar 不是壓縮軟件,它只做把一堆文件/文件夾打包到一個(gè)文件(tar 文件)里的事情,而文件聯(lián)系,文件權(quán)限,相對(duì)的路徑等都會(huì)給你保存好。一開(kāi)始設(shè)計(jì)是 tar 跟 gzip 只做一件事情,各司其事,后來(lái)發(fā)現(xiàn)太麻煩了,于是就把壓縮功能整合到 tar 里了。
- Create a gzipped archive:
tar czf target.tar.gz file1 file2 file3
最近學(xué)習(xí) OS 時(shí)寫(xiě)了一個(gè)類(lèi)似 tar 的項(xiàng)目,那么今天就趁熱打鐵簡(jiǎn)單說(shuō)一下如何寫(xiě)一個(gè)打包軟件,這個(gè)軟件會(huì)將重復(fù)的文件內(nèi)容通過(guò) md5 比較,復(fù)用舊的內(nèi)容。
基本單位 block
block 可以理解為文件系統(tǒng)的最小單位,分別有以下類(lèi)型:
?directory block,文件夾 block,存儲(chǔ)文件夾 meta 信息;
?file block,文件 block,存儲(chǔ)文件 meta 信息;
?data block,只用來(lái)存文件內(nèi)容;
Directory block,注意的是 entry 里要有 fileindex 來(lái)存儲(chǔ)重復(fù)文件的 name 的下標(biāo)。同時(shí),給 項(xiàng)目一個(gè) root dir。
typedef struct {
char name[SIFS_MAX_NAME_LENGTH]; // name of the directory
time_t modtime; // time last modified 《- time()
uint32_t nentries;// 文件夾內(nèi)的文件/文件夾數(shù)量
struct {
SIFS_BLOCKID blockID; // subdirectory 或者 file 的 blockID
uint32_t fileindex; // 重復(fù)文件的不同名字
} entries[SIFS_MAX_ENTRIES];
} SIFS_DIRBLOCK;
文件 Block,length 就是有多少 bytes 的文件內(nèi)容,之后用來(lái)算有多少個(gè) data block,firstblockID 記錄第一個(gè)數(shù)據(jù) block 的 id,nfiles 記錄有多少重復(fù)內(nèi)容的文件數(shù)量了,filenames 就是重復(fù)此文件 block 的文件內(nèi)容的文件名字。
typedef struct {
time_t modtime; // time first file added 《- time()
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數(shù)組,記錄了每個(gè) block 的類(lèi)型,有:文件、文件夾以及data block 三種類(lèi)型。
通用函數(shù)
就讓大家看看關(guān)鍵函數(shù)好了:
讀 tar 后的文件的 meta 頭,記錄了 block 的大?。?blocksize) 以及多少個(gè) 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
”, 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 同理,讀和寫(xiě)啥東西都要從 root block、root dir 出發(fā)。
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
”, dirblock-》name, dirblock-》nentries,dirblock-》modtime);
}
路徑嘛,你懂的,。/sifs_put volumn ~/res.txt /dirB/subdirB/subsubdir/newfileB,要讀的內(nèi)容可以靠 read 函數(shù)解決,但是寫(xiě)到 tar 文件里的就要手動(dòng)解析遞歸查路徑了。
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 等等操作都要做的。
實(shí)現(xiàn)
然后,應(yīng)該舉一個(gè) readfile 的例子就可以做代表了。
int recursive_dirinfo(SIFS_DIRBLOCK *cur_dir_block, char **route_names, int route_name_p, int route_cnt);
實(shí)現(xiàn):
int recursive_dirinfo(SIFS_DIRBLOCK *cur_dir_block, char **route_names, int route_name_p, int route_cnt) {
for(int i=0; i《cur_dir_block-》nentries ; 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`這個(gè)文件夾 block,進(jìn)行相應(yīng)操作:
?寫(xiě)文件就往 bitmap 一直找沒(méi)有用過(guò)的 block,夠?qū)懳募蛯?xiě)進(jìn)去,文件夾更新一下信息。
?讀文件就是根據(jù)此文件夾 block,找里面的 newfileB
int do_read_file(SIFS_DIRBLOCK *parent_dir, char *filename, int parent_dir_block) {
printf(“do_find_file_info, filename %s
”, filename);
for(int i=1; i《header.nblocks ; 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 《 need_data_blocks; d_block_id++) {
read_data_block(vol, (char*)(*data)+(d_block_id - i -1), blocksize, d_block_id * header.blocksize, start);
}
return 0;
}
}
}
return 1;
}
而真實(shí)的 tar 自然更復(fù)雜,還要記錄用戶(hù)權(quán)限、用戶(hù)、group文件等等:
struct posix_header
{ /* byte offset */
char name[100]; /* 0 */ 文件名
char mode[8]; /* 100 */ 用戶(hù)權(quán)限
char uid[8]; /* 108 */ user id
char gid[8]; /* 116 */ group id
char size[12]; /* 124 */ 文件大小
char mtime[12]; /* 136 */ 修改時(shí)間
char chksum[8]; /* 148 */ 校驗(yàn)值
char typeflag; /* 156 */ 文件類(lèi)型標(biāo)志
char linkname[100]; /* 157 */ 符號(hào)鏈接指向
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */ user name
char gname[32]; /* 297 */ group name
char devmajor[8]; /* 329 */ 設(shè)備文件 major
char devminor[8]; /* 337 */ 設(shè)備文件 minor
char prefix[155]; /* 345 */
/* 500 */
};
文件類(lèi)型標(biāo)志定義,包含了所有 Unix 系統(tǒng)中的文件類(lèi)型
#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 */
概覽如此,寫(xiě)起來(lái)其實(shí)有點(diǎn)煩 - = -,有興趣的讀者可以寫(xiě)寫(xiě)。
原文標(biāo)題:帶你寫(xiě)一個(gè) linux 下的打包軟件 tar
文章出處:【微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
責(zé)任編輯:haq
-
Linux
+關(guān)注
關(guān)注
88文章
11761瀏覽量
219071 -
軟件
+關(guān)注
關(guān)注
69文章
5332瀏覽量
91601
原文標(biāo)題:帶你寫(xiě)一個(gè) linux 下的打包軟件 tar
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
linux的壓縮和解壓操作
【飛凌OK-T153 開(kāi)發(fā)板試用】SDK初試
你覺(jué)得哪個(gè)軟件寫(xiě)verilog體驗(yàn)最好?有什么優(yōu)勢(shì)?
Linux搭建平臺(tái)
在linux中使用env時(shí)如何下載軟件包?
dist打包好的工程,還能用env工具進(jìn)行配置嗎?
聊聊 Webpack 那些安全事兒:打包風(fēng)險(xiǎn)與防護(hù)小技巧
FLASH燒寫(xiě)/編程白皮書(shū)
在linux環(huán)境下 軟件啟動(dòng)失敗怎么解決?
dist打包好的工程,還能用env工具進(jìn)行配置嗎?
打包機(jī)數(shù)據(jù)采集遠(yuǎn)程監(jiān)控系統(tǒng)方案
Linux文件系統(tǒng)打包及鏡像制作,觸覺(jué)智能RK3562開(kāi)發(fā)板演示
rootfs鏡像制作其實(shí)沒(méi)那么難
Linux下Vim編輯器的使用技巧
如何寫(xiě)Linux下的tar打包軟件?
評(píng)論