From 9e92184b7c0caaf16f66f124550e006bfad3e41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Fri, 22 Dec 2017 11:24:58 +0100 Subject: [PATCH] Allowed setting a file object id without defining its birth ids Object ids can be used to locate files which have been move to another volume. This is only possible when the birth ids are recorded, but in most cases files reside on their birth volume and their birth ids are not set. The patch enables setting a file id without changing its birth id, by setting an extended attribute "system.ntfs_object_id" limited to 16 bytes. --- libntfs-3g/object_id.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/libntfs-3g/object_id.c b/libntfs-3g/object_id.c index bd72d026..b7cc77cc 100644 --- a/libntfs-3g/object_id.c +++ b/libntfs-3g/object_id.c @@ -3,7 +3,7 @@ * * This module is part of ntfs-3g library * - * Copyright (c) 2009 Jean-Pierre Andre + * Copyright (c) 2009-2017 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 @@ -63,9 +63,13 @@ * significant byte first, and the six fields be compared individually * for ordering. RFC 4122 does not define the internal representation. * + * Windows apparently stores the first three fields in little endian + * order, and the last two fields in big endian order. + * * 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. + * of four little-endian unsigned 32 bit integers (as Windows + * does it that way.) * * --------------------- begin from RFC 4122 ---------------------- * Consider each field of the UUID to be an unsigned integer as shown @@ -349,10 +353,12 @@ static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, res = -1; } } - /* write index part if provided */ + /* overwrite index data with new value */ + memcpy(&old_attr, value, + (size < sizeof(OBJECT_ID_ATTR) + ? size : sizeof(OBJECT_ID_ATTR))); if (!res - && ((size < sizeof(OBJECT_ID_ATTR)) - || set_object_id_index(ni,xo,value))) { + && set_object_id_index(ni,xo,&old_attr)) { /* * If cannot index, try to remove the object * id and log the error. There will be an @@ -500,9 +506,11 @@ int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size) /* * 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. + * The first 16 bytes are the new object id, they can be followed + * by the birth volume id, the birth object id and the domain id. + * If they are not present, their previous value is kept. + * Only the object id is stored into the attribute, all the fields + * are stored into the index. * * Returns 0, or -1 if there is a problem */ @@ -519,10 +527,12 @@ int ntfs_set_ntfs_object_id(ntfs_inode *ni, if (ni && value && (size >= sizeof(GUID))) { xo = open_object_id_index(ni->vol); if (xo) { - /* make sure the GUID was not used somewhere */ + /* make sure the GUID was not used elsewhere */ memcpy(&key.object_id, value, sizeof(GUID)); - if (ntfs_index_lookup(&key, - sizeof(OBJECT_ID_INDEX_KEY), xo)) { + if ((ntfs_index_lookup(&key, + sizeof(OBJECT_ID_INDEX_KEY), xo)) + || (MREF_LE(((struct OBJECT_ID_INDEX*)xo->entry) + ->data.file_id) == ni->mft_no)) { ntfs_index_ctx_reinit(xo); res = add_object_id(ni, flags); if (!res) {