11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfsplus/catalog.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 51da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Handling of catalog records 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include "hfsplus_fs.h" 131da177e4SLinus Torvalds #include "hfsplus_raw.h" 141da177e4SLinus Torvalds 152179d372SDavid Elliott int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, 162179d372SDavid Elliott const hfsplus_btree_key *k2) 171da177e4SLinus Torvalds { 181da177e4SLinus Torvalds __be32 k1p, k2p; 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds k1p = k1->cat.parent; 211da177e4SLinus Torvalds k2p = k2->cat.parent; 221da177e4SLinus Torvalds if (k1p != k2p) 231da177e4SLinus Torvalds return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 241da177e4SLinus Torvalds 252179d372SDavid Elliott return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); 262179d372SDavid Elliott } 272179d372SDavid Elliott 282179d372SDavid Elliott int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, 292179d372SDavid Elliott const hfsplus_btree_key *k2) 302179d372SDavid Elliott { 312179d372SDavid Elliott __be32 k1p, k2p; 322179d372SDavid Elliott 332179d372SDavid Elliott k1p = k1->cat.parent; 342179d372SDavid Elliott k2p = k2->cat.parent; 352179d372SDavid Elliott if (k1p != k2p) 362179d372SDavid Elliott return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; 372179d372SDavid Elliott 382179d372SDavid Elliott return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); 391da177e4SLinus Torvalds } 401da177e4SLinus Torvalds 4189ac9b4dSSougata Santra /* Generates key for catalog file/folders record. */ 4289ac9b4dSSougata Santra int hfsplus_cat_build_key(struct super_block *sb, 4389ac9b4dSSougata Santra hfsplus_btree_key *key, u32 parent, struct qstr *str) 441da177e4SLinus Torvalds { 4589ac9b4dSSougata Santra int len, err; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds key->cat.parent = cpu_to_be32(parent); 4889ac9b4dSSougata Santra err = hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, 49324ef39aSVyacheslav Dubeyko str->name, str->len); 5089ac9b4dSSougata Santra if (unlikely(err < 0)) 5189ac9b4dSSougata Santra return err; 5289ac9b4dSSougata Santra 531da177e4SLinus Torvalds len = be16_to_cpu(key->cat.name.length); 541da177e4SLinus Torvalds key->key_len = cpu_to_be16(6 + 2 * len); 5589ac9b4dSSougata Santra return 0; 5689ac9b4dSSougata Santra } 5789ac9b4dSSougata Santra 5889ac9b4dSSougata Santra /* Generates key for catalog thread record. */ 5989ac9b4dSSougata Santra void hfsplus_cat_build_key_with_cnid(struct super_block *sb, 6089ac9b4dSSougata Santra hfsplus_btree_key *key, u32 parent) 6189ac9b4dSSougata Santra { 6289ac9b4dSSougata Santra key->cat.parent = cpu_to_be32(parent); 6389ac9b4dSSougata Santra key->cat.name.length = 0; 6489ac9b4dSSougata Santra key->key_len = cpu_to_be16(6); 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent, 681da177e4SLinus Torvalds struct hfsplus_unistr *name) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds int ustrlen; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds ustrlen = be16_to_cpu(name->length); 731da177e4SLinus Torvalds key->cat.parent = cpu_to_be32(parent); 741da177e4SLinus Torvalds key->cat.name.length = cpu_to_be16(ustrlen); 751da177e4SLinus Torvalds ustrlen *= 2; 761da177e4SLinus Torvalds memcpy(key->cat.name.unicode, name->unicode, ustrlen); 771da177e4SLinus Torvalds key->key_len = cpu_to_be16(6 + ustrlen); 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 8090e61690SChristoph Hellwig void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds if (inode->i_flags & S_IMMUTABLE) 831da177e4SLinus Torvalds perms->rootflags |= HFSPLUS_FLG_IMMUTABLE; 841da177e4SLinus Torvalds else 851da177e4SLinus Torvalds perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE; 861da177e4SLinus Torvalds if (inode->i_flags & S_APPEND) 871da177e4SLinus Torvalds perms->rootflags |= HFSPLUS_FLG_APPEND; 881da177e4SLinus Torvalds else 891da177e4SLinus Torvalds perms->rootflags &= ~HFSPLUS_FLG_APPEND; 9090e61690SChristoph Hellwig 9190e61690SChristoph Hellwig perms->userflags = HFSPLUS_I(inode)->userflags; 921da177e4SLinus Torvalds perms->mode = cpu_to_be16(inode->i_mode); 9316525e3fSEric W. Biederman perms->owner = cpu_to_be32(i_uid_read(inode)); 9416525e3fSEric W. Biederman perms->group = cpu_to_be32(i_gid_read(inode)); 9590e61690SChristoph Hellwig 9690e61690SChristoph Hellwig if (S_ISREG(inode->i_mode)) 9790e61690SChristoph Hellwig perms->dev = cpu_to_be32(inode->i_nlink); 9890e61690SChristoph Hellwig else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) 9990e61690SChristoph Hellwig perms->dev = cpu_to_be32(inode->i_rdev); 10090e61690SChristoph Hellwig else 10190e61690SChristoph Hellwig perms->dev = 0; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1042753cc28SAnton Salikhmetov static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, 1052753cc28SAnton Salikhmetov u32 cnid, struct inode *inode) 1061da177e4SLinus Torvalds { 107dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 108dd73a01aSChristoph Hellwig 1091da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 1101da177e4SLinus Torvalds struct hfsplus_cat_folder *folder; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds folder = &entry->folder; 1131da177e4SLinus Torvalds memset(folder, 0, sizeof(*folder)); 1141da177e4SLinus Torvalds folder->type = cpu_to_be16(HFSPLUS_FOLDER); 115d7d673a5SSergei Antonov if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) 116d7d673a5SSergei Antonov folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT); 1171da177e4SLinus Torvalds folder->id = cpu_to_be32(inode->i_ino); 1186af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = 1199a4cad95SRoman Zippel folder->create_date = 1209a4cad95SRoman Zippel folder->content_mod_date = 1219a4cad95SRoman Zippel folder->attribute_mod_date = 1229a4cad95SRoman Zippel folder->access_date = hfsp_now2mt(); 12390e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &folder->permissions); 124dd73a01aSChristoph Hellwig if (inode == sbi->hidden_dir) 1251da177e4SLinus Torvalds /* invisible and namelocked */ 1261da177e4SLinus Torvalds folder->user_info.frFlags = cpu_to_be16(0x5000); 1271da177e4SLinus Torvalds return sizeof(*folder); 1281da177e4SLinus Torvalds } else { 1291da177e4SLinus Torvalds struct hfsplus_cat_file *file; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds file = &entry->file; 1321da177e4SLinus Torvalds memset(file, 0, sizeof(*file)); 1331da177e4SLinus Torvalds file->type = cpu_to_be16(HFSPLUS_FILE); 1341da177e4SLinus Torvalds file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); 1351da177e4SLinus Torvalds file->id = cpu_to_be32(cnid); 1366af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = 1379a4cad95SRoman Zippel file->create_date = 1389a4cad95SRoman Zippel file->content_mod_date = 1399a4cad95SRoman Zippel file->attribute_mod_date = 1409a4cad95SRoman Zippel file->access_date = hfsp_now2mt(); 1411da177e4SLinus Torvalds if (cnid == inode->i_ino) { 14290e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &file->permissions); 1436b192832SRoman Zippel if (S_ISLNK(inode->i_mode)) { 1442753cc28SAnton Salikhmetov file->user_info.fdType = 1452753cc28SAnton Salikhmetov cpu_to_be32(HFSP_SYMLINK_TYPE); 1462753cc28SAnton Salikhmetov file->user_info.fdCreator = 1472753cc28SAnton Salikhmetov cpu_to_be32(HFSP_SYMLINK_CREATOR); 1486b192832SRoman Zippel } else { 1492753cc28SAnton Salikhmetov file->user_info.fdType = 1502753cc28SAnton Salikhmetov cpu_to_be32(sbi->type); 1512753cc28SAnton Salikhmetov file->user_info.fdCreator = 1522753cc28SAnton Salikhmetov cpu_to_be32(sbi->creator); 1536b192832SRoman Zippel } 1542753cc28SAnton Salikhmetov if (HFSPLUS_FLG_IMMUTABLE & 1552753cc28SAnton Salikhmetov (file->permissions.rootflags | 1562753cc28SAnton Salikhmetov file->permissions.userflags)) 1572753cc28SAnton Salikhmetov file->flags |= 1582753cc28SAnton Salikhmetov cpu_to_be16(HFSPLUS_FILE_LOCKED); 1591da177e4SLinus Torvalds } else { 1602753cc28SAnton Salikhmetov file->user_info.fdType = 1612753cc28SAnton Salikhmetov cpu_to_be32(HFSP_HARDLINK_TYPE); 1622753cc28SAnton Salikhmetov file->user_info.fdCreator = 1632753cc28SAnton Salikhmetov cpu_to_be32(HFSP_HFSPLUS_CREATOR); 1642753cc28SAnton Salikhmetov file->user_info.fdFlags = 1652753cc28SAnton Salikhmetov cpu_to_be16(0x100); 1662753cc28SAnton Salikhmetov file->create_date = 1672753cc28SAnton Salikhmetov HFSPLUS_I(sbi->hidden_dir)->create_date; 1682753cc28SAnton Salikhmetov file->permissions.dev = 1692753cc28SAnton Salikhmetov cpu_to_be32(HFSPLUS_I(inode)->linkid); 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds return sizeof(*file); 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds static int hfsplus_fill_cat_thread(struct super_block *sb, 1761da177e4SLinus Torvalds hfsplus_cat_entry *entry, int type, 1771da177e4SLinus Torvalds u32 parentid, struct qstr *str) 1781da177e4SLinus Torvalds { 17989ac9b4dSSougata Santra int err; 18089ac9b4dSSougata Santra 1811da177e4SLinus Torvalds entry->type = cpu_to_be16(type); 1821da177e4SLinus Torvalds entry->thread.reserved = 0; 1831da177e4SLinus Torvalds entry->thread.parentID = cpu_to_be32(parentid); 18489ac9b4dSSougata Santra err = hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, 185324ef39aSVyacheslav Dubeyko str->name, str->len); 18689ac9b4dSSougata Santra if (unlikely(err < 0)) 18789ac9b4dSSougata Santra return err; 18889ac9b4dSSougata Santra 1891da177e4SLinus Torvalds return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds /* Try to get a catalog entry for given catalog id */ 1931da177e4SLinus Torvalds int hfsplus_find_cat(struct super_block *sb, u32 cnid, 1941da177e4SLinus Torvalds struct hfs_find_data *fd) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds hfsplus_cat_entry tmp; 1971da177e4SLinus Torvalds int err; 1981da177e4SLinus Torvalds u16 type; 1991da177e4SLinus Torvalds 20089ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd->search_key, cnid); 2011da177e4SLinus Torvalds err = hfs_brec_read(fd, &tmp, sizeof(hfsplus_cat_entry)); 2021da177e4SLinus Torvalds if (err) 2031da177e4SLinus Torvalds return err; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds type = be16_to_cpu(tmp.type); 2061da177e4SLinus Torvalds if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { 207d6142673SJoe Perches pr_err("found bad thread record in catalog\n"); 2081da177e4SLinus Torvalds return -EIO; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 211efc7ffcbSEric Sesterhenn if (be16_to_cpu(tmp.thread.nodeName.length) > 255) { 212d6142673SJoe Perches pr_err("catalog name length corrupted\n"); 213efc7ffcbSEric Sesterhenn return -EIO; 214efc7ffcbSEric Sesterhenn } 215efc7ffcbSEric Sesterhenn 2162753cc28SAnton Salikhmetov hfsplus_cat_build_key_uni(fd->search_key, 2172753cc28SAnton Salikhmetov be32_to_cpu(tmp.thread.parentID), 2181da177e4SLinus Torvalds &tmp.thread.nodeName); 219324ef39aSVyacheslav Dubeyko return hfs_brec_find(fd, hfs_find_rec_by_key); 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 222d7d673a5SSergei Antonov static void hfsplus_subfolders_inc(struct inode *dir) 223d7d673a5SSergei Antonov { 224d7d673a5SSergei Antonov struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); 225d7d673a5SSergei Antonov 226d7d673a5SSergei Antonov if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { 227d7d673a5SSergei Antonov /* 228d7d673a5SSergei Antonov * Increment subfolder count. Note, the value is only meaningful 229d7d673a5SSergei Antonov * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set. 230d7d673a5SSergei Antonov */ 231d7d673a5SSergei Antonov HFSPLUS_I(dir)->subfolders++; 232d7d673a5SSergei Antonov } 233d7d673a5SSergei Antonov } 234d7d673a5SSergei Antonov 235d7d673a5SSergei Antonov static void hfsplus_subfolders_dec(struct inode *dir) 236d7d673a5SSergei Antonov { 237d7d673a5SSergei Antonov struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb); 238d7d673a5SSergei Antonov 239d7d673a5SSergei Antonov if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { 240d7d673a5SSergei Antonov /* 241d7d673a5SSergei Antonov * Decrement subfolder count. Note, the value is only meaningful 242d7d673a5SSergei Antonov * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set. 243d7d673a5SSergei Antonov * 244d7d673a5SSergei Antonov * Check for zero. Some subfolders may have been created 245d7d673a5SSergei Antonov * by an implementation ignorant of this counter. 246d7d673a5SSergei Antonov */ 247d7d673a5SSergei Antonov if (HFSPLUS_I(dir)->subfolders) 248d7d673a5SSergei Antonov HFSPLUS_I(dir)->subfolders--; 249d7d673a5SSergei Antonov } 250d7d673a5SSergei Antonov } 251d7d673a5SSergei Antonov 2522753cc28SAnton Salikhmetov int hfsplus_create_cat(u32 cnid, struct inode *dir, 2532753cc28SAnton Salikhmetov struct qstr *str, struct inode *inode) 2541da177e4SLinus Torvalds { 255dd73a01aSChristoph Hellwig struct super_block *sb = dir->i_sb; 2561da177e4SLinus Torvalds struct hfs_find_data fd; 2571da177e4SLinus Torvalds hfsplus_cat_entry entry; 2581da177e4SLinus Torvalds int entry_size; 2591da177e4SLinus Torvalds int err; 2601da177e4SLinus Torvalds 261c2b3e1f7SJoe Perches hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n", 2622753cc28SAnton Salikhmetov str->name, cnid, inode->i_nlink); 2635bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 2645bd9d99dSAlexey Khoroshilov if (err) 2655bd9d99dSAlexey Khoroshilov return err; 2661da177e4SLinus Torvalds 26789ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 2682753cc28SAnton Salikhmetov entry_size = hfsplus_fill_cat_thread(sb, &entry, 2692753cc28SAnton Salikhmetov S_ISDIR(inode->i_mode) ? 2701da177e4SLinus Torvalds HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, 2711da177e4SLinus Torvalds dir->i_ino, str); 27289ac9b4dSSougata Santra if (unlikely(entry_size < 0)) { 27389ac9b4dSSougata Santra err = entry_size; 27489ac9b4dSSougata Santra goto err2; 27589ac9b4dSSougata Santra } 27689ac9b4dSSougata Santra 277324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 2781da177e4SLinus Torvalds if (err != -ENOENT) { 2791da177e4SLinus Torvalds if (!err) 2801da177e4SLinus Torvalds err = -EEXIST; 2811da177e4SLinus Torvalds goto err2; 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds err = hfs_brec_insert(&fd, &entry, entry_size); 2841da177e4SLinus Torvalds if (err) 2851da177e4SLinus Torvalds goto err2; 2861da177e4SLinus Torvalds 28789ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 28889ac9b4dSSougata Santra if (unlikely(err)) 28989ac9b4dSSougata Santra goto err1; 29089ac9b4dSSougata Santra 2911da177e4SLinus Torvalds entry_size = hfsplus_cat_build_record(&entry, cnid, inode); 292324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 2931da177e4SLinus Torvalds if (err != -ENOENT) { 2941da177e4SLinus Torvalds /* panic? */ 2951da177e4SLinus Torvalds if (!err) 2961da177e4SLinus Torvalds err = -EEXIST; 2971da177e4SLinus Torvalds goto err1; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds err = hfs_brec_insert(&fd, &entry, entry_size); 3001da177e4SLinus Torvalds if (err) 3011da177e4SLinus Torvalds goto err1; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds dir->i_size++; 304d7d673a5SSergei Antonov if (S_ISDIR(inode->i_mode)) 305d7d673a5SSergei Antonov hfsplus_subfolders_inc(dir); 3061da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 307e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 308e3494705SChristoph Hellwig 3091da177e4SLinus Torvalds hfs_find_exit(&fd); 3101da177e4SLinus Torvalds return 0; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds err1: 31389ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 314324ef39aSVyacheslav Dubeyko if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) 3151da177e4SLinus Torvalds hfs_brec_remove(&fd); 3161da177e4SLinus Torvalds err2: 3171da177e4SLinus Torvalds hfs_find_exit(&fd); 3181da177e4SLinus Torvalds return err; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) 3221da177e4SLinus Torvalds { 323dd73a01aSChristoph Hellwig struct super_block *sb = dir->i_sb; 3241da177e4SLinus Torvalds struct hfs_find_data fd; 3251da177e4SLinus Torvalds struct hfsplus_fork_raw fork; 3261da177e4SLinus Torvalds struct list_head *pos; 3271da177e4SLinus Torvalds int err, off; 3281da177e4SLinus Torvalds u16 type; 3291da177e4SLinus Torvalds 330c2b3e1f7SJoe Perches hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); 3315bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 3325bd9d99dSAlexey Khoroshilov if (err) 3335bd9d99dSAlexey Khoroshilov return err; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds if (!str) { 3361da177e4SLinus Torvalds int len; 3371da177e4SLinus Torvalds 33889ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 339324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3401da177e4SLinus Torvalds if (err) 3411da177e4SLinus Torvalds goto out; 3421da177e4SLinus Torvalds 3432753cc28SAnton Salikhmetov off = fd.entryoffset + 3442753cc28SAnton Salikhmetov offsetof(struct hfsplus_cat_thread, nodeName); 3451da177e4SLinus Torvalds fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); 3462753cc28SAnton Salikhmetov hfs_bnode_read(fd.bnode, 3472753cc28SAnton Salikhmetov &fd.search_key->cat.name.length, off, 2); 3481da177e4SLinus Torvalds len = be16_to_cpu(fd.search_key->cat.name.length) * 2; 3492753cc28SAnton Salikhmetov hfs_bnode_read(fd.bnode, 3502753cc28SAnton Salikhmetov &fd.search_key->cat.name.unicode, 3512753cc28SAnton Salikhmetov off + 2, len); 3521da177e4SLinus Torvalds fd.search_key->key_len = cpu_to_be16(6 + len); 353f01fa5fbSDan Carpenter } else { 35489ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 35589ac9b4dSSougata Santra if (unlikely(err)) 35689ac9b4dSSougata Santra goto out; 357f01fa5fbSDan Carpenter } 3581da177e4SLinus Torvalds 359324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3601da177e4SLinus Torvalds if (err) 3611da177e4SLinus Torvalds goto out; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); 3641da177e4SLinus Torvalds if (type == HFSPLUS_FILE) { 3651da177e4SLinus Torvalds #if 0 3661da177e4SLinus Torvalds off = fd.entryoffset + offsetof(hfsplus_cat_file, data_fork); 3671da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 3681da177e4SLinus Torvalds hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); 3691da177e4SLinus Torvalds #endif 3701da177e4SLinus Torvalds 3712753cc28SAnton Salikhmetov off = fd.entryoffset + 3722753cc28SAnton Salikhmetov offsetof(struct hfsplus_cat_file, rsrc_fork); 3731da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); 3741da177e4SLinus Torvalds hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 377323ee8fcSAl Viro /* we only need to take spinlock for exclusion with ->release() */ 378323ee8fcSAl Viro spin_lock(&HFSPLUS_I(dir)->open_dir_lock); 3796af502deSChristoph Hellwig list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) { 3801da177e4SLinus Torvalds struct hfsplus_readdir_data *rd = 3811da177e4SLinus Torvalds list_entry(pos, struct hfsplus_readdir_data, list); 3821da177e4SLinus Torvalds if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0) 3831da177e4SLinus Torvalds rd->file->f_pos--; 3841da177e4SLinus Torvalds } 385323ee8fcSAl Viro spin_unlock(&HFSPLUS_I(dir)->open_dir_lock); 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds err = hfs_brec_remove(&fd); 3881da177e4SLinus Torvalds if (err) 3891da177e4SLinus Torvalds goto out; 3901da177e4SLinus Torvalds 39189ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, fd.search_key, cnid); 392324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&fd, hfs_find_rec_by_key); 3931da177e4SLinus Torvalds if (err) 3941da177e4SLinus Torvalds goto out; 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds err = hfs_brec_remove(&fd); 3971da177e4SLinus Torvalds if (err) 3981da177e4SLinus Torvalds goto out; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds dir->i_size--; 401d7d673a5SSergei Antonov if (type == HFSPLUS_FOLDER) 402d7d673a5SSergei Antonov hfsplus_subfolders_dec(dir); 4031da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 404e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 405324ef39aSVyacheslav Dubeyko 406324ef39aSVyacheslav Dubeyko if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) { 407324ef39aSVyacheslav Dubeyko if (HFSPLUS_SB(sb)->attr_tree) 408324ef39aSVyacheslav Dubeyko hfsplus_delete_all_attrs(dir, cnid); 409324ef39aSVyacheslav Dubeyko } 410324ef39aSVyacheslav Dubeyko 4111da177e4SLinus Torvalds out: 4121da177e4SLinus Torvalds hfs_find_exit(&fd); 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds return err; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds int hfsplus_rename_cat(u32 cnid, 4181da177e4SLinus Torvalds struct inode *src_dir, struct qstr *src_name, 4191da177e4SLinus Torvalds struct inode *dst_dir, struct qstr *dst_name) 4201da177e4SLinus Torvalds { 421dd73a01aSChristoph Hellwig struct super_block *sb = src_dir->i_sb; 4221da177e4SLinus Torvalds struct hfs_find_data src_fd, dst_fd; 4231da177e4SLinus Torvalds hfsplus_cat_entry entry; 4241da177e4SLinus Torvalds int entry_size, type; 4255bd9d99dSAlexey Khoroshilov int err; 4261da177e4SLinus Torvalds 427c2b3e1f7SJoe Perches hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", 4282753cc28SAnton Salikhmetov cnid, src_dir->i_ino, src_name->name, 4291da177e4SLinus Torvalds dst_dir->i_ino, dst_name->name); 4305bd9d99dSAlexey Khoroshilov err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); 4315bd9d99dSAlexey Khoroshilov if (err) 4325bd9d99dSAlexey Khoroshilov return err; 4331da177e4SLinus Torvalds dst_fd = src_fd; 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds /* find the old dir entry and read the data */ 43689ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, src_fd.search_key, 43789ac9b4dSSougata Santra src_dir->i_ino, src_name); 43889ac9b4dSSougata Santra if (unlikely(err)) 43989ac9b4dSSougata Santra goto out; 44089ac9b4dSSougata Santra 441324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4421da177e4SLinus Torvalds if (err) 4431da177e4SLinus Torvalds goto out; 4446f24f892SGreg Kroah-Hartman if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { 4456f24f892SGreg Kroah-Hartman err = -EIO; 4466f24f892SGreg Kroah-Hartman goto out; 4476f24f892SGreg Kroah-Hartman } 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset, 4501da177e4SLinus Torvalds src_fd.entrylength); 451d7d673a5SSergei Antonov type = be16_to_cpu(entry.type); 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds /* create new dir entry with the data from the old entry */ 45489ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, dst_fd.search_key, 45589ac9b4dSSougata Santra dst_dir->i_ino, dst_name); 45689ac9b4dSSougata Santra if (unlikely(err)) 45789ac9b4dSSougata Santra goto out; 45889ac9b4dSSougata Santra 459324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 4601da177e4SLinus Torvalds if (err != -ENOENT) { 4611da177e4SLinus Torvalds if (!err) 4621da177e4SLinus Torvalds err = -EEXIST; 4631da177e4SLinus Torvalds goto out; 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength); 4671da177e4SLinus Torvalds if (err) 4681da177e4SLinus Torvalds goto out; 4691da177e4SLinus Torvalds dst_dir->i_size++; 470d7d673a5SSergei Antonov if (type == HFSPLUS_FOLDER) 471d7d673a5SSergei Antonov hfsplus_subfolders_inc(dst_dir); 4721da177e4SLinus Torvalds dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds /* finally remove the old entry */ 47589ac9b4dSSougata Santra err = hfsplus_cat_build_key(sb, src_fd.search_key, 47689ac9b4dSSougata Santra src_dir->i_ino, src_name); 47789ac9b4dSSougata Santra if (unlikely(err)) 47889ac9b4dSSougata Santra goto out; 47989ac9b4dSSougata Santra 480324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4811da177e4SLinus Torvalds if (err) 4821da177e4SLinus Torvalds goto out; 4831da177e4SLinus Torvalds err = hfs_brec_remove(&src_fd); 4841da177e4SLinus Torvalds if (err) 4851da177e4SLinus Torvalds goto out; 4861da177e4SLinus Torvalds src_dir->i_size--; 487d7d673a5SSergei Antonov if (type == HFSPLUS_FOLDER) 488d7d673a5SSergei Antonov hfsplus_subfolders_dec(src_dir); 4891da177e4SLinus Torvalds src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds /* remove old thread entry */ 49289ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, src_fd.search_key, cnid); 493324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 4941da177e4SLinus Torvalds if (err) 4951da177e4SLinus Torvalds goto out; 4961da177e4SLinus Torvalds type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); 4971da177e4SLinus Torvalds err = hfs_brec_remove(&src_fd); 4981da177e4SLinus Torvalds if (err) 4991da177e4SLinus Torvalds goto out; 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds /* create new thread entry */ 50289ac9b4dSSougata Santra hfsplus_cat_build_key_with_cnid(sb, dst_fd.search_key, cnid); 5032753cc28SAnton Salikhmetov entry_size = hfsplus_fill_cat_thread(sb, &entry, type, 5042753cc28SAnton Salikhmetov dst_dir->i_ino, dst_name); 50589ac9b4dSSougata Santra if (unlikely(entry_size < 0)) { 50689ac9b4dSSougata Santra err = entry_size; 50789ac9b4dSSougata Santra goto out; 50889ac9b4dSSougata Santra } 50989ac9b4dSSougata Santra 510324ef39aSVyacheslav Dubeyko err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 5111da177e4SLinus Torvalds if (err != -ENOENT) { 5121da177e4SLinus Torvalds if (!err) 5131da177e4SLinus Torvalds err = -EEXIST; 5141da177e4SLinus Torvalds goto out; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds err = hfs_brec_insert(&dst_fd, &entry, entry_size); 517e3494705SChristoph Hellwig 518e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY); 519e3494705SChristoph Hellwig hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY); 5201da177e4SLinus Torvalds out: 5211da177e4SLinus Torvalds hfs_bnode_put(dst_fd.bnode); 5221da177e4SLinus Torvalds hfs_find_exit(&src_fd); 5231da177e4SLinus Torvalds return err; 5241da177e4SLinus Torvalds } 525