Changes by: antona
Update of /cvsroot/linux-ntfs/linux-ntfs/libntfs
In directory usw-pr-cvs1:/tmp/cvs-serv18654/libntfs
Modified Files:
attrib.c
Log Message:
New API for compressing run lists into mapping pairs arrays and adapt mkntfs to that API. Addition of ntfs_walk_attrs().
Index: attrib.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/libntfs/attrib.c,v
retrieving revision 1.50
retrieving revision 1.51
diff -U2 -r1.50 -r1.51
--- attrib.c 5 Jul 2002 21:15:31 -0000 1.50
+++ attrib.c 6 Jul 2002 20:07:59 -0000 1.51
@@ -2923,2 +2923,212 @@
}
+/**
+ * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number
+ * @n: number for which to get the number of bytes for
+ *
+ * Return the number of bytes required to store @n unambiguously as
+ * a signed number.
+ *
+ * This is used in the context of the mapping pairs array to determine how
+ * many bytes will be needed in the array to store a given logical cluster
+ * number (lcn) or a specific run length.
+ *
+ * Return the number of bytes written. This function cannot fail.
+ */
+__inline__ int ntfs_get_nr_significant_bytes(const s64 n)
+{
+ s64 l = n;
+ int i;
+ s8 j;
+
+ i = 0;
+ do {
+ l >>= 8;
+ i++;
+ } while (l != 0LL && l != -1LL);
+ j = (n >> 8 * (i - 1)) & 0xff;
+ /* If the sign bit is wrong, we need an extra byte. */
+ if ((n < 0LL && j >= 0) || (n > 0LL && j < 0))
+ i++;
+ return i;
+}
+
+/**
+ * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array
+ * @vol: ntfs volume (needed for the ntfs version)
+ * @rl: run list for which to determine the size of the mapping pairs
+ *
+ * Walk the run list @rl and calculate the size in bytes of the mapping pairs
+ * array corresponding to the run list @rl. This for example allows us to
+ * allocate a buffer of the right size when building the mapping pairs array.
+ *
+ * Return the calculated size in bytes on success. If @rl is NULL return 0.
+ * On error, return -1 with errno set to the error code. The following error
+ * codes are defined:
+ * EINVAL - Run list contains unmapped elements. Make sure to only pass
+ * fully mapped run lists to this function.
+ * EIO - The run list is corrupt.
+ */
+int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
+ const run_list_element *rl)
+{
+ LCN prev_lcn;
+ int i, rls;
+
+ if (!rl)
+ return 0;
+ /* Always need the termining zero byte. */
+ rls = 1;
+ for (prev_lcn = i = 0; rl[i].length; prev_lcn = rl[++i].lcn) {
+ if (rl[i].length < 0 || rl[i].lcn < LCN_HOLE)
+ goto err_out;
+ /* Header byte + length. */
+ rls += 1 + ntfs_get_nr_significant_bytes(rl[i].length);
+ /*
+ * If the logical cluster number (lcn) denotes a hole and we
+ * are on NTFS 3.0+, we don't store it at all, i.e. we need
+ * zero space. On earlier NTFS versions we just store the lcn.
+ */
+ if (rl[i].lcn == LCN_HOLE && vol->major_ver >= 3)
+ continue;
+ /* Change in lcn. */
+ rls += ntfs_get_nr_significant_bytes(rl[i].lcn - prev_lcn);
+ }
+ return rls;
+err_out:
+ if (rl[i].lcn == LCN_RL_NOT_MAPPED)
+ errno = EINVAL;
+ else
+ errno = EIO;
+ return -1;
+}
+
+/**
+ * ntfs_write_significant_bytes - write the significant bytes of a number
+ * @dst: destination buffer to write to
+ * @dst_max: pointer to last byte of destination buffer for bounds checking
+ * @n: number whose significant bytes to write
+ *
+ * Store in @dst, the minimum bytes of the number @n which are required to
+ * identify @n unambiguously as a signed number, taking care not to exceed
+ * @dest_max, the maximum position within @dst to which we are allowed to
+ * write.
+ *
+ * This is used when building the mapping pairs array of a run list to compress
+ * a given logical cluster number (lcn) or a specific run length to the minumum
+ * size possible.
+ *
+ * Return the number of bytes written on success. On error, i.e. the
+ * destination buffer @dst is too small, return -1 with errno set ENOSPC.
+ */
+__inline__ int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max,
+ const s64 n)
+{
+ s64 l = n;
+ int i;
+ s8 j;
+
+ i = 0;
+ do {
+ if (dst > dst_max)
+ goto err_out;
+ *dst++ = l & 0xffLL;
+ l >>= 8;
+ i++;
+ } while (l != 0LL && l != -1LL);
+ j = (n >> 8 * (i - 1)) & 0xff;
+ /* If the sign bit is wrong, we need an extra byte. */
+ if (n < 0LL && j >= 0) {
+ if (dst > dst_max)
+ goto err_out;
+ i++;
+ *dst = (s8)-1;
+ } else if (n > 0LL && j < 0) {
+ if (dst > dst_max)
+ goto err_out;
+ i++;
+ *dst = (s8)0;
+ }
+ return i;
+err_out:
+ errno = ENOSPC;
+ return -1;
+}
+
+/**
+ * ntfs_build_mapping_pairs - build the mapping pairs array from a run list
+ * @vol: ntfs volume (needed for the ntfs version)
+ * @dst: destination buffer to which to write the mapping pairs array
+ * @dst_len: size of destination buffer @dst in bytes
+ * @rl: run list for which to build the mapping pairs array
+ *
+ * Create the mapping pairs array from the run list @rl and save the array in
+ * @dst. @dst_len is the size of @dst in bytes and it should be at least equal
+ * to the value obtained by calling ntfs_get_size_for_mapping_pairs(@rl).
+ *
+ * Return 0 on success or when @rl is NULL. On error, return -1 with errno set
+ * to the error code. The following error codes are defined:
+ * EINVAL - Run list contains unmapped elements. Make sure to only pass
+ * fully mapped run lists to this function.
+ * EIO - The run list is corrupt.
+ * ENOSPC - The destination buffer is too small.
+ */
+int ntfs_build_mapping_pairs(const ntfs_volume *vol, s8 *dst,
+ const int dst_len, const run_list_element *rl)
+{
+ LCN prev_lcn;
+ s8 *dst_max;
+ int i;
+ s8 len_len, lcn_len;
+
+ if (!rl)
+ return 0;
+ /*
+ * @dst_max is used for bounds checking in
+ * ntfs_write_significant_bytes().
+ */
+ dst_max = dst + dst_len - 1;
+ for (prev_lcn = i = 0; rl[i].length; prev_lcn = rl[++i].lcn) {
+ if (rl[i].length < 0 || rl[i].lcn < LCN_HOLE)
+ goto err_out;
+ /* Write length. */
+ len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
+ rl[i].length);
+ if (len_len < 0)
+ goto size_err;
+ /*
+ * If the logical cluster number (lcn) denotes a hole and we
+ * are on NTFS 3.0+, we don't store it at all, i.e. we need
+ * zero space. On earlier NTFS versions we just write the lcn
+ * change. FIXME: Do we need to write the lcn change or just
+ * the lcn in that case? Not sure as I have never seen this
+ * case on NT4. (AIA)
+ */
+ if (rl[i].lcn != LCN_HOLE || vol->major_ver < 3) {
+ lcn_len = ntfs_write_significant_bytes(dst + 1 +
+ len_len, dst_max, rl[i].lcn - prev_lcn);
+ if (lcn_len < 0)
+ goto size_err;
+ } else
+ lcn_len = 0;
+ /* Update header byte. */
+ *dst = lcn_len << 4 | len_len;
+ /* Position ourselves at next mapping pairs array element. */
+ dst += 1 + len_len + lcn_len;
+ }
+ if (dst <= dst_max) {
+ /* Terminator byte. */
+ *dst = 0;
+ return 0;
+ }
+size_err:
+ errno = ENOSPC;
+ return -1;
+err_out:
+ if (rl[i].lcn == LCN_RL_NOT_MAPPED)
+ errno = EINVAL;
+ else
+ errno = EIO;
+ return -1;
+}
+
|