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 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, umode_t mode, 190 bool excl) 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 clear_nlink(inode); 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, umode_t 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 clear_nlink(inode); 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_remove() 242 * 243 * This serves as both unlink() and rmdir() in the inode_operations 244 * structure for regular HFS directories. The purpose is to delete 245 * an existing child, given the inode for the parent directory and 246 * the name (and its length) of the existing directory. 247 * 248 * HFS does not have hardlinks, so both rmdir and unlink set the 249 * link count to 0. The only difference is the emptiness check. 250 */ 251 static int hfs_remove(struct inode *dir, struct dentry *dentry) 252 { 253 struct inode *inode = dentry->d_inode; 254 int res; 255 256 if (S_ISDIR(inode->i_mode) && inode->i_size != 2) 257 return -ENOTEMPTY; 258 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); 259 if (res) 260 return res; 261 clear_nlink(inode); 262 inode->i_ctime = CURRENT_TIME_SEC; 263 hfs_delete_inode(inode); 264 mark_inode_dirty(inode); 265 return 0; 266 } 267 268 /* 269 * hfs_rename() 270 * 271 * This is the rename() entry in the inode_operations structure for 272 * regular HFS directories. The purpose is to rename an existing 273 * file or directory, given the inode for the current directory and 274 * the name (and its length) of the existing file/directory and the 275 * inode for the new directory and the name (and its length) of the 276 * new file/directory. 277 * XXX: how do you handle must_be dir? 278 */ 279 static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, 280 struct inode *new_dir, struct dentry *new_dentry) 281 { 282 int res; 283 284 /* Unlink destination if it already exists */ 285 if (new_dentry->d_inode) { 286 res = hfs_remove(new_dir, new_dentry); 287 if (res) 288 return res; 289 } 290 291 res = hfs_cat_move(old_dentry->d_inode->i_ino, 292 old_dir, &old_dentry->d_name, 293 new_dir, &new_dentry->d_name); 294 if (!res) 295 hfs_cat_build_key(old_dir->i_sb, 296 (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key, 297 new_dir->i_ino, &new_dentry->d_name); 298 return res; 299 } 300 301 const struct file_operations hfs_dir_operations = { 302 .read = generic_read_dir, 303 .readdir = hfs_readdir, 304 .llseek = generic_file_llseek, 305 .release = hfs_dir_release, 306 }; 307 308 const struct inode_operations hfs_dir_inode_operations = { 309 .create = hfs_create, 310 .lookup = hfs_lookup, 311 .unlink = hfs_remove, 312 .mkdir = hfs_mkdir, 313 .rmdir = hfs_remove, 314 .rename = hfs_rename, 315 .setattr = hfs_inode_setattr, 316 }; 317