0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "hfs_fs.h"
0015 #include "btree.h"
0016
0017
0018
0019
0020 static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
0021 unsigned int flags)
0022 {
0023 hfs_cat_rec rec;
0024 struct hfs_find_data fd;
0025 struct inode *inode = NULL;
0026 int res;
0027
0028 res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
0029 if (res)
0030 return ERR_PTR(res);
0031 hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
0032 res = hfs_brec_read(&fd, &rec, sizeof(rec));
0033 if (res) {
0034 if (res != -ENOENT)
0035 inode = ERR_PTR(res);
0036 } else {
0037 inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec);
0038 if (!inode)
0039 inode = ERR_PTR(-EACCES);
0040 }
0041 hfs_find_exit(&fd);
0042 return d_splice_alias(inode, dentry);
0043 }
0044
0045
0046
0047
0048 static int hfs_readdir(struct file *file, struct dir_context *ctx)
0049 {
0050 struct inode *inode = file_inode(file);
0051 struct super_block *sb = inode->i_sb;
0052 int len, err;
0053 char strbuf[HFS_MAX_NAMELEN];
0054 union hfs_cat_rec entry;
0055 struct hfs_find_data fd;
0056 struct hfs_readdir_data *rd;
0057 u16 type;
0058
0059 if (ctx->pos >= inode->i_size)
0060 return 0;
0061
0062 err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
0063 if (err)
0064 return err;
0065 hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
0066 err = hfs_brec_find(&fd);
0067 if (err)
0068 goto out;
0069
0070 if (ctx->pos == 0) {
0071
0072 if (!dir_emit_dot(file, ctx))
0073 goto out;
0074 ctx->pos = 1;
0075 }
0076 if (ctx->pos == 1) {
0077 if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
0078 err = -EIO;
0079 goto out;
0080 }
0081
0082 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
0083 if (entry.type != HFS_CDR_THD) {
0084 pr_err("bad catalog folder thread\n");
0085 err = -EIO;
0086 goto out;
0087 }
0088
0089
0090
0091
0092
0093 if (!dir_emit(ctx, "..", 2,
0094 be32_to_cpu(entry.thread.ParID), DT_DIR))
0095 goto out;
0096 ctx->pos = 2;
0097 }
0098 if (ctx->pos >= inode->i_size)
0099 goto out;
0100 err = hfs_brec_goto(&fd, ctx->pos - 1);
0101 if (err)
0102 goto out;
0103
0104 for (;;) {
0105 if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
0106 pr_err("walked past end of dir\n");
0107 err = -EIO;
0108 goto out;
0109 }
0110
0111 if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
0112 err = -EIO;
0113 goto out;
0114 }
0115
0116 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
0117 type = entry.type;
0118 len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
0119 if (type == HFS_CDR_DIR) {
0120 if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
0121 pr_err("small dir entry\n");
0122 err = -EIO;
0123 goto out;
0124 }
0125 if (!dir_emit(ctx, strbuf, len,
0126 be32_to_cpu(entry.dir.DirID), DT_DIR))
0127 break;
0128 } else if (type == HFS_CDR_FIL) {
0129 if (fd.entrylength < sizeof(struct hfs_cat_file)) {
0130 pr_err("small file entry\n");
0131 err = -EIO;
0132 goto out;
0133 }
0134 if (!dir_emit(ctx, strbuf, len,
0135 be32_to_cpu(entry.file.FlNum), DT_REG))
0136 break;
0137 } else {
0138 pr_err("bad catalog entry type %d\n", type);
0139 err = -EIO;
0140 goto out;
0141 }
0142 ctx->pos++;
0143 if (ctx->pos >= inode->i_size)
0144 goto out;
0145 err = hfs_brec_goto(&fd, 1);
0146 if (err)
0147 goto out;
0148 }
0149 rd = file->private_data;
0150 if (!rd) {
0151 rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL);
0152 if (!rd) {
0153 err = -ENOMEM;
0154 goto out;
0155 }
0156 file->private_data = rd;
0157 rd->file = file;
0158 spin_lock(&HFS_I(inode)->open_dir_lock);
0159 list_add(&rd->list, &HFS_I(inode)->open_dir_list);
0160 spin_unlock(&HFS_I(inode)->open_dir_lock);
0161 }
0162
0163
0164
0165
0166 memcpy(&rd->key, &fd.key->cat, sizeof(struct hfs_cat_key));
0167 out:
0168 hfs_find_exit(&fd);
0169 return err;
0170 }
0171
0172 static int hfs_dir_release(struct inode *inode, struct file *file)
0173 {
0174 struct hfs_readdir_data *rd = file->private_data;
0175 if (rd) {
0176 spin_lock(&HFS_I(inode)->open_dir_lock);
0177 list_del(&rd->list);
0178 spin_unlock(&HFS_I(inode)->open_dir_lock);
0179 kfree(rd);
0180 }
0181 return 0;
0182 }
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 static int hfs_create(struct user_namespace *mnt_userns, struct inode *dir,
0193 struct dentry *dentry, umode_t mode, bool excl)
0194 {
0195 struct inode *inode;
0196 int res;
0197
0198 inode = hfs_new_inode(dir, &dentry->d_name, mode);
0199 if (!inode)
0200 return -ENOMEM;
0201
0202 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
0203 if (res) {
0204 clear_nlink(inode);
0205 hfs_delete_inode(inode);
0206 iput(inode);
0207 return res;
0208 }
0209 d_instantiate(dentry, inode);
0210 mark_inode_dirty(inode);
0211 return 0;
0212 }
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 static int hfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
0223 struct dentry *dentry, umode_t mode)
0224 {
0225 struct inode *inode;
0226 int res;
0227
0228 inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
0229 if (!inode)
0230 return -ENOMEM;
0231
0232 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
0233 if (res) {
0234 clear_nlink(inode);
0235 hfs_delete_inode(inode);
0236 iput(inode);
0237 return res;
0238 }
0239 d_instantiate(dentry, inode);
0240 mark_inode_dirty(inode);
0241 return 0;
0242 }
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255 static int hfs_remove(struct inode *dir, struct dentry *dentry)
0256 {
0257 struct inode *inode = d_inode(dentry);
0258 int res;
0259
0260 if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
0261 return -ENOTEMPTY;
0262 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
0263 if (res)
0264 return res;
0265 clear_nlink(inode);
0266 inode->i_ctime = current_time(inode);
0267 hfs_delete_inode(inode);
0268 mark_inode_dirty(inode);
0269 return 0;
0270 }
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283 static int hfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
0284 struct dentry *old_dentry, struct inode *new_dir,
0285 struct dentry *new_dentry, unsigned int flags)
0286 {
0287 int res;
0288
0289 if (flags & ~RENAME_NOREPLACE)
0290 return -EINVAL;
0291
0292
0293 if (d_really_is_positive(new_dentry)) {
0294 res = hfs_remove(new_dir, new_dentry);
0295 if (res)
0296 return res;
0297 }
0298
0299 res = hfs_cat_move(d_inode(old_dentry)->i_ino,
0300 old_dir, &old_dentry->d_name,
0301 new_dir, &new_dentry->d_name);
0302 if (!res)
0303 hfs_cat_build_key(old_dir->i_sb,
0304 (btree_key *)&HFS_I(d_inode(old_dentry))->cat_key,
0305 new_dir->i_ino, &new_dentry->d_name);
0306 return res;
0307 }
0308
0309 const struct file_operations hfs_dir_operations = {
0310 .read = generic_read_dir,
0311 .iterate_shared = hfs_readdir,
0312 .llseek = generic_file_llseek,
0313 .release = hfs_dir_release,
0314 };
0315
0316 const struct inode_operations hfs_dir_inode_operations = {
0317 .create = hfs_create,
0318 .lookup = hfs_lookup,
0319 .unlink = hfs_remove,
0320 .mkdir = hfs_mkdir,
0321 .rmdir = hfs_remove,
0322 .rename = hfs_rename,
0323 .setattr = hfs_inode_setattr,
0324 };