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 24 static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino); 25 static struct buffer_head *bfs_find_entry(struct inode *dir, 26 const struct qstr *child, 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:%08llx\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 static int bfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) 72 { 73 return mmb_fsync(file, 74 &BFS_I(file->f_mapping->host)->i_metadata_bhs, 75 start, end, datasync); 76 } 77 78 const struct file_operations bfs_dir_operations = { 79 .read = generic_read_dir, 80 .iterate_shared = bfs_readdir, 81 .fsync = bfs_fsync, 82 .llseek = generic_file_llseek, 83 }; 84 85 static int bfs_create(struct mnt_idmap *idmap, struct inode *dir, 86 struct dentry *dentry, umode_t mode, bool excl) 87 { 88 int err; 89 struct inode *inode; 90 struct super_block *s = dir->i_sb; 91 struct bfs_sb_info *info = BFS_SB(s); 92 unsigned long ino; 93 94 inode = new_inode(s); 95 if (!inode) 96 return -ENOMEM; 97 mutex_lock(&info->bfs_lock); 98 ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1); 99 if (ino > info->si_lasti) { 100 mutex_unlock(&info->bfs_lock); 101 iput(inode); 102 return -ENOSPC; 103 } 104 set_bit(ino, info->si_imap); 105 info->si_freei--; 106 inode_init_owner(&nop_mnt_idmap, inode, dir, mode); 107 simple_inode_init_ts(inode); 108 inode->i_blocks = 0; 109 inode->i_op = &bfs_file_inops; 110 inode->i_fop = &bfs_file_operations; 111 inode->i_mapping->a_ops = &bfs_aops; 112 inode->i_ino = ino; 113 BFS_I(inode)->i_dsk_ino = ino; 114 BFS_I(inode)->i_sblock = 0; 115 BFS_I(inode)->i_eblock = 0; 116 insert_inode_hash(inode); 117 mark_inode_dirty(inode); 118 bfs_dump_imap("create", s); 119 120 err = bfs_add_entry(dir, &dentry->d_name, inode->i_ino); 121 if (err) { 122 inode_dec_link_count(inode); 123 mutex_unlock(&info->bfs_lock); 124 iput(inode); 125 return err; 126 } 127 mutex_unlock(&info->bfs_lock); 128 d_instantiate(dentry, inode); 129 return 0; 130 } 131 132 static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, 133 unsigned int flags) 134 { 135 struct inode *inode = NULL; 136 struct buffer_head *bh; 137 struct bfs_dirent *de; 138 struct bfs_sb_info *info = BFS_SB(dir->i_sb); 139 140 if (dentry->d_name.len > BFS_NAMELEN) 141 return ERR_PTR(-ENAMETOOLONG); 142 143 mutex_lock(&info->bfs_lock); 144 bh = bfs_find_entry(dir, &dentry->d_name, &de); 145 if (bh) { 146 unsigned long ino = (unsigned long)le16_to_cpu(de->ino); 147 brelse(bh); 148 inode = bfs_iget(dir->i_sb, ino); 149 } 150 mutex_unlock(&info->bfs_lock); 151 return d_splice_alias(inode, dentry); 152 } 153 154 static int bfs_link(struct dentry *old, struct inode *dir, 155 struct dentry *new) 156 { 157 struct inode *inode = d_inode(old); 158 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 159 int err; 160 161 mutex_lock(&info->bfs_lock); 162 err = bfs_add_entry(dir, &new->d_name, inode->i_ino); 163 if (err) { 164 mutex_unlock(&info->bfs_lock); 165 return err; 166 } 167 inc_nlink(inode); 168 inode_set_ctime_current(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, &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:%llu (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 mmb_mark_buffer_dirty(bh, &BFS_I(dir)->i_metadata_bhs); 197 inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); 198 mark_inode_dirty(dir); 199 inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); 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 mnt_idmap *idmap, struct inode *old_dir, 210 struct dentry *old_dentry, struct inode *new_dir, 211 struct dentry *new_dentry, 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, &old_dentry->d_name, &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 = d_inode(new_dentry); 237 new_bh = bfs_find_entry(new_dir, &new_dentry->d_name, &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, &new_dentry->d_name, 245 old_inode->i_ino); 246 if (error) 247 goto end_rename; 248 } 249 old_de->ino = 0; 250 inode_set_mtime_to_ts(old_dir, inode_set_ctime_current(old_dir)); 251 mark_inode_dirty(old_dir); 252 if (new_inode) { 253 inode_set_ctime_current(new_inode); 254 inode_dec_link_count(new_inode); 255 } 256 mmb_mark_buffer_dirty(old_bh, &BFS_I(old_dir)->i_metadata_bhs); 257 error = 0; 258 259 end_rename: 260 mutex_unlock(&info->bfs_lock); 261 brelse(old_bh); 262 brelse(new_bh); 263 return error; 264 } 265 266 const struct inode_operations bfs_dir_inops = { 267 .create = bfs_create, 268 .lookup = bfs_lookup, 269 .link = bfs_link, 270 .unlink = bfs_unlink, 271 .rename = bfs_rename, 272 }; 273 274 static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino) 275 { 276 const unsigned char *name = child->name; 277 int namelen = child->len; 278 struct buffer_head *bh; 279 struct bfs_dirent *de; 280 int block, sblock, eblock, off, pos; 281 int i; 282 283 dprintf("name=%s, namelen=%d\n", name, namelen); 284 285 sblock = BFS_I(dir)->i_sblock; 286 eblock = BFS_I(dir)->i_eblock; 287 for (block = sblock; block <= eblock; block++) { 288 bh = sb_bread(dir->i_sb, block); 289 if (!bh) 290 return -EIO; 291 for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) { 292 de = (struct bfs_dirent *)(bh->b_data + off); 293 if (!de->ino) { 294 pos = (block - sblock) * BFS_BSIZE + off; 295 if (pos >= dir->i_size) { 296 dir->i_size += BFS_DIRENT_SIZE; 297 inode_set_ctime_current(dir); 298 } 299 inode_set_mtime_to_ts(dir, 300 inode_set_ctime_current(dir)); 301 mark_inode_dirty(dir); 302 de->ino = cpu_to_le16((u16)ino); 303 for (i = 0; i < BFS_NAMELEN; i++) 304 de->name[i] = 305 (i < namelen) ? name[i] : 0; 306 mmb_mark_buffer_dirty(bh, 307 &BFS_I(dir)->i_metadata_bhs); 308 brelse(bh); 309 return 0; 310 } 311 } 312 brelse(bh); 313 } 314 return -ENOSPC; 315 } 316 317 static inline int bfs_namecmp(int len, const unsigned char *name, 318 const char *buffer) 319 { 320 if ((len < BFS_NAMELEN) && buffer[len]) 321 return 0; 322 return !memcmp(name, buffer, len); 323 } 324 325 static struct buffer_head *bfs_find_entry(struct inode *dir, 326 const struct qstr *child, 327 struct bfs_dirent **res_dir) 328 { 329 unsigned long block = 0, offset = 0; 330 struct buffer_head *bh = NULL; 331 struct bfs_dirent *de; 332 const unsigned char *name = child->name; 333 int namelen = child->len; 334 335 *res_dir = NULL; 336 if (namelen > BFS_NAMELEN) 337 return NULL; 338 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 (le16_to_cpu(de->ino) && 350 bfs_namecmp(namelen, name, de->name)) { 351 *res_dir = de; 352 return bh; 353 } 354 if (offset < bh->b_size) 355 continue; 356 brelse(bh); 357 bh = NULL; 358 offset = 0; 359 block++; 360 } 361 brelse(bh); 362 return NULL; 363 } 364