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 
set_object_id_index(ntfs_inode * ni,ntfs_index_context * xo,const OBJECT_ID_ATTR * object_id)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 
open_object_id_index(ntfs_volume * vol)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 
merge_index_data(ntfs_inode * ni,const OBJECT_ID_ATTR * objectid_attr,OBJECT_ID_ATTR * full_objectid)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 
remove_object_id_index(ntfs_attr * na,ntfs_index_context * xo,OBJECT_ID_ATTR * old_attr)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 = ENOATTR;
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 
update_object_id(ntfs_inode * ni,ntfs_index_context * xo,const OBJECT_ID_ATTR * value,size_t size)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 
add_object_id(ntfs_inode * ni,int flags)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 = ENOATTR;
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 
ntfs_delete_object_id_index(ntfs_inode * ni)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 
ntfs_get_ntfs_object_id(ntfs_inode * ni,char * value,size_t size)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 = ENOATTR;
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 
ntfs_set_ntfs_object_id(ntfs_inode * ni,const char * value,size_t size,int flags)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 
ntfs_remove_ntfs_object_id(ntfs_inode * ni)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 = ENOATTR;
618 			res = -1;
619 		}
620 		NInoSetDirty(ni);
621 	} else {
622 		errno = EINVAL;
623 		res = -1;
624 	}
625 	return (res ? -1 : 0);
626 }
627