summaryrefslogtreecommitdiff
Diffstat
-rwxr-xr-xAUTHORS23
-rwxr-xr-xAndroid.mk89
-rwxr-xr-xAndroid.mk.bak89
-rwxr-xr-xCOPYING340
-rwxr-xr-xCOPYING.LIB482
-rwxr-xr-xCREDITS41
-rwxr-xr-xChangeLog7
-rwxr-xr-xINSTALL237
-rwxr-xr-xMakefile715
-rwxr-xr-xMakefile.am66
-rwxr-xr-xMakefile.in722
-rwxr-xr-xNEWS5
-rwxr-xr-xREADME68
-rwxr-xr-xaclocal.m47723
-rwxr-xr-xautogen.sh22
-rwxr-xr-xcompile142
-rwxr-xr-xconfig.guess1536
-rwxr-xr-xconfig.h361
-rwxr-xr-xconfig.h.in350
-rwxr-xr-xconfig.log3290
-rwxr-xr-xconfig.status1220
-rwxr-xr-xconfig.sub1658
-rwxr-xr-xconfigure25302
-rwxr-xr-xconfigure.ac441
-rwxr-xr-xdepcomp589
-rwxr-xr-xinclude/Makefile.am4
-rwxr-xr-xinclude/Makefile.in503
-rwxr-xr-xinclude/fuse-lite/Makefile.am10
-rwxr-xr-xinclude/fuse-lite/Makefile.in400
-rwxr-xr-xinclude/fuse-lite/fuse.h654
-rwxr-xr-xinclude/fuse-lite/fuse_common.h193
-rwxr-xr-xinclude/fuse-lite/fuse_kernel.h422
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel.h1375
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel_compat.h16
-rwxr-xr-xinclude/fuse-lite/fuse_opt.h261
-rwxr-xr-xinclude/ntfs-3g/Makefile.am45
-rwxr-xr-xinclude/ntfs-3g/Makefile.in471
-rwxr-xr-xinclude/ntfs-3g/acls.h199
-rwxr-xr-xinclude/ntfs-3g/attrib.h358
-rwxr-xr-xinclude/ntfs-3g/attrlist.h51
-rwxr-xr-xinclude/ntfs-3g/bitmap.h96
-rwxr-xr-xinclude/ntfs-3g/bootsect.h42
-rwxr-xr-xinclude/ntfs-3g/cache.h115
-rwxr-xr-xinclude/ntfs-3g/collate.h34
-rwxr-xr-xinclude/ntfs-3g/compat.h69
-rwxr-xr-xinclude/ntfs-3g/compress.h39
-rwxr-xr-xinclude/ntfs-3g/debug.h47
-rwxr-xr-xinclude/ntfs-3g/device.h128
-rwxr-xr-xinclude/ntfs-3g/device_io.h77
-rwxr-xr-xinclude/ntfs-3g/dir.h128
-rwxr-xr-xinclude/ntfs-3g/efs.h30
-rwxr-xr-xinclude/ntfs-3g/endians.h203
-rwxr-xr-xinclude/ntfs-3g/index.h167
-rwxr-xr-xinclude/ntfs-3g/inode.h225
-rwxr-xr-xinclude/ntfs-3g/layout.h2661
-rwxr-xr-xinclude/ntfs-3g/lcnalloc.h50
-rwxr-xr-xinclude/ntfs-3g/logfile.h394
-rwxr-xr-xinclude/ntfs-3g/logging.h118
-rwxr-xr-xinclude/ntfs-3g/mft.h132
-rwxr-xr-xinclude/ntfs-3g/misc.h30
-rwxr-xr-xinclude/ntfs-3g/mst.h34
-rwxr-xr-xinclude/ntfs-3g/ntfstime.h131
-rwxr-xr-xinclude/ntfs-3g/object_id.h35
-rwxr-xr-xinclude/ntfs-3g/param.h63
-rwxr-xr-xinclude/ntfs-3g/reparse.h39
-rwxr-xr-xinclude/ntfs-3g/runlist.h89
-rwxr-xr-xinclude/ntfs-3g/security.h353
-rwxr-xr-xinclude/ntfs-3g/support.h85
-rwxr-xr-xinclude/ntfs-3g/types.h124
-rwxr-xr-xinclude/ntfs-3g/unistr.h116
-rwxr-xr-xinclude/ntfs-3g/volume.h277
-rwxr-xr-xinstall-sh519
-rwxr-xr-xlibfuse-lite/Makefile.am28
-rwxr-xr-xlibfuse-lite/Makefile.in572
-rwxr-xr-xlibfuse-lite/fuse.c2789
-rwxr-xr-xlibfuse-lite/fuse_i.h25
-rwxr-xr-xlibfuse-lite/fuse_kern_chan.c96
-rwxr-xr-xlibfuse-lite/fuse_loop.c40
-rwxr-xr-xlibfuse-lite/fuse_lowlevel.c1395
-rwxr-xr-xlibfuse-lite/fuse_misc.h106
-rwxr-xr-xlibfuse-lite/fuse_opt.c368
-rwxr-xr-xlibfuse-lite/fuse_session.c183
-rwxr-xr-xlibfuse-lite/fuse_signals.c73
-rwxr-xr-xlibfuse-lite/fusermount.c772
-rwxr-xr-xlibfuse-lite/helper.c40
-rwxr-xr-xlibfuse-lite/mount.c256
-rwxr-xr-xlibfuse-lite/mount_util.c219
-rwxr-xr-xlibfuse-lite/mount_util.h22
-rwxr-xr-xlibntfs-3g/Makefile.am79
-rwxr-xr-xlibntfs-3g/Makefile.in841
-rwxr-xr-xlibntfs-3g/acls.c4296
-rwxr-xr-xlibntfs-3g/attrib.c5913
-rwxr-xr-xlibntfs-3g/attrlist.c314
-rwxr-xr-xlibntfs-3g/bitmap.c300
-rwxr-xr-xlibntfs-3g/bootsect.c285
-rwxr-xr-xlibntfs-3g/cache.c609
-rwxr-xr-xlibntfs-3g/collate.c271
-rwxr-xr-xlibntfs-3g/compat.c250
-rwxr-xr-xlibntfs-3g/compress.c1431
-rwxr-xr-xlibntfs-3g/debug.c79
-rwxr-xr-xlibntfs-3g/device.c730
-rwxr-xr-xlibntfs-3g/dir.c2582
-rwxr-xr-xlibntfs-3g/efs.c346
-rwxr-xr-xlibntfs-3g/index.c2063
-rwxr-xr-xlibntfs-3g/inode.c1566
-rwxr-xr-xlibntfs-3g/lcnalloc.c735
-rwxr-xr-xlibntfs-3g/libntfs-3g.pc.in10
-rwxr-xr-xlibntfs-3g/libntfs-3g.script.so.in2
-rwxr-xr-xlibntfs-3g/logfile.c737
-rwxr-xr-xlibntfs-3g/logging.c613
-rwxr-xr-xlibntfs-3g/mft.c1909
-rwxr-xr-xlibntfs-3g/misc.c61
-rwxr-xr-xlibntfs-3g/mst.c231
-rwxr-xr-xlibntfs-3g/object_id.c637
-rwxr-xr-xlibntfs-3g/reparse.c1222
-rwxr-xr-xlibntfs-3g/runlist.c2166
-rwxr-xr-xlibntfs-3g/security.c5167
-rwxr-xr-xlibntfs-3g/unistr.c1321
-rwxr-xr-xlibntfs-3g/unix_io.c386
-rwxr-xr-xlibntfs-3g/volume.c1663
-rwxr-xr-xlibntfs-3g/win32_io.c1477
-rwxr-xr-xlibtool7621
-rwxr-xr-xltmain.sh6956
-rwxr-xr-xm4/.keep0
-rwxr-xr-xmissing367
-rwxr-xr-xprog.IAB1071
-rwxr-xr-xprog.IAD5
-rwxr-xr-xprog.IMB466
-rwxr-xr-xprog.IMD2
-rwxr-xr-xprog.PFI2
-rwxr-xr-xprog.PO1
-rwxr-xr-xprog.PR14
-rwxr-xr-xprog.PRI219
-rwxr-xr-xprog.PS979
-rwxr-xr-xprog.SearchResults3
-rwxr-xr-xprog.WK39
-rwxr-xr-xsrc/lowntfs-3g.c4492
-rwxr-xr-xsrc/ntfs-3g.8.in349
-rwxr-xr-xsrc/ntfs-3g.c4461
-rwxr-xr-xsrc/ntfs-3g.probe.8.in81
-rwxr-xr-xsrc/ntfs-3g.probe.c163
-rwxr-xr-xsrc/ntfs-3g.secaudit.8.in171
-rwxr-xr-xsrc/ntfs-3g.usermap.8.in96
-rwxr-xr-xsrc/secaudit.c7176
-rwxr-xr-xsrc/secaudit.h731
-rwxr-xr-xsrc/test.c88
-rwxr-xr-xsrc/usermap.c1356
-rwxr-xr-xstamp-h11
148 files changed, 141286 insertions, 0 deletions
diff --git a/libntfs-3g/object_id.c b/libntfs-3g/object_id.c
new file mode 100755
index 0000000..555dd13
--- a/dev/null
+++ b/libntfs-3g/object_id.c
@@ -0,0 +1,637 @@
+/**
+ * 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 */