Add new function attrib.c::ntfs_non_resident_attr_expand, thus we can expand non resident attributes

(Logical change 1.466)
edge.strict_endians
(none)!yura 2004-08-01 11:05:46 +00:00
parent 50b9026628
commit 70bfea1080
1 changed files with 233 additions and 10 deletions

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
* Copyright (c) 2004 Yura Pakhuchiy
*
* 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
@ -42,6 +43,7 @@
#include "lcnalloc.h"
#include "dir.h"
#include "compress.h"
#include "bitmap.h"
ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') };
@ -2378,7 +2380,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na,
/* Start by allocating clusters to hold the attribute value. */
rl = ntfs_cluster_alloc(vol, new_allocated_size >>
vol->cluster_size_bits, -1, DATA_ZONE);
vol->cluster_size_bits, -1, DATA_ZONE, 0);
if (!rl) {
if (errno != ENOSPC) {
int eo = errno;
@ -3102,6 +3104,228 @@ put_err_out:
return -1;
}
/**
* ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute
* @na: non-resident ntfs attribute to expand
* @newsize: new size (in bytes) to which to expand the attribute
*
* Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes,
* by allocating new clusters.
*
* On success return 0 and on error return -1 with errno set to the error code.
* The following error codes are defined:
* ENOTSUP - The desired resize is not implemented yet.
* ENOMEM - Not enough memory to complete operation.
* ERANGE - @newsize is not valid for the attribute type of @na.
*/
static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize)
{
ntfs_volume *vol;
ntfs_attr_search_ctx *ctx;
ATTR_RECORD *a;
MFT_RECORD *m;
VCN first_free_vcn;
s64 nr_need_allocate;
u32 new_alen, new_muse;
int err, mp_size, cur_max_mp_size, exp_max_mp_size;
runlist *rl, *rln;
LCN lcn_seek_from = 0;
Dprintf("%s(): Entering for inode 0x%llx, attr 0x%x.\n", __FUNCTION__,
(unsigned long long)na->ni->mft_no, na->type);
vol = na->ni->vol;
/* Get the first attribute record that needs modification. */
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
if (!ctx)
return -1;
if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0,
NULL, 0, ctx)) {
err = errno;
if (err == ENOENT)
err = EIO;
goto put_err_out;
}
a = ctx->attr;
m = ctx->mrec;
/*
* Check the attribute type and the corresponding maximum size
* against @newsize and fail if @newsize is too big.
*/
if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
err = errno;
if (err == ERANGE) {
fprintf(stderr, "%s(): Eeek! Size bounds check "
"failed. Aborting...\n", __FUNCTION__);
} else if (err == ENOENT)
err = EIO;
goto put_err_out;
}
if (NInoAttrList(na->ni)) {
err = ENOTSUP;
goto put_err_out;
}
/* The first cluster outside the new allocation. */
first_free_vcn = (newsize + vol->cluster_size - 1) >>
vol->cluster_size_bits;
/*
* Compare the new allocation with the old one and only deallocate
* clusters if there is a change.
*/
if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) {
nr_need_allocate = first_free_vcn -
(na->allocated_size >> vol->cluster_size_bits);
if (ntfs_attr_map_whole_runlist (na)) {
err = EIO;
fprintf(stderr, "%s(): Eeek! "
"ntfs_attr_map_whole_runlist failed.\n",
__FUNCTION__);
goto put_err_out;
}
/*
* Determine first after last LCN of attribute. We will start
* seek clusters from this LCN to avoid fragmentation.
*/
if (na->rl->length) {
for (rl = na->rl; (rl + 1)->length; rl++)
;
lcn_seek_from = rl->lcn + rl->length;
}
rl = ntfs_cluster_alloc(vol, nr_need_allocate, lcn_seek_from,
DATA_ZONE, na->allocated_size >>
vol->cluster_size_bits);
if (!rl) {
err = errno;
fprintf(stderr, "%s(): Eeek! Cluster allocation "
"failed.\n", __FUNCTION__);
goto put_err_out;
}
/* Append new clusters to attribute runlist */
rln = ntfs_runlists_merge (na->rl, rl);
if (!rln) {
/* Failed, free just allocated clusters */
err = errno;
fprintf(stderr, "%s(): Eeek! Run list merge "
"failed.\n", __FUNCTION__);
rln = rl;
if (rln->lcn == LCN_RL_NOT_MAPPED) rln++;
while (rln->length) {
if (ntfs_bitmap_clear_run(vol->lcnbmp_na,
rln->lcn, rln->length))
fprintf(stderr, "%s(): Eeek! "
"Deallocation of just "
"allocated clusters "
"failed.\n", __FUNCTION__);
rln++;
}
free (rl);
goto put_err_out;
}
na->rl = rln;
/* Get the size for the new mapping pairs array. */
mp_size = ntfs_get_size_for_mapping_pairs(vol, na->rl);
/*
* Determine maximum possible length of mapping pairs,
* if we shall *not* expand space for mapping pairs
*/
cur_max_mp_size = le32_to_cpu(a->length) -
le16_to_cpu(a->mapping_pairs_offset);
/*
* Determine maximum possible length of mapping pairs,
* if we shall expand space for mapping pairs
*/
exp_max_mp_size = le32_to_cpu(m->bytes_allocated)
- le32_to_cpu(m->bytes_in_use) + cur_max_mp_size;
if (mp_size > exp_max_mp_size) {
err = ENOTSUP;
fprintf(stderr, "%s(): Eeek! Maping pairs size is"
" too big.\n", __FUNCTION__);
ntfs_cluster_free (vol, na, na->allocated_size >>
vol->cluster_size_bits, -1);
goto put_err_out;
}
/* Expand space for mapping pairs if we need this*/
if (mp_size > cur_max_mp_size) {
/*
* Calculate the new attribute length and mft record
* bytes used.
*/
new_alen = (le16_to_cpu(a->mapping_pairs_offset)
+ mp_size + 7) & ~7;
new_muse = le32_to_cpu(m->bytes_in_use) -
le32_to_cpu(a->length) + new_alen;
if (new_muse > le32_to_cpu(m->bytes_allocated)) {
fprintf(stderr, "%s(): BUG! Ran out of space in"
" mft record. Please report to "
"linux-ntfs-dev@lists.sf.net\n",
__FUNCTION__);
ntfs_cluster_free (vol, na, na->allocated_size
>> vol->cluster_size_bits, -1);
err = EIO;
goto put_err_out;
}
/* Move the following attributes forward. */
memmove((u8*)a + new_alen, (u8*)a + le32_to_cpu(
a->length), le32_to_cpu(m->bytes_in_use)
- ((u8*)a - (u8*)m) - le32_to_cpu(
a->length));
/* Update the sizes of the attribute and mft records. */
a->length = cpu_to_le32(new_alen);
m->bytes_in_use = cpu_to_le32(new_muse);
}
if (mp_size <= 0) {
err = errno;
fprintf(stderr, "%s(): Eeek! Get size for mapping "
"pairs failed.\n", __FUNCTION__);
ntfs_cluster_free (vol, na, na->allocated_size >>
vol->cluster_size_bits, -1);
goto put_err_out;
}
/*
* Generate the new mapping pairs array directly into the
* correct destination, i.e. the attribute record itself.
*/
if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
a->mapping_pairs_offset), mp_size, na->rl)) {
err = errno;
fprintf(stderr, "%s(): Eeek! Mapping pairs build "
"failed.\n", __FUNCTION__);
ntfs_cluster_free (vol, na, na->allocated_size >>
vol->cluster_size_bits, -1);
goto put_err_out;
}
/* Update the attribute record and the ntfs_attr structure. */
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
a->allocated_size = scpu_to_le64(na->allocated_size);
if (a->highest_vcn)
a->highest_vcn = scpu_to_le64(first_free_vcn - 1);
}
/* Update the attribute record and the ntfs attribute structure. */
na->data_size = newsize;
a->data_size = scpu_to_le64(newsize);
/* Set the inode dirty so it is written out later. */
ntfs_inode_mark_dirty(ctx->ntfs_ino);
/* Done! */
ntfs_attr_put_search_ctx(ctx);
return 0;
put_err_out:
ntfs_attr_put_search_ctx(ctx);
errno = err;
return -1;
}
/**
* ntfs_attr_truncate - resize an ntfs attribute
* @na: open ntfs attribute to resize
@ -3130,9 +3354,6 @@ put_err_out:
* The following error codes are defined:
* EINVAL - Invalid arguments were passed to the function.
* ENOTSUP - The desired resize is not implemented yet.
*
* NOTE: At present attributes can only be made smaller using this function,
* never bigger.
*/
int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
{
@ -3149,15 +3370,17 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
return -1;
}
/*
* TODO: Implement making non-resident attributes bigger/filling in of
* uninitialized holes as well as handling of compressed attributes.
* TODO: Implement making handling of compressed attributes.
*/
if ((NAttrNonResident(na) && newsize > na->initialized_size) ||
NAttrCompressed(na)) {
if (NAttrCompressed(na)) {
errno = ENOTSUP;
return -1;
}
if (NAttrNonResident(na))
return ntfs_non_resident_attr_shrink(na, newsize);
if (NAttrNonResident(na)) {
if (newsize > na->initialized_size)
return ntfs_non_resident_attr_expand(na, newsize);
else
return ntfs_non_resident_attr_shrink(na, newsize);
}
return ntfs_resident_attr_resize(na, newsize);
}