| // SPDX-License-Identifier: GPL-2.0-or-later | |
| /* | |
| * Pocessing of object ids | |
| * | |
| * Part of this file is based on code from the NTFS-3G. | |
| * | |
| * Copyright (c) 2009-2019 Jean-Pierre Andre | |
| * Copyright (c) 2026 LG Electronics Co., Ltd. | |
| */ | |
| #include "ntfs.h" | |
| #include "index.h" | |
| #include "object_id.h" | |
| struct object_id_index_key { | |
| union { | |
| u32 alignment; | |
| struct guid guid; | |
| } object_id; | |
| } __packed; | |
| struct object_id_index_data { | |
| __le64 file_id; | |
| struct guid birth_volume_id; | |
| struct guid birth_object_id; | |
| struct guid domain_id; | |
| } __packed; | |
| /* Index entry in $Extend/$ObjId */ | |
| struct object_id_index { | |
| struct index_entry_header header; | |
| struct object_id_index_key key; | |
| struct object_id_index_data data; | |
| } __packed; | |
| __le16 objid_index_name[] = {cpu_to_le16('$'), cpu_to_le16('O'), 0}; | |
| /* | |
| * open_object_id_index - Open the $Extend/$ObjId file and its index | |
| * @vol: NTFS volume structure | |
| * | |
| * Opens the $ObjId system file and retrieves its index context. | |
| * | |
| * Return: The index context if opened successfully, or NULL if an error | |
| * occurred. | |
| */ | |
| static struct ntfs_index_context *open_object_id_index(struct ntfs_volume *vol) | |
| { | |
| struct inode *dir_vi, *vi; | |
| struct ntfs_inode *dir_ni; | |
| struct ntfs_index_context *xo = NULL; | |
| struct ntfs_name *name = NULL; | |
| u64 mref; | |
| int uname_len; | |
| __le16 *uname; | |
| uname_len = ntfs_nlstoucs(vol, "$ObjId", 6, &uname, | |
| NTFS_MAX_NAME_LEN); | |
| if (uname_len < 0) | |
| return NULL; | |
| /* do not use path_name_to inode - could reopen root */ | |
| dir_vi = ntfs_iget(vol->sb, FILE_Extend); | |
| if (IS_ERR(dir_vi)) { | |
| kmem_cache_free(ntfs_name_cache, uname); | |
| return NULL; | |
| } | |
| dir_ni = NTFS_I(dir_vi); | |
| mutex_lock_nested(&dir_ni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); | |
| mref = ntfs_lookup_inode_by_name(dir_ni, uname, uname_len, &name); | |
| mutex_unlock(&dir_ni->mrec_lock); | |
| kfree(name); | |
| kmem_cache_free(ntfs_name_cache, uname); | |
| if (IS_ERR_MREF(mref)) | |
| goto put_dir_vi; | |
| vi = ntfs_iget(vol->sb, MREF(mref)); | |
| if (IS_ERR(vi)) | |
| goto put_dir_vi; | |
| xo = ntfs_index_ctx_get(NTFS_I(vi), objid_index_name, 2); | |
| if (!xo) | |
| iput(vi); | |
| put_dir_vi: | |
| iput(dir_vi); | |
| return xo; | |
| } | |
| /* | |
| * remove_object_id_index - Remove an object id index entry if attribute present | |
| * @ni: NTFS inode structure containing the attribute | |
| * @xo: Index context for the object id index | |
| * | |
| * Reads the existing object ID attribute and removes it from the index. | |
| * | |
| * Return: 0 on success, or a negative error code on failure. | |
| */ | |
| static int remove_object_id_index(struct ntfs_inode *ni, struct ntfs_index_context *xo) | |
| { | |
| struct object_id_index_key key = {0}; | |
| s64 size; | |
| if (ni->data_size == 0) | |
| return -ENODATA; | |
| /* read the existing object id attribute */ | |
| size = ntfs_inode_attr_pread(VFS_I(ni), 0, sizeof(struct guid), | |
| (char *)&key); | |
| if (size != sizeof(struct guid)) | |
| return -ENODATA; | |
| if (!ntfs_index_lookup(&key, sizeof(struct object_id_index_key), xo)) | |
| return ntfs_index_rm(xo); | |
| return 0; | |
| } | |
| /* | |
| * ntfs_delete_object_id_index - Delete an object_id index entry | |
| * @ni: NTFS inode structure | |
| * | |
| * Opens the object ID index and removes the entry corresponding to the inode. | |
| * | |
| * Return: 0 on success, or a negative error code on failure. | |
| */ | |
| int ntfs_delete_object_id_index(struct ntfs_inode *ni) | |
| { | |
| struct ntfs_index_context *xo; | |
| struct ntfs_inode *xoni; | |
| struct inode *attr_vi; | |
| int ret = 0; | |
| attr_vi = ntfs_attr_iget(VFS_I(ni), AT_OBJECT_ID, AT_UNNAMED, 0); | |
| if (IS_ERR(attr_vi)) | |
| return PTR_ERR(attr_vi); | |
| /* | |
| * read the existing object id and un-index it | |
| */ | |
| xo = open_object_id_index(ni->vol); | |
| if (xo) { | |
| xoni = xo->idx_ni; | |
| mutex_lock_nested(&xoni->mrec_lock, NTFS_EXTEND_MUTEX_PARENT); | |
| ret = remove_object_id_index(NTFS_I(attr_vi), xo); | |
| if (!ret) { | |
| ntfs_index_entry_mark_dirty(xo); | |
| mark_mft_record_dirty(xoni); | |
| } | |
| ntfs_index_ctx_put(xo); | |
| mutex_unlock(&xoni->mrec_lock); | |
| iput(VFS_I(xoni)); | |
| } | |
| iput(attr_vi); | |
| return ret; | |
| } |