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_SEC; 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_SEC; 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_SEC; 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 { 212 struct inode *old_inode, *new_inode; 213 struct buffer_head *old_bh, *new_bh; 214 struct bfs_dirent *old_de, *new_de; 215 struct bfs_sb_info *info; 216 int error = -ENOENT; 217 218 old_bh = new_bh = NULL; 219 old_inode = d_inode(old_dentry); 220 if (S_ISDIR(old_inode->i_mode)) 221 return -EINVAL; 222 223 info = BFS_SB(old_inode->i_sb); 224 225 mutex_lock(&info->bfs_lock); 226 old_bh = bfs_find_entry(old_dir, 227 old_dentry->d_name.name, 228 old_dentry->d_name.len, &old_de); 229 230 if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino)) 231 goto end_rename; 232 233 error = -EPERM; 234 new_inode = d_inode(new_dentry); 235 new_bh = bfs_find_entry(new_dir, 236 new_dentry->d_name.name, 237 new_dentry->d_name.len, &new_de); 238 239 if (new_bh && !new_inode) { 240 brelse(new_bh); 241 new_bh = NULL; 242 } 243 if (!new_bh) { 244 error = bfs_add_entry(new_dir, 245 new_dentry->d_name.name, 246 new_dentry->d_name.len, 247 old_inode->i_ino); 248 if (error) 249 goto end_rename; 250 } 251 old_de->ino = 0; 252 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; 253 mark_inode_dirty(old_dir); 254 if (new_inode) { 255 new_inode->i_ctime = CURRENT_TIME_SEC; 256 inode_dec_link_count(new_inode); 257 } 258 mark_buffer_dirty_inode(old_bh, old_dir); 259 error = 0; 260 261 end_rename: 262 mutex_unlock(&info->bfs_lock); 263 brelse(old_bh); 264 brelse(new_bh); 265 return error; 266 } 267 268 const struct inode_operations bfs_dir_inops = { 269 .create = bfs_create, 270 .lookup = bfs_lookup, 271 .link = bfs_link, 272 .unlink = bfs_unlink, 273 .rename = bfs_rename, 274 }; 275 276 static int bfs_add_entry(struct inode *dir, const unsigned char *name, 277 int namelen, int ino) 278 { 279 struct buffer_head *bh; 280 struct bfs_dirent *de; 281 int block, sblock, eblock, off, pos; 282 int i; 283 284 dprintf("name=%s, namelen=%d\n", name, namelen); 285 286 if (!namelen) 287 return -ENOENT; 288 if (namelen > BFS_NAMELEN) 289 return -ENAMETOOLONG; 290 291 sblock = BFS_I(dir)->i_sblock; 292 eblock = BFS_I(dir)->i_eblock; 293 for (block = sblock; block <= eblock; block++) { 294 bh = sb_bread(dir->i_sb, block); 295 if (!bh) 296 return -EIO; 297 for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { 298 de = (struct bfs_dirent *)(bh->b_data + off); 299 if (!de->ino) { 300 pos = (block - sblock) * BFS_BSIZE + off; 301 if (pos >= dir->i_size) { 302 dir->i_size += BFS_DIRENT_SIZE; 303 dir->i_ctime = CURRENT_TIME_SEC; 304 } 305 dir->i_mtime = CURRENT_TIME_SEC; 306 mark_inode_dirty(dir); 307 de->ino = cpu_to_le16((u16)ino); 308 for (i = 0; i < BFS_NAMELEN; i++) 309 de->name[i] = 310 (i < namelen) ? name[i] : 0; 311 mark_buffer_dirty_inode(bh, dir); 312 brelse(bh); 313 return 0; 314 } 315 } 316 brelse(bh); 317 } 318 return -ENOSPC; 319 } 320 321 static inline int bfs_namecmp(int len, const unsigned char *name, 322 const char *buffer) 323 { 324 if ((len < BFS_NAMELEN) && buffer[len]) 325 return 0; 326 return !memcmp(name, buffer, len); 327 } 328 329 static struct buffer_head *bfs_find_entry(struct inode *dir, 330 const unsigned char *name, int namelen, 331 struct bfs_dirent **res_dir) 332 { 333 unsigned long block = 0, offset = 0; 334 struct buffer_head *bh = NULL; 335 struct bfs_dirent *de; 336 337 *res_dir = NULL; 338 if (namelen > BFS_NAMELEN) 339 return NULL; 340 341 while (block * BFS_BSIZE + offset < dir->i_size) { 342 if (!bh) { 343 bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block); 344 if (!bh) { 345 block++; 346 continue; 347 } 348 } 349 de = (struct bfs_dirent *)(bh->b_data + offset); 350 offset += BFS_DIRENT_SIZE; 351 if (le16_to_cpu(de->ino) && 352 bfs_namecmp(namelen, name, de->name)) { 353 *res_dir = de; 354 return bh; 355 } 356 if (offset < bh->b_size) 357 continue; 358 brelse(bh); 359 bh = NULL; 360 offset = 0; 361 block++; 362 } 363 brelse(bh); 364 return NULL; 365 } 366