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