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 pr_err("bad catalog folder thread\n"); 92 err = -EIO; 93 goto out; 94 } 95 //if (fd.entrylength < HFS_MIN_THREAD_SZ) { 96 // pr_err("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 pr_err("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 pr_err("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 pr_err("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 pr_err("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 mutex_lock(&inode->i_mutex); 180 list_del(&rd->list); 181 mutex_unlock(&inode->i_mutex); 182 kfree(rd); 183 } 184 return 0; 185 } 186 187 /* 188 * hfs_create() 189 * 190 * This is the create() entry in the inode_operations structure for 191 * regular HFS directories. The purpose is to create a new file in 192 * a directory and return a corresponding inode, given the inode for 193 * the directory and the name (and its length) of the new file. 194 */ 195 static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 196 bool excl) 197 { 198 struct inode *inode; 199 int res; 200 201 inode = hfs_new_inode(dir, &dentry->d_name, mode); 202 if (!inode) 203 return -ENOSPC; 204 205 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 206 if (res) { 207 clear_nlink(inode); 208 hfs_delete_inode(inode); 209 iput(inode); 210 return res; 211 } 212 d_instantiate(dentry, inode); 213 mark_inode_dirty(inode); 214 return 0; 215 } 216 217 /* 218 * hfs_mkdir() 219 * 220 * This is the mkdir() entry in the inode_operations structure for 221 * regular HFS directories. The purpose is to create a new directory 222 * in a directory, given the inode for the parent directory and the 223 * name (and its length) of the new directory. 224 */ 225 static int hfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 226 { 227 struct inode *inode; 228 int res; 229 230 inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode); 231 if (!inode) 232 return -ENOSPC; 233 234 res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode); 235 if (res) { 236 clear_nlink(inode); 237 hfs_delete_inode(inode); 238 iput(inode); 239 return res; 240 } 241 d_instantiate(dentry, inode); 242 mark_inode_dirty(inode); 243 return 0; 244 } 245 246 /* 247 * hfs_remove() 248 * 249 * This serves as both unlink() and rmdir() in the inode_operations 250 * structure for regular HFS directories. The purpose is to delete 251 * an existing child, given the inode for the parent directory and 252 * the name (and its length) of the existing directory. 253 * 254 * HFS does not have hardlinks, so both rmdir and unlink set the 255 * link count to 0. The only difference is the emptiness check. 256 */ 257 static int hfs_remove(struct inode *dir, struct dentry *dentry) 258 { 259 struct inode *inode = dentry->d_inode; 260 int res; 261 262 if (S_ISDIR(inode->i_mode) && inode->i_size != 2) 263 return -ENOTEMPTY; 264 res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name); 265 if (res) 266 return res; 267 clear_nlink(inode); 268 inode->i_ctime = CURRENT_TIME_SEC; 269 hfs_delete_inode(inode); 270 mark_inode_dirty(inode); 271 return 0; 272 } 273 274 /* 275 * hfs_rename() 276 * 277 * This is the rename() entry in the inode_operations structure for 278 * regular HFS directories. The purpose is to rename an existing 279 * file or directory, given the inode for the current directory and 280 * the name (and its length) of the existing file/directory and the 281 * inode for the new directory and the name (and its length) of the 282 * new file/directory. 283 * XXX: how do you handle must_be dir? 284 */ 285 static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, 286 struct inode *new_dir, struct dentry *new_dentry) 287 { 288 int res; 289 290 /* Unlink destination if it already exists */ 291 if (new_dentry->d_inode) { 292 res = hfs_remove(new_dir, new_dentry); 293 if (res) 294 return res; 295 } 296 297 res = hfs_cat_move(old_dentry->d_inode->i_ino, 298 old_dir, &old_dentry->d_name, 299 new_dir, &new_dentry->d_name); 300 if (!res) 301 hfs_cat_build_key(old_dir->i_sb, 302 (btree_key *)&HFS_I(old_dentry->d_inode)->cat_key, 303 new_dir->i_ino, &new_dentry->d_name); 304 return res; 305 } 306 307 const struct file_operations hfs_dir_operations = { 308 .read = generic_read_dir, 309 .readdir = hfs_readdir, 310 .llseek = generic_file_llseek, 311 .release = hfs_dir_release, 312 }; 313 314 const struct inode_operations hfs_dir_inode_operations = { 315 .create = hfs_create, 316 .lookup = hfs_lookup, 317 .unlink = hfs_remove, 318 .mkdir = hfs_mkdir, 319 .rmdir = hfs_remove, 320 .rename = hfs_rename, 321 .setattr = hfs_inode_setattr, 322 }; 323