1 /** 2 * object_id.c - Processing of object ids 3 * 4 * This module is part of ntfs-3g library 5 * 6 * Copyright (c) 2009 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 41 #ifdef HAVE_SETXATTR 42 #include <sys/xattr.h> 43 #endif 44 45 #ifdef HAVE_SYS_SYSMACROS_H 46 #include <sys/sysmacros.h> 47 #endif 48 49 #include "compat.h" 50 #include "types.h" 51 #include "debug.h" 52 #include "attrib.h" 53 #include "inode.h" 54 #include "dir.h" 55 #include "volume.h" 56 #include "mft.h" 57 #include "index.h" 58 #include "lcnalloc.h" 59 #include "object_id.h" 60 #include "logging.h" 61 #include "misc.h" 62 63 /* 64 * Endianness considerations 65 * 66 * According to RFC 4122, GUIDs should be printed with the most 67 * significant byte first, and the six fields be compared individually 68 * for ordering. RFC 4122 does not define the internal representation. 69 * 70 * Here we always copy disk images with no endianness change, 71 * and, for indexing, GUIDs are compared as if they were a sequence 72 * of four unsigned 32 bit integers. 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 #ifdef HAVE_SETXATTR /* extended attributes interface required */ 134 135 /* 136 * Set the index for a new object id 137 * 138 * Returns 0 if success 139 * -1 if failure, explained by errno 140 */ 141 142 static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo, 143 const OBJECT_ID_ATTR *object_id) 144 { 145 struct OBJECT_ID_INDEX indx; 146 u64 file_id_cpu; 147 le64 file_id; 148 le16 seqn; 149 150 seqn = ni->mrec->sequence_number; 151 file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn)); 152 file_id = cpu_to_le64(file_id_cpu); 153 indx.header.data_offset = const_cpu_to_le16( 154 sizeof(INDEX_ENTRY_HEADER) 155 + sizeof(OBJECT_ID_INDEX_KEY)); 156 indx.header.data_length = const_cpu_to_le16( 157 sizeof(OBJECT_ID_INDEX_DATA)); 158 indx.header.reservedV = const_cpu_to_le32(0); 159 indx.header.length = const_cpu_to_le16( 160 sizeof(struct OBJECT_ID_INDEX)); 161 indx.header.key_length = const_cpu_to_le16( 162 sizeof(OBJECT_ID_INDEX_KEY)); 163 indx.header.flags = const_cpu_to_le16(0); 164 indx.header.reserved = const_cpu_to_le16(0); 165 166 memcpy(&indx.key.object_id,object_id,sizeof(GUID)); 167 168 indx.data.file_id = file_id; 169 memcpy(&indx.data.birth_volume_id, 170 &object_id->birth_volume_id,sizeof(GUID)); 171 memcpy(&indx.data.birth_object_id, 172 &object_id->birth_object_id,sizeof(GUID)); 173 memcpy(&indx.data.domain_id, 174 &object_id->domain_id,sizeof(GUID)); 175 ntfs_index_ctx_reinit(xo); 176 return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx)); 177 } 178 179 #endif /* HAVE_SETXATTR */ 180 181 /* 182 * Open the $Extend/$ObjId file and its index 183 * 184 * Return the index context if opened 185 * or NULL if an error occurred (errno tells why) 186 * 187 * The index has to be freed and inode closed when not needed any more. 188 */ 189 190 static ntfs_index_context *open_object_id_index(ntfs_volume *vol) 191 { 192 u64 inum; 193 ntfs_inode *ni; 194 ntfs_inode *dir_ni; 195 ntfs_index_context *xo; 196 197 /* do not use path_name_to inode - could reopen root */ 198 dir_ni = ntfs_inode_open(vol, FILE_Extend); 199 ni = (ntfs_inode*)NULL; 200 if (dir_ni) { 201 inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId"); 202 if (inum != (u64)-1) 203 ni = ntfs_inode_open(vol, inum); 204 ntfs_inode_close(dir_ni); 205 } 206 if (ni) { 207 xo = ntfs_index_ctx_get(ni, objid_index_name, 2); 208 if (!xo) { 209 ntfs_inode_close(ni); 210 } 211 } else 212 xo = (ntfs_index_context*)NULL; 213 return (xo); 214 } 215 216 #ifdef HAVE_SETXATTR /* extended attributes interface required */ 217 218 /* 219 * Merge object_id data stored in the index into 220 * a full object_id struct. 221 * 222 * returns 0 if merging successful 223 * -1 if no data could be merged. This is generally not an error 224 */ 225 226 static int merge_index_data(ntfs_inode *ni, 227 const OBJECT_ID_ATTR *objectid_attr, 228 OBJECT_ID_ATTR *full_objectid) 229 { 230 OBJECT_ID_INDEX_KEY key; 231 struct OBJECT_ID_INDEX *entry; 232 ntfs_index_context *xo; 233 ntfs_inode *xoni; 234 int res; 235 236 res = -1; 237 xo = open_object_id_index(ni->vol); 238 if (xo) { 239 memcpy(&key.object_id,objectid_attr,sizeof(GUID)); 240 if (!ntfs_index_lookup(&key, 241 sizeof(OBJECT_ID_INDEX_KEY), xo)) { 242 entry = (struct OBJECT_ID_INDEX*)xo->entry; 243 /* make sure inode numbers match */ 244 if (entry 245 && (MREF(le64_to_cpu(entry->data.file_id)) 246 == ni->mft_no)) { 247 memcpy(&full_objectid->birth_volume_id, 248 &entry->data.birth_volume_id, 249 sizeof(GUID)); 250 memcpy(&full_objectid->birth_object_id, 251 &entry->data.birth_object_id, 252 sizeof(GUID)); 253 memcpy(&full_objectid->domain_id, 254 &entry->data.domain_id, 255 sizeof(GUID)); 256 res = 0; 257 } 258 } 259 xoni = xo->ni; 260 ntfs_index_ctx_put(xo); 261 ntfs_inode_close(xoni); 262 } 263 return (res); 264 } 265 266 #endif /* HAVE_SETXATTR */ 267 268 /* 269 * Remove an object id index entry if attribute present 270 * 271 * Returns the size of existing object id 272 * (the existing object_d is returned) 273 * -1 if failure, explained by errno 274 */ 275 276 static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo, 277 OBJECT_ID_ATTR *old_attr) 278 { 279 OBJECT_ID_INDEX_KEY key; 280 struct OBJECT_ID_INDEX *entry; 281 s64 size; 282 int ret; 283 284 ret = na->data_size; 285 if (ret) { 286 /* read the existing object id attribute */ 287 size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr); 288 if (size >= (s64)sizeof(GUID)) { 289 memcpy(&key.object_id, 290 &old_attr->object_id,sizeof(GUID)); 291 if (!ntfs_index_lookup(&key, 292 sizeof(OBJECT_ID_INDEX_KEY), xo)) { 293 entry = (struct OBJECT_ID_INDEX*)xo->entry; 294 memcpy(&old_attr->birth_volume_id, 295 &entry->data.birth_volume_id, 296 sizeof(GUID)); 297 memcpy(&old_attr->birth_object_id, 298 &entry->data.birth_object_id, 299 sizeof(GUID)); 300 memcpy(&old_attr->domain_id, 301 &entry->data.domain_id, 302 sizeof(GUID)); 303 if (ntfs_index_rm(xo)) 304 ret = -1; 305 } 306 } else { 307 ret = -1; 308 errno = ENODATA; 309 } 310 } 311 return (ret); 312 } 313 314 #ifdef HAVE_SETXATTR /* extended attributes interface required */ 315 316 /* 317 * Update the object id and index 318 * 319 * The object_id attribute should have been created and the 320 * non-duplication of the GUID should have been checked before. 321 * 322 * Returns 0 if success 323 * -1 if failure, explained by errno 324 * If could not remove the existing index, nothing is done, 325 * If could not write the new data, no index entry is inserted 326 * If failed to insert the index, data is removed 327 */ 328 329 static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, 330 const OBJECT_ID_ATTR *value, size_t size) 331 { 332 OBJECT_ID_ATTR old_attr; 333 ntfs_attr *na; 334 int oldsize; 335 int written; 336 int res; 337 338 res = 0; 339 340 na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); 341 if (na) { 342 343 /* remove the existing index entry */ 344 oldsize = remove_object_id_index(na,xo,&old_attr); 345 if (oldsize < 0) 346 res = -1; 347 else { 348 /* resize attribute */ 349 res = ntfs_attr_truncate(na, (s64)sizeof(GUID)); 350 /* write the object_id in attribute */ 351 if (!res && value) { 352 written = (int)ntfs_attr_pwrite(na, 353 (s64)0, (s64)sizeof(GUID), 354 &value->object_id); 355 if (written != (s64)sizeof(GUID)) { 356 ntfs_log_error("Failed to update " 357 "object id\n"); 358 errno = EIO; 359 res = -1; 360 } 361 } 362 /* write index part if provided */ 363 if (!res 364 && ((size < sizeof(OBJECT_ID_ATTR)) 365 || set_object_id_index(ni,xo,value))) { 366 /* 367 * If cannot index, try to remove the object 368 * id and log the error. There will be an 369 * inconsistency if removal fails. 370 */ 371 ntfs_attr_rm(na); 372 ntfs_log_error("Failed to index object id." 373 " Possible corruption.\n"); 374 } 375 } 376 ntfs_attr_close(na); 377 NInoSetDirty(ni); 378 } else 379 res = -1; 380 return (res); 381 } 382 383 /* 384 * Add a (dummy) object id to an inode if it does not exist 385 * 386 * returns 0 if attribute was inserted (or already present) 387 * -1 if adding failed (explained by errno) 388 */ 389 390 static int add_object_id(ntfs_inode *ni, int flags) 391 { 392 int res; 393 u8 dummy; 394 395 res = -1; /* default return */ 396 if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) { 397 if (!(flags & XATTR_REPLACE)) { 398 /* 399 * no object id attribute : add one, 400 * apparently, this does not feed the new value in 401 * Note : NTFS version must be >= 3 402 */ 403 if (ni->vol->major_ver >= 3) { 404 res = ntfs_attr_add(ni, AT_OBJECT_ID, 405 AT_UNNAMED, 0, &dummy, (s64)0); 406 NInoSetDirty(ni); 407 } else 408 errno = EOPNOTSUPP; 409 } else 410 errno = ENODATA; 411 } else { 412 if (flags & XATTR_CREATE) 413 errno = EEXIST; 414 else 415 res = 0; 416 } 417 return (res); 418 } 419 420 #endif /* HAVE_SETXATTR */ 421 422 /* 423 * Delete an object_id index entry 424 * 425 * Returns 0 if success 426 * -1 if failure, explained by errno 427 */ 428 429 int ntfs_delete_object_id_index(ntfs_inode *ni) 430 { 431 ntfs_index_context *xo; 432 ntfs_inode *xoni; 433 ntfs_attr *na; 434 OBJECT_ID_ATTR old_attr; 435 int res; 436 437 res = 0; 438 na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); 439 if (na) { 440 /* 441 * read the existing object id 442 * and un-index it 443 */ 444 xo = open_object_id_index(ni->vol); 445 if (xo) { 446 if (remove_object_id_index(na,xo,&old_attr) < 0) 447 res = -1; 448 xoni = xo->ni; 449 ntfs_index_entry_mark_dirty(xo); 450 NInoSetDirty(xoni); 451 ntfs_index_ctx_put(xo); 452 ntfs_inode_close(xoni); 453 } 454 ntfs_attr_close(na); 455 } 456 return (res); 457 } 458 459 #ifdef HAVE_SETXATTR /* extended attributes interface required */ 460 461 /* 462 * Get the ntfs object id into an extended attribute 463 * 464 * If present, the object_id from the attribute and the GUIDs 465 * from the index are returned (formatted as OBJECT_ID_ATTR) 466 * 467 * Returns the global size (can be 0, 16 or 64) 468 * and the buffer is updated if it is long enough 469 */ 470 471 int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size) 472 { 473 OBJECT_ID_ATTR full_objectid; 474 OBJECT_ID_ATTR *objectid_attr; 475 s64 attr_size; 476 int full_size; 477 478 full_size = 0; /* default to no data and some error to be defined */ 479 if (ni) { 480 objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni, 481 AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size); 482 if (objectid_attr) { 483 /* restrict to only GUID present in attr */ 484 if (attr_size == sizeof(GUID)) { 485 memcpy(&full_objectid.object_id, 486 objectid_attr,sizeof(GUID)); 487 full_size = sizeof(GUID); 488 /* get data from index, if any */ 489 if (!merge_index_data(ni, objectid_attr, 490 &full_objectid)) { 491 full_size = sizeof(OBJECT_ID_ATTR); 492 } 493 if (full_size <= (s64)size) { 494 if (value) 495 memcpy(value,&full_objectid, 496 full_size); 497 else 498 errno = EINVAL; 499 } 500 } else { 501 /* unexpected size, better return unsupported */ 502 errno = EOPNOTSUPP; 503 full_size = 0; 504 } 505 free(objectid_attr); 506 } else 507 errno = ENODATA; 508 } 509 return (full_size ? (int)full_size : -errno); 510 } 511 512 /* 513 * Set the object id from an extended attribute 514 * 515 * If the size is 64, the attribute and index are set. 516 * else if the size is not less than 16 only the attribute is set. 517 * The object id index is set accordingly. 518 * 519 * Returns 0, or -1 if there is a problem 520 */ 521 522 int ntfs_set_ntfs_object_id(ntfs_inode *ni, 523 const char *value, size_t size, int flags) 524 { 525 OBJECT_ID_INDEX_KEY key; 526 ntfs_inode *xoni; 527 ntfs_index_context *xo; 528 int res; 529 530 res = 0; 531 if (ni && value && (size >= sizeof(GUID))) { 532 xo = open_object_id_index(ni->vol); 533 if (xo) { 534 /* make sure the GUID was not used somewhere */ 535 memcpy(&key.object_id, value, sizeof(GUID)); 536 if (ntfs_index_lookup(&key, 537 sizeof(OBJECT_ID_INDEX_KEY), xo)) { 538 ntfs_index_ctx_reinit(xo); 539 res = add_object_id(ni, flags); 540 if (!res) { 541 /* update value and index */ 542 res = update_object_id(ni,xo, 543 (const OBJECT_ID_ATTR*)value, 544 size); 545 } 546 } else { 547 /* GUID is present elsewhere */ 548 res = -1; 549 errno = EEXIST; 550 } 551 xoni = xo->ni; 552 ntfs_index_entry_mark_dirty(xo); 553 NInoSetDirty(xoni); 554 ntfs_index_ctx_put(xo); 555 ntfs_inode_close(xoni); 556 } else { 557 res = -1; 558 } 559 } else { 560 errno = EINVAL; 561 res = -1; 562 } 563 return (res ? -1 : 0); 564 } 565 566 /* 567 * Remove the object id 568 * 569 * Returns 0, or -1 if there is a problem 570 */ 571 572 int ntfs_remove_ntfs_object_id(ntfs_inode *ni) 573 { 574 int res; 575 int olderrno; 576 ntfs_attr *na; 577 ntfs_inode *xoni; 578 ntfs_index_context *xo; 579 int oldsize; 580 OBJECT_ID_ATTR old_attr; 581 582 res = 0; 583 if (ni) { 584 /* 585 * open and delete the object id 586 */ 587 na = ntfs_attr_open(ni, AT_OBJECT_ID, 588 AT_UNNAMED,0); 589 if (na) { 590 /* first remove index (old object id needed) */ 591 xo = open_object_id_index(ni->vol); 592 if (xo) { 593 oldsize = remove_object_id_index(na,xo, 594 &old_attr); 595 if (oldsize < 0) { 596 res = -1; 597 } else { 598 /* now remove attribute */ 599 res = ntfs_attr_rm(na); 600 if (res 601 && (oldsize > (int)sizeof(GUID))) { 602 /* 603 * If we could not remove the 604 * attribute, try to restore the 605 * index and log the error. There 606 * will be an inconsistency if 607 * the reindexing fails. 608 */ 609 set_object_id_index(ni, xo, 610 &old_attr); 611 ntfs_log_error( 612 "Failed to remove object id." 613 " Possible corruption.\n"); 614 } 615 } 616 617 xoni = xo->ni; 618 ntfs_index_entry_mark_dirty(xo); 619 NInoSetDirty(xoni); 620 ntfs_index_ctx_put(xo); 621 ntfs_inode_close(xoni); 622 } 623 olderrno = errno; 624 ntfs_attr_close(na); 625 /* avoid errno pollution */ 626 if (errno == ENOENT) 627 errno = olderrno; 628 } else { 629 errno = ENODATA; 630 res = -1; 631 } 632 NInoSetDirty(ni); 633 } else { 634 errno = EINVAL; 635 res = -1; 636 } 637 return (res ? -1 : 0); 638 } 639 640 #endif /* HAVE_SETXATTR */ 641