📄 compress.c
字号:
/* Map the next runlist fragment if it is not mapped. */ if (rl->lcn < LCN_HOLE || !rl->length) { cb_start_vcn = rl->vcn; rl = ntfs_attr_find_vcn(na, rl->vcn); if (!rl || rl->lcn < LCN_HOLE || !rl->length) return TRUE; /* * If the runs were merged need to deal with the * resulting partial run so simply restart. */ if (rl->vcn < cb_start_vcn) goto restart; } /* If the current run is sparse, the cb is compressed. */ if (rl->lcn == LCN_HOLE) return TRUE; /* If the whole cb is not sparse, it is not compressed. */ if (rl->length >= cb_clusters) return FALSE; cb_clusters -= rl->length; }; /* All cb_clusters were not sparse thus the cb is not compressed. */ return FALSE;}/** * ntfs_compressed_attr_pread - read from a compressed attribute * @na: ntfs attribute to read from * @pos: byte position in the attribute to begin reading from * @count: number of bytes to read * @b: output data buffer * * NOTE: You probably want to be using attrib.c::ntfs_attr_pread() instead. * * This function will read @count bytes starting at offset @pos from the * compressed ntfs attribute @na into the data buffer @b. * * On success, return the number of successfully read bytes. If this number * is lower than @count this means that the read reached end of file or that * an error was encountered during the read so that the read is partial. * 0 means end of file or nothing was read (also return 0 when @count is 0). * * On error and nothing has been read, return -1 with errno set appropriately * to the return code of ntfs_pread(), or to EINVAL in case of invalid * arguments. */s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b){ s64 br, to_read, ofs, total, total2; u64 cb_size_mask; VCN start_vcn, vcn, end_vcn; ntfs_volume *vol; runlist_element *rl; u8 *dest, *cb, *cb_pos, *cb_end; u32 cb_size; int err; unsigned int nr_cbs, cb_clusters; ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count 0x%llx.\n", (unsigned long long)na->ni->mft_no, na->type, (long long)pos, (long long)count); if (!na || !NAttrCompressed(na) || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; return -1; } /* * Encrypted attributes are not supported. We return access denied, * which is what Windows NT4 does, too. */ if (NAttrEncrypted(na)) { errno = EACCES; return -1; } if (!count) return 0; /* Truncate reads beyond end of attribute. */ if (pos + count > na->data_size) { if (pos >= na->data_size) { return 0; } count = na->data_size - pos; } /* If it is a resident attribute, simply use ntfs_attr_pread(). */ if (!NAttrNonResident(na)) return ntfs_attr_pread(na, pos, count, b); total = total2 = 0; /* Zero out reads beyond initialized size. */ if (pos + count > na->initialized_size) { if (pos >= na->initialized_size) { memset(b, 0, count); return count; } total2 = pos + count - na->initialized_size; count -= total2; memset((u8*)b + count, 0, total2); } vol = na->ni->vol; cb_size = na->compression_block_size; cb_size_mask = cb_size - 1UL; cb_clusters = na->compression_block_clusters; /* Need a temporary buffer for each loaded compression block. */ cb = malloc(cb_size); if (!cb) return -1; /* Need a temporary buffer for each uncompressed block. */ dest = malloc(cb_size); if (!dest) { err = errno; free(cb); errno = err; return -1; } /* * The first vcn in the first compression block (cb) which we need to * decompress. */ start_vcn = (pos & ~cb_size_mask) >> vol->cluster_size_bits; /* Offset in the uncompressed cb at which to start reading data. */ ofs = pos & cb_size_mask; /* * The first vcn in the cb after the last cb which we need to * decompress. */ end_vcn = ((pos + count + cb_size - 1) & ~cb_size_mask) >> vol->cluster_size_bits; /* Number of compression blocks (cbs) in the wanted vcn range. */ nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits >> na->compression_block_size_bits; cb_end = cb + cb_size;do_next_cb: nr_cbs--; cb_pos = cb; vcn = start_vcn; start_vcn += cb_clusters; /* Check whether the compression block is sparse. */ rl = ntfs_attr_find_vcn(na, vcn); if (!rl || rl->lcn < LCN_HOLE) { free(cb); free(dest); if (total) return total; /* FIXME: Do we want EIO or the error code? (AIA) */ errno = EIO; return -1; } if (rl->lcn == LCN_HOLE) { /* Sparse cb, zero out destination range overlapping the cb. */ ntfs_log_debug("Found sparse compression block.\n"); to_read = min(count, cb_size - ofs); memset(b, 0, to_read); ofs = 0; total += to_read; count -= to_read; b = (u8*)b + to_read; } else if (!ntfs_is_cb_compressed(na, rl, vcn, cb_clusters)) { s64 tdata_size, tinitialized_size; /* * Uncompressed cb, read it straight into the destination range * overlapping the cb. */ ntfs_log_debug("Found uncompressed compression block.\n"); /* * Read the uncompressed data into the destination buffer. * NOTE: We cheat a little bit here by marking the attribute as * not compressed in the ntfs_attr structure so that we can * read the data by simply using ntfs_attr_pread(). (-8 * NOTE: we have to modify data_size and initialized_size * temporarily as well... */ to_read = min(count, cb_size - ofs); ofs += vcn << vol->cluster_size_bits; NAttrClearCompressed(na); tdata_size = na->data_size; tinitialized_size = na->initialized_size; na->data_size = na->initialized_size = na->allocated_size; do { br = ntfs_attr_pread(na, ofs, to_read, b); if (br < 0) { err = errno; na->data_size = tdata_size; na->initialized_size = tinitialized_size; NAttrSetCompressed(na); free(cb); free(dest); if (total) return total; errno = err; return br; } total += br; count -= br; b = (u8*)b + br; to_read -= br; ofs += br; } while (to_read > 0); na->data_size = tdata_size; na->initialized_size = tinitialized_size; NAttrSetCompressed(na); ofs = 0; } else { s64 tdata_size, tinitialized_size; /* * Compressed cb, decompress it into the temporary buffer, then * copy the data to the destination range overlapping the cb. */ ntfs_log_debug("Found compressed compression block.\n"); /* * Read the compressed data into the temporary buffer. * NOTE: We cheat a little bit here by marking the attribute as * not compressed in the ntfs_attr structure so that we can * read the raw, compressed data by simply using * ntfs_attr_pread(). (-8 * NOTE: We have to modify data_size and initialized_size * temporarily as well... */ to_read = cb_size; NAttrClearCompressed(na); tdata_size = na->data_size; tinitialized_size = na->initialized_size; na->data_size = na->initialized_size = na->allocated_size; do { br = ntfs_attr_pread(na, (vcn << vol->cluster_size_bits) + (cb_pos - cb), to_read, cb_pos); if (br < 0) { err = errno; na->data_size = tdata_size; na->initialized_size = tinitialized_size; NAttrSetCompressed(na); free(cb); free(dest); if (total) return total; errno = err; return br; } cb_pos += br; to_read -= br; } while (to_read > 0); na->data_size = tdata_size; na->initialized_size = tinitialized_size; NAttrSetCompressed(na); /* Just a precaution. */ if (cb_pos + 2 <= cb_end) *(u16*)cb_pos = 0; ntfs_log_debug("Successfully read the compression block.\n"); if (ntfs_decompress(dest, cb_size, cb, cb_size) < 0) { err = errno; free(cb); free(dest); if (total) return total; errno = err; return -1; } to_read = min(count, cb_size - ofs); memcpy(b, dest + ofs, to_read); total += to_read; count -= to_read; b = (u8*)b + to_read; ofs = 0; } /* Do we have more work to do? */ if (nr_cbs) goto do_next_cb; /* We no longer need the buffers. */ free(cb); free(dest); /* Return number of bytes read. */ return total + total2;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -