0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何寫Linux下的tar打包軟件?

Linux愛好者 ? 來源:YongHao寫東西的cache ? 作者:YongHao寫東西的ca ? 2021-03-10 10:44 ? 次閱讀

相信你對 linux 的 .tar.gz 有點(diǎn)熟悉,這就是先 tar 打包(.tar 后綴),再對此 tar 文件用 gzip 壓縮(.tar.gz)的后綴名。

值得注意的是, tar 不是壓縮軟件,它只做把一堆文件/文件夾打包到一個(gè)文件(tar 文件)里的事情,而文件聯(lián)系,文件權(quán)限,相對的路徑等都會給你保存好。一開始設(shè)計(jì)是 tar 跟 gzip 只做一件事情,各司其事,后來發(fā)現(xiàn)太麻煩了,于是就把壓縮功能整合到 tar 里了。

- Create a gzipped archive:

tar czf target.tar.gz file1 file2 file3

最近學(xué)習(xí) OS 時(shí)寫了一個(gè)類似 tar 的項(xiàng)目,那么今天就趁熱打鐵簡單說一下如何寫一個(gè)打包軟件,這個(gè)軟件會將重復(fù)的文件內(nèi)容通過 md5 比較,復(fù)用舊的內(nèi)容。

基本單位 block

block 可以理解為文件系統(tǒng)的最小單位,分別有以下類型:

?directory block,文件夾 block,存儲文件夾 meta 信息;

?file block,文件 block,存儲文件 meta 信息;

?data block,只用來存文件內(nèi)容;

Directory block,注意的是 entry 里要有 fileindex 來存儲重復(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)容,之后用來算有多少個(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 的類型,有:文件、文件夾以及data block 三種類型。

通用函數(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 同理,讀和寫啥東西都要從 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ù)解決,但是寫到 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 等等操作都要做的。

實(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)操作:

?寫文件就往 bitmap 一直找沒有用過的 block,夠?qū)懳募蛯戇M(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ù)雜,還要記錄用戶權(quán)限、用戶、group文件等等:

struct posix_header

{ /* byte offset */

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

char mode[8]; /* 100 */ 用戶權(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 */ 文件類型標(biāo)志

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 */ 設(shè)備文件 major

char devminor[8]; /* 337 */ 設(shè)備文件 minor

char prefix[155]; /* 345 */

/* 500 */

};

文件類型標(biāo)志定義,包含了所有 Unix 系統(tǒng)中的文件類型

#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 */

概覽如此,寫起來其實(shí)有點(diǎn)煩 - = -,有興趣的讀者可以寫寫。

原文標(biāo)題:帶你寫一個(gè) linux 下的打包軟件 tar

文章出處:【微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11213

    瀏覽量

    208736
  • 軟件
    +關(guān)注

    關(guān)注

    69

    文章

    4720

    瀏覽量

    87097

原文標(biāo)題:帶你寫一個(gè) linux 下的打包軟件 tar

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-libjpeg庫移植

    打包bin目錄下的所有測試工具。elf@ubuntu:~/work$ cd install/bin/elf@ubuntu:~/work/install/bin$ tar cvjf
    發(fā)表于 07-11 08:36

    飛凌嵌入式ElfBoard ELF 1板卡-libjpeg庫移植

    打包bin目錄下的所有測試工具。elf@ubuntu:~/work$ cd install/bin/elf@ubuntu:~/work/install/bin$ tar cvjf
    發(fā)表于 07-10 11:42

    ubuntu平臺下安裝ESP32-IDF時(shí),openocd-esp32-linux64-0.10.0-esp32-20190708.tar.gz下載不了的原因?

    下載openocd-esp32-linux64-0.10.0-esp32-20190708.tar.gz,卻始終下載失??? https://github.com/espressif/openocd-es ... 2-20190708
    發(fā)表于 06-25 06:17

    摩托羅拉P200軟件

    摩托羅拉P200軟件摩托羅拉P200軟件
    發(fā)表于 06-17 11:53 ?6次下載

    全志D1s軟件入門之Tina Linux教程

    Tina Linux,即將編譯打包好的固件下載到設(shè)備 燒方式簡介 全志平臺為開發(fā)者提供了多種多樣的燒
    發(fā)表于 06-05 13:41

