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