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 = bfs_readdir, 74 .fsync = generic_file_fsync, 75 .llseek = generic_file_llseek, 76 }; 77 78 extern void dump_imap(const char *, struct super_block *); 79 80 static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 81 bool excl) 82 { 83 int err; 84 struct inode *inode; 85 struct super_block *s = dir->i_sb; 86 struct bfs_sb_info *info = BFS_SB(s); 87 unsigned long ino; 88 89 inode = new_inode(s); 90 if (!inode) 91 return -ENOSPC; 92 mutex_lock(&info->bfs_lock); 93 ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1); 94 if (ino > info->si_lasti) { 95 mutex_unlock(&info->bfs_lock); 96 iput(inode); 97 return -ENOSPC; 98 } 99 set_bit(ino, info->si_imap); 100 info->si_freei--; 101 inode_init_owner(inode, dir, mode); 102 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 103 inode->i_blocks = 0; 104 inode->i_op = &bfs_file_inops; 105 inode->i_fop = &bfs_file_operations; 106 inode->i_mapping->a_ops = &bfs_aops; 107 inode->i_ino = ino; 108 BFS_I(inode)->i_dsk_ino = ino; 109 BFS_I(inode)->i_sblock = 0; 110 BFS_I(inode)->i_eblock = 0; 111 insert_inode_hash(inode); 112 mark_inode_dirty(inode); 113 dump_imap("create", s); 114 115 err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, 116 inode->i_ino); 117 if (err) { 118 inode_dec_link_count(inode); 119 mutex_unlock(&info->bfs_lock); 120 iput(inode); 121 return err; 122 } 123 mutex_unlock(&info->bfs_lock); 124 d_instantiate(dentry, inode); 125 return 0; 126 } 127 128 static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, 129 unsigned int flags) 130 { 131 struct inode *inode = NULL; 132 struct buffer_head *bh; 133 struct bfs_dirent *de; 134 struct bfs_sb_info *info = BFS_SB(dir->i_sb); 135 136 if (dentry->d_name.len > BFS_NAMELEN) 137 return ERR_PTR(-ENAMETOOLONG); 138 139 mutex_lock(&info->bfs_lock); 140 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 141 if (bh) { 142 unsigned long ino = (unsigned long)le16_to_cpu(de->ino); 143 brelse(bh); 144 inode = bfs_iget(dir->i_sb, ino); 145 if (IS_ERR(inode)) { 146 mutex_unlock(&info->bfs_lock); 147 return ERR_CAST(inode); 148 } 149 } 150 mutex_unlock(&info->bfs_lock); 151 d_add(dentry, inode); 152 return NULL; 153 } 154 155 static int bfs_link(struct dentry *old, struct inode *dir, 156 struct dentry *new) 157 { 158 struct inode *inode = old->d_inode; 159 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 160 int err; 161 162 mutex_lock(&info->bfs_lock); 163 err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, 164 inode->i_ino); 165 if (err) { 166 mutex_unlock(&info->bfs_lock); 167 return err; 168 } 169 inc_nlink(inode); 170 inode->i_ctime = CURRENT_TIME_SEC; 171 mark_inode_dirty(inode); 172 ihold(inode); 173 d_instantiate(new, inode); 174 mutex_unlock(&info->bfs_lock); 175 return 0; 176 } 177 178 static int bfs_unlink(struct inode *dir, struct dentry *dentry) 179 { 180 int error = -ENOENT; 181 struct inode *inode = dentry->d_inode; 182 struct buffer_head *bh; 183 struct bfs_dirent *de; 184 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 185 186 mutex_lock(&info->bfs_lock); 187 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 188 if (!bh || (le16_to_cpu(de->ino) != inode->i_ino)) 189 goto out_brelse; 190 191 if (!inode->i_nlink) { 192 printf("unlinking non-existent file %s:%lu (nlink=%d)\n", 193 inode->i_sb->s_id, inode->i_ino, 194 inode->i_nlink); 195 set_nlink(inode, 1); 196 } 197 de->ino = 0; 198 mark_buffer_dirty_inode(bh, dir); 199 dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; 200 mark_inode_dirty(dir); 201 inode->i_ctime = dir->i_ctime; 202 inode_dec_link_count(inode); 203 error = 0; 204 205 out_brelse: 206 brelse(bh); 207 mutex_unlock(&info->bfs_lock); 208 return error; 209 } 210 211 static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, 212 struct inode *new_dir, struct dentry *new_dentry) 213 { 214 struct inode *old_inode, *new_inode; 215 struct buffer_head *old_bh, *new_bh; 216 struct bfs_dirent *old_de, *new_de; 217 struct bfs_sb_info *info; 218 int error = -ENOENT; 219 220 old_bh = new_bh = NULL; 221 old_inode = old_dentry->d_inode; 222 if (S_ISDIR(old_inode->i_mode)) 223 return -EINVAL; 224 225 info = BFS_SB(old_inode->i_sb); 226 227 mutex_lock(&info->bfs_lock); 228 old_bh = bfs_find_entry(old_dir, 229 old_dentry->d_name.name, 230 old_dentry->d_name.len, &old_de); 231 232 if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino)) 233 goto end_rename; 234 235 error = -EPERM; 236 new_inode = new_dentry->d_inode; 237 new_bh = bfs_find_entry(new_dir, 238 new_dentry->d_name.name, 239 new_dentry->d_name.len, &new_de); 240 241 if (new_bh && !new_inode) { 242 brelse(new_bh); 243 new_bh = NULL; 244 } 245 if (!new_bh) { 246 error = bfs_add_entry(new_dir, 247 new_dentry->d_name.name, 248 new_dentry->d_name.len, 249 old_inode->i_ino); 250 if (error) 251 goto end_rename; 252 } 253 old_de->ino = 0; 254 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; 255 mark_inode_dirty(old_dir); 256 if (new_inode) { 257 new_inode->i_ctime = CURRENT_TIME_SEC; 258 inode_dec_link_count(new_inode); 259 } 260 mark_buffer_dirty_inode(old_bh, old_dir); 261 error = 0; 262 263 end_rename: 264 mutex_unlock(&info->bfs_lock); 265 brelse(old_bh); 266 brelse(new_bh); 267 return error; 268 } 269 270 const struct inode_operations bfs_dir_inops = { 271 .create = bfs_create, 272 .lookup = bfs_lookup, 273 .link = bfs_link, 274 .unlink = bfs_unlink, 275 .rename = bfs_rename, 276 }; 277 278 static int bfs_add_entry(struct inode *dir, const unsigned char *name, 279 int namelen, int ino) 280 { 281 struct buffer_head *bh; 282 struct bfs_dirent *de; 283 int block, sblock, eblock, off, pos; 284 int i; 285 286 dprintf("name=%s, namelen=%d\n", name, namelen); 287 288 if (!namelen) 289 return -ENOENT; 290 if (namelen > BFS_NAMELEN) 291 return -ENAMETOOLONG; 292 293 sblock = BFS_I(dir)->i_sblock; 294 eblock = BFS_I(dir)->i_eblock; 295 for (block = sblock; block <= eblock; block++) { 296 bh = sb_bread(dir->i_sb, block); 297 if (!bh) 298 return -ENOSPC; 299 for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { 300 de = (struct bfs_dirent *)(bh->b_data + off); 301 if (!de->ino) { 302 pos = (block - sblock) * BFS_BSIZE + off; 303 if (pos >= dir->i_size) { 304 dir->i_size += BFS_DIRENT_SIZE; 305 dir->i_ctime = CURRENT_TIME_SEC; 306 } 307 dir->i_mtime = CURRENT_TIME_SEC; 308 mark_inode_dirty(dir); 309 de->ino = cpu_to_le16((u16)ino); 310 for (i = 0; i < BFS_NAMELEN; i++) 311 de->name[i] = 312 (i < namelen) ? name[i] : 0; 313 mark_buffer_dirty_inode(bh, dir); 314 brelse(bh); 315 return 0; 316 } 317 } 318 brelse(bh); 319 } 320 return -ENOSPC; 321 } 322 323 static inline int bfs_namecmp(int len, const unsigned char *name, 324 const char *buffer) 325 { 326 if ((len < BFS_NAMELEN) && buffer[len]) 327 return 0; 328 return !memcmp(name, buffer, len); 329 } 330 331 static struct buffer_head *bfs_find_entry(struct inode *dir, 332 const unsigned char *name, int namelen, 333 struct bfs_dirent **res_dir) 334 { 335 unsigned long block = 0, offset = 0; 336 struct buffer_head *bh = NULL; 337 struct bfs_dirent *de; 338 339 *res_dir = NULL; 340 if (namelen > BFS_NAMELEN) 341 return NULL; 342 343 while (block * BFS_BSIZE + offset < dir->i_size) { 344 if (!bh) { 345 bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block); 346 if (!bh) { 347 block++; 348 continue; 349 } 350 } 351 de = (struct bfs_dirent *)(bh->b_data + offset); 352 offset += BFS_DIRENT_SIZE; 353 if (le16_to_cpu(de->ino) && 354 bfs_namecmp(namelen, name, de->name)) { 355 *res_dir = de; 356 return bh; 357 } 358 if (offset < bh->b_size) 359 continue; 360 brelse(bh); 361 bh = NULL; 362 offset = 0; 363 block++; 364 } 365 brelse(bh); 366 return NULL; 367 } 368