1 /** 2 * object_id.c - Processing of object ids 3 * 4 * This module is part of ntfs-3g library 5 * 6 * Copyright (c) 2009-2019 Jean-Pierre Andre 7 * 8 * This program/include file is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as published 10 * by the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program/include file is distributed in the hope that it will be 14 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program (in the main directory of the NTFS-3G 20 * distribution in the file COPYING); if not, write to the Free Software 21 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include "config.h" 26 #endif 27 28 #ifdef HAVE_STDLIB_H 29 #include <stdlib.h> 30 #endif 31 #ifdef HAVE_ERRNO_H 32 #include <errno.h> 33 #endif 34 #ifdef HAVE_STRING_H 35 #include <string.h> 36 #endif 37 #ifdef HAVE_SYS_STAT_H 38 #include <sys/stat.h> 39 #endif 40 #ifdef HAVE_SYS_SYSMACROS_H 41 #include <sys/sysmacros.h> 42 #endif 43 44 #include "compat.h" 45 #include "types.h" 46 #include "debug.h" 47 #include "attrib.h" 48 #include "inode.h" 49 #include "dir.h" 50 #include "volume.h" 51 #include "mft.h" 52 #include "index.h" 53 #include "lcnalloc.h" 54 #include "object_id.h" 55 #include "logging.h" 56 #include "misc.h" 57 #include "xattrs.h" 58 59 /* 60 * Endianness considerations 61 * 62 * According to RFC 4122, GUIDs should be printed with the most 63 * significant byte first, and the six fields be compared individually 64 * for ordering. RFC 4122 does not define the internal representation. 65 * 66 * Windows apparently stores the first three fields in little endian 67 * order, and the last two fields in big endian order. 68 * 69 * Here we always copy disk images with no endianness change, 70 * and, for indexing, GUIDs are compared as if they were a sequence 71 * of four little-endian unsigned 32 bit integers (as Windows 72 * does it that way.) 73 * 74 * --------------------- begin from RFC 4122 ---------------------- 75 * Consider each field of the UUID to be an unsigned integer as shown 76 * in the table in section Section 4.1.2. Then, to compare a pair of 77 * UUIDs, arithmetically compare the corresponding fields from each 78 * UUID in order of significance and according to their data type. 79 * Two UUIDs are equal if and only if all the corresponding fields 80 * are equal. 81 * 82 * UUIDs, as defined in this document, can also be ordered 83 * lexicographically. For a pair of UUIDs, the first one follows the 84 * second if the most significant field in which the UUIDs differ is 85 * greater for the first UUID. The second precedes the first if the 86 * most significant field in which the UUIDs differ is greater for 87 * the second UUID. 88 * 89 * The fields are encoded as 16 octets, with the sizes and order of the 90 * fields defined above, and with each field encoded with the Most 91 * Significant Byte first (known as network byte order). Note that the 92 * field names, particularly for multiplexed fields, follow historical 93 * practice. 94 * 95 * 0 1 2 3 96 * 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 97 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 98 * | time_low | 99 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 100 * | time_mid | time_hi_and_version | 101 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 102 * |clk_seq_hi_res | clk_seq_low | node (0-1) | 103 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 104 * | node (2-5) | 105 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 106 * 107 * ---------------------- end from RFC 4122 ----------------------- 108 */ 109 110 typedef struct { 111 union { 112 /* alignment may be needed to evaluate collations */ 113 u32 alignment; 114 GUID guid; 115 } object_id; 116 } OBJECT_ID_INDEX_KEY; 117 118 typedef struct { 119 le64 file_id; 120 GUID birth_volume_id; 121 GUID birth_object_id; 122 GUID domain_id; 123 } OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA 124 125 struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */ 126 INDEX_ENTRY_HEADER header; 127 OBJECT_ID_INDEX_KEY key; 128 OBJECT_ID_INDEX_DATA data; 129 } ; 130 131 static ntfschar objid_index_name[] = { const_cpu_to_le16('$'), 132 const_cpu_to_le16('O') }; 133 134 /* 135 * Set the index for a new object id 136 * 137 * Returns 0 if success 138 * -1 if failure, explained by errno 139 */ 140 141 static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo, 142 const OBJECT_ID_ATTR *object_id) 143 { 144 struct OBJECT_ID_INDEX indx; 145 u64 file_id_cpu; 146 le64 file_id; 147 le16 seqn; 148 149 seqn = ni->mrec->sequence_number; 150 file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn)); 151 file_id = cpu_to_le64(file_id_cpu); 152 indx.header.data_offset = const_cpu_to_le16( 153 sizeof(INDEX_ENTRY_HEADER) 154 + sizeof(OBJECT_ID_INDEX_KEY)); 155 indx.header.data_length = const_cpu_to_le16( 156 sizeof(OBJECT_ID_INDEX_DATA)); 157 indx.header.reservedV = const_cpu_to_le32(0); 158 indx.header.length = const_cpu_to_le16( 159 sizeof(struct OBJECT_ID_INDEX)); 160 indx.header.key_length = const_cpu_to_le16( 161 sizeof(OBJECT_ID_INDEX_KEY)); 162 indx.header.flags = const_cpu_to_le16(0); 163 indx.header.reserved = const_cpu_to_le16(0); 164 165 memcpy(&indx.key.object_id,object_id,sizeof(GUID)); 166 167 indx.data.file_id = file_id; 168 memcpy(&indx.data.birth_volume_id, 169 &object_id->birth_volume_id,sizeof(GUID)); 170 memcpy(&indx.data.birth_object_id, 171 &object_id->birth_object_id,sizeof(GUID)); 172 memcpy(&indx.data.domain_id, 173 &object_id->domain_id,sizeof(GUID)); 174 ntfs_index_ctx_reinit(xo); 175 return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx)); 176 } 177 178 /* 179 * Open the $Extend/$ObjId file and its index 180 * 181 * Return the index context if opened 182 * or NULL if an error occurred (errno tells why) 183 * 184 * The index has to be freed and inode closed when not needed any more. 185 */ 186 187 static ntfs_index_context *open_object_id_index(ntfs_volume *vol) 188 { 189 u64 inum; 190 ntfs_inode *ni; 191 ntfs_inode *dir_ni; 192 ntfs_index_context *xo; 193 194 /* do not use path_name_to inode - could reopen root */ 195 dir_ni = ntfs_inode_open(vol, FILE_Extend); 196 ni = (ntfs_inode*)NULL; 197 if (dir_ni) { 198 inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId"); 199 if (inum != (u64)-1) 200 ni = ntfs_inode_open(vol, inum); 201 ntfs_inode_close(dir_ni); 202 } 203 if (ni) { 204 xo = ntfs_index_ctx_get(ni, objid_index_name, 2); 205 if (!xo) { 206 ntfs_inode_close(ni); 207 } 208 } else 209 xo = (ntfs_index_context*)NULL; 210 return (xo); 211 } 212 213 214 /* 215 * Merge object_id data stored in the index into 216 * a full object_id struct. 217 * 218 * returns 0 if merging successful 219 * -1 if no data could be merged. This is generally not an error 220 */ 221 222 static int merge_index_data(ntfs_inode *ni, 223 const OBJECT_ID_ATTR *objectid_attr, 224 OBJECT_ID_ATTR *full_objectid) 225 { 226 OBJECT_ID_INDEX_KEY key; 227 struct OBJECT_ID_INDEX *entry; 228 ntfs_index_context *xo; 229 ntfs_inode *xoni; 230 int res; 231 232 res = -1; 233 xo = open_object_id_index(ni->vol); 234 if (xo) { 235 memcpy(&key.object_id,objectid_attr,sizeof(GUID)); 236 if (!ntfs_index_lookup(&key, 237 sizeof(OBJECT_ID_INDEX_KEY), xo)) { 238 entry = (struct OBJECT_ID_INDEX*)xo->entry; 239 /* make sure inode numbers match */ 240 if (entry 241 && (MREF(le64_to_cpu(entry->data.file_id)) 242 == ni->mft_no)) { 243 memcpy(&full_objectid->birth_volume_id, 244 &entry->data.birth_volume_id, 245 sizeof(GUID)); 246 memcpy(&full_objectid->birth_object_id, 247 &entry->data.birth_object_id, 248 sizeof(GUID)); 249 memcpy(&full_objectid->domain_id, 250 &entry->data.domain_id, 251 sizeof(GUID)); 252 res = 0; 253 } 254 } 255 xoni = xo->ni; 256 ntfs_index_ctx_put(xo); 257 ntfs_inode_close(xoni); 258 } 259 return (res); 260 } 261 262 263 /* 264 * Remove an object id index entry if attribute present 265 * 266 * Returns the size of existing object id 267 * (the existing object_d is returned) 268 * -1 if failure, explained by errno 269 */ 270 271 static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo, 272 OBJECT_ID_ATTR *old_attr) 273 { 274 OBJECT_ID_INDEX_KEY key; 275 struct OBJECT_ID_INDEX *entry; 276 s64 size; 277 int ret; 278 279 ret = na->data_size; 280 if (ret) { 281 /* read the existing object id attribute */ 282 size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr); 283 if (size >= (s64)sizeof(GUID)) { 284 memcpy(&key.object_id, 285 &old_attr->object_id,sizeof(GUID)); 286 if (!ntfs_index_lookup(&key, 287 sizeof(OBJECT_ID_INDEX_KEY), xo)) { 288 entry = (struct OBJECT_ID_INDEX*)xo->entry; 289 memcpy(&old_attr->birth_volume_id, 290 &entry->data.birth_volume_id, 291 sizeof(GUID)); 292 memcpy(&old_attr->birth_object_id, 293 &entry->data.birth_object_id, 294 sizeof(GUID)); 295 memcpy(&old_attr->domain_id, 296 &entry->data.domain_id, 297 sizeof(GUID)); 298 if (ntfs_index_rm(xo)) 299 ret = -1; 300 } 301 } else { 302 ret = -1; 303 errno = ENODATA; 304 } 305 } 306 return (ret); 307 } 308 309 310 /* 311 * Update the object id and index 312 * 313 * The object_id attribute should have been created and the 314 * non-duplication of the GUID should have been checked before. 315 * 316 * Returns 0 if success 317 * -1 if failure, explained by errno 318 * If could not remove the existing index, nothing is done, 319 * If could not write the new data, no index entry is inserted 320 * If failed to insert the index, data is removed 321 */ 322 323 static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, 324 const OBJECT_ID_ATTR *value, size_t size) 325 { 326 OBJECT_ID_ATTR old_attr; 327 ntfs_attr *na; 328 int oldsize; 329 int written; 330 int res; 331 332 res = 0; 333 334 na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); 335 if (na) { 336 memset(&old_attr, 0, sizeof(OBJECT_ID_ATTR)); 337 /* remove the existing index entry */ 338 oldsize = remove_object_id_index(na,xo,&old_attr); 339 if (oldsize < 0) 340 res = -1; 341 else { 342 /* resize attribute */ 343 res = ntfs_attr_truncate(na, (s64)sizeof(GUID)); 344 /* write the object_id in attribute */ 345 if (!res && value) { 346 written = (int)ntfs_attr_pwrite(na, 347 (s64)0, (s64)sizeof(GUID), 348 &value->object_id); 349 if (written != (s64)sizeof(GUID)) { 350 ntfs_log_error("Failed to update " 351 "object id\n"); 352 errno = EIO; 353 res = -1; 354 } 355 } 356 /* overwrite index data with new value */ 357 memcpy(&old_attr, value, 358 (size < sizeof(OBJECT_ID_ATTR) 359 ? size : sizeof(OBJECT_ID_ATTR))); 360 if (!res 361 && set_object_id_index(ni,xo,&old_attr)) { 362 /* 363 * If cannot index, try to remove the object 364 * id and log the error. There will be an 365 * inconsistency if removal fails. 366 */ 367 ntfs_attr_rm(na); 368 ntfs_log_error("Failed to index object id." 369 " Possible corruption.\n"); 370 } 371 } 372 ntfs_attr_close(na); 373 NInoSetDirty(ni); 374 } else 375 res = -1; 376 return (res); 377 } 378 379 /* 380 * Add a (dummy) object id to an inode if it does not exist 381 * 382 * returns 0 if attribute was inserted (or already present) 383 * -1 if adding failed (explained by errno) 384 */ 385 386 static int add_object_id(ntfs_inode *ni, int flags) 387 { 388 int res; 389 u8 dummy; 390 391 res = -1; /* default return */ 392 if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) { 393 if (!(flags & XATTR_REPLACE)) { 394 /* 395 * no object id attribute : add one, 396 * apparently, this does not feed the new value in 397 * Note : NTFS version must be >= 3 398 */ 399 if (ni->vol->major_ver >= 3) { 400 res = ntfs_attr_add(ni, AT_OBJECT_ID, 401 AT_UNNAMED, 0, &dummy, (s64)0); 402 NInoSetDirty(ni); 403 } else 404 errno = EOPNOTSUPP; 405 } else 406 errno = ENODATA; 407 } else { 408 if (flags & XATTR_CREATE) 409 errno = EEXIST; 410 else 411 res = 0; 412 } 413 return (res); 414 } 415 416 417 /* 418 * Delete an object_id index entry 419 * 420 * Returns 0 if success 421 * -1 if failure, explained by errno 422 */ 423 424 int ntfs_delete_object_id_index(ntfs_inode *ni) 425 { 426 ntfs_index_context *xo; 427 ntfs_inode *xoni; 428 ntfs_attr *na; 429 OBJECT_ID_ATTR old_attr; 430 int res; 431 432 res = 0; 433 na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); 434 if (na) { 435 /* 436 * read the existing object id 437 * and un-index it 438 */ 439 xo = open_object_id_index(ni->vol); 440 if (xo) { 441 if (remove_object_id_index(na,xo,&old_attr) < 0) 442 res = -1; 443 xoni = xo->ni; 444 ntfs_index_entry_mark_dirty(xo); 445 NInoSetDirty(xoni); 446 ntfs_index_ctx_put(xo); 447 ntfs_inode_close(xoni); 448 } 449 ntfs_attr_close(na); 450 } 451 return (res); 452 } 453 454 455 /* 456 * Get the ntfs object id into an extended attribute 457 * 458 * If present, the object_id from the attribute and the GUIDs 459 * from the index are returned (formatted as OBJECT_ID_ATTR) 460 * 461 * Returns the global size (can be 0, 16 or 64) 462 * and the buffer is updated if it is long enough 463 */ 464 465 int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size) 466 { 467 OBJECT_ID_ATTR full_objectid; 468 OBJECT_ID_ATTR *objectid_attr; 469 s64 attr_size; 470 int full_size; 471 472 full_size = 0; /* default to no data and some error to be defined */ 473 if (ni) { 474 objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni, 475 AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size); 476 if (objectid_attr) { 477 /* restrict to only GUID present in attr */ 478 if (attr_size == sizeof(GUID)) { 479 memcpy(&full_objectid.object_id, 480 objectid_attr,sizeof(GUID)); 481 full_size = sizeof(GUID); 482 /* get data from index, if any */ 483 if (!merge_index_data(ni, objectid_attr, 484 &full_objectid)) { 485 full_size = sizeof(OBJECT_ID_ATTR); 486 } 487 if (full_size <= (s64)size) { 488 if (value) 489 memcpy(value,&full_objectid, 490 full_size); 491 else 492 errno = EINVAL; 493 } 494 } else { 495 /* unexpected size, better return unsupported */ 496 errno = EOPNOTSUPP; 497 full_size = 0; 498 } 499 free(objectid_attr); 500 } else 501 errno = ENODATA; 502 } 503 return (full_size ? (int)full_size : -errno); 504 } 505 506 /* 507 * Set the object id from an extended attribute 508 * 509 * The first 16 bytes are the new object id, they can be followed 510 * by the birth volume id, the birth object id and the domain id. 511 * If they are not present, their previous value is kept. 512 * Only the object id is stored into the attribute, all the fields 513 * are stored into the index. 514 * 515 * Returns 0, or -1 if there is a problem 516 */ 517 518 int ntfs_set_ntfs_object_id(ntfs_inode *ni, 519 const char *value, size_t size, int flags) 520 { 521 OBJECT_ID_INDEX_KEY key; 522 ntfs_inode *xoni; 523 ntfs_index_context *xo; 524 int res; 525 526 res = 0; 527 if (ni && value && (size >= sizeof(GUID))) { 528 xo = open_object_id_index(ni->vol); 529 if (xo) { 530 /* make sure the GUID was not used elsewhere */ 531 memcpy(&key.object_id, value, sizeof(GUID)); 532 if ((ntfs_index_lookup(&key, 533 sizeof(OBJECT_ID_INDEX_KEY), xo)) 534 || (MREF_LE(((struct OBJECT_ID_INDEX*)xo->entry) 535 ->data.file_id) == ni->mft_no)) { 536 ntfs_index_ctx_reinit(xo); 537 res = add_object_id(ni, flags); 538 if (!res) { 539 /* update value and index */ 540 res = update_object_id(ni,xo, 541 (const OBJECT_ID_ATTR*)value, 542 size); 543 } 544 } else { 545 /* GUID is present elsewhere */ 546 res = -1; 547 errno = EEXIST; 548 } 549 xoni = xo->ni; 550 ntfs_index_entry_mark_dirty(xo); 551 NInoSetDirty(xoni); 552 ntfs_index_ctx_put(xo); 553 ntfs_inode_close(xoni); 554 } else { 555 res = -1; 556 } 557 } else { 558 errno = EINVAL; 559 res = -1; 560 } 561 return (res ? -1 : 0); 562 } 563 564 /* 565 * Remove the object id 566 * 567 * Returns 0, or -1 if there is a problem 568 */ 569 570 int ntfs_remove_ntfs_object_id(ntfs_inode *ni) 571 { 572 int res; 573 int olderrno; 574 ntfs_attr *na; 575 ntfs_inode *xoni; 576 ntfs_index_context *xo; 577 int oldsize; 578 OBJECT_ID_ATTR old_attr; 579 580 res = 0; 581 if (ni) { 582 /* 583 * open and delete the object id 584 */ 585 na = ntfs_attr_open(ni, AT_OBJECT_ID, 586 AT_UNNAMED,0); 587 if (na) { 588 /* first remove index (old object id needed) */ 589 xo = open_object_id_index(ni->vol); 590 if (xo) { 591 oldsize = remove_object_id_index(na,xo, 592 &old_attr); 593 if (oldsize < 0) { 594 res = -1; 595 } else { 596 /* now remove attribute */ 597 res = ntfs_attr_rm(na); 598 if (res 599 && (oldsize > (int)sizeof(GUID))) { 600 /* 601 * If we could not remove the 602 * attribute, try to restore the 603 * index and log the error. There 604 * will be an inconsistency if 605 * the reindexing fails. 606 */ 607 set_object_id_index(ni, xo, 608 &old_attr); 609 ntfs_log_error( 610 "Failed to remove object id." 611 " Possible corruption.\n"); 612 } 613 } 614 615 xoni = xo->ni; 616 ntfs_index_entry_mark_dirty(xo); 617 NInoSetDirty(xoni); 618 ntfs_index_ctx_put(xo); 619 ntfs_inode_close(xoni); 620 } 621 olderrno = errno; 622 ntfs_attr_close(na); 623 /* avoid errno pollution */ 624 if (errno == ENOENT) 625 errno = olderrno; 626 } else { 627 errno = ENODATA; 628 res = -1; 629 } 630 NInoSetDirty(ni); 631 } else { 632 errno = EINVAL; 633 res = -1; 634 } 635 return (res ? -1 : 0); 636 } 637