1 /* 2 * fs/bfs/dir.c 3 * BFS directory operations. 4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 5 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005 6 */ 7 8 #include <linux/time.h> 9 #include <linux/string.h> 10 #include <linux/fs.h> 11 #include <linux/buffer_head.h> 12 #include <linux/sched.h> 13 #include "bfs.h" 14 15 #undef DEBUG 16 17 #ifdef DEBUG 18 #define dprintf(x...) printf(x) 19 #else 20 #define dprintf(x...) 21 #endif 22 23 static int bfs_add_entry(struct inode *dir, const unsigned char *name, 24 int namelen, int ino); 25 static struct buffer_head *bfs_find_entry(struct inode *dir, 26 const unsigned char *name, int namelen, 27 struct bfs_dirent **res_dir); 28 29 static int bfs_readdir(struct file *f, struct dir_context *ctx) 30 { 31 struct inode *dir = file_inode(f); 32 struct buffer_head *bh; 33 struct bfs_dirent *de; 34 unsigned int offset; 35 int block; 36 37 if (ctx->pos & (BFS_DIRENT_SIZE - 1)) { 38 printf("Bad f_pos=%08lx for %s:%08lx\n", 39 (unsigned long)ctx->pos, 40 dir->i_sb->s_id, dir->i_ino); 41 return -EINVAL; 42 } 43 44 while (ctx->pos < dir->i_size) { 45 offset = ctx->pos & (BFS_BSIZE - 1); 46 block = BFS_I(dir)->i_sblock + (ctx->pos >> BFS_BSIZE_BITS); 47 bh = sb_bread(dir->i_sb, block); 48 if (!bh) { 49 ctx->pos += BFS_BSIZE - offset; 50 continue; 51 } 52 do { 53 de = (struct bfs_dirent *)(bh->b_data + offset); 54 if (de->ino) { 55 int size = strnlen(de->name, BFS_NAMELEN); 56 if (!dir_emit(ctx, de->name, size, 57 le16_to_cpu(de->ino), 58 DT_UNKNOWN)) { 59 brelse(bh); 60 return 0; 61 } 62 } 63 offset += BFS_DIRENT_SIZE; 64 ctx->pos += BFS_DIRENT_SIZE; 65 } while ((offset < BFS_BSIZE) && (ctx->pos < dir->i_size)); 66 brelse(bh); 67 } 68 return 0; 69 } 70 71 const struct file_operations bfs_dir_operations = { 72 .read = generic_read_dir, 73 .iterate_shared = bfs_readdir, 74 .fsync = generic_file_fsync, 75 .llseek = generic_file_llseek, 76 }; 77 78 static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 79 bool excl) 80 { 81 int err; 82 struct inode *inode; 83 struct super_block *s = dir->i_sb; 84 struct bfs_sb_info *info = BFS_SB(s); 85 unsigned long ino; 86 87 inode = new_inode(s); 88 if (!inode) 89 return -ENOMEM; 90 mutex_lock(&info->bfs_lock); 91 ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1); 92 if (ino > info->si_lasti) { 93 mutex_unlock(&info->bfs_lock); 94 iput(inode); 95 return -ENOSPC; 96 } 97 set_bit(ino, info->si_imap); 98 info->si_freei--; 99 inode_init_owner(inode, dir, mode); 100 inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 101 inode->i_blocks = 0; 102 inode->i_op = &bfs_file_inops; 103 inode->i_fop = &bfs_file_operations; 104 inode->i_mapping->a_ops = &bfs_aops; 105 inode->i_ino = ino; 106 BFS_I(inode)->i_dsk_ino = ino; 107 BFS_I(inode)->i_sblock = 0; 108 BFS_I(inode)->i_eblock = 0; 109 insert_inode_hash(inode); 110 mark_inode_dirty(inode); 111 bfs_dump_imap("create", s); 112 113 err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, 114 inode->i_ino); 115 if (err) { 116 inode_dec_link_count(inode); 117 mutex_unlock(&info->bfs_lock); 118 iput(inode); 119 return err; 120 } 121 mutex_unlock(&info->bfs_lock); 122 d_instantiate(dentry, inode); 123 return 0; 124 } 125 126 static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, 127 unsigned int flags) 128 { 129 struct inode *inode = NULL; 130 struct buffer_head *bh; 131 struct bfs_dirent *de; 132 struct bfs_sb_info *info = BFS_SB(dir->i_sb); 133 134 if (dentry->d_name.len > BFS_NAMELEN) 135 return ERR_PTR(-ENAMETOOLONG); 136 137 mutex_lock(&info->bfs_lock); 138 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 139 if (bh) { 140 unsigned long ino = (unsigned long)le16_to_cpu(de->ino); 141 brelse(bh); 142 inode = bfs_iget(dir->i_sb, ino); 143 if (IS_ERR(inode)) { 144 mutex_unlock(&info->bfs_lock); 145 return ERR_CAST(inode); 146 } 147 } 148 mutex_unlock(&info->bfs_lock); 149 d_add(dentry, inode); 150 return NULL; 151 } 152 153 static int bfs_link(struct dentry *old, struct inode *dir, 154 struct dentry *new) 155 { 156 struct inode *inode = d_inode(old); 157 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 158 int err; 159 160 mutex_lock(&info->bfs_lock); 161 err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, 162 inode->i_ino); 163 if (err) { 164 mutex_unlock(&info->bfs_lock); 165 return err; 166 } 167 inc_nlink(inode); 168 inode->i_ctime = current_time(inode); 169 mark_inode_dirty(inode); 170 ihold(inode); 171 d_instantiate(new, inode); 172 mutex_unlock(&info->bfs_lock); 173 return 0; 174 } 175 176 static int bfs_unlink(struct inode *dir, struct dentry *dentry) 177 { 178 int error = -ENOENT; 179 struct inode *inode = d_inode(dentry); 180 struct buffer_head *bh; 181 struct bfs_dirent *de; 182 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 183 184 mutex_lock(&info->bfs_lock); 185 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 186 if (!bh || (le16_to_cpu(de->ino) != inode->i_ino)) 187 goto out_brelse; 188 189 if (!inode->i_nlink) { 190 printf("unlinking non-existent file %s:%lu (nlink=%d)\n", 191 inode->i_sb->s_id, inode->i_ino, 192 inode->i_nlink); 193 set_nlink(inode, 1); 194 } 195 de->ino = 0; 196 mark_buffer_dirty_inode(bh, dir); 197 dir->i_ctime = dir->i_mtime = current_time(dir); 198 mark_inode_dirty(dir); 199 inode->i_ctime = dir->i_ctime; 200 inode_dec_link_count(inode); 201 error = 0; 202 203 out_brelse: 204 brelse(bh); 205 mutex_unlock(&info->bfs_lock); 206 return error; 207 } 208 209 static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, 210 struct inode *new_dir, struct dentry *new_dentry, 211 unsigned int flags) 212 { 213 struct inode *old_inode, *new_inode; 214 struct buffer_head *old_bh, *new_bh; 215 struct bfs_dirent *old_de, *new_de; 216 struct bfs_sb_info *info; 217 int error = -ENOENT; 218 219 if (flags & ~RENAME_NOREPLACE) 220 return -EINVAL; 221 222 old_bh = new_bh = NULL; 223 old_inode = d_inode(old_dentry); 224 if (S_ISDIR(old_inode->i_mode)) 225 return -EINVAL; 226 227 info = BFS_SB(old_inode->i_sb); 228 229 mutex_lock(&info->bfs_lock); 230 old_bh = bfs_find_entry(old_dir, 231 old_dentry->d_name.name, 232 old_dentry->d_name.len, &old_de); 233 234 if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino)) 235 goto end_rename; 236 237 error = -EPERM; 238 new_inode = d_inode(new_dentry); 239 new_bh = bfs_find_entry(new_dir, 240 new_dentry->d_name.name, 241 new_dentry->d_name.len, &new_de); 242 243 if (new_bh && !new_inode) { 244 brelse(new_bh); 245 new_bh = NULL; 246 } 247 if (!new_bh) { 248 error = bfs_add_entry(new_dir, 249 new_dentry->d_name.name, 250 new_dentry->d_name.len, 251 old_inode->i_ino); 252 if (error) 253 goto end_rename; 254 } 255 old_de->ino = 0; 256 old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); 257 mark_inode_dirty(old_dir); 258 if (new_inode) { 259 new_inode->i_ctime = current_time(new_inode); 260 inode_dec_link_count(new_inode); 261 } 262 mark_buffer_dirty_inode(old_bh, old_dir); 263 error = 0; 264 265 end_rename: 266 mutex_unlock(&info->bfs_lock); 267 brelse(old_bh); 268 brelse(new_bh); 269 return error; 270 } 271 272 const struct inode_operations bfs_dir_inops = { 273 .create = bfs_create, 274 .lookup = bfs_lookup, 275 .link = bfs_link, 276 .unlink = bfs_unlink, 277 .rename = bfs_rename, 278 }; 279 280 static int bfs_add_entry(struct inode *dir, const unsigned char *name, 281 int namelen, int ino) 282 { 283 struct buffer_head *bh; 284 struct bfs_dirent *de; 285 int block, sblock, eblock, off, pos; 286 int i; 287 288 dprintf("name=%s, namelen=%d\n", name, namelen); 289 290 if (!namelen) 291 return -ENOENT; 292 if (namelen > BFS_NAMELEN) 293 return -ENAMETOOLONG; 294 295 sblock = BFS_I(dir)->i_sblock; 296 eblock = BFS_I(dir)->i_eblock; 297 for (block = sblock; block <= eblock; block++) { 298 bh = sb_bread(dir->i_sb, block); 299 if (!bh) 300 return -EIO; 301 for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { 302 de = (struct bfs_dirent *)(bh->b_data + off); 303 if (!de->ino) { 304 pos = (block - sblock) * BFS_BSIZE + off; 305 if (pos >= dir->i_size) { 306 dir->i_size += BFS_DIRENT_SIZE; 307 dir->i_ctime = current_time(dir); 308 } 309 dir->i_mtime = current_time(dir); 310 mark_inode_dirty(dir); 311 de->ino = cpu_to_le16((u16)ino); 312 for (i = 0; i < BFS_NAMELEN; i++) 313 de->name[i] = 314 (i < namelen) ? name[i] : 0; 315 mark_buffer_dirty_inode(bh, dir); 316 brelse(bh); 317 return 0; 318 } 319 } 320 brelse(bh); 321 } 322 return -ENOSPC; 323 } 324 325 static inline int bfs_namecmp(int len, const unsigned char *name, 326 const char *buffer) 327 { 328 if ((len < BFS_NAMELEN) && buffer[len]) 329 return 0; 330 return !memcmp(name, buffer, len); 331 } 332 333 static struct buffer_head *bfs_find_entry(struct inode *dir, 334 const unsigned char *name, int namelen, 335 struct bfs_dirent **res_dir) 336 { 337 unsigned long block = 0, offset = 0; 338 struct buffer_head *bh = NULL; 339 struct bfs_dirent *de; 340 341 *res_dir = NULL; 342 if (namelen > BFS_NAMELEN) 343 return NULL; 344 345 while (block * BFS_BSIZE + offset < dir->i_size) { 346 if (!bh) { 347 bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block); 348 if (!bh) { 349 block++; 350 continue; 351 } 352 } 353 de = (struct bfs_dirent *)(bh->b_data + offset); 354 offset += BFS_DIRENT_SIZE; 355 if (le16_to_cpu(de->ino) && 356 bfs_namecmp(namelen, name, de->name)) { 357 *res_dir = de; 358 return bh; 359 } 360 if (offset < bh->b_size) 361 continue; 362 brelse(bh); 363 bh = NULL; 364 offset = 0; 365 block++; 366 } 367 brelse(bh); 368 return NULL; 369 } 370