    全志D1s軟件入門之Tina Linux編譯教程

    編譯 Tina Linux 在搭建好編譯環(huán)境并下載好源碼后,即可對源碼進(jìn)行編譯,編譯打包好后,即可將打包好的固件燒寫到設(shè)備中去。本文主要介紹編譯和燒的方法。 Tina
    發(fā)表于 06-05 09:50

    請教一F7系列里的OTP如何寫入?

    請教一F7系列里的OTP如何寫入?
    發(fā)表于 05-06 06:18

    嵌入式學(xué)習(xí)-飛凌ElfBoard ELF 1板卡 - 重新打包文件系統(tǒng)發(fā)現(xiàn)ftp無法正常連接

    使用 tar cvjf rootfs.tar.bz2 * 重新打包文件系統(tǒng)之后發(fā)現(xiàn)ftp無法正常連接了? 用戶根據(jù)自己需求對文件系統(tǒng)做出修改后,利用 tar 命令再壓縮文件系統(tǒng)。若使用
    發(fā)表于 04-07 09:58

    嵌入式學(xué)習(xí)-ElfBoard ELF 1板卡- otg燒增加分區(qū)的方法

    之前有介紹過sd卡燒增加分區(qū)的方法,現(xiàn)在小風(fēng)來介紹一,otg燒增加分區(qū)的方法。 現(xiàn)有emmc分區(qū):mmcblk1p1、mmcblk1p2 新增emmc分區(qū)mmcblk1p3 實(shí)現(xiàn)方法
    發(fā)表于 01-03 11:21

    嵌入式學(xué)習(xí)-ElfBoard ELF 1板卡-移植openssl

    openssl是一個(gè)開放源代碼的軟件庫包,應(yīng)用程序可以使用這個(gè)包來進(jìn)行安全通信,避免竊聽,同時(shí)確認(rèn)另一端連線者的身份。這個(gè)包被廣泛應(yīng)用于互聯(lián)網(wǎng)的網(wǎng)頁服務(wù)器上。下面這篇文章就給各位小伙伴介紹一如何在
    發(fā)表于 12-28 08:53

    教你在Ubuntu系統(tǒng)上定制文件系統(tǒng)

    apt-get、ldd等常用的命令,若需要安裝軟件則直接apt-get在線安裝即可,不需進(jìn)行交叉編譯移植等繁瑣操作。但是每次重新燒鏡像之后,之前安裝的軟件就得重新安裝,比較繁瑣,如果需要批量操作則每塊
    發(fā)表于 12-26 16:33

    【飛凌OK113i-S開發(fā)板試用】軟件開發(fā)環(huán)境搭建

    改為完全可讀寫 然后: linux執(zhí)行cp /mnt/hgfs/share/OK113i-linux-sdk.tar.bz2.* /home/forlinx/work/ 然后執(zhí)行cat
    發(fā)表于 12-25 12:06

    DshanMCU-R128s2 燒固件

    編譯系統(tǒng)源碼后,打包后生成的系統(tǒng)文件稱之為固件。固件一般為.img格式。把固件下載到開發(fā)板或者產(chǎn)品上的過程稱之為 燒固件 。
    的頭像 發(fā)表于 12-22 15:08 ?1071次閱讀
    DshanMCU-R128s2 燒<b class='flag-5'>寫</b>固件

    gdb本地調(diào)試版本移植至ARM-Linux系統(tǒng)

    /ncurses-5.9.tar.gz1.將ncurses壓縮包拷貝至Linux主機(jī)或使用wget命令下載并解壓tar-zxvfncurses-5.9.tar.gz2.解壓后進(jìn)入到ncurses-5.9
    的頭像 發(fā)表于 12-12 14:42 ?571次閱讀
    gdb本地調(diào)試版本移植至ARM-<b class='flag-5'>Linux</b>系統(tǒng)

    如何寫出高效優(yōu)美的C語言代碼

    電子發(fā)燒友網(wǎng)站提供《如何寫出高效優(yōu)美的C語言代碼.pdf》資料免費(fèi)下載
    發(fā)表于 11-18 10:55 ?0次下載
    <b class='flag-5'>如何寫</b>出高效優(yōu)美的C語言代碼