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