From ea773ce760bee12eaa90875f8773b82b4a8ae5c0 Mon Sep 17 00:00:00 2001 From: "cantab.net!aia21" Date: Wed, 8 Jan 2003 10:48:09 +0000 Subject: [PATCH] - New API function: ntfs_attr_can_be_non_resident(). - Check whether the attribute name needs moving when resizing the resident part of an attribute record. - Create internal function ntfs_attr_find_in_attrdef(). (Logical change 1.78) --- libntfs/attrib.c | 185 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 151 insertions(+), 34 deletions(-) diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 77ff65dc..14534052 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -1,7 +1,7 @@ /* * attrib.c - Attribute handling code. Part of the Linux-NTFS project. * - * Copyright (c) 2000-2002 Anton Altaparmakov + * Copyright (c) 2000-2003 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -1909,6 +1909,45 @@ void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) return; } +/** + * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to find + * + * Search for the attribute definition record corresponding to the attribute + * @type in the $AttrDef system file. + * + * Return the attribute type definition record if found and NULL if not found + * or an error occured. On error the error code is stored in errno. The + * following error codes are defined: + * ENOENT - The attribute @type is not specified in $AttrDef. + * EINVAL - Invalid parameters (e.g. @vol is not valid). + */ +static ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, + const ATTR_TYPES type) +{ + ATTR_DEF *ad; + + if (!vol || !vol->attrdef || !type) { + errno = EINVAL; + return NULL; + } + for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < + vol->attrdef_len && ad->type; ++ad) { + /* We haven't found it yet, carry on searching. */ + if (ad->type < type) + continue; + /* We found the attribute; return it. */ + if (ad->type == type) + return ad; + /* We have gone too far already. No point in continuing. */ + break; + } + /* Attribute not found?!? */ + errno = ENOENT; + return NULL; +} + /** * ntfs_attr_size_bounds_check - check a size of an attribute type for validity * @vol: ntfs volume to which the attribute belongs @@ -1916,43 +1955,60 @@ void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) * @size: size which to check * * Check whether the @size in bytes is valid for an attribute of @type on the - * ntfs volume @vol. + * ntfs volume @vol. This information is obtained from $AttrDef system file. * * Return 0 if valid and -1 if not valid or an error occured. On error the * error code is stored in errno. The following error codes are defined: * ERANGE - @size is not valid for the attribute @type. * ENOENT - The attribute @type is not specified in $AttrDef. - * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid) + * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid). */ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, const s64 size) { ATTR_DEF *ad; - if (!vol || !vol->attrdef || size < 0) { + if (size < 0) { errno = EINVAL; return -1; } - - for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < - vol->attrdef_len && ad->type; ++ad) { - /* We haven't found it yet, carry on searching. */ - if (ad->type < type) - continue; - /* We have gone too far already. No point in continuing. */ - if (ad->type > type) - break; - /* We found the attribute. - Do the bounds check. */ - if (size >= le64_to_cpu(ad->min_size) && - size <= le64_to_cpu(ad->max_size)) - return 0; - /* @size is out of range! */ - errno = ERANGE; + ad = ntfs_attr_find_in_attrdef(vol, type); + if (!ad) return -1; - } + /* We found the attribute. - Do the bounds check. */ + if (size >= le64_to_cpu(ad->min_size) && + size <= le64_to_cpu(ad->max_size)) + return 0; + /* @size is out of range! */ + errno = ERANGE; + return -1; +} - /* Attribute not found?!? */ - errno = ENOENT; +/** + * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident + * @vol: ntfs volume to which the attribute belongs + * @type: attribute type which to check + * + * Check whether the attribute of @type on the ntfs volume @vol is allowed to + * be non-resident. This information is obtained from $AttrDef system file. + * + * Return 0 if the attribute is allowed to be non-resident and -1 if not or an + * error occured. On error the error code is stored in errno. The following + * error codes are defined: + * EPERM - The attribute is not allowed to be non-resident. + * ENOENT - The attribute @type is not specified in $AttrDef. + * EINVAL - Invalid parameters (e.g. @vol is not valid). + */ +int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type) +{ + ATTR_DEF *ad; + + ad = ntfs_attr_find_in_attrdef(vol, type); + if (!ad) + return -1; + if (ad->flags & CAN_BE_NON_RESIDENT) + return 0; + errno = EPERM; return -1; } @@ -1975,10 +2031,33 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, { u32 new_alen, new_muse; - // FIXME: Should verify that the attribute name hasn't been placed - // after the attribute value and if it is, we need to move the - // name, too. (AIA) - + /* + * Check that the attribute name hasn't been placed after the + * attribute value/mapping pairs array. If it has we need to move it. + * TODO: Implement the move. For now just abort. (AIA) + */ + if (a->name_length) { + BOOL move_name = FALSE; + if (a->non_resident) { + if (le16_to_cpu(a->name_offset) >= + le16_to_cpu(a->mapping_pairs_offset)) + move_name = TRUE; + } else { + if (le16_to_cpu(a->name_offset) >= + le16_to_cpu(a->value_offset)) + move_name = TRUE; + + } + if (move_name) { + // FIXME: Eeek! + fprintf(stderr, "%s(): Eeek! Name is placed after the " + "%s. Aborting...\n", __FUNCTION__, + a->non_resident ? "mapping pairs array": + "attribute value"); + errno = ENOTSUP; + return -1; + } + } /* Calculate the new attribute length and mft record bytes used. */ new_alen = (le16_to_cpu(a->value_offset) + newsize + 7) & ~7; /* If the actual attribute length has changed, move things around. */ @@ -2027,6 +2106,7 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) { ntfs_attr_search_ctx *ctx; + ntfs_volume *vol; int err; Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x.\n", __FUNCTION__, @@ -2040,11 +2120,12 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) err = errno; goto put_err_out; } + vol = na->ni->vol; /* * Check the attribute type and the corresponding minimum and maximum * sizes against @newsize and fail if @newsize is out of bounds. */ - if (ntfs_attr_size_bounds_check(na->ni->vol, na->type, newsize) < 0) { + if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { err = errno; if (err == ERANGE) { // FIXME: Eeek! @@ -2059,7 +2140,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) * attribute non-resident if the attribute type supports it. If it is * smaller we can go ahead and attempt the resize. */ - if (newsize < na->ni->vol->mft_record_size) { + if (newsize < vol->mft_record_size) { /* Perform the resize of the attribute record. */ if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, newsize)) { @@ -2078,7 +2159,20 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) /* There is not enough space in the mft record to perform the resize. */ // FIXME: Need to try to: - // - make the attribute non-resident if the attribute type allows + + /* Check if the attribute is allowed to be non-resident. */ + if (ntfs_attr_can_be_non_resident(vol, na->type) < 0) { + /* If an error occured, abort. */ + if (errno != EPERM) { + err = errno; + goto put_err_out; + } + /* Attribute is not allowed to be non-resident. */ + } else { + /* Make the attribute non-resident. */ + // TODO: do it! + } + // - make other attributes non-resident to free up enough space // - move the attribute to a new mft record // Note that some of the above changes also require changes in the @@ -2304,11 +2398,34 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) "metadata!\n", __FUNCTION__); goto put_err_out; } - - // FIXME: Should verify that the attribute name hasn't been - // placed after the attribute value and if it is, we - // need to move the name, too. (AIA) - + /* + * Check that the attribute name hasn't been placed after the + * attribute value/mapping pairs array. If it has we need to + * move it. TODO: Implement the move. For now just abort. (AIA) + */ + if (a->name_length) { + BOOL move_name = FALSE; + if (a->non_resident) { + if (le16_to_cpu(a->name_offset) >= le16_to_cpu( + a->mapping_pairs_offset)) + move_name = TRUE; + } else { + if (le16_to_cpu(a->name_offset) >= + le16_to_cpu(a->value_offset)) + move_name = TRUE; + + } + if (move_name) { + // FIXME: Eeek! + fprintf(stderr, "%s(): Eeek! Name is placed " + "after the %s. Aborting...\n", + __FUNCTION__, a->non_resident ? + "mapping pairs array": + "attribute value"); + err = ENOTSUP; + goto put_err_out; + } + } /* * Calculate the new attribute length and mft record bytes * used.