- add ntfs_inode_free_space and ntfs_inode_attach_all_extents

- update ntfs_inode_add_attrlist to use ntfs_inode_free_space

(Logical change 1.599)
edge.strict_endians
(none)!yura 2004-10-10 17:20:48 +00:00
parent 3f9fac7647
commit 1154b815de
1 changed files with 202 additions and 4 deletions

View File

@ -357,6 +357,53 @@ err_out:
return NULL;
}
/**
* ntfs_inode_attach_all_extents - atach all extents for target inode
* @ni: opened ntfs inode for which perform atach
*
* Return 0 on success and -1 on error with errno set to the error code.
*/
int ntfs_inode_attach_all_extents(ntfs_inode *ni)
{
ATTR_LIST_ENTRY *ale;
if (!ni) {
Dprintf("%s(): Invalid argumets.\n", __FUNCTION__);
errno = EINVAL;
return -1;
}
if (ni->nr_extents == -1)
ni = ni->base_ni;
Dprintf("%s(): Entering for inode 0x%llx.\n",
__FUNCTION__, (long long) ni->mft_no);
/* Inode haven't got attribute list, thus nothing to attach. */
if (!NInoAttrList(ni))
return 0;
if (!ni->attr_list) {
Dprintf("%s(): Corrput in-memory struct.\n", __FUNCTION__);
errno = EINVAL;
return -1;
}
/* Walk thru attribute list and attach all extents. */
errno = 0;
ale = (ATTR_LIST_ENTRY *)ni->attr_list;
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
if (!ntfs_extent_inode_open(ni, MREF_LE(ale->mft_reference))) {
Dprintf("%s(): Couldn't attach extent inode.\n",
__FUNCTION__);
return -1;
}
ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
}
return 0;
}
/**
* ntfs_inode_sync - write the inode (and its dirty extents) to disk
* @ni: ntfs inode to write
@ -584,15 +631,41 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
al = aln;
ntfs_attr_put_search_ctx(ctx);
/* Free space if there is not enough it for $ATTRIBUTE_LIST. */
if (le32_to_cpu(ni->mrec->bytes_allocated) -
le32_to_cpu(ni->mrec->bytes_in_use) <
offsetof(ATTR_RECORD, resident_attr_end)) {
/*
* Set temporary in-memory attribute list. We need this to be
* able perform attribute lookups and move out attributes.
*/
ni->attr_list = al;
ni->attr_list_size = al_len;
NInoSetAttrList(ni);
/* Free space. */
if (ntfs_inode_free_space(ni,
offsetof(ATTR_RECORD, resident_attr_end))) {
/*
* Couldn't free space, unset temporary in-memory
* attribute list and fail.
*/
err = errno;
Dprintf("%s(): Failed to free space for "
"$ATTRIBUTE_LIST.\n", __FUNCTION__);
ni->attr_list = NULL;
NInoClearAttrList(ni);
goto err_out;
}
/* Unset temporary in-memory attribute list. */
ni->attr_list = NULL;
NInoClearAttrList(ni);
}
/* Add $ATTRIBUTE_LIST to mft record. */
if (ntfs_resident_attr_record_add(ni, AT_ATTRIBUTE_LIST, 0, 0, 0) < 0) {
err = errno;
Dprintf("%s(): Couldn't add $ATTRIBUTE_LIST to MFT record.\n",
__FUNCTION__);
if (err == ENOSPC) {
//FIXME: Move out attributes and try once again.
err = ENOTSUP;
}
goto err_out;
}
@ -611,3 +684,128 @@ err_out:
errno = err;
return -1;
}
/**
* ntfs_inode_free_space - free space in the MFT record of inode
* @ni: ntfs inode in which MFT record free space
* @size: amount of space needed to free
*
* Return 0 on success or -1 on error with errno set to the error code.
*/
int ntfs_inode_free_space(ntfs_inode *ni, int size)
{
ntfs_attr_search_ctx *ctx;
int freed = 0, err;
if (!ni || size < 0) {
Dprintf("%s(): Invalid argumets.\n", __FUNCTION__);
errno = EINVAL;
return -1;
}
Dprintf("%s(): Entering for inode 0x%llx, size %d.\n",
__FUNCTION__, (long long) ni->mft_no, size);
if (!size)
return 0;
ctx = ntfs_attr_get_search_ctx(ni, 0);
if (!ctx) {
err = errno;
Dprintf("%s(): Failed to get attribute search context.\n",
__FUNCTION__);
errno = err;
return -1;
}
/*
* Chkdsk complain if $STANDART_INFORMATION is not in the base MFT
* record. FIXME: I'm not sure in this, need to recheck. For now simply
* do not move $STANDART_INFORMATION at all.
*
* Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position
* search context on first attribute after $STANDARD_INFORMATION and
* $ATTRIBUTE_LIST.
*
* Why we reposition instead of simply skip this attributes during
* enumeration? Because in case we have got only in-memory attribute
* list ntfs_attr_lookup will fail when it will try to find
* $ATTRIBUTE_LIST.
*/
if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
0, ctx)) {
if (errno != ENOENT) {
err = errno;
Dprintf("%s(): Attribute lookup failed.\n",
__FUNCTION__);
goto put_err_out;
}
if (ctx->attr->type == AT_END) {
err = ENOSPC;
goto put_err_out;
}
}
while (1) {
int record_size;
/*
* Check whether attribute is from different MFT record. If so,
* find next, because we don't need such.
*/
while (ctx->ntfs_ino->mft_no != ni->mft_no) {
if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE,
0, NULL, 0, ctx)) {
err = errno;
if (errno != ENOENT) {
Dprintf("%s(): Attribute lookup failed."
"\n", __FUNCTION__);
}
break;
}
}
record_size = le32_to_cpu(ctx->attr->length);
/* Move away attribute. */
if (ntfs_attr_record_move_away(ctx)) {
err = errno;
Dprintf("%s(): Failed to move out attribute.\n",
__FUNCTION__);
break;
}
freed += record_size;
/* Check whether we done. */
if (size <= freed) {
ntfs_attr_put_search_ctx(ctx);
return 0;
}
/*
* Repostion to first attribute after $STANDARD_INFORMATION and
* $ATTRIBUTE_LIST (see comments upwards).
*/
ntfs_attr_reinit_search_ctx(ctx);
if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0,
NULL, 0, ctx)) {
if (errno != ENOENT) {
err = errno;
Dprintf("%s(): Attribute lookup failed.\n",
__FUNCTION__);
break;
}
if (ctx->attr->type == AT_END) {
err = ENOSPC;
break;
}
}
}
put_err_out:
ntfs_attr_put_search_ctx(ctx);
if (err == ENOSPC)
Dprintf("%s(): No attributes left that can be moved out.\n",
__FUNCTION__);
errno = err;
return -1;
}