dir.c (8782B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * fs/bfs/dir.c 4 * BFS directory operations. 5 * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com> 6 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005 7 */ 8 9#include <linux/time.h> 10#include <linux/string.h> 11#include <linux/fs.h> 12#include <linux/buffer_head.h> 13#include <linux/sched.h> 14#include "bfs.h" 15 16#undef DEBUG 17 18#ifdef DEBUG 19#define dprintf(x...) printf(x) 20#else 21#define dprintf(x...) 22#endif 23 24static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino); 25static struct buffer_head *bfs_find_entry(struct inode *dir, 26 const struct qstr *child, 27 struct bfs_dirent **res_dir); 28 29static 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 71const 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 78static int bfs_create(struct user_namespace *mnt_userns, struct inode *dir, 79 struct dentry *dentry, umode_t mode, 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(&init_user_ns, 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, inode->i_ino); 114 if (err) { 115 inode_dec_link_count(inode); 116 mutex_unlock(&info->bfs_lock); 117 iput(inode); 118 return err; 119 } 120 mutex_unlock(&info->bfs_lock); 121 d_instantiate(dentry, inode); 122 return 0; 123} 124 125static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, 126 unsigned int flags) 127{ 128 struct inode *inode = NULL; 129 struct buffer_head *bh; 130 struct bfs_dirent *de; 131 struct bfs_sb_info *info = BFS_SB(dir->i_sb); 132 133 if (dentry->d_name.len > BFS_NAMELEN) 134 return ERR_PTR(-ENAMETOOLONG); 135 136 mutex_lock(&info->bfs_lock); 137 bh = bfs_find_entry(dir, &dentry->d_name, &de); 138 if (bh) { 139 unsigned long ino = (unsigned long)le16_to_cpu(de->ino); 140 brelse(bh); 141 inode = bfs_iget(dir->i_sb, ino); 142 } 143 mutex_unlock(&info->bfs_lock); 144 return d_splice_alias(inode, dentry); 145} 146 147static int bfs_link(struct dentry *old, struct inode *dir, 148 struct dentry *new) 149{ 150 struct inode *inode = d_inode(old); 151 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 152 int err; 153 154 mutex_lock(&info->bfs_lock); 155 err = bfs_add_entry(dir, &new->d_name, inode->i_ino); 156 if (err) { 157 mutex_unlock(&info->bfs_lock); 158 return err; 159 } 160 inc_nlink(inode); 161 inode->i_ctime = current_time(inode); 162 mark_inode_dirty(inode); 163 ihold(inode); 164 d_instantiate(new, inode); 165 mutex_unlock(&info->bfs_lock); 166 return 0; 167} 168 169static int bfs_unlink(struct inode *dir, struct dentry *dentry) 170{ 171 int error = -ENOENT; 172 struct inode *inode = d_inode(dentry); 173 struct buffer_head *bh; 174 struct bfs_dirent *de; 175 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 176 177 mutex_lock(&info->bfs_lock); 178 bh = bfs_find_entry(dir, &dentry->d_name, &de); 179 if (!bh || (le16_to_cpu(de->ino) != inode->i_ino)) 180 goto out_brelse; 181 182 if (!inode->i_nlink) { 183 printf("unlinking non-existent file %s:%lu (nlink=%d)\n", 184 inode->i_sb->s_id, inode->i_ino, 185 inode->i_nlink); 186 set_nlink(inode, 1); 187 } 188 de->ino = 0; 189 mark_buffer_dirty_inode(bh, dir); 190 dir->i_ctime = dir->i_mtime = current_time(dir); 191 mark_inode_dirty(dir); 192 inode->i_ctime = dir->i_ctime; 193 inode_dec_link_count(inode); 194 error = 0; 195 196out_brelse: 197 brelse(bh); 198 mutex_unlock(&info->bfs_lock); 199 return error; 200} 201 202static int bfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, 203 struct dentry *old_dentry, struct inode *new_dir, 204 struct dentry *new_dentry, unsigned int flags) 205{ 206 struct inode *old_inode, *new_inode; 207 struct buffer_head *old_bh, *new_bh; 208 struct bfs_dirent *old_de, *new_de; 209 struct bfs_sb_info *info; 210 int error = -ENOENT; 211 212 if (flags & ~RENAME_NOREPLACE) 213 return -EINVAL; 214 215 old_bh = new_bh = NULL; 216 old_inode = d_inode(old_dentry); 217 if (S_ISDIR(old_inode->i_mode)) 218 return -EINVAL; 219 220 info = BFS_SB(old_inode->i_sb); 221 222 mutex_lock(&info->bfs_lock); 223 old_bh = bfs_find_entry(old_dir, &old_dentry->d_name, &old_de); 224 225 if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino)) 226 goto end_rename; 227 228 error = -EPERM; 229 new_inode = d_inode(new_dentry); 230 new_bh = bfs_find_entry(new_dir, &new_dentry->d_name, &new_de); 231 232 if (new_bh && !new_inode) { 233 brelse(new_bh); 234 new_bh = NULL; 235 } 236 if (!new_bh) { 237 error = bfs_add_entry(new_dir, &new_dentry->d_name, 238 old_inode->i_ino); 239 if (error) 240 goto end_rename; 241 } 242 old_de->ino = 0; 243 old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); 244 mark_inode_dirty(old_dir); 245 if (new_inode) { 246 new_inode->i_ctime = current_time(new_inode); 247 inode_dec_link_count(new_inode); 248 } 249 mark_buffer_dirty_inode(old_bh, old_dir); 250 error = 0; 251 252end_rename: 253 mutex_unlock(&info->bfs_lock); 254 brelse(old_bh); 255 brelse(new_bh); 256 return error; 257} 258 259const struct inode_operations bfs_dir_inops = { 260 .create = bfs_create, 261 .lookup = bfs_lookup, 262 .link = bfs_link, 263 .unlink = bfs_unlink, 264 .rename = bfs_rename, 265}; 266 267static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino) 268{ 269 const unsigned char *name = child->name; 270 int namelen = child->len; 271 struct buffer_head *bh; 272 struct bfs_dirent *de; 273 int block, sblock, eblock, off, pos; 274 int i; 275 276 dprintf("name=%s, namelen=%d\n", name, namelen); 277 278 if (!namelen) 279 return -ENOENT; 280 if (namelen > BFS_NAMELEN) 281 return -ENAMETOOLONG; 282 283 sblock = BFS_I(dir)->i_sblock; 284 eblock = BFS_I(dir)->i_eblock; 285 for (block = sblock; block <= eblock; block++) { 286 bh = sb_bread(dir->i_sb, block); 287 if (!bh) 288 return -EIO; 289 for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { 290 de = (struct bfs_dirent *)(bh->b_data + off); 291 if (!de->ino) { 292 pos = (block - sblock) * BFS_BSIZE + off; 293 if (pos >= dir->i_size) { 294 dir->i_size += BFS_DIRENT_SIZE; 295 dir->i_ctime = current_time(dir); 296 } 297 dir->i_mtime = current_time(dir); 298 mark_inode_dirty(dir); 299 de->ino = cpu_to_le16((u16)ino); 300 for (i = 0; i < BFS_NAMELEN; i++) 301 de->name[i] = 302 (i < namelen) ? name[i] : 0; 303 mark_buffer_dirty_inode(bh, dir); 304 brelse(bh); 305 return 0; 306 } 307 } 308 brelse(bh); 309 } 310 return -ENOSPC; 311} 312 313static inline int bfs_namecmp(int len, const unsigned char *name, 314 const char *buffer) 315{ 316 if ((len < BFS_NAMELEN) && buffer[len]) 317 return 0; 318 return !memcmp(name, buffer, len); 319} 320 321static struct buffer_head *bfs_find_entry(struct inode *dir, 322 const struct qstr *child, 323 struct bfs_dirent **res_dir) 324{ 325 unsigned long block = 0, offset = 0; 326 struct buffer_head *bh = NULL; 327 struct bfs_dirent *de; 328 const unsigned char *name = child->name; 329 int namelen = child->len; 330 331 *res_dir = NULL; 332 if (namelen > BFS_NAMELEN) 333 return NULL; 334 335 while (block * BFS_BSIZE + offset < dir->i_size) { 336 if (!bh) { 337 bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block); 338 if (!bh) { 339 block++; 340 continue; 341 } 342 } 343 de = (struct bfs_dirent *)(bh->b_data + offset); 344 offset += BFS_DIRENT_SIZE; 345 if (le16_to_cpu(de->ino) && 346 bfs_namecmp(namelen, name, de->name)) { 347 *res_dir = de; 348 return bh; 349 } 350 if (offset < bh->b_size) 351 continue; 352 brelse(bh); 353 bh = NULL; 354 offset = 0; 355 block++; 356 } 357 brelse(bh); 358 return NULL; 359}