Change ntfs_inode_close() to disconnect extent inodes from their base

inode when an extent inode is closed. This is needed byt ntfs_mft_record_free()
in order to be able to free extent mft records.

(Logical change 1.74)
edge.strict_endians
cantab.net!aia21 2002-12-29 21:37:21 +00:00
parent 58f750c289
commit 3bcc223bfd
1 changed files with 35 additions and 12 deletions

View File

@ -122,7 +122,8 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx)
goto err_out;
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
if (errno != ENOENT)
goto put_err_out;
/* Attribute list attribute not present so we are done. */
@ -184,10 +185,8 @@ err_out:
* then deallocate all memory attached to it, and finally free the ntfs inode
* structure itself.
*
* If it is an extent inode, we postpone to when the base inode is being closed
* with ntfs_inode_close() to tear down all structures and free all allocated
* memory. That way we keep the extent records cached in memory so we get an
* efficient ntfs_lookup_attr().
* If it is an extent inode, we disconnect it from its base inode before we
* destroy it.
*
* Return 0 on success or -1 on error with errno set to the error code. On
* error, @ni has not been freed. The user should attempt to handle the error
@ -200,13 +199,6 @@ err_out:
*/
int ntfs_inode_close(ntfs_inode *ni)
{
/* If the inode is an extent inode, complain rudely! */
if (ni->nr_extents == -1) {
Dprintf("%s(): BUG: Tried to close extent inode!\n",
__FUNCTION__);
errno = EINVAL;
return -1;
}
/* If we have dirty metadata, write it out. */
if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
if (ntfs_inode_sync(ni)) {
@ -223,6 +215,37 @@ int ntfs_inode_close(ntfs_inode *ni)
for (i = 0; i < ni->nr_extents; i++)
__ntfs_inode_release(ni->extent_nis[i]);
free(ni->extent_nis);
} else if (ni->nr_extents == -1) {
ntfs_inode **tmp_nis;
ntfs_inode *base_ni;
s32 i;
/*
* If the inode is an extent inode, disconnect it from the
* base inode before destroying it.
*/
base_ni = ni->base_ni;
for (i = 0; i < base_ni->nr_extents; ++i) {
tmp_nis = base_ni->extent_nis;
if (tmp_nis[i] != ni)
continue;
/* Found it. Disconnect. */
memmove(tmp_nis + i, tmp_nis + i + 1,
(base_ni->nr_extents - i - 1) *
sizeof(ntfs_inode *));
base_ni->nr_extents--;
/* Resize the memory buffer. */
tmp_nis = realloc(tmp_nis, base_ni->nr_extents *
sizeof(ntfs_inode *));
/* Ignore errors, they don't really matter. */
if (tmp_nis)
base_ni->extent_nis = tmp_nis;
/* Allow for error checking. */
i = -1;
}
if (i != -1)
Dputs("Extent inode was not attached to base inode! "
"Weird! Continuing regardless.");
}
return __ntfs_inode_release(ni);
}