mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-18 17:29:17 +01:00
9e79c9d99b
* code cleanup
698 lines
21 KiB
C
698 lines
21 KiB
C
/**
|
|
* object_id.c - Processing of object ids
|
|
*
|
|
* This module is part of ntfs-3g library
|
|
*
|
|
* Copyright (c) 2009 Jean-Pierre Andre
|
|
*
|
|
* 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_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SETXATTR
|
|
#include <sys/xattr.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SYSMACROS_H
|
|
#include <sys/sysmacros.h>
|
|
#endif
|
|
|
|
#include "types.h"
|
|
#include "debug.h"
|
|
#include "attrib.h"
|
|
#include "inode.h"
|
|
#include "dir.h"
|
|
#include "volume.h"
|
|
#include "mft.h"
|
|
#include "index.h"
|
|
#include "lcnalloc.h"
|
|
#include "object_id.h"
|
|
#include "logging.h"
|
|
#include "misc.h"
|
|
|
|
/*
|
|
* Endianness considerations
|
|
*
|
|
* According to RFC 4122, GUIDs should be printed with the most
|
|
* significant byte first, and the six fields be compared individually
|
|
* for ordering. RFC 4122 does not define the internal representation.
|
|
*
|
|
* Here we always copy disk images with no endianness change,
|
|
* and, for indexing, GUIDs are compared as if they were a sequence
|
|
* of four unsigned 32 bit integers.
|
|
*
|
|
* --------------------- begin from RFC 4122 ----------------------
|
|
* Consider each field of the UUID to be an unsigned integer as shown
|
|
* in the table in section Section 4.1.2. Then, to compare a pair of
|
|
* UUIDs, arithmetically compare the corresponding fields from each
|
|
* UUID in order of significance and according to their data type.
|
|
* Two UUIDs are equal if and only if all the corresponding fields
|
|
* are equal.
|
|
*
|
|
* UUIDs, as defined in this document, can also be ordered
|
|
* lexicographically. For a pair of UUIDs, the first one follows the
|
|
* second if the most significant field in which the UUIDs differ is
|
|
* greater for the first UUID. The second precedes the first if the
|
|
* most significant field in which the UUIDs differ is greater for
|
|
* the second UUID.
|
|
*
|
|
* The fields are encoded as 16 octets, with the sizes and order of the
|
|
* fields defined above, and with each field encoded with the Most
|
|
* Significant Byte first (known as network byte order). Note that the
|
|
* field names, particularly for multiplexed fields, follow historical
|
|
* practice.
|
|
*
|
|
* 0 1 2 3
|
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | time_low |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | time_mid | time_hi_and_version |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* |clk_seq_hi_res | clk_seq_low | node (0-1) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | node (2-5) |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*
|
|
* ---------------------- end from RFC 4122 -----------------------
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
GUID object_id;
|
|
} OBJECT_ID_INDEX_KEY;
|
|
|
|
typedef struct
|
|
{
|
|
le64 file_id;
|
|
GUID birth_volume_id;
|
|
GUID birth_object_id;
|
|
GUID domain_id;
|
|
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
|
|
|
|
struct OBJECT_ID_INDEX /* index entry in $Extend/$ObjId */
|
|
{
|
|
INDEX_ENTRY_HEADER header;
|
|
OBJECT_ID_INDEX_KEY key;
|
|
OBJECT_ID_INDEX_DATA data;
|
|
} ;
|
|
|
|
static ntfschar objid_index_name[] = { const_cpu_to_le16( '$' ),
|
|
const_cpu_to_le16( 'O' )
|
|
};
|
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
|
|
|
/*
|
|
* Set the index for a new object id
|
|
*
|
|
* Returns 0 if success
|
|
* -1 if failure, explained by errno
|
|
*/
|
|
|
|
static int set_object_id_index( ntfs_inode *ni, ntfs_index_context *xo,
|
|
const OBJECT_ID_ATTR *object_id )
|
|
{
|
|
struct OBJECT_ID_INDEX indx;
|
|
u64 file_id_cpu;
|
|
le64 file_id;
|
|
le16 seqn;
|
|
|
|
seqn = ni->mrec->sequence_number;
|
|
file_id_cpu = MK_MREF( ni->mft_no, le16_to_cpu( seqn ) );
|
|
file_id = cpu_to_le64( file_id_cpu );
|
|
indx.header.data_offset = const_cpu_to_le16(
|
|
sizeof( INDEX_ENTRY_HEADER )
|
|
+ sizeof( OBJECT_ID_INDEX_KEY ) );
|
|
indx.header.data_length = const_cpu_to_le16(
|
|
sizeof( OBJECT_ID_INDEX_DATA ) );
|
|
indx.header.reservedV = const_cpu_to_le32( 0 );
|
|
indx.header.length = const_cpu_to_le16(
|
|
sizeof( struct OBJECT_ID_INDEX ) );
|
|
indx.header.key_length = const_cpu_to_le16(
|
|
sizeof( OBJECT_ID_INDEX_KEY ) );
|
|
indx.header.flags = const_cpu_to_le16( 0 );
|
|
indx.header.reserved = const_cpu_to_le16( 0 );
|
|
|
|
memcpy( &indx.key.object_id, object_id, sizeof( GUID ) );
|
|
|
|
indx.data.file_id = file_id;
|
|
memcpy( &indx.data.birth_volume_id,
|
|
&object_id->birth_volume_id, sizeof( GUID ) );
|
|
memcpy( &indx.data.birth_object_id,
|
|
&object_id->birth_object_id, sizeof( GUID ) );
|
|
memcpy( &indx.data.domain_id,
|
|
&object_id->domain_id, sizeof( GUID ) );
|
|
ntfs_index_ctx_reinit( xo );
|
|
return ( ntfs_ie_add( xo, ( INDEX_ENTRY* )&indx ) );
|
|
}
|
|
|
|
#endif /* HAVE_SETXATTR */
|
|
|
|
/*
|
|
* Open the $Extend/$ObjId file and its index
|
|
*
|
|
* Return the index context if opened
|
|
* or NULL if an error occurred (errno tells why)
|
|
*
|
|
* The index has to be freed and inode closed when not needed any more.
|
|
*/
|
|
|
|
static ntfs_index_context *open_object_id_index( ntfs_volume *vol )
|
|
{
|
|
u64 inum;
|
|
ntfs_inode *ni;
|
|
ntfs_inode *dir_ni;
|
|
ntfs_index_context *xo;
|
|
|
|
/* do not use path_name_to inode - could reopen root */
|
|
dir_ni = ntfs_inode_open( vol, FILE_Extend );
|
|
ni = ( ntfs_inode* )NULL;
|
|
if ( dir_ni )
|
|
{
|
|
inum = ntfs_inode_lookup_by_mbsname( dir_ni, "$ObjId" );
|
|
if ( inum != ( u64 ) - 1 )
|
|
ni = ntfs_inode_open( vol, inum );
|
|
ntfs_inode_close( dir_ni );
|
|
}
|
|
if ( ni )
|
|
{
|
|
xo = ntfs_index_ctx_get( ni, objid_index_name, 2 );
|
|
if ( !xo )
|
|
{
|
|
ntfs_inode_close( ni );
|
|
}
|
|
}
|
|
else
|
|
xo = ( ntfs_index_context* )NULL;
|
|
return ( xo );
|
|
}
|
|
|
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
|
|
|
/*
|
|
* Merge object_id data stored in the index into
|
|
* a full object_id struct.
|
|
*
|
|
* returns 0 if merging successful
|
|
* -1 if no data could be merged. This is generally not an error
|
|
*/
|
|
|
|
static int merge_index_data( ntfs_inode *ni,
|
|
const OBJECT_ID_ATTR *objectid_attr,
|
|
OBJECT_ID_ATTR *full_objectid )
|
|
{
|
|
OBJECT_ID_INDEX_KEY key;
|
|
struct OBJECT_ID_INDEX *entry;
|
|
ntfs_index_context *xo;
|
|
ntfs_inode *xoni;
|
|
int res;
|
|
|
|
res = -1;
|
|
xo = open_object_id_index( ni->vol );
|
|
if ( xo )
|
|
{
|
|
memcpy( &key.object_id, objectid_attr, sizeof( GUID ) );
|
|
if ( !ntfs_index_lookup( &key,
|
|
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
|
{
|
|
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
|
/* make sure inode numbers match */
|
|
if ( entry
|
|
&& ( MREF( le64_to_cpu( entry->data.file_id ) )
|
|
== ni->mft_no ) )
|
|
{
|
|
memcpy( &full_objectid->birth_volume_id,
|
|
&entry->data.birth_volume_id,
|
|
sizeof( GUID ) );
|
|
memcpy( &full_objectid->birth_object_id,
|
|
&entry->data.birth_object_id,
|
|
sizeof( GUID ) );
|
|
memcpy( &full_objectid->domain_id,
|
|
&entry->data.domain_id,
|
|
sizeof( GUID ) );
|
|
res = 0;
|
|
}
|
|
}
|
|
xoni = xo->ni;
|
|
ntfs_index_ctx_put( xo );
|
|
ntfs_inode_close( xoni );
|
|
}
|
|
return ( res );
|
|
}
|
|
|
|
#endif /* HAVE_SETXATTR */
|
|
|
|
/*
|
|
* Remove an object id index entry if attribute present
|
|
*
|
|
* Returns the size of existing object id
|
|
* (the existing object_d is returned)
|
|
* -1 if failure, explained by errno
|
|
*/
|
|
|
|
static int remove_object_id_index( ntfs_attr *na, ntfs_index_context *xo,
|
|
OBJECT_ID_ATTR *old_attr )
|
|
{
|
|
OBJECT_ID_INDEX_KEY key;
|
|
struct OBJECT_ID_INDEX *entry;
|
|
s64 size;
|
|
int ret;
|
|
|
|
ret = na->data_size;
|
|
if ( ret )
|
|
{
|
|
/* read the existing object id attribute */
|
|
size = ntfs_attr_pread( na, 0, sizeof( GUID ), old_attr );
|
|
if ( size >= ( s64 )sizeof( GUID ) )
|
|
{
|
|
memcpy( &key.object_id,
|
|
&old_attr->object_id, sizeof( GUID ) );
|
|
size = sizeof( GUID );
|
|
if ( !ntfs_index_lookup( &key,
|
|
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
|
{
|
|
entry = ( struct OBJECT_ID_INDEX* )xo->entry;
|
|
memcpy( &old_attr->birth_volume_id,
|
|
&entry->data.birth_volume_id,
|
|
sizeof( GUID ) );
|
|
memcpy( &old_attr->birth_object_id,
|
|
&entry->data.birth_object_id,
|
|
sizeof( GUID ) );
|
|
memcpy( &old_attr->domain_id,
|
|
&entry->data.domain_id,
|
|
sizeof( GUID ) );
|
|
size = sizeof( OBJECT_ID_ATTR );
|
|
if ( ntfs_index_rm( xo ) )
|
|
ret = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = -1;
|
|
errno = ENODATA;
|
|
}
|
|
}
|
|
return ( ret );
|
|
}
|
|
|
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
|
|
|
/*
|
|
* Update the object id and index
|
|
*
|
|
* The object_id attribute should have been created and the
|
|
* non-duplication of the GUID should have been checked before.
|
|
*
|
|
* Returns 0 if success
|
|
* -1 if failure, explained by errno
|
|
* If could not remove the existing index, nothing is done,
|
|
* If could not write the new data, no index entry is inserted
|
|
* If failed to insert the index, data is removed
|
|
*/
|
|
|
|
static int update_object_id( ntfs_inode *ni, ntfs_index_context *xo,
|
|
const OBJECT_ID_ATTR *value, size_t size )
|
|
{
|
|
OBJECT_ID_ATTR old_attr;
|
|
ntfs_attr *na;
|
|
int oldsize;
|
|
int written;
|
|
int res;
|
|
|
|
res = 0;
|
|
|
|
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
|
if ( na )
|
|
{
|
|
|
|
/* remove the existing index entry */
|
|
oldsize = remove_object_id_index( na, xo, &old_attr );
|
|
if ( oldsize < 0 )
|
|
res = -1;
|
|
else
|
|
{
|
|
/* resize attribute */
|
|
res = ntfs_attr_truncate( na, ( s64 )sizeof( GUID ) );
|
|
/* write the object_id in attribute */
|
|
if ( !res && value )
|
|
{
|
|
written = ( int )ntfs_attr_pwrite( na,
|
|
( s64 )0, ( s64 )sizeof( GUID ),
|
|
&value->object_id );
|
|
if ( written != ( s64 )sizeof( GUID ) )
|
|
{
|
|
ntfs_log_error( "Failed to update "
|
|
"object id\n" );
|
|
errno = EIO;
|
|
res = -1;
|
|
}
|
|
}
|
|
/* write index part if provided */
|
|
if ( !res
|
|
&& ( ( size < sizeof( OBJECT_ID_ATTR ) )
|
|
|| set_object_id_index( ni, xo, value ) ) )
|
|
{
|
|
/*
|
|
* If cannot index, try to remove the object
|
|
* id and log the error. There will be an
|
|
* inconsistency if removal fails.
|
|
*/
|
|
ntfs_attr_rm( na );
|
|
ntfs_log_error( "Failed to index object id."
|
|
" Possible corruption.\n" );
|
|
}
|
|
}
|
|
ntfs_attr_close( na );
|
|
NInoSetDirty( ni );
|
|
}
|
|
else
|
|
res = -1;
|
|
return ( res );
|
|
}
|
|
|
|
/*
|
|
* Add a (dummy) object id to an inode if it does not exist
|
|
*
|
|
* returns 0 if attribute was inserted (or already present)
|
|
* -1 if adding failed (explained by errno)
|
|
*/
|
|
|
|
static int add_object_id( ntfs_inode *ni, int flags )
|
|
{
|
|
int res;
|
|
u8 dummy;
|
|
|
|
res = -1; /* default return */
|
|
if ( !ntfs_attr_exist( ni, AT_OBJECT_ID, AT_UNNAMED, 0 ) )
|
|
{
|
|
if ( !( flags & XATTR_REPLACE ) )
|
|
{
|
|
/*
|
|
* no object id attribute : add one,
|
|
* apparently, this does not feed the new value in
|
|
* Note : NTFS version must be >= 3
|
|
*/
|
|
if ( ni->vol->major_ver >= 3 )
|
|
{
|
|
res = ntfs_attr_add( ni, AT_OBJECT_ID,
|
|
AT_UNNAMED, 0, &dummy, ( s64 )0 );
|
|
NInoSetDirty( ni );
|
|
}
|
|
else
|
|
errno = EOPNOTSUPP;
|
|
}
|
|
else
|
|
errno = ENODATA;
|
|
}
|
|
else
|
|
{
|
|
if ( flags & XATTR_CREATE )
|
|
errno = EEXIST;
|
|
else
|
|
res = 0;
|
|
}
|
|
return ( res );
|
|
}
|
|
|
|
#endif /* HAVE_SETXATTR */
|
|
|
|
/*
|
|
* Delete an object_id index entry
|
|
*
|
|
* Returns 0 if success
|
|
* -1 if failure, explained by errno
|
|
*/
|
|
|
|
int ntfs_delete_object_id_index( ntfs_inode *ni )
|
|
{
|
|
ntfs_index_context *xo;
|
|
ntfs_inode *xoni;
|
|
ntfs_attr *na;
|
|
OBJECT_ID_ATTR old_attr;
|
|
int res;
|
|
|
|
res = 0;
|
|
na = ntfs_attr_open( ni, AT_OBJECT_ID, AT_UNNAMED, 0 );
|
|
if ( na )
|
|
{
|
|
/*
|
|
* read the existing object id
|
|
* and un-index it
|
|
*/
|
|
xo = open_object_id_index( ni->vol );
|
|
if ( xo )
|
|
{
|
|
if ( remove_object_id_index( na, xo, &old_attr ) < 0 )
|
|
res = -1;
|
|
xoni = xo->ni;
|
|
ntfs_index_entry_mark_dirty( xo );
|
|
NInoSetDirty( xoni );
|
|
ntfs_index_ctx_put( xo );
|
|
ntfs_inode_close( xoni );
|
|
}
|
|
ntfs_attr_close( na );
|
|
}
|
|
return ( res );
|
|
}
|
|
|
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
|
|
|
/*
|
|
* Get the ntfs object id into an extended attribute
|
|
*
|
|
* If present, the object_id from the attribute and the GUIDs
|
|
* from the index are returned (formatted as OBJECT_ID_ATTR)
|
|
*
|
|
* Returns the global size (can be 0, 16 or 64)
|
|
* and the buffer is updated if it is long enough
|
|
*/
|
|
|
|
int ntfs_get_ntfs_object_id( ntfs_inode *ni, char *value, size_t size )
|
|
{
|
|
OBJECT_ID_ATTR full_objectid;
|
|
OBJECT_ID_ATTR *objectid_attr;
|
|
s64 attr_size;
|
|
int full_size;
|
|
|
|
full_size = 0; /* default to no data and some error to be defined */
|
|
if ( ni )
|
|
{
|
|
objectid_attr = ( OBJECT_ID_ATTR* )ntfs_attr_readall( ni,
|
|
AT_OBJECT_ID, ( ntfschar* )NULL, 0, &attr_size );
|
|
if ( objectid_attr )
|
|
{
|
|
/* restrict to only GUID present in attr */
|
|
if ( attr_size == sizeof( GUID ) )
|
|
{
|
|
memcpy( &full_objectid.object_id,
|
|
objectid_attr, sizeof( GUID ) );
|
|
full_size = sizeof( GUID );
|
|
/* get data from index, if any */
|
|
if ( !merge_index_data( ni, objectid_attr,
|
|
&full_objectid ) )
|
|
{
|
|
full_size = sizeof( OBJECT_ID_ATTR );
|
|
}
|
|
if ( full_size <= ( s64 )size )
|
|
{
|
|
if ( value )
|
|
memcpy( value, &full_objectid,
|
|
full_size );
|
|
else
|
|
errno = EINVAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* unexpected size, better return unsupported */
|
|
errno = EOPNOTSUPP;
|
|
full_size = 0;
|
|
}
|
|
free( objectid_attr );
|
|
}
|
|
else
|
|
errno = ENODATA;
|
|
}
|
|
return ( full_size ? ( int )full_size : -errno );
|
|
}
|
|
|
|
/*
|
|
* Set the object id from an extended attribute
|
|
*
|
|
* If the size is 64, the attribute and index are set.
|
|
* else if the size is not less than 16 only the attribute is set.
|
|
* The object id index is set accordingly.
|
|
*
|
|
* Returns 0, or -1 if there is a problem
|
|
*/
|
|
|
|
int ntfs_set_ntfs_object_id( ntfs_inode *ni,
|
|
const char *value, size_t size, int flags )
|
|
{
|
|
OBJECT_ID_INDEX_KEY key;
|
|
ntfs_inode *xoni;
|
|
ntfs_index_context *xo;
|
|
int res;
|
|
|
|
res = 0;
|
|
if ( ni && value && ( size >= sizeof( GUID ) ) )
|
|
{
|
|
xo = open_object_id_index( ni->vol );
|
|
if ( xo )
|
|
{
|
|
/* make sure the GUID was not used somewhere */
|
|
memcpy( &key.object_id, value, sizeof( GUID ) );
|
|
if ( ntfs_index_lookup( &key,
|
|
sizeof( OBJECT_ID_INDEX_KEY ), xo ) )
|
|
{
|
|
ntfs_index_ctx_reinit( xo );
|
|
res = add_object_id( ni, flags );
|
|
if ( !res )
|
|
{
|
|
/* update value and index */
|
|
res = update_object_id( ni, xo,
|
|
( const OBJECT_ID_ATTR* )value,
|
|
size );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* GUID is present elsewhere */
|
|
res = -1;
|
|
errno = EEXIST;
|
|
}
|
|
xoni = xo->ni;
|
|
ntfs_index_entry_mark_dirty( xo );
|
|
NInoSetDirty( xoni );
|
|
ntfs_index_ctx_put( xo );
|
|
ntfs_inode_close( xoni );
|
|
}
|
|
else
|
|
{
|
|
res = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errno = EINVAL;
|
|
res = -1;
|
|
}
|
|
return ( res ? -1 : 0 );
|
|
}
|
|
|
|
/*
|
|
* Remove the object id
|
|
*
|
|
* Returns 0, or -1 if there is a problem
|
|
*/
|
|
|
|
int ntfs_remove_ntfs_object_id( ntfs_inode *ni )
|
|
{
|
|
int res;
|
|
int olderrno;
|
|
ntfs_attr *na;
|
|
ntfs_inode *xoni;
|
|
ntfs_index_context *xo;
|
|
int oldsize;
|
|
OBJECT_ID_ATTR old_attr;
|
|
|
|
res = 0;
|
|
if ( ni )
|
|
{
|
|
/*
|
|
* open and delete the object id
|
|
*/
|
|
na = ntfs_attr_open( ni, AT_OBJECT_ID,
|
|
AT_UNNAMED, 0 );
|
|
if ( na )
|
|
{
|
|
/* first remove index (old object id needed) */
|
|
xo = open_object_id_index( ni->vol );
|
|
if ( xo )
|
|
{
|
|
oldsize = remove_object_id_index( na, xo,
|
|
&old_attr );
|
|
if ( oldsize < 0 )
|
|
{
|
|
res = -1;
|
|
}
|
|
else
|
|
{
|
|
/* now remove attribute */
|
|
res = ntfs_attr_rm( na );
|
|
if ( res
|
|
&& ( oldsize > ( int )sizeof( GUID ) ) )
|
|
{
|
|
/*
|
|
* If we could not remove the
|
|
* attribute, try to restore the
|
|
* index and log the error. There
|
|
* will be an inconsistency if
|
|
* the reindexing fails.
|
|
*/
|
|
set_object_id_index( ni, xo,
|
|
&old_attr );
|
|
ntfs_log_error(
|
|
"Failed to remove object id."
|
|
" Possible corruption.\n" );
|
|
}
|
|
}
|
|
|
|
xoni = xo->ni;
|
|
ntfs_index_entry_mark_dirty( xo );
|
|
NInoSetDirty( xoni );
|
|
ntfs_index_ctx_put( xo );
|
|
ntfs_inode_close( xoni );
|
|
}
|
|
olderrno = errno;
|
|
ntfs_attr_close( na );
|
|
/* avoid errno pollution */
|
|
if ( errno == ENOENT )
|
|
errno = olderrno;
|
|
}
|
|
else
|
|
{
|
|
errno = ENODATA;
|
|
res = -1;
|
|
}
|
|
NInoSetDirty( ni );
|
|
}
|
|
else
|
|
{
|
|
errno = EINVAL;
|
|
res = -1;
|
|
}
|
|
return ( res ? -1 : 0 );
|
|
}
|
|
|
|
#endif /* HAVE_SETXATTR */
|