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
set_object_id_index(ntfs_inode * ni,ntfs_index_context * xo,const OBJECT_ID_ATTR * object_id)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
open_object_id_index(ntfs_volume * vol)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
merge_index_data(ntfs_inode * ni,const OBJECT_ID_ATTR * objectid_attr,OBJECT_ID_ATTR * full_objectid)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
remove_object_id_index(ntfs_attr * na,ntfs_index_context * xo,OBJECT_ID_ATTR * old_attr)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
update_object_id(ntfs_inode * ni,ntfs_index_context * xo,const OBJECT_ID_ATTR * value,size_t size)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
add_object_id(ntfs_inode * ni,int flags)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
ntfs_delete_object_id_index(ntfs_inode * ni)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
ntfs_get_ntfs_object_id(ntfs_inode * ni,char * value,size_t size)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
ntfs_set_ntfs_object_id(ntfs_inode * ni,const char * value,size_t size,int flags)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
ntfs_remove_ntfs_object_id(ntfs_inode * ni)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