From 0636632d5a14ae3f97135fb922658cfa00274162 Mon Sep 17 00:00:00 2001 From: "cantab.net!aia21" Date: Fri, 9 Jan 2004 12:38:56 +0000 Subject: [PATCH] (Logical change 1.259) --- libntfs/compress.c | 217 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 libntfs/compress.c diff --git a/libntfs/compress.c b/libntfs/compress.c new file mode 100644 index 00000000..ceeb5c05 --- /dev/null +++ b/libntfs/compress.c @@ -0,0 +1,217 @@ +/* + * compress.c - Compressed attribute handling code. Part of the Linux-NTFS + * project. + * + * Copyright (c) 2004 Anton Altaparmakov + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the Linux-NTFS + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "attrib.h" +#include "debug.h" +#include "volume.h" +#include "types.h" +#include "layout.h" +#include "runlist.h" + +/** + * 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, const s64 pos, s64 count, + void *b) +{ + s64 br, to_read, ofs, total, total2; + u64 cb_size_mask; + VCN start_vcn, end_vcn; + ntfs_volume *vol; + runlist_element *rl; + u8 *ntfs_compression_buffer, *ntfs_uncompressed_buffer; + u8 *cb, *cb_pos, *cb_end; + u32 cb_size; + unsigned int nr_cbs, cb_clusters; + + Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x, pos 0x%Lx, " + "count 0x%Lx.\n", __FUNCTION__, + (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. */ + ntfs_compression_buffer = malloc(cb_size); + if (!ntfs_compression_buffer) + return -1; + /* Need a temporary buffer for each uncompressed block. */ + ntfs_uncompressed_buffer = malloc(cb_size); + if (!ntfs_uncompressed_buffer) { + int eo = errno; + free(ntfs_compression_buffer); + errno = eo; + 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; + /* + * 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; +do_next_cb: + nr_cbs--; + cb_pos = cb = ntfs_compression_buffer; + cb_end = cb + cb_size; + +// FIXME: I am here... (AIA) + + free(ntfs_compression_buffer); + free(ntfs_uncompressed_buffer); + errno = ENOTSUP; + return -1; + + /* Find the runlist element containing the vcn. */ + rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); + if (!rl) { + /* + * If the vcn is not present it is an out of bounds read. + * However, we already truncated the read to the data_size, + * so getting this here is an error. + */ + if (errno == ENOENT) + errno = EIO; + return -1; + } + /* + * Gather the requested data into the linear destination buffer. Note, + * a partial final vcn is taken care of by the @count capping of read + * length. + */ + ofs = pos - (rl->vcn << vol->cluster_size_bits); + for (; count; rl++, ofs = 0) { + if (!rl->length) + goto rl_err_out; + if (rl->lcn < (LCN)0) { + if (rl->lcn != (LCN)LCN_HOLE) + goto rl_err_out; + /* It is a hole, just zero the matching @b range. */ + to_read = min(count, (rl->length << + vol->cluster_size_bits) - ofs); + memset(b, 0, to_read); + /* Update progress counters. */ + total += to_read; + count -= to_read; + (u8*)b += to_read; + continue; + } + /* It is a real lcn, read it into @dst. */ + to_read = min(count, (rl->length << vol->cluster_size_bits) - + ofs); +retry: + Dprintf("%s(): Reading 0x%Lx bytes from vcn 0x%Lx, lcn 0x%Lx, " + "ofs 0x%Lx.\n", __FUNCTION__, to_read, + rl->vcn, rl->lcn, ofs); + br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + + ofs, to_read, b); + /* If everything ok, update progress counters and continue. */ + if (br > 0) { + total += br; + count -= br; + (u8*)b += br; + continue; + } + /* If the syscall was interrupted, try again. */ + if (br == (s64)-1 && errno == EINTR) + goto retry; + if (total) + return total; + if (!br) + errno = EIO; + return -1; + } + /* Finally, return the number of bytes read. */ + return total + total2; +rl_err_out: + if (total) + return total; + errno = EIO; + return -1; +} +