1/* 2 * linux/fs/hfs/dir.c 3 * 4 * Copyright (C) 1995-1997 Paul H. Hargrove 5 * (C) 2003 Ardis Technologies <roman@ardistech.com> 6 * This file may be distributed under the terms of the GNU General Public License. 7 * 8 * This file contains directory-related functions independent of which 9 * scheme is being used to represent forks. 10 * 11 * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds 12 */ 13 14#include "hfs_fs.h" 15#include "btree.h" 16 17/* 18 * hfs_lookup() 19 */ 20static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, 21 unsigned int flags) 22{ 23 hfs_cat_rec rec; 24 struct hfs_find_data fd; 25 struct inode *inode = NULL; 26 int res; 27 28 res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); 29 if (res) 30 return ERR_PTR(res); 31 hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name); 32 res = hfs_brec_read(&fd, &rec, sizeof(rec)); 33 if (res) { 34 hfs_find_exit(&fd); 35 if (res == -ENOENT) { 36 /* No such entry */ 37 inode = NULL; 38 goto done; 39 } 40 return ERR_PTR(res); 41 } 42 inode = hfs_iget(dir->i_sb, &fd.search_key->cat, &rec); 43 hfs_find_exit(&fd); 44 if (!inode) 45 return ERR_PTR(-EACCES); 46done: 47 d_add(dentry, inode); 48 return NULL; 49} 50 51/* 52 * hfs_readdir 53 */ 54static int hfs_readdir(struct file *file, struct dir_context *ctx) 55{ 56 struct inode *inode = file_inode(file); 57 struct super_block *sb = inode->i_sb; 58 int len, err; 59 char strbuf[HFS_MAX_NAMELEN]; 60 union hfs_cat_rec entry; 61 struct hfs_find_data fd; 62 struct hfs_readdir_data *rd; 63 u16 type; 64 65 if (ctx->pos >= inode->i_size) 66 return 0; 67 68 err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd); 69 if (err) 70 return err; 71 hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); 72 err = hfs_brec_find(&fd); 73 if (err) 74 goto out; 75 76 if (ctx->pos == 0) { 77 /* This is completely artificial... */ 78 if (!dir_emit_dot(file, ctx)) 79 goto out; 80 ctx->pos = 1; 81 } 82 if (ctx->pos == 1) { 83 if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) { 84 err = -EIO; 85 goto out; 86 } 87 88 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 89 if (entry.type != HFS_CDR_THD) { 90 pr_err("bad catalog folder thread\n"); 91 err = -EIO; 92 goto out; 93 } 94 //if (fd.entrylength < HFS_MIN_THREAD_SZ) { 95 // pr_err("truncated catalog thread\n"); 96 // err = -EIO; 97 // goto out; 98 //} 99 if (!dir_emit(ctx, "..", 2, 100 be32_to_cpu(entry.thread.ParID), DT_DIR)) 101 goto out; 102 ctx->pos = 2; 103 } 104 if (ctx->pos >= inode->i_size) 105 goto out; 106 err = hfs_brec_goto(&fd, ctx->pos - 1); 107 if (err) 108 goto out; 109 110 for (;;) { 111 if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) { 112 pr_err("walked past end of dir\n"); 113 err = -EIO; 114 goto out; 115 } 116 117 if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) { 118 err = -EIO; 119 goto out; 120 } 121 122 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 123 type = entry.type; 124 len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); 125 if (type == HFS_CDR_DIR) { 126 if (fd.entrylength < sizeof(struct hfs_cat_dir)) { 127 pr_err("small dir entry\n"); 128 err = -EIO; 129 goto out; 130 } 131 if (!dir_emit(ctx, strbuf, len, 132 be32_to_cpu(entry.dir.DirID), DT_DIR)) 133 break; 134 } else if (type == HFS_CDR_FIL) { 135 if (fd.entrylength < sizeof(struct hfs_cat_file)) { 136 pr_err("small file entry\n"); 137 err = -EIO; 138 goto out; 139 } 140 if (!dir_emit(ctx, strbuf, len, 141 be32_to_cpu(entry.file.FlNum), DT_REG)) 142 break; 143 } else { 144 pr_err("bad catalog entry type %d\n", type); 145 err = -EIO; 146 goto out; 147 } 148 ctx->pos++; 149 if (ctx->pos >= inode->i_size) 150 goto out; 151 err = hfs_brec_goto(&fd, 1); 152 if (err) 153 goto out; 154 } 155 rd = file->private_data; 156 if (!rd) { 157 rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL); 158 if (!rd) { 159 err = -ENOMEM; 160 goto out; 161 } 162 file->private_data = rd; 163 rd->file = file; 164 list_add(&rd->list, &HFS_I(inode)->open_dir_list); 165 } 166 memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key)); 167out: 168 hfs_find_exit(&fd); 169 return err; 170} 171 172static int hfs_dir_release(struct inode *inode, struct file *file) 173{ 174 struct hfs_readdir_data *rd = file->private_data; 175 if (rd) { 176 mutex_lock(&inode->i_mutex); 177 list_del(&rd->list); 178 mutex_unlock(&inode->i_mutex); 179 kfree(rd); 180 } 181 return 0; 182} 183 184/* 185 * hfs_create() 186 * 187 * This is the create() entry in the inode_operations structure for 188 * regular HFS directories. The purpose is to create a new file in 189 * a directory and return a corresponding inode, given the inode for 190 * the directory and the name (and its length) of the new file. 191 */ 192static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 193 bool excl) 194{ 195 struct inode *inode; 196 int res; 197 198 inode = hfs_new_inode(dir, &dentry->d_name, mode); 199 if (!inode) 200 return -ENOMEM; 201 202 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 203 if (res) { 204 clear_nlink(inode); 205 hfs_delete_inode(inode); 206 iput(inode); 207 return res; 208 } 209 d_instantiate(dentry, inode); 210 mark_inode_dirty(inode); 211 return 0; 212} 213 214/* 215 * hfs_mkdir() 216 * 217 * This is the mkdir() entry in the inode_operations structure for 218 * regular HFS directories. The purpose is to create a new directory 219 * in a directory, given the inode for the parent directory and the 220 * name (and its length) of the new directory. 221 */ 222static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 223{ 224 struct inode *inode; 225 int res; 226 227 inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); 228 if (!inode) 229 return -ENOMEM; 230 231 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 232 if (res) { 233 clear_nlink(inode); 234 hfs_delete_inode(inode); 235 iput(inode); 236 return res; 237 } 238 d_instantiate(dentry, inode); 239 mark_inode_dirty(inode); 240 return 0; 241} 242 243/* 244 * hfs_remove() 245 * 246 * This serves as both unlink() and rmdir() in the inode_operations 247 * structure for regular HFS directories. The purpose is to delete 248 * an existing child, given the inode for the parent directory and 249 * the name (and its length) of the existing directory. 250 * 251 * HFS does not have hardlinks, so both rmdir and unlink set the 252 * link count to 0. The only difference is the emptiness check. 253 */ 254static int hfs_remove(struct inode *dir, struct dentry *dentry) 255{ 256 struct inode *inode = d_inode(dentry); 257 int res; 258 259 if (S_ISDIR(inode->i_mode) && inode->i_size != 2) 260 return -ENOTEMPTY; 261 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); 262 if (res) 263 return res; 264 clear_nlink(inode); 265 inode->i_ctime = CURRENT_TIME_SEC; 266 hfs_delete_inode(inode); 267 mark_inode_dirty(inode); 268 return 0; 269} 270 271/* 272 * hfs_rename() 273 * 274 * This is the rename() entry in the inode_operations structure for 275 * regular HFS directories. The purpose is to rename an existing 276 * file or directory, given the inode for the current directory and 277 * the name (and its length) of the existing file/directory and the 278 * inode for the new directory and the name (and its length) of the 279 * new file/directory. 280 * XXX: how do you handle must_be dir? 281 */ 282static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, 283 struct inode *new_dir, struct dentry *new_dentry) 284{ 285 int res; 286 287 /* Unlink destination if it already exists */ 288 if (d_really_is_positive(new_dentry)) { 289 res = hfs_remove(new_dir, new_dentry); 290 if (res) 291 return res; 292 } 293 294 res = hfs_cat_move(d_inode(old_dentry)->i_ino, 295 old_dir, &old_dentry->d_name, 296 new_dir, &new_dentry->d_name); 297 if (!res) 298 hfs_cat_build_key(old_dir->i_sb, 299 (btree_key *)&HFS_I(d_inode(old_dentry))->cat_key, 300 new_dir->i_ino, &new_dentry->d_name); 301 return res; 302} 303 304const struct file_operations hfs_dir_operations = { 305 .read = generic_read_dir, 306 .iterate = hfs_readdir, 307 .llseek = generic_file_llseek, 308 .release = hfs_dir_release, 309}; 310 311const struct inode_operations hfs_dir_inode_operations = { 312 .create = hfs_create, 313 .lookup = hfs_lookup, 314 .unlink = hfs_remove, 315 .mkdir = hfs_mkdir, 316 .rmdir = hfs_remove, 317 .rename = hfs_rename, 318 .setattr = hfs_inode_setattr, 319}; 320