xref: /linux/fs/ntfs/object_id.c (revision cdd4dc3aebeab43a72ce0bc2b5bab6f0a80b97a5)
1*5218cd10SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later
2*5218cd10SNamjae Jeon /*
3*5218cd10SNamjae Jeon  * Pocessing of object ids
4*5218cd10SNamjae Jeon  *
5*5218cd10SNamjae Jeon  * Part of this file is based on code from the NTFS-3G.
6*5218cd10SNamjae Jeon  *
7*5218cd10SNamjae Jeon  * Copyright (c) 2009-2019 Jean-Pierre Andre
8*5218cd10SNamjae Jeon  * Copyright (c) 2026 LG Electronics Co., Ltd.
9*5218cd10SNamjae Jeon  */
10*5218cd10SNamjae Jeon 
11*5218cd10SNamjae Jeon #include "ntfs.h"
12*5218cd10SNamjae Jeon #include "index.h"
13*5218cd10SNamjae Jeon #include "object_id.h"
14*5218cd10SNamjae Jeon 
15*5218cd10SNamjae Jeon struct object_id_index_key {
16*5218cd10SNamjae Jeon 	union {
17*5218cd10SNamjae Jeon 		u32 alignment;
18*5218cd10SNamjae Jeon 		struct guid guid;
19*5218cd10SNamjae Jeon 	} object_id;
20*5218cd10SNamjae Jeon } __packed;
21*5218cd10SNamjae Jeon 
22*5218cd10SNamjae Jeon struct object_id_index_data {
23*5218cd10SNamjae Jeon 	__le64 file_id;
24*5218cd10SNamjae Jeon 	struct guid birth_volume_id;
25*5218cd10SNamjae Jeon 	struct guid birth_object_id;
26*5218cd10SNamjae Jeon 	struct guid domain_id;
27*5218cd10SNamjae Jeon } __packed;
28*5218cd10SNamjae Jeon 
29*5218cd10SNamjae Jeon /* Index entry in $Extend/$ObjId */
30*5218cd10SNamjae Jeon struct object_id_index {
31*5218cd10SNamjae Jeon 	struct index_entry_header header;
32*5218cd10SNamjae Jeon 	struct object_id_index_key key;
33*5218cd10SNamjae Jeon 	struct object_id_index_data data;
34*5218cd10SNamjae Jeon } __packed;
35*5218cd10SNamjae Jeon 
36*5218cd10SNamjae Jeon __le16 objid_index_name[] = {cpu_to_le16('$'), cpu_to_le16('O'), 0};
37*5218cd10SNamjae Jeon 
38*5218cd10SNamjae Jeon /*
39*5218cd10SNamjae Jeon  * open_object_id_index - Open the $Extend/$ObjId file and its index
40*5218cd10SNamjae Jeon  * @vol: NTFS volume structure
41*5218cd10SNamjae Jeon  *
42*5218cd10SNamjae Jeon  * Opens the $ObjId system file and retrieves its index context.
43*5218cd10SNamjae Jeon  *
44*5218cd10SNamjae Jeon  * Return: The index context if opened successfully, or NULL if an error
45*5218cd10SNamjae Jeon  *	   occurred.
46*5218cd10SNamjae Jeon  */
47*5218cd10SNamjae Jeon static struct ntfs_index_context *open_object_id_index(struct ntfs_volume *vol)
48*5218cd10SNamjae Jeon {
49*5218cd10SNamjae Jeon 	struct inode *dir_vi, *vi;
50*5218cd10SNamjae Jeon 	struct ntfs_inode *dir_ni;
51*5218cd10SNamjae Jeon 	struct ntfs_index_context *xo = NULL;
52*5218cd10SNamjae Jeon 	struct ntfs_name *name = NULL;
53*5218cd10SNamjae Jeon 	u64 mref;
54*5218cd10SNamjae Jeon 	int uname_len;
55*5218cd10SNamjae Jeon 	__le16 *uname;
56*5218cd10SNamjae Jeon 
57*5218cd10SNamjae Jeon 	uname_len = ntfs_nlstoucs(vol, "$ObjId", 6, &uname,
58*5218cd10SNamjae Jeon 			NTFS_MAX_NAME_LEN);
59*5218cd10SNamjae Jeon 	if (uname_len < 0)
60*5218cd10SNamjae Jeon 		return NULL;
61*5218cd10SNamjae Jeon 
62*5218cd10SNamjae Jeon 	/* do not use path_name_to inode - could reopen root */
63*5218cd10SNamjae Jeon 	dir_vi = ntfs_iget(vol->sb, FILE_Extend);
64*5218cd10SNamjae Jeon 	if (IS_ERR(dir_vi)) {
65*5218cd10SNamjae Jeon 		kmem_cache_free(ntfs_name_cache, uname);
66*5218cd10SNamjae Jeon 		return NULL;
67*5218cd10SNamjae Jeon 	}
68*5218cd10SNamjae Jeon 	dir_ni = NTFS_I(dir_vi);
69*5218cd10SNamjae Jeon 
70*5218cd10SNamjae Jeon 	mutex_lock_nested(&dir_ni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT);
71*5218cd10SNamjae Jeon 	mref = ntfs_lookup_inode_by_name(dir_ni, uname, uname_len, &name);
72*5218cd10SNamjae Jeon 	mutex_unlock(&dir_ni->mrec_lock);
73*5218cd10SNamjae Jeon 	kfree(name);
74*5218cd10SNamjae Jeon 	kmem_cache_free(ntfs_name_cache, uname);
75*5218cd10SNamjae Jeon 	if (IS_ERR_MREF(mref))
76*5218cd10SNamjae Jeon 		goto put_dir_vi;
77*5218cd10SNamjae Jeon 
78*5218cd10SNamjae Jeon 	vi = ntfs_iget(vol->sb, MREF(mref));
79*5218cd10SNamjae Jeon 	if (IS_ERR(vi))
80*5218cd10SNamjae Jeon 		goto put_dir_vi;
81*5218cd10SNamjae Jeon 
82*5218cd10SNamjae Jeon 	xo = ntfs_index_ctx_get(NTFS_I(vi), objid_index_name, 2);
83*5218cd10SNamjae Jeon 	if (!xo)
84*5218cd10SNamjae Jeon 		iput(vi);
85*5218cd10SNamjae Jeon put_dir_vi:
86*5218cd10SNamjae Jeon 	iput(dir_vi);
87*5218cd10SNamjae Jeon 	return xo;
88*5218cd10SNamjae Jeon }
89*5218cd10SNamjae Jeon 
90*5218cd10SNamjae Jeon 
91*5218cd10SNamjae Jeon /*
92*5218cd10SNamjae Jeon  * remove_object_id_index - Remove an object id index entry if attribute present
93*5218cd10SNamjae Jeon  * @ni: NTFS inode structure containing the attribute
94*5218cd10SNamjae Jeon  * @xo:	Index context for the object id index
95*5218cd10SNamjae Jeon  *
96*5218cd10SNamjae Jeon  * Reads the existing object ID attribute and removes it from the index.
97*5218cd10SNamjae Jeon  *
98*5218cd10SNamjae Jeon  * Return: 0 on success, or a negative error code on failure.
99*5218cd10SNamjae Jeon  */
100*5218cd10SNamjae Jeon static int remove_object_id_index(struct ntfs_inode *ni, struct ntfs_index_context *xo)
101*5218cd10SNamjae Jeon {
102*5218cd10SNamjae Jeon 	struct object_id_index_key key = {0};
103*5218cd10SNamjae Jeon 	s64 size;
104*5218cd10SNamjae Jeon 
105*5218cd10SNamjae Jeon 	if (ni->data_size == 0)
106*5218cd10SNamjae Jeon 		return -ENODATA;
107*5218cd10SNamjae Jeon 
108*5218cd10SNamjae Jeon 	/* read the existing object id attribute */
109*5218cd10SNamjae Jeon 	size = ntfs_inode_attr_pread(VFS_I(ni), 0, sizeof(struct guid),
110*5218cd10SNamjae Jeon 				     (char *)&key);
111*5218cd10SNamjae Jeon 	if (size != sizeof(struct guid))
112*5218cd10SNamjae Jeon 		return -ENODATA;
113*5218cd10SNamjae Jeon 
114*5218cd10SNamjae Jeon 	if (!ntfs_index_lookup(&key, sizeof(struct object_id_index_key), xo))
115*5218cd10SNamjae Jeon 		return ntfs_index_rm(xo);
116*5218cd10SNamjae Jeon 
117*5218cd10SNamjae Jeon 	return 0;
118*5218cd10SNamjae Jeon }
119*5218cd10SNamjae Jeon 
120*5218cd10SNamjae Jeon /*
121*5218cd10SNamjae Jeon  * ntfs_delete_object_id_index - Delete an object_id index entry
122*5218cd10SNamjae Jeon  * @ni:	NTFS inode structure
123*5218cd10SNamjae Jeon  *
124*5218cd10SNamjae Jeon  * Opens the object ID index and removes the entry corresponding to the inode.
125*5218cd10SNamjae Jeon  *
126*5218cd10SNamjae Jeon  * Return: 0 on success, or a negative error code on failure.
127*5218cd10SNamjae Jeon  */
128*5218cd10SNamjae Jeon int ntfs_delete_object_id_index(struct ntfs_inode *ni)
129*5218cd10SNamjae Jeon {
130*5218cd10SNamjae Jeon 	struct ntfs_index_context *xo;
131*5218cd10SNamjae Jeon 	struct ntfs_inode *xoni;
132*5218cd10SNamjae Jeon 	struct inode *attr_vi;
133*5218cd10SNamjae Jeon 	int ret = 0;
134*5218cd10SNamjae Jeon 
135*5218cd10SNamjae Jeon 	attr_vi = ntfs_attr_iget(VFS_I(ni), AT_OBJECT_ID, AT_UNNAMED, 0);
136*5218cd10SNamjae Jeon 	if (IS_ERR(attr_vi))
137*5218cd10SNamjae Jeon 		return PTR_ERR(attr_vi);
138*5218cd10SNamjae Jeon 
139*5218cd10SNamjae Jeon 	/*
140*5218cd10SNamjae Jeon 	 * read the existing object id and un-index it
141*5218cd10SNamjae Jeon 	 */
142*5218cd10SNamjae Jeon 	xo = open_object_id_index(ni->vol);
143*5218cd10SNamjae Jeon 	if (xo) {
144*5218cd10SNamjae Jeon 		xoni = xo->idx_ni;
145*5218cd10SNamjae Jeon 		mutex_lock_nested(&xoni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT);
146*5218cd10SNamjae Jeon 		ret = remove_object_id_index(NTFS_I(attr_vi), xo);
147*5218cd10SNamjae Jeon 		if (!ret) {
148*5218cd10SNamjae Jeon 			ntfs_index_entry_mark_dirty(xo);
149*5218cd10SNamjae Jeon 			mark_mft_record_dirty(xoni);
150*5218cd10SNamjae Jeon 		}
151*5218cd10SNamjae Jeon 		ntfs_index_ctx_put(xo);
152*5218cd10SNamjae Jeon 		mutex_unlock(&xoni->mrec_lock);
153*5218cd10SNamjae Jeon 		iput(VFS_I(xoni));
154*5218cd10SNamjae Jeon 	}
155*5218cd10SNamjae Jeon 
156*5218cd10SNamjae Jeon 	iput(attr_vi);
157*5218cd10SNamjae Jeon 	return ret;
158*5218cd10SNamjae Jeon }
159