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 */ 20 static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, 21 struct nameidata *nd) 22 { 23 hfs_cat_rec rec; 24 struct hfs_find_data fd; 25 struct inode *inode = NULL; 26 int res; 27 28 dentry->d_op = &hfs_dentry_operations; 29 30 hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); 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); 46 done: 47 d_add(dentry, inode); 48 return NULL; 49 } 50 51 /* 52 * hfs_readdir 53 */ 54 static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) 55 { 56 struct inode *inode = filp->f_path.dentry->d_inode; 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 (filp->f_pos >= inode->i_size) 66 return 0; 67 68 hfs_find_init(HFS_SB(sb)->cat_tree, &fd); 69 hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); 70 err = hfs_brec_find(&fd); 71 if (err) 72 goto out; 73 74 switch ((u32)filp->f_pos) { 75 case 0: 76 /* This is completely artificial... */ 77 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) 78 goto out; 79 filp->f_pos++; 80 /* fall through */ 81 case 1: 82 if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) { 83 err = -EIO; 84 goto out; 85 } 86 87 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 88 if (entry.type != HFS_CDR_THD) { 89 printk(KERN_ERR "hfs: bad catalog folder thread\n"); 90 err = -EIO; 91 goto out; 92 } 93 //if (fd.entrylength < HFS_MIN_THREAD_SZ) { 94 // printk(KERN_ERR "hfs: truncated catalog thread\n"); 95 // err = -EIO; 96 // goto out; 97 //} 98 if (filldir(dirent, "..", 2, 1, 99 be32_to_cpu(entry.thread.ParID), DT_DIR)) 100 goto out; 101 filp->f_pos++; 102 /* fall through */ 103 default: 104 if (filp->f_pos >= inode->i_size) 105 goto out; 106 err = hfs_brec_goto(&fd, filp->f_pos - 1); 107 if (err) 108 goto out; 109 } 110 111 for (;;) { 112 if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) { 113 printk(KERN_ERR "hfs: walked past end of dir\n"); 114 err = -EIO; 115 goto out; 116 } 117 118 if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) { 119 err = -EIO; 120 goto out; 121 } 122 123 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); 124 type = entry.type; 125 len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); 126 if (type == HFS_CDR_DIR) { 127 if (fd.entrylength < sizeof(struct hfs_cat_dir)) { 128 printk(KERN_ERR "hfs: small dir entry\n"); 129 err = -EIO; 130 goto out; 131 } 132 if (filldir(dirent, strbuf, len, filp->f_pos, 133 be32_to_cpu(entry.dir.DirID), DT_DIR)) 134 break; 135 } else if (type == HFS_CDR_FIL) { 136 if (fd.entrylength < sizeof(struct hfs_cat_file)) { 137 printk(KERN_ERR "hfs: small file entry\n"); 138 err = -EIO; 139 goto out; 140 } 141 if (filldir(dirent, strbuf, len, filp->f_pos, 142 be32_to_cpu(entry.file.FlNum), DT_REG)) 143 break; 144 } else { 145 printk(KERN_ERR "hfs: bad catalog entry type %d\n", type); 146 err = -EIO; 147 goto out; 148 } 149 filp->f_pos++; 150 if (filp->f_pos >= inode->i_size) 151 goto out; 152 err = hfs_brec_goto(&fd, 1); 153 if (err) 154 goto out; 155 } 156 rd = filp->private_data; 157 if (!rd) { 158 rd = kmalloc(sizeof(struct hfs_readdir_data), GFP_KERNEL); 159 if (!rd) { 160 err = -ENOMEM; 161 goto out; 162 } 163 filp->private_data = rd; 164 rd->file = filp; 165 list_add(&rd->list, &HFS_I(inode)->open_dir_list); 166 } 167 memcpy(&rd->key, &fd.key, sizeof(struct hfs_cat_key)); 168 out: 169 hfs_find_exit(&fd); 170 return err; 171 } 172 173 static int hfs_dir_release(struct inode *inode, struct file *file) 174 { 175 struct hfs_readdir_data *rd = file->private_data; 176 if (rd) { 177 list_del(&rd->list); 178 kfree(rd); 179 } 180 return 0; 181 } 182 183 /* 184 * hfs_create() 185 * 186 * This is the create() entry in the inode_operations structure for 187 * regular HFS directories. The purpose is to create a new file in 188 * a directory and return a corresponding inode, given the inode for 189 * the directory and the name (and its length) of the new file. 190 */ 191 static int hfs_create(struct inode *dir, struct dentry *dentry, int mode, 192 struct nameidata *nd) 193 { 194 struct inode *inode; 195 int res; 196 197 inode = hfs_new_inode(dir, &dentry->d_name, mode); 198 if (!inode) 199 return -ENOSPC; 200 201 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 202 if (res) { 203 inode->i_nlink = 0; 204 hfs_delete_inode(inode); 205 iput(inode); 206 return res; 207 } 208 d_instantiate(dentry, inode); 209 mark_inode_dirty(inode); 210 return 0; 211 } 212 213 /* 214 * hfs_mkdir() 215 * 216 * This is the mkdir() entry in the inode_operations structure for 217 * regular HFS directories. The purpose is to create a new directory 218 * in a directory, given the inode for the parent directory and the 219 * name (and its length) of the new directory. 220 */ 221 static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 222 { 223 struct inode *inode; 224 int res; 225 226 inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); 227 if (!inode) 228 return -ENOSPC; 229 230 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 231 if (res) { 232 inode->i_nlink = 0; 233 hfs_delete_inode(inode); 234 iput(inode); 235 return res; 236 } 237 d_instantiate(dentry, inode); 238 mark_inode_dirty(inode); 239 return 0; 240 } 241 242 /* 243 * hfs_unlink() 244 * 245 * This is the unlink() entry in the inode_operations structure for 246 * regular HFS directories. The purpose is to delete an existing 247 * file, given the inode for the parent directory and the name 248 * (and its length) of the existing file. 249 */ 250 static int hfs_unlink(struct inode *dir, struct dentry *dentry) 251 { 252 struct inode *inode; 253 int res; 254 255 inode = dentry->d_inode; 256 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); 257 if (res) 258 return res; 259 260 drop_nlink(inode); 261 hfs_delete_inode(inode); 262 inode->i_ctime = CURRENT_TIME_SEC; 263 mark_inode_dirty(inode); 264 265 return res; 266 } 267 268 /* 269 * hfs_rmdir() 270 * 271 * This is the rmdir() entry in the inode_operations structure for 272 * regular HFS directories. The purpose is to delete an existing 273 * directory, given the inode for the parent directory and the name 274 * (and its length) of the existing directory. 275 */ 276 static int hfs_rmdir(struct inode *dir, struct dentry *dentry) 277 { 278 struct inode *inode; 279 int res; 280 281 inode = dentry->d_inode; 282 if (inode->i_size != 2) 283 return -ENOTEMPTY; 284 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); 285 if (res) 286 return res; 287 clear_nlink(inode); 288 inode->i_ctime = CURRENT_TIME_SEC; 289 hfs_delete_inode(inode); 290 mark_inode_dirty(inode); 291 return 0; 292 } 293 294 /* 295 * hfs_rename() 296 * 297 * This is the rename() entry in the inode_operations structure for 298 * regular HFS directories. The purpose is to rename an existing 299 * file or directory, given the inode for the current directory and 300 * the name (and its length) of the existing file/directory and the 301 * inode for the new directory and the name (and its length) of the 302 * new file/directory. 303 * XXX: how do you handle must_be dir? 304 */ 305 static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, 306 struct inode *new_dir, struct dentry *new_dentry) 307 { 308 int res; 309 310 /* Unlink destination if it already exists */ 311 if (new_dentry->d_inode) { 312 res = hfs_unlink(new_dir, new_dentry); 313 if (res) 314 return res; 315 } 316 317 res = hfs_cat_move(old_dentry->d_inode->i_ino, 318 old_dir, &old_dentry->d_name, 319 new_dir, &new_dentry->d_name); 320 if (!res) 321 hfs_cat_build_key(old_dir->i_sb, 322 (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key, 323 new_dir->i_ino, &new_dentry->d_name); 324 return res; 325 } 326 327 const struct file_operations hfs_dir_operations = { 328 .read = generic_read_dir, 329 .readdir = hfs_readdir, 330 .llseek = generic_file_llseek, 331 .release = hfs_dir_release, 332 }; 333 334 const struct inode_operations hfs_dir_inode_operations = { 335 .create = hfs_create, 336 .lookup = hfs_lookup, 337 .unlink = hfs_unlink, 338 .mkdir = hfs_mkdir, 339 .rmdir = hfs_rmdir, 340 .rename = hfs_rename, 341 .setattr = hfs_inode_setattr, 342 }; 343