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