1 /* 2 * fs/bfs/dir.c 3 * BFS directory operations. 4 * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 5 */ 6 7 #include <linux/time.h> 8 #include <linux/string.h> 9 #include <linux/fs.h> 10 #include <linux/smp_lock.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 char * name, int namelen, int ino); 24 static struct buffer_head * bfs_find_entry(struct inode * dir, 25 const char * name, int namelen, struct bfs_dirent ** res_dir); 26 27 static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir) 28 { 29 struct inode * dir = f->f_dentry->d_inode; 30 struct buffer_head * bh; 31 struct bfs_dirent * de; 32 unsigned int offset; 33 int block; 34 35 lock_kernel(); 36 37 if (f->f_pos & (BFS_DIRENT_SIZE-1)) { 38 printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos, 39 dir->i_sb->s_id, dir->i_ino); 40 unlock_kernel(); 41 return -EBADF; 42 } 43 44 while (f->f_pos < dir->i_size) { 45 offset = f->f_pos & (BFS_BSIZE-1); 46 block = BFS_I(dir)->i_sblock + (f->f_pos >> BFS_BSIZE_BITS); 47 bh = sb_bread(dir->i_sb, block); 48 if (!bh) { 49 f->f_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 (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) { 57 brelse(bh); 58 unlock_kernel(); 59 return 0; 60 } 61 } 62 offset += BFS_DIRENT_SIZE; 63 f->f_pos += BFS_DIRENT_SIZE; 64 } while (offset < BFS_BSIZE && f->f_pos < dir->i_size); 65 brelse(bh); 66 } 67 68 unlock_kernel(); 69 return 0; 70 } 71 72 struct file_operations bfs_dir_operations = { 73 .read = generic_read_dir, 74 .readdir = bfs_readdir, 75 .fsync = file_fsync, 76 }; 77 78 extern void dump_imap(const char *, struct super_block *); 79 80 static int bfs_create(struct inode * dir, struct dentry * dentry, int mode, 81 struct nameidata *nd) 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 lock_kernel(); 93 ino = find_first_zero_bit(info->si_imap, info->si_lasti); 94 if (ino > info->si_lasti) { 95 unlock_kernel(); 96 iput(inode); 97 return -ENOSPC; 98 } 99 set_bit(ino, info->si_imap); 100 info->si_freei--; 101 inode->i_uid = current->fsuid; 102 inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; 103 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 104 inode->i_blocks = inode->i_blksize = 0; 105 inode->i_op = &bfs_file_inops; 106 inode->i_fop = &bfs_file_operations; 107 inode->i_mapping->a_ops = &bfs_aops; 108 inode->i_mode = mode; 109 inode->i_ino = ino; 110 BFS_I(inode)->i_dsk_ino = ino; 111 BFS_I(inode)->i_sblock = 0; 112 BFS_I(inode)->i_eblock = 0; 113 insert_inode_hash(inode); 114 mark_inode_dirty(inode); 115 dump_imap("create",s); 116 117 err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino); 118 if (err) { 119 inode->i_nlink--; 120 mark_inode_dirty(inode); 121 iput(inode); 122 unlock_kernel(); 123 return err; 124 } 125 unlock_kernel(); 126 d_instantiate(dentry, inode); 127 return 0; 128 } 129 130 static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) 131 { 132 struct inode * inode = NULL; 133 struct buffer_head * bh; 134 struct bfs_dirent * de; 135 136 if (dentry->d_name.len > BFS_NAMELEN) 137 return ERR_PTR(-ENAMETOOLONG); 138 139 lock_kernel(); 140 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 141 if (bh) { 142 unsigned long ino = le32_to_cpu(de->ino); 143 brelse(bh); 144 inode = iget(dir->i_sb, ino); 145 if (!inode) { 146 unlock_kernel(); 147 return ERR_PTR(-EACCES); 148 } 149 } 150 unlock_kernel(); 151 d_add(dentry, inode); 152 return NULL; 153 } 154 155 static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new) 156 { 157 struct inode * inode = old->d_inode; 158 int err; 159 160 lock_kernel(); 161 err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, inode->i_ino); 162 if (err) { 163 unlock_kernel(); 164 return err; 165 } 166 inode->i_nlink++; 167 inode->i_ctime = CURRENT_TIME_SEC; 168 mark_inode_dirty(inode); 169 atomic_inc(&inode->i_count); 170 d_instantiate(new, inode); 171 unlock_kernel(); 172 return 0; 173 } 174 175 176 static int bfs_unlink(struct inode * dir, struct dentry * dentry) 177 { 178 int error = -ENOENT; 179 struct inode * inode; 180 struct buffer_head * bh; 181 struct bfs_dirent * de; 182 183 inode = dentry->d_inode; 184 lock_kernel(); 185 bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); 186 if (!bh || 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", inode->i_sb->s_id, 191 inode->i_ino, inode->i_nlink); 192 inode->i_nlink = 1; 193 } 194 de->ino = 0; 195 mark_buffer_dirty(bh); 196 dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; 197 mark_inode_dirty(dir); 198 inode->i_nlink--; 199 inode->i_ctime = dir->i_ctime; 200 mark_inode_dirty(inode); 201 error = 0; 202 203 out_brelse: 204 brelse(bh); 205 unlock_kernel(); 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 int error = -ENOENT; 216 217 old_bh = new_bh = NULL; 218 old_inode = old_dentry->d_inode; 219 if (S_ISDIR(old_inode->i_mode)) 220 return -EINVAL; 221 222 lock_kernel(); 223 old_bh = bfs_find_entry(old_dir, 224 old_dentry->d_name.name, 225 old_dentry->d_name.len, &old_de); 226 227 if (!old_bh || old_de->ino != old_inode->i_ino) 228 goto end_rename; 229 230 error = -EPERM; 231 new_inode = new_dentry->d_inode; 232 new_bh = bfs_find_entry(new_dir, 233 new_dentry->d_name.name, 234 new_dentry->d_name.len, &new_de); 235 236 if (new_bh && !new_inode) { 237 brelse(new_bh); 238 new_bh = NULL; 239 } 240 if (!new_bh) { 241 error = bfs_add_entry(new_dir, 242 new_dentry->d_name.name, 243 new_dentry->d_name.len, old_inode->i_ino); 244 if (error) 245 goto end_rename; 246 } 247 old_de->ino = 0; 248 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; 249 mark_inode_dirty(old_dir); 250 if (new_inode) { 251 new_inode->i_nlink--; 252 new_inode->i_ctime = CURRENT_TIME_SEC; 253 mark_inode_dirty(new_inode); 254 } 255 mark_buffer_dirty(old_bh); 256 error = 0; 257 258 end_rename: 259 unlock_kernel(); 260 brelse(old_bh); 261 brelse(new_bh); 262 return error; 263 } 264 265 struct inode_operations bfs_dir_inops = { 266 .create = bfs_create, 267 .lookup = bfs_lookup, 268 .link = bfs_link, 269 .unlink = bfs_unlink, 270 .rename = bfs_rename, 271 }; 272 273 static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino) 274 { 275 struct buffer_head * bh; 276 struct bfs_dirent * de; 277 int block, sblock, eblock, off, eoff; 278 int i; 279 280 dprintf("name=%s, namelen=%d\n", name, namelen); 281 282 if (!namelen) 283 return -ENOENT; 284 if (namelen > BFS_NAMELEN) 285 return -ENAMETOOLONG; 286 287 sblock = BFS_I(dir)->i_sblock; 288 eblock = BFS_I(dir)->i_eblock; 289 eoff = dir->i_size % BFS_BSIZE; 290 for (block=sblock; block<=eblock; block++) { 291 bh = sb_bread(dir->i_sb, block); 292 if(!bh) 293 return -ENOSPC; 294 for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) { 295 de = (struct bfs_dirent *)(bh->b_data + off); 296 if (block==eblock && off>=eoff) { 297 /* Do not read/interpret the garbage in the end of eblock. */ 298 de->ino = 0; 299 } 300 if (!de->ino) { 301 if ((block-sblock)*BFS_BSIZE + off >= 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 = ino; 308 for (i=0; i<BFS_NAMELEN; i++) 309 de->name[i] = (i < namelen) ? name[i] : 0; 310 mark_buffer_dirty(bh); 311 brelse(bh); 312 return 0; 313 } 314 } 315 brelse(bh); 316 } 317 return -ENOSPC; 318 } 319 320 static inline int bfs_namecmp(int len, const char * name, const char * buffer) 321 { 322 if (len < BFS_NAMELEN && buffer[len]) 323 return 0; 324 return !memcmp(name, buffer, len); 325 } 326 327 static struct buffer_head * bfs_find_entry(struct inode * dir, 328 const char * name, int namelen, struct bfs_dirent ** res_dir) 329 { 330 unsigned long block, offset; 331 struct buffer_head * bh; 332 struct bfs_dirent * de; 333 334 *res_dir = NULL; 335 if (namelen > BFS_NAMELEN) 336 return NULL; 337 bh = NULL; 338 block = offset = 0; 339 while (block * BFS_BSIZE + offset < dir->i_size) { 340 if (!bh) { 341 bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block); 342 if (!bh) { 343 block++; 344 continue; 345 } 346 } 347 de = (struct bfs_dirent *)(bh->b_data + offset); 348 offset += BFS_DIRENT_SIZE; 349 if (de->ino && bfs_namecmp(namelen, name, de->name)) { 350 *res_dir = de; 351 return bh; 352 } 353 if (offset < bh->b_size) 354 continue; 355 brelse(bh); 356 bh = NULL; 357 offset = 0; 358 block++; 359 } 360 brelse(bh); 361 return NULL; 362 } 363