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