usbloadergx/source/libntfs/attrlist.c

333 lines
10 KiB
C
Raw Normal View History

2009-12-19 15:06:57 +01:00
/**
* attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS
* project.
2009-12-19 15:06:57 +01:00
*
* Copyright (c) 2004-2005 Anton Altaparmakov
* Copyright (c) 2004-2005 Yura Pakhuchiy
* Copyright (c) 2006 Szabolcs Szakacsits
*
* 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
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include "types.h"
#include "layout.h"
#include "attrib.h"
#include "attrlist.h"
#include "debug.h"
#include "unistr.h"
#include "logging.h"
#include "misc.h"
/**
* ntfs_attrlist_need - check whether inode need attribute list
* @ni: opened ntfs inode for which perform check
2009-12-19 15:06:57 +01:00
*
* Check whether all are attributes belong to one MFT record, in that case
* attribute list is not needed.
*
* Return 1 if inode need attribute list, 0 if not, -1 on error with errno set
* to the error code. If function succeed errno set to 0. The following error
* codes are defined:
* EINVAL - Invalid arguments passed to function or attribute haven't got
* attribute list.
2009-12-19 15:06:57 +01:00
*/
int ntfs_attrlist_need( ntfs_inode *ni )
{
ATTR_LIST_ENTRY *ale;
2009-12-19 15:06:57 +01:00
if ( !ni )
{
ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
ntfs_log_trace( "Entering for inode 0x%llx.\n", ( long long ) ni->mft_no );
2009-12-19 15:06:57 +01:00
if ( !NInoAttrList( ni ) )
{
ntfs_log_trace( "Inode haven't got attribute list.\n" );
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
if ( !ni->attr_list )
{
ntfs_log_trace( "Corrupt in-memory struct.\n" );
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
errno = 0;
ale = ( ATTR_LIST_ENTRY * )ni->attr_list;
while ( ( u8* )ale < ni->attr_list + ni->attr_list_size )
{
if ( MREF_LE( ale->mft_reference ) != ni->mft_no )
return 1;
ale = ( ATTR_LIST_ENTRY * )( ( u8* )ale + le16_to_cpu( ale->length ) );
}
return 0;
2009-12-19 15:06:57 +01:00
}
/**
* ntfs_attrlist_entry_add - add an attribute list attribute entry
* @ni: opened ntfs inode, which contains that attribute
* @attr: attribute record to add to attribute list
2009-12-19 15:06:57 +01:00
*
* Return 0 on success and -1 on error with errno set to the error code. The
* following error codes are defined:
* EINVAL - Invalid arguments passed to function.
* ENOMEM - Not enough memory to allocate necessary buffers.
* EIO - I/O error occurred or damaged filesystem.
* EEXIST - Such attribute already present in attribute list.
2009-12-19 15:06:57 +01:00
*/
int ntfs_attrlist_entry_add( ntfs_inode *ni, ATTR_RECORD *attr )
{
ATTR_LIST_ENTRY *ale;
MFT_REF mref;
ntfs_attr *na = NULL;
ntfs_attr_search_ctx *ctx;
u8 *new_al;
int entry_len, entry_offset, err;
2009-12-19 15:06:57 +01:00
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x.\n",
( long long ) ni->mft_no,
( unsigned ) le32_to_cpu( attr->type ) );
2009-12-19 15:06:57 +01:00
if ( !ni || !attr )
{
ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
mref = MK_LE_MREF( ni->mft_no, le16_to_cpu( ni->mrec->sequence_number ) );
2009-12-19 15:06:57 +01:00
if ( ni->nr_extents == -1 )
ni = ni->base_ni;
2009-12-19 15:06:57 +01:00
if ( !NInoAttrList( ni ) )
{
ntfs_log_trace( "Attribute list isn't present.\n" );
errno = ENOENT;
return -1;
}
2009-12-19 15:06:57 +01:00
/* Determine size and allocate memory for new attribute list. */
entry_len = ( sizeof( ATTR_LIST_ENTRY ) + sizeof( ntfschar ) *
attr->name_length + 7 ) & ~7;
new_al = ntfs_calloc( ni->attr_list_size + entry_len );
if ( !new_al )
return -1;
2009-12-19 15:06:57 +01:00
/* Find place for the new entry. */
ctx = ntfs_attr_get_search_ctx( ni, NULL );
if ( !ctx )
{
err = errno;
goto err_out;
}
if ( !ntfs_attr_lookup( attr->type, ( attr->name_length ) ? ( ntfschar* )
( ( u8* )attr + le16_to_cpu( attr->name_offset ) ) :
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
( attr->non_resident ) ? le64_to_cpu( attr->lowest_vcn ) :
0, ( attr->non_resident ) ? NULL : ( ( u8* )attr +
le16_to_cpu( attr->value_offset ) ), ( attr->non_resident ) ?
0 : le32_to_cpu( attr->value_length ), ctx ) )
{
/* Found some extent, check it to be before new extent. */
if ( ctx->al_entry->lowest_vcn == attr->lowest_vcn )
{
err = EEXIST;
ntfs_log_trace( "Such attribute already present in the "
"attribute list.\n" );
ntfs_attr_put_search_ctx( ctx );
goto err_out;
}
/* Add new entry after this extent. */
ale = ( ATTR_LIST_ENTRY* )( ( u8* )ctx->al_entry +
le16_to_cpu( ctx->al_entry->length ) );
}
else
{
/* Check for real errors. */
if ( errno != ENOENT )
{
err = errno;
ntfs_log_trace( "Attribute lookup failed.\n" );
ntfs_attr_put_search_ctx( ctx );
goto err_out;
}
/* No previous extents found. */
ale = ctx->al_entry;
}
/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
ntfs_attr_put_search_ctx( ctx );
2009-12-19 15:06:57 +01:00
/* Determine new entry offset. */
entry_offset = ( ( u8 * )ale - ni->attr_list );
/* Set pointer to new entry. */
ale = ( ATTR_LIST_ENTRY * )( new_al + entry_offset );
/* Zero it to fix valgrind warning. */
memset( ale, 0, entry_len );
/* Form new entry. */
ale->type = attr->type;
ale->length = cpu_to_le16( entry_len );
ale->name_length = attr->name_length;
ale->name_offset = offsetof( ATTR_LIST_ENTRY, name );
if ( attr->non_resident )
ale->lowest_vcn = attr->lowest_vcn;
else
ale->lowest_vcn = 0;
ale->mft_reference = mref;
ale->instance = attr->instance;
memcpy( ale->name, ( u8 * )attr + le16_to_cpu( attr->name_offset ),
attr->name_length * sizeof( ntfschar ) );
2009-12-19 15:06:57 +01:00
/* Resize $ATTRIBUTE_LIST to new length. */
na = ntfs_attr_open( ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
if ( !na )
{
err = errno;
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
goto err_out;
}
if ( ntfs_attr_truncate( na, ni->attr_list_size + entry_len ) )
{
err = errno;
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
goto err_out;
}
2009-12-19 15:06:57 +01:00
/* Copy entries from old attribute list to new. */
memcpy( new_al, ni->attr_list, entry_offset );
memcpy( new_al + entry_offset + entry_len, ni->attr_list +
entry_offset, ni->attr_list_size - entry_offset );
2009-12-19 15:06:57 +01:00
/* Set new runlist. */
free( ni->attr_list );
ni->attr_list = new_al;
ni->attr_list_size = ni->attr_list_size + entry_len;
NInoAttrListSetDirty( ni );
/* Done! */
ntfs_attr_close( na );
return 0;
2009-12-19 15:06:57 +01:00
err_out:
if ( na )
ntfs_attr_close( na );
free( new_al );
errno = err;
return -1;
2009-12-19 15:06:57 +01:00
}
/**
* ntfs_attrlist_entry_rm - remove an attribute list attribute entry
* @ctx: attribute search context describing the attribute list entry
2009-12-19 15:06:57 +01:00
*
* Remove the attribute list entry @ctx->al_entry from the attribute list.
*
* Return 0 on success and -1 on error with errno set to the error code.
*/
int ntfs_attrlist_entry_rm( ntfs_attr_search_ctx *ctx )
{
u8 *new_al;
int new_al_len;
ntfs_inode *base_ni;
ntfs_attr *na;
ATTR_LIST_ENTRY *ale;
int err;
2009-12-19 15:06:57 +01:00
if ( !ctx || !ctx->ntfs_ino || !ctx->al_entry )
{
ntfs_log_trace( "Invalid arguments.\n" );
errno = EINVAL;
return -1;
}
2009-12-19 15:06:57 +01:00
if ( ctx->base_ntfs_ino )
base_ni = ctx->base_ntfs_ino;
else
base_ni = ctx->ntfs_ino;
ale = ctx->al_entry;
2009-12-19 15:06:57 +01:00
ntfs_log_trace( "Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
( long long ) ctx->ntfs_ino->mft_no,
( unsigned ) le32_to_cpu( ctx->al_entry->type ),
( long long ) le64_to_cpu( ctx->al_entry->lowest_vcn ) );
2009-12-19 15:06:57 +01:00
if ( !NInoAttrList( base_ni ) )
{
ntfs_log_trace( "Attribute list isn't present.\n" );
errno = ENOENT;
return -1;
}
2009-12-19 15:06:57 +01:00
/* Allocate memory for new attribute list. */
new_al_len = base_ni->attr_list_size - le16_to_cpu( ale->length );
new_al = ntfs_calloc( new_al_len );
if ( !new_al )
return -1;
2009-12-19 15:06:57 +01:00
/* Reisze $ATTRIBUTE_LIST to new length. */
na = ntfs_attr_open( base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0 );
if ( !na )
{
err = errno;
ntfs_log_trace( "Failed to open $ATTRIBUTE_LIST attribute.\n" );
goto err_out;
}
if ( ntfs_attr_truncate( na, new_al_len ) )
{
err = errno;
ntfs_log_trace( "$ATTRIBUTE_LIST resize failed.\n" );
goto err_out;
}
2009-12-19 15:06:57 +01:00
/* Copy entries from old attribute list to new. */
memcpy( new_al, base_ni->attr_list, ( u8* )ale - base_ni->attr_list );
memcpy( new_al + ( ( u8* )ale - base_ni->attr_list ), ( u8* )ale + le16_to_cpu(
ale->length ), new_al_len - ( ( u8* )ale - base_ni->attr_list ) );
2009-12-19 15:06:57 +01:00
/* Set new runlist. */
free( base_ni->attr_list );
base_ni->attr_list = new_al;
base_ni->attr_list_size = new_al_len;
NInoAttrListSetDirty( base_ni );
/* Done! */
ntfs_attr_close( na );
return 0;
2009-12-19 15:06:57 +01:00
err_out:
if ( na )
ntfs_attr_close( na );
free( new_al );
errno = err;
return -1;
2009-12-19 15:06:57 +01:00
}