18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/hfsplus/catalog.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001 68c2ecf20Sopenharmony_ci * Brad Boyer (flar@allandria.com) 78c2ecf20Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Handling of catalog records 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "hfsplus_fs.h" 148c2ecf20Sopenharmony_ci#include "hfsplus_raw.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, 178c2ecf20Sopenharmony_ci const hfsplus_btree_key *k2) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci __be32 k1p, k2p; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci k1p = k1->cat.parent; 228c2ecf20Sopenharmony_ci k2p = k2->cat.parent; 238c2ecf20Sopenharmony_ci if (k1p != k2p) 248c2ecf20Sopenharmony_ci return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciint hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, 308c2ecf20Sopenharmony_ci const hfsplus_btree_key *k2) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci __be32 k1p, k2p; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci k1p = k1->cat.parent; 358c2ecf20Sopenharmony_ci k2p = k2->cat.parent; 368c2ecf20Sopenharmony_ci if (k1p != k2p) 378c2ecf20Sopenharmony_ci return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Generates key for catalog file/folders record. */ 438c2ecf20Sopenharmony_ciint hfsplus_cat_build_key(struct super_block *sb, 448c2ecf20Sopenharmony_ci hfsplus_btree_key *key, u32 parent, const struct qstr *str) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci int len, err; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci key->cat.parent = cpu_to_be32(parent); 498c2ecf20Sopenharmony_ci err = hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, 508c2ecf20Sopenharmony_ci str->name, str->len); 518c2ecf20Sopenharmony_ci if (unlikely(err < 0)) 528c2ecf20Sopenharmony_ci return err; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci len = be16_to_cpu(key->cat.name.length); 558c2ecf20Sopenharmony_ci key->key_len = cpu_to_be16(6 + 2 * len); 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Generates key for catalog thread record. */ 608c2ecf20Sopenharmony_civoid hfsplus_cat_build_key_with_cnid(struct super_block *sb, 618c2ecf20Sopenharmony_ci hfsplus_btree_key *key, u32 parent) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci key->cat.parent = cpu_to_be32(parent); 648c2ecf20Sopenharmony_ci key->cat.name.length = 0; 658c2ecf20Sopenharmony_ci key->key_len = cpu_to_be16(6); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent, 698c2ecf20Sopenharmony_ci struct hfsplus_unistr *name) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int ustrlen; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci ustrlen = be16_to_cpu(name->length); 748c2ecf20Sopenharmony_ci key->cat.parent = cpu_to_be32(parent); 758c2ecf20Sopenharmony_ci key->cat.name.length = cpu_to_be16(ustrlen); 768c2ecf20Sopenharmony_ci ustrlen *= 2; 778c2ecf20Sopenharmony_ci memcpy(key->cat.name.unicode, name->unicode, ustrlen); 788c2ecf20Sopenharmony_ci key->key_len = cpu_to_be16(6 + ustrlen); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_civoid hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci if (inode->i_flags & S_IMMUTABLE) 848c2ecf20Sopenharmony_ci perms->rootflags |= HFSPLUS_FLG_IMMUTABLE; 858c2ecf20Sopenharmony_ci else 868c2ecf20Sopenharmony_ci perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE; 878c2ecf20Sopenharmony_ci if (inode->i_flags & S_APPEND) 888c2ecf20Sopenharmony_ci perms->rootflags |= HFSPLUS_FLG_APPEND; 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci perms->rootflags &= ~HFSPLUS_FLG_APPEND; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci perms->userflags = HFSPLUS_I(inode)->userflags; 938c2ecf20Sopenharmony_ci perms->mode = cpu_to_be16(inode->i_mode); 948c2ecf20Sopenharmony_ci perms->owner = cpu_to_be32(i_uid_read(inode)); 958c2ecf20Sopenharmony_ci perms->group = cpu_to_be32(i_gid_read(inode)); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) 988c2ecf20Sopenharmony_ci perms->dev = cpu_to_be32(inode->i_nlink); 998c2ecf20Sopenharmony_ci else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) 1008c2ecf20Sopenharmony_ci perms->dev = cpu_to_be32(inode->i_rdev); 1018c2ecf20Sopenharmony_ci else 1028c2ecf20Sopenharmony_ci perms->dev = 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int hfsplus_cat_build_record(hfsplus_cat_entry *entry, 1068c2ecf20Sopenharmony_ci u32 cnid, struct inode *inode) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 1118c2ecf20Sopenharmony_ci struct hfsplus_cat_folder *folder; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci folder = &entry->folder; 1148c2ecf20Sopenharmony_ci memset(folder, 0, sizeof(*folder)); 1158c2ecf20Sopenharmony_ci folder->type = cpu_to_be16(HFSPLUS_FOLDER); 1168c2ecf20Sopenharmony_ci if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) 1178c2ecf20Sopenharmony_ci folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT); 1188c2ecf20Sopenharmony_ci folder->id = cpu_to_be32(inode->i_ino); 1198c2ecf20Sopenharmony_ci HFSPLUS_I(inode)->create_date = 1208c2ecf20Sopenharmony_ci folder->create_date = 1218c2ecf20Sopenharmony_ci folder->content_mod_date = 1228c2ecf20Sopenharmony_ci folder->attribute_mod_date = 1238c2ecf20Sopenharmony_ci folder->access_date = hfsp_now2mt(); 1248c2ecf20Sopenharmony_ci hfsplus_cat_set_perms(inode, &folder->permissions); 1258c2ecf20Sopenharmony_ci if (inode == sbi->hidden_dir) 1268c2ecf20Sopenharmony_ci /* invisible and namelocked */ 1278c2ecf20Sopenharmony_ci folder->user_info.frFlags = cpu_to_be16(0x5000); 1288c2ecf20Sopenharmony_ci return sizeof(*folder); 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci struct hfsplus_cat_file *file; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci file = &entry->file; 1338c2ecf20Sopenharmony_ci memset(file, 0, sizeof(*file)); 1348c2ecf20Sopenharmony_ci file->type = cpu_to_be16(HFSPLUS_FILE); 1358c2ecf20Sopenharmony_ci file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); 1368c2ecf20Sopenharmony_ci file->id = cpu_to_be32(cnid); 1378c2ecf20Sopenharmony_ci HFSPLUS_I(inode)->create_date = 1388c2ecf20Sopenharmony_ci file->create_date = 1398c2ecf20Sopenharmony_ci file->content_mod_date = 1408c2ecf20Sopenharmony_ci file->attribute_mod_date = 1418c2ecf20Sopenharmony_ci file->access_date = hfsp_now2mt(); 1428c2ecf20Sopenharmony_ci if (cnid == inode->i_ino) { 1438c2ecf20Sopenharmony_ci hfsplus_cat_set_perms(inode, &file->permissions); 1448c2ecf20Sopenharmony_ci if (S_ISLNK(inode->i_mode)) { 1458c2ecf20Sopenharmony_ci file->user_info.fdType = 1468c2ecf20Sopenharmony_ci cpu_to_be32(HFSP_SYMLINK_TYPE); 1478c2ecf20Sopenharmony_ci file->user_info.fdCreator = 1488c2ecf20Sopenharmony_ci cpu_to_be32(HFSP_SYMLINK_CREATOR); 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci file->user_info.fdType = 1518c2ecf20Sopenharmony_ci cpu_to_be32(sbi->type); 1528c2ecf20Sopenharmony_ci file->user_info.fdCreator = 1538c2ecf20Sopenharmony_ci cpu_to_be32(sbi->creator); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci if (HFSPLUS_FLG_IMMUTABLE & 1568c2ecf20Sopenharmony_ci (file->permissions.rootflags | 1578c2ecf20Sopenharmony_ci file->permissions.userflags)) 1588c2ecf20Sopenharmony_ci file->flags |= 1598c2ecf20Sopenharmony_ci cpu_to_be16(HFSPLUS_FILE_LOCKED); 1608c2ecf20Sopenharmony_ci } else { 1618c2ecf20Sopenharmony_ci file->user_info.fdType = 1628c2ecf20Sopenharmony_ci cpu_to_be32(HFSP_HARDLINK_TYPE); 1638c2ecf20Sopenharmony_ci file->user_info.fdCreator = 1648c2ecf20Sopenharmony_ci cpu_to_be32(HFSP_HFSPLUS_CREATOR); 1658c2ecf20Sopenharmony_ci file->user_info.fdFlags = 1668c2ecf20Sopenharmony_ci cpu_to_be16(0x100); 1678c2ecf20Sopenharmony_ci file->create_date = 1688c2ecf20Sopenharmony_ci HFSPLUS_I(sbi->hidden_dir)->create_date; 1698c2ecf20Sopenharmony_ci file->permissions.dev = 1708c2ecf20Sopenharmony_ci cpu_to_be32(HFSPLUS_I(inode)->linkid); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci return sizeof(*file); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int hfsplus_fill_cat_thread(struct super_block *sb, 1778c2ecf20Sopenharmony_ci hfsplus_cat_entry *entry, int type, 1788c2ecf20Sopenharmony_ci u32 parentid, const struct qstr *str) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci int err; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci entry->type = cpu_to_be16(type); 1838c2ecf20Sopenharmony_ci entry->thread.reserved = 0; 1848c2ecf20Sopenharmony_ci entry->thread.parentID = cpu_to_be32(parentid); 1858c2ecf20Sopenharmony_ci err = hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, 1868c2ecf20Sopenharmony_ci str->name, str->len); 1878c2ecf20Sopenharmony_ci if (unlikely(err < 0)) 1888c2ecf20Sopenharmony_ci return err; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* Try to get a catalog entry for given catalog id */ 1948c2ecf20Sopenharmony_ciint hfsplus_find_cat(struct super_block *sb, u32 cnid, 1958c2ecf20Sopenharmony_ci struct hfs_find_data *fd) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci hfsplus_cat_entry tmp; 1988c2ecf20Sopenharmony_ci int err; 1998c2ecf20Sopenharmony_ci u16 type; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid); 2028c2ecf20Sopenharmony_ci err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry)); 2038c2ecf20Sopenharmony_ci if (err) 2048c2ecf20Sopenharmony_ci return err; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci type = be16_to_cpu(tmp.type); 2078c2ecf20Sopenharmony_ci if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { 2088c2ecf20Sopenharmony_ci pr_err("found bad thread record in catalog\n"); 2098c2ecf20Sopenharmony_ci return -EIO; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (be16_to_cpu(tmp.thread.nodeName.length) > 255) { 2138c2ecf20Sopenharmony_ci pr_err("catalog name length corrupted\n"); 2148c2ecf20Sopenharmony_ci return -EIO; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci hfsplus_cat_build_key_uni(fd->search_key, 2188c2ecf20Sopenharmony_ci be32_to_cpu(tmp.thread.parentID), 2198c2ecf20Sopenharmony_ci &tmp.thread.nodeName); 2208c2ecf20Sopenharmony_ci return hfs_brec_find(fd, hfs_find_rec_by_key); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void hfsplus_subfolders_inc(struct inode *dir) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * Increment subfolder count. Note, the value is only meaningful 2308c2ecf20Sopenharmony_ci * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci HFSPLUS_I(dir)->subfolders++; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void hfsplus_subfolders_dec(struct inode *dir) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * Decrement subfolder count. Note, the value is only meaningful 2438c2ecf20Sopenharmony_ci * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set. 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * Check for zero. Some subfolders may have been created 2468c2ecf20Sopenharmony_ci * by an implementation ignorant of this counter. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci if (HFSPLUS_I(dir)->subfolders) 2498c2ecf20Sopenharmony_ci HFSPLUS_I(dir)->subfolders--; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciint hfsplus_create_cat(u32 cnid, struct inode *dir, 2548c2ecf20Sopenharmony_ci const struct qstr *str, struct inode *inode) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 2578c2ecf20Sopenharmony_ci struct hfs_find_data fd; 2588c2ecf20Sopenharmony_ci hfsplus_cat_entry entry; 2598c2ecf20Sopenharmony_ci int entry_size; 2608c2ecf20Sopenharmony_ci int err; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n", 2638c2ecf20Sopenharmony_ci str->name, cnid, inode->i_nlink); 2648c2ecf20Sopenharmony_ci err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 2658c2ecf20Sopenharmony_ci if (err) 2668c2ecf20Sopenharmony_ci return err; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Fail early and avoid ENOSPC during the btree operations. We may 2708c2ecf20Sopenharmony_ci * have to split the root node at most once. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth); 2738c2ecf20Sopenharmony_ci if (err) 2748c2ecf20Sopenharmony_ci goto err2; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 2778c2ecf20Sopenharmony_ci entry_size = hfsplus_fill_cat_thread(sb, &entry, 2788c2ecf20Sopenharmony_ci S_ISDIR(inode->i_mode) ? 2798c2ecf20Sopenharmony_ci HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, 2808c2ecf20Sopenharmony_ci dir->i_ino, str); 2818c2ecf20Sopenharmony_ci if (unlikely(entry_size < 0)) { 2828c2ecf20Sopenharmony_ci err = entry_size; 2838c2ecf20Sopenharmony_ci goto err2; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci err = hfs_brec_find(&fd, hfs_find_rec_by_key); 2878c2ecf20Sopenharmony_ci if (err != -ENOENT) { 2888c2ecf20Sopenharmony_ci if (!err) 2898c2ecf20Sopenharmony_ci err = -EEXIST; 2908c2ecf20Sopenharmony_ci goto err2; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci err = hfs_brec_insert(&fd, &entry, entry_size); 2938c2ecf20Sopenharmony_ci if (err) 2948c2ecf20Sopenharmony_ci goto err2; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 2978c2ecf20Sopenharmony_ci if (unlikely(err)) 2988c2ecf20Sopenharmony_ci goto err1; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci entry_size = hfsplus_cat_build_record(&entry, cnid, inode); 3018c2ecf20Sopenharmony_ci err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3028c2ecf20Sopenharmony_ci if (err != -ENOENT) { 3038c2ecf20Sopenharmony_ci /* panic? */ 3048c2ecf20Sopenharmony_ci if (!err) 3058c2ecf20Sopenharmony_ci err = -EEXIST; 3068c2ecf20Sopenharmony_ci goto err1; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci err = hfs_brec_insert(&fd, &entry, entry_size); 3098c2ecf20Sopenharmony_ci if (err) 3108c2ecf20Sopenharmony_ci goto err1; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dir->i_size++; 3138c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 3148c2ecf20Sopenharmony_ci hfsplus_subfolders_inc(dir); 3158c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = current_time(dir); 3168c2ecf20Sopenharmony_ci hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci hfs_find_exit(&fd); 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cierr1: 3228c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 3238c2ecf20Sopenharmony_ci if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) 3248c2ecf20Sopenharmony_ci hfs_brec_remove(&fd); 3258c2ecf20Sopenharmony_cierr2: 3268c2ecf20Sopenharmony_ci hfs_find_exit(&fd); 3278c2ecf20Sopenharmony_ci return err; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ciint hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 3338c2ecf20Sopenharmony_ci struct hfs_find_data fd; 3348c2ecf20Sopenharmony_ci struct hfsplus_fork_raw fork; 3358c2ecf20Sopenharmony_ci struct list_head *pos; 3368c2ecf20Sopenharmony_ci int err, off; 3378c2ecf20Sopenharmony_ci u16 type; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); 3408c2ecf20Sopenharmony_ci err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 3418c2ecf20Sopenharmony_ci if (err) 3428c2ecf20Sopenharmony_ci return err; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* 3458c2ecf20Sopenharmony_ci * Fail early and avoid ENOSPC during the btree operations. We may 3468c2ecf20Sopenharmony_ci * have to split the root node at most once. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci err = hfs_bmap_reserve(fd.tree, 2 * (int)fd.tree->depth - 2); 3498c2ecf20Sopenharmony_ci if (err) 3508c2ecf20Sopenharmony_ci goto out; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!str) { 3538c2ecf20Sopenharmony_ci int len; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 3568c2ecf20Sopenharmony_ci err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3578c2ecf20Sopenharmony_ci if (err) 3588c2ecf20Sopenharmony_ci goto out; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci off = fd.entryoffset + 3618c2ecf20Sopenharmony_ci offsetof(struct hfsplus_cat_thread, nodeName); 3628c2ecf20Sopenharmony_ci fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); 3638c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, 3648c2ecf20Sopenharmony_ci &fd.search_key->cat.name.length, off, 2); 3658c2ecf20Sopenharmony_ci len = be16_to_cpu(fd.search_key->cat.name.length) * 2; 3668c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, 3678c2ecf20Sopenharmony_ci &fd.search_key->cat.name.unicode, 3688c2ecf20Sopenharmony_ci off + 2, len); 3698c2ecf20Sopenharmony_ci fd.search_key->key_len = cpu_to_be16(6 + len); 3708c2ecf20Sopenharmony_ci } else { 3718c2ecf20Sopenharmony_ci err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 3728c2ecf20Sopenharmony_ci if (unlikely(err)) 3738c2ecf20Sopenharmony_ci goto out; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3778c2ecf20Sopenharmony_ci if (err) 3788c2ecf20Sopenharmony_ci goto out; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 3818c2ecf20Sopenharmony_ci if (type == HFSPLUS_FILE) { 3828c2ecf20Sopenharmony_ci#if 0 3838c2ecf20Sopenharmony_ci off = fd.entryoffset + offsetof(hfsplus_cat_file, data_fork); 3848c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 3858c2ecf20Sopenharmony_ci hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); 3868c2ecf20Sopenharmony_ci#endif 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci off = fd.entryoffset + 3898c2ecf20Sopenharmony_ci offsetof(struct hfsplus_cat_file, rsrc_fork); 3908c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 3918c2ecf20Sopenharmony_ci hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* we only need to take spinlock for exclusion with ->release() */ 3958c2ecf20Sopenharmony_ci spin_lock(&HFSPLUS_I(dir)->open_dir_lock); 3968c2ecf20Sopenharmony_ci list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) { 3978c2ecf20Sopenharmony_ci struct hfsplus_readdir_data *rd = 3988c2ecf20Sopenharmony_ci list_entry(pos, struct hfsplus_readdir_data, list); 3998c2ecf20Sopenharmony_ci if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0) 4008c2ecf20Sopenharmony_ci rd->file->f_pos--; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci spin_unlock(&HFSPLUS_I(dir)->open_dir_lock); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci err = hfs_brec_remove(&fd); 4058c2ecf20Sopenharmony_ci if (err) 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 4098c2ecf20Sopenharmony_ci err = hfs_brec_find(&fd, hfs_find_rec_by_key); 4108c2ecf20Sopenharmony_ci if (err) 4118c2ecf20Sopenharmony_ci goto out; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci err = hfs_brec_remove(&fd); 4148c2ecf20Sopenharmony_ci if (err) 4158c2ecf20Sopenharmony_ci goto out; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dir->i_size--; 4188c2ecf20Sopenharmony_ci if (type == HFSPLUS_FOLDER) 4198c2ecf20Sopenharmony_ci hfsplus_subfolders_dec(dir); 4208c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = current_time(dir); 4218c2ecf20Sopenharmony_ci hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) { 4248c2ecf20Sopenharmony_ci if (HFSPLUS_SB(sb)->attr_tree) 4258c2ecf20Sopenharmony_ci hfsplus_delete_all_attrs(dir, cnid); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ciout: 4298c2ecf20Sopenharmony_ci hfs_find_exit(&fd); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return err; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ciint hfsplus_rename_cat(u32 cnid, 4358c2ecf20Sopenharmony_ci struct inode *src_dir, const struct qstr *src_name, 4368c2ecf20Sopenharmony_ci struct inode *dst_dir, const struct qstr *dst_name) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct super_block *sb = src_dir->i_sb; 4398c2ecf20Sopenharmony_ci struct hfs_find_data src_fd, dst_fd; 4408c2ecf20Sopenharmony_ci hfsplus_cat_entry entry; 4418c2ecf20Sopenharmony_ci int entry_size, type; 4428c2ecf20Sopenharmony_ci int err; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", 4458c2ecf20Sopenharmony_ci cnid, src_dir->i_ino, src_name->name, 4468c2ecf20Sopenharmony_ci dst_dir->i_ino, dst_name->name); 4478c2ecf20Sopenharmony_ci err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); 4488c2ecf20Sopenharmony_ci if (err) 4498c2ecf20Sopenharmony_ci return err; 4508c2ecf20Sopenharmony_ci dst_fd = src_fd; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* 4538c2ecf20Sopenharmony_ci * Fail early and avoid ENOSPC during the btree operations. We may 4548c2ecf20Sopenharmony_ci * have to split the root node at most twice. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci err = hfs_bmap_reserve(src_fd.tree, 4 * (int)src_fd.tree->depth - 1); 4578c2ecf20Sopenharmony_ci if (err) 4588c2ecf20Sopenharmony_ci goto out; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* find the old dir entry and read the data */ 4618c2ecf20Sopenharmony_ci err = hfsplus_cat_build_key(sb, src_fd.search_key, 4628c2ecf20Sopenharmony_ci src_dir->i_ino, src_name); 4638c2ecf20Sopenharmony_ci if (unlikely(err)) 4648c2ecf20Sopenharmony_ci goto out; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4678c2ecf20Sopenharmony_ci if (err) 4688c2ecf20Sopenharmony_ci goto out; 4698c2ecf20Sopenharmony_ci if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { 4708c2ecf20Sopenharmony_ci err = -EIO; 4718c2ecf20Sopenharmony_ci goto out; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset, 4758c2ecf20Sopenharmony_ci src_fd.entrylength); 4768c2ecf20Sopenharmony_ci type = be16_to_cpu(entry.type); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* create new dir entry with the data from the old entry */ 4798c2ecf20Sopenharmony_ci err = hfsplus_cat_build_key(sb, dst_fd.search_key, 4808c2ecf20Sopenharmony_ci dst_dir->i_ino, dst_name); 4818c2ecf20Sopenharmony_ci if (unlikely(err)) 4828c2ecf20Sopenharmony_ci goto out; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 4858c2ecf20Sopenharmony_ci if (err != -ENOENT) { 4868c2ecf20Sopenharmony_ci if (!err) 4878c2ecf20Sopenharmony_ci err = -EEXIST; 4888c2ecf20Sopenharmony_ci goto out; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength); 4928c2ecf20Sopenharmony_ci if (err) 4938c2ecf20Sopenharmony_ci goto out; 4948c2ecf20Sopenharmony_ci dst_dir->i_size++; 4958c2ecf20Sopenharmony_ci if (type == HFSPLUS_FOLDER) 4968c2ecf20Sopenharmony_ci hfsplus_subfolders_inc(dst_dir); 4978c2ecf20Sopenharmony_ci dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci /* finally remove the old entry */ 5008c2ecf20Sopenharmony_ci err = hfsplus_cat_build_key(sb, src_fd.search_key, 5018c2ecf20Sopenharmony_ci src_dir->i_ino, src_name); 5028c2ecf20Sopenharmony_ci if (unlikely(err)) 5038c2ecf20Sopenharmony_ci goto out; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 5068c2ecf20Sopenharmony_ci if (err) 5078c2ecf20Sopenharmony_ci goto out; 5088c2ecf20Sopenharmony_ci err = hfs_brec_remove(&src_fd); 5098c2ecf20Sopenharmony_ci if (err) 5108c2ecf20Sopenharmony_ci goto out; 5118c2ecf20Sopenharmony_ci src_dir->i_size--; 5128c2ecf20Sopenharmony_ci if (type == HFSPLUS_FOLDER) 5138c2ecf20Sopenharmony_ci hfsplus_subfolders_dec(src_dir); 5148c2ecf20Sopenharmony_ci src_dir->i_mtime = src_dir->i_ctime = current_time(src_dir); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* remove old thread entry */ 5178c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, src_fd.search_key, cnid); 5188c2ecf20Sopenharmony_ci err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 5198c2ecf20Sopenharmony_ci if (err) 5208c2ecf20Sopenharmony_ci goto out; 5218c2ecf20Sopenharmony_ci type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); 5228c2ecf20Sopenharmony_ci err = hfs_brec_remove(&src_fd); 5238c2ecf20Sopenharmony_ci if (err) 5248c2ecf20Sopenharmony_ci goto out; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* create new thread entry */ 5278c2ecf20Sopenharmony_ci hfsplus_cat_build_key_with_cnid(sb, dst_fd.search_key, cnid); 5288c2ecf20Sopenharmony_ci entry_size = hfsplus_fill_cat_thread(sb, &entry, type, 5298c2ecf20Sopenharmony_ci dst_dir->i_ino, dst_name); 5308c2ecf20Sopenharmony_ci if (unlikely(entry_size < 0)) { 5318c2ecf20Sopenharmony_ci err = entry_size; 5328c2ecf20Sopenharmony_ci goto out; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 5368c2ecf20Sopenharmony_ci if (err != -ENOENT) { 5378c2ecf20Sopenharmony_ci if (!err) 5388c2ecf20Sopenharmony_ci err = -EEXIST; 5398c2ecf20Sopenharmony_ci goto out; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci err = hfs_brec_insert(&dst_fd, &entry, entry_size); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY); 5448c2ecf20Sopenharmony_ci hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY); 5458c2ecf20Sopenharmony_ciout: 5468c2ecf20Sopenharmony_ci hfs_bnode_put(dst_fd.bnode); 5478c2ecf20Sopenharmony_ci hfs_find_exit(&src_fd); 5488c2ecf20Sopenharmony_ci return err; 5498c2ecf20Sopenharmony_ci} 550