0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include "hfs_fs.h"
0016 #include "btree.h"
0017
0018
0019
0020
0021
0022
0023 void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, const struct qstr *name)
0024 {
0025 key->cat.reserved = 0;
0026 key->cat.ParID = cpu_to_be32(parent);
0027 if (name) {
0028 hfs_asc2mac(sb, &key->cat.CName, name);
0029 key->key_len = 6 + key->cat.CName.len;
0030 } else {
0031 memset(&key->cat.CName, 0, sizeof(struct hfs_name));
0032 key->key_len = 6;
0033 }
0034 }
0035
0036 static int hfs_cat_build_record(hfs_cat_rec *rec, u32 cnid, struct inode *inode)
0037 {
0038 __be32 mtime = hfs_mtime();
0039
0040 memset(rec, 0, sizeof(*rec));
0041 if (S_ISDIR(inode->i_mode)) {
0042 rec->type = HFS_CDR_DIR;
0043 rec->dir.DirID = cpu_to_be32(cnid);
0044 rec->dir.CrDat = mtime;
0045 rec->dir.MdDat = mtime;
0046 rec->dir.BkDat = 0;
0047 rec->dir.UsrInfo.frView = cpu_to_be16(0xff);
0048 return sizeof(struct hfs_cat_dir);
0049 } else {
0050
0051 rec->type = HFS_CDR_FIL;
0052 rec->file.Flags = HFS_FIL_USED | HFS_FIL_THD;
0053 if (!(inode->i_mode & S_IWUSR))
0054 rec->file.Flags |= HFS_FIL_LOCK;
0055 rec->file.FlNum = cpu_to_be32(cnid);
0056 rec->file.CrDat = mtime;
0057 rec->file.MdDat = mtime;
0058 rec->file.BkDat = 0;
0059 rec->file.UsrWds.fdType = HFS_SB(inode->i_sb)->s_type;
0060 rec->file.UsrWds.fdCreator = HFS_SB(inode->i_sb)->s_creator;
0061 return sizeof(struct hfs_cat_file);
0062 }
0063 }
0064
0065 static int hfs_cat_build_thread(struct super_block *sb,
0066 hfs_cat_rec *rec, int type,
0067 u32 parentid, const struct qstr *name)
0068 {
0069 rec->type = type;
0070 memset(rec->thread.reserved, 0, sizeof(rec->thread.reserved));
0071 rec->thread.ParID = cpu_to_be32(parentid);
0072 hfs_asc2mac(sb, &rec->thread.CName, name);
0073 return sizeof(struct hfs_cat_thread);
0074 }
0075
0076
0077
0078
0079
0080
0081
0082 int hfs_cat_create(u32 cnid, struct inode *dir, const struct qstr *str, struct inode *inode)
0083 {
0084 struct hfs_find_data fd;
0085 struct super_block *sb;
0086 union hfs_cat_rec entry;
0087 int entry_size;
0088 int err;
0089
0090 hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n",
0091 str->name, cnid, inode->i_nlink);
0092 if (dir->i_size >= HFS_MAX_VALENCE)
0093 return -ENOSPC;
0094
0095 sb = dir->i_sb;
0096 err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
0097 if (err)
0098 return err;
0099
0100
0101
0102
0103
0104 err = hfs_bmap_reserve(fd.tree, 2 * fd.tree->depth);
0105 if (err)
0106 goto err2;
0107
0108 hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
0109 entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
0110 HFS_CDR_THD : HFS_CDR_FTH,
0111 dir->i_ino, str);
0112 err = hfs_brec_find(&fd);
0113 if (err != -ENOENT) {
0114 if (!err)
0115 err = -EEXIST;
0116 goto err2;
0117 }
0118 err = hfs_brec_insert(&fd, &entry, entry_size);
0119 if (err)
0120 goto err2;
0121
0122 hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
0123 entry_size = hfs_cat_build_record(&entry, cnid, inode);
0124 err = hfs_brec_find(&fd);
0125 if (err != -ENOENT) {
0126
0127 if (!err)
0128 err = -EEXIST;
0129 goto err1;
0130 }
0131 err = hfs_brec_insert(&fd, &entry, entry_size);
0132 if (err)
0133 goto err1;
0134
0135 dir->i_size++;
0136 dir->i_mtime = dir->i_ctime = current_time(dir);
0137 mark_inode_dirty(dir);
0138 hfs_find_exit(&fd);
0139 return 0;
0140
0141 err1:
0142 hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
0143 if (!hfs_brec_find(&fd))
0144 hfs_brec_remove(&fd);
0145 err2:
0146 hfs_find_exit(&fd);
0147 return err;
0148 }
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
0172 {
0173 __be32 k1p, k2p;
0174
0175 k1p = key1->cat.ParID;
0176 k2p = key2->cat.ParID;
0177
0178 if (k1p != k2p)
0179 return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1;
0180
0181 return hfs_strcmp(key1->cat.CName.name, key1->cat.CName.len,
0182 key2->cat.CName.name, key2->cat.CName.len);
0183 }
0184
0185
0186
0187 int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
0188 struct hfs_find_data *fd)
0189 {
0190 hfs_cat_rec rec;
0191 int res, len, type;
0192
0193 hfs_cat_build_key(sb, fd->search_key, cnid, NULL);
0194 res = hfs_brec_read(fd, &rec, sizeof(rec));
0195 if (res)
0196 return res;
0197
0198 type = rec.type;
0199 if (type != HFS_CDR_THD && type != HFS_CDR_FTH) {
0200 pr_err("found bad thread record in catalog\n");
0201 return -EIO;
0202 }
0203
0204 fd->search_key->cat.ParID = rec.thread.ParID;
0205 len = fd->search_key->cat.CName.len = rec.thread.CName.len;
0206 if (len > HFS_NAMELEN) {
0207 pr_err("bad catalog namelength\n");
0208 return -EIO;
0209 }
0210 memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
0211 return hfs_brec_find(fd);
0212 }
0213
0214
0215
0216
0217
0218
0219
0220
0221 int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
0222 {
0223 struct super_block *sb;
0224 struct hfs_find_data fd;
0225 struct hfs_readdir_data *rd;
0226 int res, type;
0227
0228 hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
0229 sb = dir->i_sb;
0230 res = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
0231 if (res)
0232 return res;
0233
0234 hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
0235 res = hfs_brec_find(&fd);
0236 if (res)
0237 goto out;
0238
0239 type = hfs_bnode_read_u8(fd.bnode, fd.entryoffset);
0240 if (type == HFS_CDR_FIL) {
0241 struct hfs_cat_file file;
0242 hfs_bnode_read(fd.bnode, &file, fd.entryoffset, sizeof(file));
0243 if (be32_to_cpu(file.FlNum) == cnid) {
0244 #if 0
0245 hfs_free_fork(sb, &file, HFS_FK_DATA);
0246 #endif
0247 hfs_free_fork(sb, &file, HFS_FK_RSRC);
0248 }
0249 }
0250
0251
0252 spin_lock(&HFS_I(dir)->open_dir_lock);
0253 list_for_each_entry(rd, &HFS_I(dir)->open_dir_list, list) {
0254 if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
0255 rd->file->f_pos--;
0256 }
0257 spin_unlock(&HFS_I(dir)->open_dir_lock);
0258
0259 res = hfs_brec_remove(&fd);
0260 if (res)
0261 goto out;
0262
0263 hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
0264 res = hfs_brec_find(&fd);
0265 if (!res) {
0266 res = hfs_brec_remove(&fd);
0267 if (res)
0268 goto out;
0269 }
0270
0271 dir->i_size--;
0272 dir->i_mtime = dir->i_ctime = current_time(dir);
0273 mark_inode_dirty(dir);
0274 res = 0;
0275 out:
0276 hfs_find_exit(&fd);
0277
0278 return res;
0279 }
0280
0281
0282
0283
0284
0285
0286
0287
0288 int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
0289 struct inode *dst_dir, const struct qstr *dst_name)
0290 {
0291 struct super_block *sb;
0292 struct hfs_find_data src_fd, dst_fd;
0293 union hfs_cat_rec entry;
0294 int entry_size, type;
0295 int err;
0296
0297 hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
0298 cnid, src_dir->i_ino, src_name->name,
0299 dst_dir->i_ino, dst_name->name);
0300 sb = src_dir->i_sb;
0301 err = hfs_find_init(HFS_SB(sb)->cat_tree, &src_fd);
0302 if (err)
0303 return err;
0304 dst_fd = src_fd;
0305
0306
0307
0308
0309
0310 err = hfs_bmap_reserve(src_fd.tree, 2 * src_fd.tree->depth);
0311 if (err)
0312 goto out;
0313
0314
0315 hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
0316 err = hfs_brec_find(&src_fd);
0317 if (err)
0318 goto out;
0319 if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) {
0320 err = -EIO;
0321 goto out;
0322 }
0323
0324 hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
0325 src_fd.entrylength);
0326
0327
0328 hfs_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
0329 err = hfs_brec_find(&dst_fd);
0330 if (err != -ENOENT) {
0331 if (!err)
0332 err = -EEXIST;
0333 goto out;
0334 }
0335
0336 err = hfs_brec_insert(&dst_fd, &entry, src_fd.entrylength);
0337 if (err)
0338 goto out;
0339 dst_dir->i_size++;
0340 dst_dir->i_mtime = dst_dir->i_ctime = current_time(dst_dir);
0341 mark_inode_dirty(dst_dir);
0342
0343
0344 hfs_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
0345 err = hfs_brec_find(&src_fd);
0346 if (err)
0347 goto out;
0348 err = hfs_brec_remove(&src_fd);
0349 if (err)
0350 goto out;
0351 src_dir->i_size--;
0352 src_dir->i_mtime = src_dir->i_ctime = current_time(src_dir);
0353 mark_inode_dirty(src_dir);
0354
0355 type = entry.type;
0356 if (type == HFS_CDR_FIL && !(entry.file.Flags & HFS_FIL_THD))
0357 goto out;
0358
0359
0360 hfs_cat_build_key(sb, src_fd.search_key, cnid, NULL);
0361 err = hfs_brec_find(&src_fd);
0362 if (err)
0363 goto out;
0364 err = hfs_brec_remove(&src_fd);
0365 if (err)
0366 goto out;
0367
0368
0369 hfs_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
0370 entry_size = hfs_cat_build_thread(sb, &entry, type == HFS_CDR_FIL ? HFS_CDR_FTH : HFS_CDR_THD,
0371 dst_dir->i_ino, dst_name);
0372 err = hfs_brec_find(&dst_fd);
0373 if (err != -ENOENT) {
0374 if (!err)
0375 err = -EEXIST;
0376 goto out;
0377 }
0378 err = hfs_brec_insert(&dst_fd, &entry, entry_size);
0379 out:
0380 hfs_bnode_put(dst_fd.bnode);
0381 hfs_find_exit(&src_fd);
0382 return err;
0383 }