當(dāng)前位置:
首頁 >
xz压缩文件的解压缩过程
發(fā)布時(shí)間:2023/12/20
43
豆豆
生活随笔
收集整理的這篇文章主要介紹了
xz压缩文件的解压缩过程
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
[摘要]
[正文] 讀文件回顧
[正文] xz解壓縮過程
注意:請(qǐng)使用谷歌瀏覽器閱讀(IE瀏覽器排版混亂)
【摘要】
本文可以作為另一篇博文:?squashfs文件的讀取過程?的后續(xù)。根據(jù)squashfs文件的讀取過程?一文介紹,當(dāng)從flash上獲取了文件數(shù)據(jù)后,如果數(shù)據(jù)是壓縮的還要經(jīng)過解壓縮,本文就為您介紹一下xz壓縮文件的解壓縮過程。
【正文】讀文件回顧
1 首先回顧一下?squashfs文件的讀取過程一文中介紹的讀文件數(shù)據(jù)過程:
int squashfs_read_data(struct super_block *sb, u64 index, int length,u64 *next_index, struct squashfs_page_actor *output) { /* 上面squashfs_fill_super中賦值 */ struct squashfs_sb_info *msblk = sb->s_fs_info; struct buffer_head **bh; /* index是要操作的flash 分區(qū)內(nèi)偏移地址,devlbksize=1024byte*/ int offset = index & ((1 << msblk->devblksize_log2) - 1); /* flash分區(qū)內(nèi)偏移地址msblk->devblksize_log2=10;cur_index表示flash分區(qū)內(nèi)偏移地址對(duì)應(yīng)的邏輯塊; */ u64 cur_index = index >> msblk->devblksize_log2; int bytes, compressed, b = 0, k = 0, avail, i;bh = kcalloc(((output->length + msblk->devblksize - 1)>> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL); if (bh == NULL) return -ENOMEM;if (length) { /* * Datablock.讀取數(shù)據(jù)塊內(nèi)容. */ bytes = -offset; compressed = SQUASHFS_COMPRESSED_BLOCK(length); length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length); if (next_index) *next_index = index + length; /*output->length=512k mksquashfs時(shí)指定的塊大小*/ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index, compressed ? "" : "un", length, output->length);if (length < 0 || length > output->length || (index + length) > msblk->bytes_used) goto read_failure; /* 循環(huán)讀取邏輯塊;每次讀取devblksize=1024大小;最先讀取的邏輯塊是flash分區(qū)內(nèi)偏移地址所在的邏輯塊. */ for (b = 0; bytes < length; b++, cur_index++) { /*獲取buffer_head*/ bh[b] = sb_getblk(sb, cur_index); if (bh[b] == NULL) goto block_release; /*devblksize=1024*/ bytes += msblk->devblksize; } /* 1 提交一個(gè)讀請(qǐng)求 ll_rw_block->submit_bh->submit_bio->do_blktrans_request(); 2 處理讀請(qǐng)求,真正實(shí)現(xiàn)驅(qū)動(dòng)中的讀操作 : mtd_blktrans_work->do_blktrans_request->mtdblock_tr->mtdblock_readsect->do_cached_read->(mtd_read->mtd->_read=part_read) ->nand_read()->nand_do_read_ops()->(chip->cmdfunc) */ ll_rw_block(READ, b, bh); } else { /* * Metadata block.讀取邏輯塊內(nèi)容; */ if ((index + 2) > msblk->bytes_used) goto read_failure;bh[0] = get_block_length(sb, &cur_index, &offset, &length); if (bh[0] == NULL) goto read_failure; b = 1;bytes = msblk->devblksize - offset; compressed = SQUASHFS_COMPRESSED(length); length = SQUASHFS_COMPRESSED_SIZE(length); if (next_index) *next_index = index + length + 2;TRACE("Block @ 0x%llx, %scompressed size %d\n", index,compressed ? "" : "un", length);if (length < 0 || length > output->length || (index + length) > msblk->bytes_used) goto block_release;for (; bytes < length; b++) { bh[b] = sb_getblk(sb, ++cur_index); if (bh[b] == NULL) goto block_release; bytes += msblk->devblksize; } ll_rw_block(READ, b - 1, bh + 1); }for (i = 0; i < b; i++) { wait_on_buffer(bh[i]); if (!buffer_uptodate(bh[i])) goto block_release; }if (compressed) { /* 解壓縮操作,將flash上讀出的數(shù)據(jù)解壓縮 msblk:超級(jí)塊信息squashfs_sb_info ; bh:buffer_head,bh->data中保存從flash上讀取的數(shù)據(jù); b:表示讀取的數(shù)據(jù)長(zhǎng)度對(duì)應(yīng)的邏輯塊個(gè)數(shù); offset:表示讀取的flash地址對(duì)應(yīng)的邏輯塊偏移地址,一個(gè)邏輯塊為1024byte,offset=index&0x3ff length:表示從flash上讀取的數(shù)據(jù)長(zhǎng)度; output->length=512k mksquashfs時(shí)指定的塊大小 */ length = squashfs_decompress(msblk, bh, b, offset, length,output); if (length < 0) goto read_failure; } else { /* * Block is uncompressed. */ int in, pg_offset = 0; void *data = squashfs_first_page(output);for (bytes = length; k < b; k++) { in = min(bytes, msblk->devblksize - offset); bytes -= in; while (in) { if (pg_offset == PAGE_CACHE_SIZE) { data = squashfs_next_page(output); pg_offset = 0; } avail = min_t(int, in, PAGE_CACHE_SIZE - pg_offset); memcpy(data + pg_offset, bh[k]->b_data + offset, avail); in -= avail; pg_offset += avail; offset += avail; } offset = 0; put_bh(bh[k]); } squashfs_finish_page(output); }kfree(bh); return length;block_release: for (; k < b; k++) put_bh(bh[k]);read_failure: ERROR("squashfs_read_data failed to read block 0x%llx\n", (unsigned long long) index); kfree(bh); return -EIO; } 其中squashfs_read_data->squashfs_decompres是解壓縮過程,因?yàn)榇藭r(shí)的squashfs文件系統(tǒng)使用xz方式壓縮,所以解壓縮時(shí)使用squashfs_xz_uncompress
【正文】xz解壓縮過程
下面介紹下xz方式解壓縮squashfs文件:squashfs_decompress->squashfs_xz_uncompress
/* 解壓縮操作,將flash上讀出的數(shù)據(jù)解壓縮 msblk:超級(jí)塊信息squashfs_sb_info ; bh:buffer_head,bh->b_data中保存從flash上讀取的數(shù)據(jù); b:表示讀取的數(shù)據(jù)長(zhǎng)度對(duì)應(yīng)的邏輯塊個(gè)數(shù); offset:表示讀取的flash地址對(duì)應(yīng)的邏輯塊偏移地址,一個(gè)邏輯塊為1024byte,offset=index&0x3ff length:表示從flash上讀取的數(shù)據(jù)長(zhǎng)度 */ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,struct buffer_head **bh, int b, int offset, int length,struct squashfs_page_actor *output) {enum xz_ret xz_err;int avail, total = 0, k = 0;struct squashfs_xz *stream = strm; /* xz_dec->sequence=SEQ_STREAM_HEADER;解壓類型 xz_dec->temp.pos=0;解壓位置; xz_dec->temp.size=STREAM_HEADER_SIZE;需要解壓12byte的頭; */xz_dec_reset(stream->state);stream->buf.in_pos = 0;stream->buf.in_size = 0;stream->buf.out_pos = 0;stream->buf.out_size = PAGE_CACHE_SIZE;stream->buf.out = squashfs_first_page(output); /* while循環(huán)中逐個(gè)邏輯塊進(jìn)行解壓,msblk->devblksize=1024byte ;注意不一定一個(gè)循環(huán)就解壓一個(gè)塊, 如果一個(gè)循環(huán)內(nèi)因?yàn)?xz_dec_run異常未解壓完一個(gè)塊內(nèi)指定長(zhǎng)度的數(shù)據(jù),則循環(huán)解壓這個(gè)塊的數(shù)據(jù),直到完成. */do { /* 分兩種情況:讀取的flash地址是邏輯塊大小對(duì)齊的情況和非對(duì)齊情況 ; 對(duì)齊時(shí):offset=0; 非對(duì)齊時(shí):offset != 0; 第一次循環(huán)時(shí):stream->buf.in_pos==stream->buf.in_size=0; 因?yàn)橹髎tream->buf.in_pos會(huì)在 xz_dec_run中更新,該值表示解壓進(jìn)度,即已經(jīng)解壓到了一個(gè)塊內(nèi)的哪個(gè)位置(這個(gè)塊中需要解壓的數(shù)據(jù)是否解壓完, 讀取地址可能非塊大小對(duì)齊,所以需要解壓的數(shù)據(jù)不一定是1024即一個(gè)塊的大小,如果in_pos==in_size表示這個(gè)塊內(nèi)需要解壓的數(shù)據(jù)解壓完了); stream->buf.in_size在此初始化為一個(gè)邏輯塊內(nèi)真正要解壓的數(shù)據(jù)大小.用xz_buf->in_size和xz_dec_run處理后的xz_buf->in_pos來判斷解壓進(jìn)度. */if (stream->buf.in_pos == stream->buf.in_size && k < b) { /* 此次計(jì)算一個(gè)塊里需要解壓的數(shù)據(jù)的大小(可能不需要解壓一整個(gè)塊),因?yàn)樽x取的地址范圍可能非邏輯塊對(duì)齊; 舉例:假設(shè)讀取flash分區(qū)內(nèi)偏移位1020的地址,讀取大小為10byte:則 要先讀取第0個(gè)塊的:1020-1024地址范圍和第1個(gè)塊的0-6地址范圍; */avail = min(length, msblk->devblksize - offset);length -= avail; /* 要解壓的數(shù)據(jù)保存的地址*/stream->buf.in = bh[k]->b_data + offset; /* 一個(gè)塊里要解壓的數(shù)據(jù)大小 */stream->buf.in_size = avail; /* 一個(gè)塊解壓之前,解壓進(jìn)度當(dāng)然是0 */stream->buf.in_pos = 0;offset = 0;}if (stream->buf.out_pos == stream->buf.out_size) {stream->buf.out = squashfs_next_page(output);if (stream->buf.out != NULL) {stream->buf.out_pos = 0;total += PAGE_CACHE_SIZE;}} /*1 stream->buf=xz_buf:該結(jié)構(gòu)里保存了讀取到的一個(gè)邏輯塊里的內(nèi)容(xz_buf->in)和讀取的大小(xz_buf->in_size), 因?yàn)樽x取長(zhǎng)度可能非邏輯塊對(duì)齊,所以讀取大小也可能不是1024字節(jié). stream->buf.in_pos表示解壓到了一個(gè)塊的地址區(qū)間上的哪個(gè)位置,當(dāng)一個(gè)塊第一次解壓時(shí)in_pos初始化為0, 只有當(dāng)xz_dec_run里面全部解壓完,即in_pos==in_size,時(shí)才會(huì)解壓下一個(gè)邏輯塊;如果xz_dec_run處理之后, in_pos!=in_size表示該邏輯塊未解壓完,while循環(huán)處理中不會(huì)處理下一個(gè)塊 2 stream->state=xz_dec第一次循環(huán)時(shí)使用前面xz_dec_reset()初始化的信息,表示SEQ_STREAM_HEADER; */xz_err = xz_dec_run(stream->state, &stream->buf);if (stream->buf.in_pos == stream->buf.in_size && k < b)put_bh(bh[k++]);} while (xz_err == XZ_OK);squashfs_finish_page(output);if (xz_err != XZ_STREAM_END || k < b)goto out;return total + stream->buf.out_pos; out:for (; k < b; k++)put_bh(bh[k]);return -EIO; }squashfs_xz_uncompressxz_dec_runXZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b) {size_t in_start;size_t out_start;enum xz_ret ret;if (DEC_IS_SINGLE(s->mode))xz_dec_reset(s);in_start = b->in_pos;out_start = b->out_pos;ret = dec_main(s, b);if (DEC_IS_SINGLE(s->mode)) {if (ret == XZ_OK)ret = b->in_pos == b->in_size? XZ_DATA_ERROR : XZ_BUF_ERROR;if (ret != XZ_STREAM_END) {b->in_pos = in_start;b->out_pos = out_start;}} else if (ret == XZ_OK && in_start == b->in_pos&& out_start == b->out_pos) {if (s->allow_buf_error)ret = XZ_BUF_ERROR;s->allow_buf_error = true;} else {s->allow_buf_error = false;}return ret; } squashfs_xz_uncompressxz_dec_run->dec_main static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) {while(true) /*squashfs_xz_uncompress中有介紹,第一次解壓時(shí)s->sequence=SEQ_STREAM_HEADER*/switch(s->sequence){ /* 解壓 STREAM_HEADER_SIZE=12字節(jié)的頭信息*/case SEQ_STREAM_HEADER: /*把STREAM_HEADER_SIZE=12字節(jié)的數(shù)據(jù)copy到xz_dec->temp.buf上*/if (!fill_temp(s, b))return XZ_OK;/** If dec_stream_header() returns* XZ_UNSUPPORTED_CHECK, it is still possible* to continue decoding if working in multi-call* mode. Thus, update s->sequence before calling* dec_stream_header().*/s->sequence = SEQ_BLOCK_START;ret = dec_stream_header(s);if (ret != XZ_OK)return ret; /* 按順序依次解壓 不依次介紹*/ case..} }
【總結(jié)】
本文以squashfs文件系統(tǒng)為例,簡(jiǎn)單介紹了下linux系統(tǒng)中xz的解壓縮過程。撰寫本文主要目的是作為另一篇博文:?squashfs文件的讀取過程?的后續(xù).
總結(jié)
以上是生活随笔為你收集整理的xz压缩文件的解压缩过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 枫叶防注入程序漏洞
- 下一篇: pygame(十五)拼图游戏