1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/fs/hfsplus/catalog.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 2001 61da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 71da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Handling of catalog records 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include "hfsplus_fs.h" 141da177e4SLinus Torvalds #include "hfsplus_raw.h" 151da177e4SLinus Torvalds 162179d372SDavid Elliott int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, 172179d372SDavid Elliott const hfsplus_btree_key *k2) 181da177e4SLinus Torvalds { 191da177e4SLinus Torvalds __be32 k1p, k2p; 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds k1p = k1->cat.parent; 221da177e4SLinus Torvalds k2p = k2->cat.parent; 231da177e4SLinus Torvalds if (k1p != k2p) 241da177e4SLinus Torvalds return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 251da177e4SLinus Torvalds 262179d372SDavid Elliott return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); 272179d372SDavid Elliott } 282179d372SDavid Elliott 292179d372SDavid Elliott int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, 302179d372SDavid Elliott const hfsplus_btree_key *k2) 312179d372SDavid Elliott { 322179d372SDavid Elliott __be32 k1p, k2p; 332179d372SDavid Elliott 342179d372SDavid Elliott k1p = k1->cat.parent; 352179d372SDavid Elliott k2p = k2->cat.parent; 362179d372SDavid Elliott if (k1p != k2p) 372179d372SDavid Elliott return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 382179d372SDavid Elliott 392179d372SDavid Elliott return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds 4289ac9b4dSSougata Santra /* Generates key for catalog file/folders record. */ 4389ac9b4dSSougata Santra int hfsplus_cat_build_key(struct super_block *sb, 44b5cce521SAl Viro hfsplus_btree_key *key, u32 parent, const struct qstr *str) 451da177e4SLinus Torvalds { 4689ac9b4dSSougata Santra int len, err; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds key->cat.parent = cpu_to_be32(parent); 4989ac9b4dSSougata Santra err = hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, 50324ef39aSVyacheslav Dubeyko str->name, str->len); 5189ac9b4dSSougata Santra if (unlikely(err < 0)) 5289ac9b4dSSougata Santra return err; 5389ac9b4dSSougata Santra 541da177e4SLinus Torvalds len = be16_to_cpu(key->cat.name.length); 551da177e4SLinus Torvalds key->key_len = cpu_to_be16(6 + 2 * len); 5689ac9b4dSSougata Santra return 0; 5789ac9b4dSSougata Santra } 5889ac9b4dSSougata Santra 5989ac9b4dSSougata Santra /* Generates key for catalog thread record. */ 6089ac9b4dSSougata Santra void hfsplus_cat_build_key_with_cnid(struct super_block *sb, 6189ac9b4dSSougata Santra hfsplus_btree_key *key, u32 parent) 6289ac9b4dSSougata Santra { 6389ac9b4dSSougata Santra key->cat.parent = cpu_to_be32(parent); 6489ac9b4dSSougata Santra key->cat.name.length = 0; 6589ac9b4dSSougata Santra key->key_len = cpu_to_be16(6); 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent, 691da177e4SLinus Torvalds struct hfsplus_unistr *name) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds int ustrlen; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds ustrlen = be16_to_cpu(name->length); 741da177e4SLinus Torvalds key->cat.parent = cpu_to_be32(parent); 751da177e4SLinus Torvalds key->cat.name.length = cpu_to_be16(ustrlen); 761da177e4SLinus Torvalds ustrlen *= 2; 771da177e4SLinus Torvalds memcpy(key->cat.name.unicode, name->unicode, ustrlen); 781da177e4SLinus Torvalds key->key_len = cpu_to_be16(6 + ustrlen); 791da177e4SLinus Torvalds } 801da177e4SLinus Torvalds 8190e61690SChristoph Hellwig void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds if (inode->i_flags & S_IMMUTABLE) 841da177e4SLinus Torvalds perms->rootflags |= HFSPLUS_FLG_IMMUTABLE; 851da177e4SLinus Torvalds else 861da177e4SLinus Torvalds perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE; 871da177e4SLinus Torvalds if (inode->i_flags & S_APPEND) 881da177e4SLinus Torvalds perms->rootflags |= HFSPLUS_FLG_APPEND; 891da177e4SLinus Torvalds else 901da177e4SLinus Torvalds perms->rootflags &= ~HFSPLUS_FLG_APPEND; 9190e61690SChristoph Hellwig 9290e61690SChristoph Hellwig perms->userflags = HFSPLUS_I(inode)->userflags; 931da177e4SLinus Torvalds perms->mode = cpu_to_be16(inode->i_mode); 9416525e3fSEric W. Biederman perms->owner = cpu_to_be32(i_uid_read(inode)); 9516525e3fSEric W. Biederman perms->group = cpu_to_be32(i_gid_read(inode)); 9690e61690SChristoph Hellwig 9790e61690SChristoph Hellwig if (S_ISREG(inode->i_mode)) 9890e61690SChristoph Hellwig perms->dev = cpu_to_be32(inode->i_nlink); 9990e61690SChristoph Hellwig else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) 10090e61690SChristoph Hellwig perms->dev = cpu_to_be32(inode->i_rdev); 10190e61690SChristoph Hellwig else 10290e61690SChristoph Hellwig perms->dev = 0; 1031da177e4SLinus Torvalds } 1041da177e4SLinus Torvalds 1052753cc28SAnton Salikhmetov static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, 1062753cc28SAnton Salikhmetov u32 cnid, struct inode *inode) 1071da177e4SLinus Torvalds { 108dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 109dd73a01aSChristoph Hellwig 1101da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 1111da177e4SLinus Torvalds struct hfsplus_cat_folder *folder; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds folder = &entry->folder; 1141da177e4SLinus Torvalds memset(folder, 0, sizeof(*folder)); 1151da177e4SLinus Torvalds folder->type = cpu_to_be16(HFSPLUS_FOLDER); 116d7d673a5SSergei Antonov if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) 117d7d673a5SSergei Antonov folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT); 1181da177e4SLinus Torvalds folder->id = cpu_to_be32(inode->i_ino); 1196af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = 1209a4cad95SRoman Zippel folder->create_date = 1219a4cad95SRoman Zippel folder->content_mod_date = 1229a4cad95SRoman Zippel folder->attribute_mod_date = 1239a4cad95SRoman Zippel folder->access_date = hfsp_now2mt(); 12490e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &folder->permissions); 125dd73a01aSChristoph Hellwig if (inode == sbi->hidden_dir) 1261da177e4SLinus Torvalds /* invisible and namelocked */ 1271da177e4SLinus Torvalds folder->user_info.frFlags = cpu_to_be16(0x5000); 1281da177e4SLinus Torvalds return sizeof(*folder); 1291da177e4SLinus Torvalds } else { 1301da177e4SLinus Torvalds struct hfsplus_cat_file *file; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds file = &entry->file; 1331da177e4SLinus Torvalds memset(file, 0, sizeof(*file)); 1341da177e4SLinus Torvalds file->type = cpu_to_be16(HFSPLUS_FILE); 1351da177e4SLinus Torvalds file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); 1361da177e4SLinus Torvalds file->id = cpu_to_be32(cnid); 1376af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = 1389a4cad95SRoman Zippel file->create_date = 1399a4cad95SRoman Zippel file->content_mod_date = 1409a4cad95SRoman Zippel file->attribute_mod_date = 1419a4cad95SRoman Zippel file->access_date = hfsp_now2mt(); 1421da177e4SLinus Torvalds if (cnid == inode->i_ino) { 14390e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &file->permissions); 1446b192832SRoman Zippel if (S_ISLNK(inode->i_mode)) { 1452753cc28SAnton Salikhmetov file->user_info.fdType = 1462753cc28SAnton Salikhmetov cpu_to_be32(HFSP_SYMLINK_TYPE); 1472753cc28SAnton Salikhmetov file->user_info.fdCreator = 1482753cc28SAnton Salikhmetov cpu_to_be32(HFSP_SYMLINK_CREATOR); 1496b192832SRoman Zippel } else { 1502753cc28SAnton Salikhmetov file->user_info.fdType = 1512753cc28SAnton Salikhmetov cpu_to_be32(sbi->type); 1522753cc28SAnton Salikhmetov file->user_info.fdCreator = 1532753cc28SAnton Salikhmetov cpu_to_be32(sbi->creator); 1546b192832SRoman Zippel } 1552753cc28SAnton Salikhmetov if (HFSPLUS_FLG_IMMUTABLE & 1562753cc28SAnton Salikhmetov (file->permissions.rootflags | 1572753cc28SAnton Salikhmetov file->permissions.userflags)) 1582753cc28SAnton Salikhmetov file->flags |= 1592753cc28SAnton Salikhmetov cpu_to_be16(HFSPLUS_FILE_LOCKED); 1601da177e4SLinus Torvalds } else { 1612753cc28SAnton Salikhmetov file->user_info.fdType = 1622753cc28SAnton Salikhmetov cpu_to_be32(HFSP_HARDLINK_TYPE); 1632753cc28SAnton Salikhmetov file->user_info.fdCreator = 1642753cc28SAnton Salikhmetov cpu_to_be32(HFSP_HFSPLUS_CREATOR); 1652753cc28SAnton Salikhmetov file->user_info.fdFlags = 1662753cc28SAnton Salikhmetov cpu_to_be16(0x100); 1672753cc28SAnton Salikhmetov file->create_date = 1682753cc28SAnton Salikhmetov HFSPLUS_I(sbi->hidden_dir)->create_date; 1692753cc28SAnton Salikhmetov file->permissions.dev = 1702753cc28SAnton Salikhmetov cpu_to_be32(HFSPLUS_I(inode)->linkid); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds return sizeof(*file); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds static int hfsplus_fill_cat_thread(struct super_block *sb, 1771da177e4SLinus Torvalds hfsplus_cat_entry *entry, int type, 178b5cce521SAl Viro u32 parentid, const struct qstr *str) 1791da177e4SLinus Torvalds { 18089ac9b4dSSougata Santra int err; 18189ac9b4dSSougata Santra 1821da177e4SLinus Torvalds entry->type = cpu_to_be16(type); 1831da177e4SLinus Torvalds entry->thread.reserved = 0; 1841da177e4SLinus Torvalds entry->thread.parentID = cpu_to_be32(parentid); 18589ac9b4dSSougata Santra err = hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, 186324ef39aSVyacheslav Dubeyko str->name, str->len); 18789ac9b4dSSougata Santra if (unlikely(err < 0)) 18889ac9b4dSSougata Santra return err; 18989ac9b4dSSougata Santra 1901da177e4SLinus Torvalds return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /* Try to get a catalog entry for given catalog id */ 1941da177e4SLinus Torvalds int hfsplus_find_cat(struct super_block *sb, u32 cnid, 1951da177e4SLinus Torvalds struct hfs_find_data *fd) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds hfsplus_cat_entry tmp; 1981da177e4SLinus Torvalds int err; 1991da177e4SLinus Torvalds u16 type; 2001da177e4SLinus Torvalds 20189ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid); 2021da177e4SLinus Torvalds err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry)); 2031da177e4SLinus Torvalds if (err) 2041da177e4SLinus Torvalds return err; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds type = be16_to_cpu(tmp.type); 2071da177e4SLinus Torvalds if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { 208d6142673SJoe Perches pr_err("found bad thread record in catalog\n"); 2091da177e4SLinus Torvalds return -EIO; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 212efc7ffcbSEric Sesterhenn if (be16_to_cpu(tmp.thread.nodeName.length) > 255) { 213d6142673SJoe Perches pr_err("catalog name length corrupted\n"); 214efc7ffcbSEric Sesterhenn return -EIO; 215efc7ffcbSEric Sesterhenn } 216efc7ffcbSEric Sesterhenn 2172753cc28SAnton Salikhmetov hfsplus_cat_build_key_uni(fd->search_key, 2182753cc28SAnton Salikhmetov be32_to_cpu(tmp.thread.parentID), 2191da177e4SLinus Torvalds &tmp.thread.nodeName); 220324ef39aSVyacheslav Dubeyko return hfs_brec_find(fd, hfs_find_rec_by_key); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 223d7d673a5SSergei Antonov static void hfsplus_subfolders_inc(struct inode *dir) 224d7d673a5SSergei Antonov { 225d7d673a5SSergei Antonov struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); 226d7d673a5SSergei Antonov 227d7d673a5SSergei Antonov if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { 228d7d673a5SSergei Antonov /* 229d7d673a5SSergei Antonov * Increment subfolder count. Note, the value is only meaningful 230d7d673a5SSergei Antonov * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set. 231d7d673a5SSergei Antonov */ 232d7d673a5SSergei Antonov HFSPLUS_I(dir)->subfolders++; 233d7d673a5SSergei Antonov } 234d7d673a5SSergei Antonov } 235d7d673a5SSergei Antonov 236d7d673a5SSergei Antonov static void hfsplus_subfolders_dec(struct inode *dir) 237d7d673a5SSergei Antonov { 238d7d673a5SSergei Antonov struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); 239d7d673a5SSergei Antonov 240d7d673a5SSergei Antonov if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { 241d7d673a5SSergei Antonov /* 242d7d673a5SSergei Antonov * Decrement subfolder count. Note, the value is only meaningful 243d7d673a5SSergei Antonov * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set. 244d7d673a5SSergei Antonov * 245d7d673a5SSergei Antonov * Check for zero. Some subfolders may have been created 246d7d673a5SSergei Antonov * by an implementation ignorant of this counter. 247d7d673a5SSergei Antonov */ 248d7d673a5SSergei Antonov if (HFSPLUS_I(dir)->subfolders) 249d7d673a5SSergei Antonov HFSPLUS_I(dir)->subfolders--; 250d7d673a5SSergei Antonov } 251d7d673a5SSergei Antonov } 252d7d673a5SSergei Antonov 2532753cc28SAnton Salikhmetov int hfsplus_create_cat(u32 cnid, struct inode *dir, 254b5cce521SAl Viro const struct qstr *str, struct inode *inode) 2551da177e4SLinus Torvalds { 256dd73a01aSChristoph Hellwig struct super_block *sb = dir->i_sb; 2571da177e4SLinus Torvalds struct hfs_find_data fd; 2581da177e4SLinus Torvalds hfsplus_cat_entry entry; 2591da177e4SLinus Torvalds int entry_size; 2601da177e4SLinus Torvalds int err; 2611da177e4SLinus Torvalds 262c2b3e1f7SJoe Perches hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n", 2632753cc28SAnton Salikhmetov str->name, cnid, inode->i_nlink); 2645bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 2655bd9d99dSAlexey Khoroshilov if (err) 2665bd9d99dSAlexey Khoroshilov return err; 2671da177e4SLinus Torvalds 26889ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 2692753cc28SAnton Salikhmetov entry_size = hfsplus_fill_cat_thread(sb, &entry, 2702753cc28SAnton Salikhmetov S_ISDIR(inode->i_mode) ? 2711da177e4SLinus Torvalds HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, 2721da177e4SLinus Torvalds dir->i_ino, str); 27389ac9b4dSSougata Santra if (unlikely(entry_size < 0)) { 27489ac9b4dSSougata Santra err = entry_size; 27589ac9b4dSSougata Santra goto err2; 27689ac9b4dSSougata Santra } 27789ac9b4dSSougata Santra 278324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 2791da177e4SLinus Torvalds if (err != -ENOENT) { 2801da177e4SLinus Torvalds if (!err) 2811da177e4SLinus Torvalds err = -EEXIST; 2821da177e4SLinus Torvalds goto err2; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds err = hfs_brec_insert(&fd, &entry, entry_size); 2851da177e4SLinus Torvalds if (err) 2861da177e4SLinus Torvalds goto err2; 2871da177e4SLinus Torvalds 28889ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 28989ac9b4dSSougata Santra if (unlikely(err)) 29089ac9b4dSSougata Santra goto err1; 29189ac9b4dSSougata Santra 2921da177e4SLinus Torvalds entry_size = hfsplus_cat_build_record(&entry, cnid, inode); 293324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 2941da177e4SLinus Torvalds if (err != -ENOENT) { 2951da177e4SLinus Torvalds /* panic? */ 2961da177e4SLinus Torvalds if (!err) 2971da177e4SLinus Torvalds err = -EEXIST; 2981da177e4SLinus Torvalds goto err1; 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds err = hfs_brec_insert(&fd, &entry, entry_size); 3011da177e4SLinus Torvalds if (err) 3021da177e4SLinus Torvalds goto err1; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds dir->i_size++; 305d7d673a5SSergei Antonov if (S_ISDIR(inode->i_mode)) 306d7d673a5SSergei Antonov hfsplus_subfolders_inc(dir); 30702027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 308e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 309e3494705SChristoph Hellwig 3101da177e4SLinus Torvalds hfs_find_exit(&fd); 3111da177e4SLinus Torvalds return 0; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds err1: 31489ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 315324ef39aSVyacheslav Dubeyko if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) 3161da177e4SLinus Torvalds hfs_brec_remove(&fd); 3171da177e4SLinus Torvalds err2: 3181da177e4SLinus Torvalds hfs_find_exit(&fd); 3191da177e4SLinus Torvalds return err; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 322b5cce521SAl Viro int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str) 3231da177e4SLinus Torvalds { 324dd73a01aSChristoph Hellwig struct super_block *sb = dir->i_sb; 3251da177e4SLinus Torvalds struct hfs_find_data fd; 3261da177e4SLinus Torvalds struct hfsplus_fork_raw fork; 3271da177e4SLinus Torvalds struct list_head *pos; 3281da177e4SLinus Torvalds int err, off; 3291da177e4SLinus Torvalds u16 type; 3301da177e4SLinus Torvalds 331c2b3e1f7SJoe Perches hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); 3325bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 3335bd9d99dSAlexey Khoroshilov if (err) 3345bd9d99dSAlexey Khoroshilov return err; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds if (!str) { 3371da177e4SLinus Torvalds int len; 3381da177e4SLinus Torvalds 33989ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 340324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3411da177e4SLinus Torvalds if (err) 3421da177e4SLinus Torvalds goto out; 3431da177e4SLinus Torvalds 3442753cc28SAnton Salikhmetov off = fd.entryoffset + 3452753cc28SAnton Salikhmetov offsetof(struct hfsplus_cat_thread, nodeName); 3461da177e4SLinus Torvalds fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); 3472753cc28SAnton Salikhmetov hfs_bnode_read(fd.bnode, 3482753cc28SAnton Salikhmetov &fd.search_key->cat.name.length, off, 2); 3491da177e4SLinus Torvalds len = be16_to_cpu(fd.search_key->cat.name.length) * 2; 3502753cc28SAnton Salikhmetov hfs_bnode_read(fd.bnode, 3512753cc28SAnton Salikhmetov &fd.search_key->cat.name.unicode, 3522753cc28SAnton Salikhmetov off + 2, len); 3531da177e4SLinus Torvalds fd.search_key->key_len = cpu_to_be16(6 + len); 354f01fa5fbSDan Carpenter } else { 35589ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 35689ac9b4dSSougata Santra if (unlikely(err)) 35789ac9b4dSSougata Santra goto out; 358f01fa5fbSDan Carpenter } 3591da177e4SLinus Torvalds 360324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3611da177e4SLinus Torvalds if (err) 3621da177e4SLinus Torvalds goto out; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 3651da177e4SLinus Torvalds if (type == HFSPLUS_FILE) { 3661da177e4SLinus Torvalds #if 0 3671da177e4SLinus Torvalds off = fd.entryoffset + offsetof(hfsplus_cat_file, data_fork); 3681da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 3691da177e4SLinus Torvalds hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); 3701da177e4SLinus Torvalds #endif 3711da177e4SLinus Torvalds 3722753cc28SAnton Salikhmetov off = fd.entryoffset + 3732753cc28SAnton Salikhmetov offsetof(struct hfsplus_cat_file, rsrc_fork); 3741da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 3751da177e4SLinus Torvalds hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 378323ee8fcSAl Viro /* we only need to take spinlock for exclusion with ->release() */ 379323ee8fcSAl Viro spin_lock(&HFSPLUS_I(dir)->open_dir_lock); 3806af502deSChristoph Hellwig list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) { 3811da177e4SLinus Torvalds struct hfsplus_readdir_data *rd = 3821da177e4SLinus Torvalds list_entry(pos, struct hfsplus_readdir_data, list); 3831da177e4SLinus Torvalds if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0) 3841da177e4SLinus Torvalds rd->file->f_pos--; 3851da177e4SLinus Torvalds } 386323ee8fcSAl Viro spin_unlock(&HFSPLUS_I(dir)->open_dir_lock); 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds err = hfs_brec_remove(&fd); 3891da177e4SLinus Torvalds if (err) 3901da177e4SLinus Torvalds goto out; 3911da177e4SLinus Torvalds 39289ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 393324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3941da177e4SLinus Torvalds if (err) 3951da177e4SLinus Torvalds goto out; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds err = hfs_brec_remove(&fd); 3981da177e4SLinus Torvalds if (err) 3991da177e4SLinus Torvalds goto out; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds dir->i_size--; 402d7d673a5SSergei Antonov if (type == HFSPLUS_FOLDER) 403d7d673a5SSergei Antonov hfsplus_subfolders_dec(dir); 40402027d42SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 405e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 406324ef39aSVyacheslav Dubeyko 407324ef39aSVyacheslav Dubeyko if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) { 408324ef39aSVyacheslav Dubeyko if (HFSPLUS_SB(sb)->attr_tree) 409324ef39aSVyacheslav Dubeyko hfsplus_delete_all_attrs(dir, cnid); 410324ef39aSVyacheslav Dubeyko } 411324ef39aSVyacheslav Dubeyko 4121da177e4SLinus Torvalds out: 4131da177e4SLinus Torvalds hfs_find_exit(&fd); 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds return err; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds int hfsplus_rename_cat(u32 cnid, 419b5cce521SAl Viro struct inode *src_dir, const struct qstr *src_name, 420b5cce521SAl Viro struct inode *dst_dir, const struct qstr *dst_name) 4211da177e4SLinus Torvalds { 422dd73a01aSChristoph Hellwig struct super_block *sb = src_dir->i_sb; 4231da177e4SLinus Torvalds struct hfs_find_data src_fd, dst_fd; 4241da177e4SLinus Torvalds hfsplus_cat_entry entry; 4251da177e4SLinus Torvalds int entry_size, type; 4265bd9d99dSAlexey Khoroshilov int err; 4271da177e4SLinus Torvalds 428c2b3e1f7SJoe Perches hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", 4292753cc28SAnton Salikhmetov cnid, src_dir->i_ino, src_name->name, 4301da177e4SLinus Torvalds dst_dir->i_ino, dst_name->name); 4315bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); 4325bd9d99dSAlexey Khoroshilov if (err) 4335bd9d99dSAlexey Khoroshilov return err; 4341da177e4SLinus Torvalds dst_fd = src_fd; 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds /* find the old dir entry and read the data */ 43789ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, src_fd.search_key, 43889ac9b4dSSougata Santra src_dir->i_ino, src_name); 43989ac9b4dSSougata Santra if (unlikely(err)) 44089ac9b4dSSougata Santra goto out; 44189ac9b4dSSougata Santra 442324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4431da177e4SLinus Torvalds if (err) 4441da177e4SLinus Torvalds goto out; 4456f24f892SGreg Kroah-Hartman if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { 4466f24f892SGreg Kroah-Hartman err = -EIO; 4476f24f892SGreg Kroah-Hartman goto out; 4486f24f892SGreg Kroah-Hartman } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset, 4511da177e4SLinus Torvalds src_fd.entrylength); 452d7d673a5SSergei Antonov type = be16_to_cpu(entry.type); 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds /* create new dir entry with the data from the old entry */ 45589ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, dst_fd.search_key, 45689ac9b4dSSougata Santra dst_dir->i_ino, dst_name); 45789ac9b4dSSougata Santra if (unlikely(err)) 45889ac9b4dSSougata Santra goto out; 45989ac9b4dSSougata Santra 460324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 4611da177e4SLinus Torvalds if (err != -ENOENT) { 4621da177e4SLinus Torvalds if (!err) 4631da177e4SLinus Torvalds err = -EEXIST; 4641da177e4SLinus Torvalds goto out; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength); 4681da177e4SLinus Torvalds if (err) 4691da177e4SLinus Torvalds goto out; 4701da177e4SLinus Torvalds dst_dir->i_size++; 471d7d673a5SSergei Antonov if (type == HFSPLUS_FOLDER) 472d7d673a5SSergei Antonov hfsplus_subfolders_inc(dst_dir); 47302027d42SDeepa Dinamani dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds /* finally remove the old entry */ 47689ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, src_fd.search_key, 47789ac9b4dSSougata Santra src_dir->i_ino, src_name); 47889ac9b4dSSougata Santra if (unlikely(err)) 47989ac9b4dSSougata Santra goto out; 48089ac9b4dSSougata Santra 481324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4821da177e4SLinus Torvalds if (err) 4831da177e4SLinus Torvalds goto out; 4841da177e4SLinus Torvalds err = hfs_brec_remove(&src_fd); 4851da177e4SLinus Torvalds if (err) 4861da177e4SLinus Torvalds goto out; 4871da177e4SLinus Torvalds src_dir->i_size--; 488d7d673a5SSergei Antonov if (type == HFSPLUS_FOLDER) 489d7d673a5SSergei Antonov hfsplus_subfolders_dec(src_dir); 49002027d42SDeepa Dinamani src_dir->i_mtime = src_dir->i_ctime = current_time(src_dir); 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds /* remove old thread entry */ 49389ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, src_fd.search_key, cnid); 494324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4951da177e4SLinus Torvalds if (err) 4961da177e4SLinus Torvalds goto out; 4971da177e4SLinus Torvalds type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); 4981da177e4SLinus Torvalds err = hfs_brec_remove(&src_fd); 4991da177e4SLinus Torvalds if (err) 5001da177e4SLinus Torvalds goto out; 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds /* create new thread entry */ 50389ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, dst_fd.search_key, cnid); 5042753cc28SAnton Salikhmetov entry_size = hfsplus_fill_cat_thread(sb, &entry, type, 5052753cc28SAnton Salikhmetov dst_dir->i_ino, dst_name); 50689ac9b4dSSougata Santra if (unlikely(entry_size < 0)) { 50789ac9b4dSSougata Santra err = entry_size; 50889ac9b4dSSougata Santra goto out; 50989ac9b4dSSougata Santra } 51089ac9b4dSSougata Santra 511324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 5121da177e4SLinus Torvalds if (err != -ENOENT) { 5131da177e4SLinus Torvalds if (!err) 5141da177e4SLinus Torvalds err = -EEXIST; 5151da177e4SLinus Torvalds goto out; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds err = hfs_brec_insert(&dst_fd, &entry, entry_size); 518e3494705SChristoph Hellwig 519e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY); 520e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY); 5211da177e4SLinus Torvalds out: 5221da177e4SLinus Torvalds hfs_bnode_put(dst_fd.bnode); 5231da177e4SLinus Torvalds hfs_find_exit(&src_fd); 5241da177e4SLinus Torvalds return err; 5251da177e4SLinus Torvalds } 526