0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/time.h>
0010 #include <linux/string.h>
0011 #include <linux/fs.h>
0012 #include <linux/buffer_head.h>
0013 #include <linux/sched.h>
0014 #include "bfs.h"
0015
0016 #undef DEBUG
0017
0018 #ifdef DEBUG
0019 #define dprintf(x...) printf(x)
0020 #else
0021 #define dprintf(x...)
0022 #endif
0023
0024 static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino);
0025 static struct buffer_head *bfs_find_entry(struct inode *dir,
0026 const struct qstr *child,
0027 struct bfs_dirent **res_dir);
0028
0029 static int bfs_readdir(struct file *f, struct dir_context *ctx)
0030 {
0031 struct inode *dir = file_inode(f);
0032 struct buffer_head *bh;
0033 struct bfs_dirent *de;
0034 unsigned int offset;
0035 int block;
0036
0037 if (ctx->pos & (BFS_DIRENT_SIZE - 1)) {
0038 printf("Bad f_pos=%08lx for %s:%08lx\n",
0039 (unsigned long)ctx->pos,
0040 dir->i_sb->s_id, dir->i_ino);
0041 return -EINVAL;
0042 }
0043
0044 while (ctx->pos < dir->i_size) {
0045 offset = ctx->pos & (BFS_BSIZE - 1);
0046 block = BFS_I(dir)->i_sblock + (ctx->pos >> BFS_BSIZE_BITS);
0047 bh = sb_bread(dir->i_sb, block);
0048 if (!bh) {
0049 ctx->pos += BFS_BSIZE - offset;
0050 continue;
0051 }
0052 do {
0053 de = (struct bfs_dirent *)(bh->b_data + offset);
0054 if (de->ino) {
0055 int size = strnlen(de->name, BFS_NAMELEN);
0056 if (!dir_emit(ctx, de->name, size,
0057 le16_to_cpu(de->ino),
0058 DT_UNKNOWN)) {
0059 brelse(bh);
0060 return 0;
0061 }
0062 }
0063 offset += BFS_DIRENT_SIZE;
0064 ctx->pos += BFS_DIRENT_SIZE;
0065 } while ((offset < BFS_BSIZE) && (ctx->pos < dir->i_size));
0066 brelse(bh);
0067 }
0068 return 0;
0069 }
0070
0071 const struct file_operations bfs_dir_operations = {
0072 .read = generic_read_dir,
0073 .iterate_shared = bfs_readdir,
0074 .fsync = generic_file_fsync,
0075 .llseek = generic_file_llseek,
0076 };
0077
0078 static int bfs_create(struct user_namespace *mnt_userns, struct inode *dir,
0079 struct dentry *dentry, umode_t mode, bool excl)
0080 {
0081 int err;
0082 struct inode *inode;
0083 struct super_block *s = dir->i_sb;
0084 struct bfs_sb_info *info = BFS_SB(s);
0085 unsigned long ino;
0086
0087 inode = new_inode(s);
0088 if (!inode)
0089 return -ENOMEM;
0090 mutex_lock(&info->bfs_lock);
0091 ino = find_first_zero_bit(info->si_imap, info->si_lasti + 1);
0092 if (ino > info->si_lasti) {
0093 mutex_unlock(&info->bfs_lock);
0094 iput(inode);
0095 return -ENOSPC;
0096 }
0097 set_bit(ino, info->si_imap);
0098 info->si_freei--;
0099 inode_init_owner(&init_user_ns, inode, dir, mode);
0100 inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
0101 inode->i_blocks = 0;
0102 inode->i_op = &bfs_file_inops;
0103 inode->i_fop = &bfs_file_operations;
0104 inode->i_mapping->a_ops = &bfs_aops;
0105 inode->i_ino = ino;
0106 BFS_I(inode)->i_dsk_ino = ino;
0107 BFS_I(inode)->i_sblock = 0;
0108 BFS_I(inode)->i_eblock = 0;
0109 insert_inode_hash(inode);
0110 mark_inode_dirty(inode);
0111 bfs_dump_imap("create", s);
0112
0113 err = bfs_add_entry(dir, &dentry->d_name, inode->i_ino);
0114 if (err) {
0115 inode_dec_link_count(inode);
0116 mutex_unlock(&info->bfs_lock);
0117 iput(inode);
0118 return err;
0119 }
0120 mutex_unlock(&info->bfs_lock);
0121 d_instantiate(dentry, inode);
0122 return 0;
0123 }
0124
0125 static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
0126 unsigned int flags)
0127 {
0128 struct inode *inode = NULL;
0129 struct buffer_head *bh;
0130 struct bfs_dirent *de;
0131 struct bfs_sb_info *info = BFS_SB(dir->i_sb);
0132
0133 if (dentry->d_name.len > BFS_NAMELEN)
0134 return ERR_PTR(-ENAMETOOLONG);
0135
0136 mutex_lock(&info->bfs_lock);
0137 bh = bfs_find_entry(dir, &dentry->d_name, &de);
0138 if (bh) {
0139 unsigned long ino = (unsigned long)le16_to_cpu(de->ino);
0140 brelse(bh);
0141 inode = bfs_iget(dir->i_sb, ino);
0142 }
0143 mutex_unlock(&info->bfs_lock);
0144 return d_splice_alias(inode, dentry);
0145 }
0146
0147 static int bfs_link(struct dentry *old, struct inode *dir,
0148 struct dentry *new)
0149 {
0150 struct inode *inode = d_inode(old);
0151 struct bfs_sb_info *info = BFS_SB(inode->i_sb);
0152 int err;
0153
0154 mutex_lock(&info->bfs_lock);
0155 err = bfs_add_entry(dir, &new->d_name, inode->i_ino);
0156 if (err) {
0157 mutex_unlock(&info->bfs_lock);
0158 return err;
0159 }
0160 inc_nlink(inode);
0161 inode->i_ctime = current_time(inode);
0162 mark_inode_dirty(inode);
0163 ihold(inode);
0164 d_instantiate(new, inode);
0165 mutex_unlock(&info->bfs_lock);
0166 return 0;
0167 }
0168
0169 static int bfs_unlink(struct inode *dir, struct dentry *dentry)
0170 {
0171 int error = -ENOENT;
0172 struct inode *inode = d_inode(dentry);
0173 struct buffer_head *bh;
0174 struct bfs_dirent *de;
0175 struct bfs_sb_info *info = BFS_SB(inode->i_sb);
0176
0177 mutex_lock(&info->bfs_lock);
0178 bh = bfs_find_entry(dir, &dentry->d_name, &de);
0179 if (!bh || (le16_to_cpu(de->ino) != inode->i_ino))
0180 goto out_brelse;
0181
0182 if (!inode->i_nlink) {
0183 printf("unlinking non-existent file %s:%lu (nlink=%d)\n",
0184 inode->i_sb->s_id, inode->i_ino,
0185 inode->i_nlink);
0186 set_nlink(inode, 1);
0187 }
0188 de->ino = 0;
0189 mark_buffer_dirty_inode(bh, dir);
0190 dir->i_ctime = dir->i_mtime = current_time(dir);
0191 mark_inode_dirty(dir);
0192 inode->i_ctime = dir->i_ctime;
0193 inode_dec_link_count(inode);
0194 error = 0;
0195
0196 out_brelse:
0197 brelse(bh);
0198 mutex_unlock(&info->bfs_lock);
0199 return error;
0200 }
0201
0202 static int bfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
0203 struct dentry *old_dentry, struct inode *new_dir,
0204 struct dentry *new_dentry, unsigned int flags)
0205 {
0206 struct inode *old_inode, *new_inode;
0207 struct buffer_head *old_bh, *new_bh;
0208 struct bfs_dirent *old_de, *new_de;
0209 struct bfs_sb_info *info;
0210 int error = -ENOENT;
0211
0212 if (flags & ~RENAME_NOREPLACE)
0213 return -EINVAL;
0214
0215 old_bh = new_bh = NULL;
0216 old_inode = d_inode(old_dentry);
0217 if (S_ISDIR(old_inode->i_mode))
0218 return -EINVAL;
0219
0220 info = BFS_SB(old_inode->i_sb);
0221
0222 mutex_lock(&info->bfs_lock);
0223 old_bh = bfs_find_entry(old_dir, &old_dentry->d_name, &old_de);
0224
0225 if (!old_bh || (le16_to_cpu(old_de->ino) != old_inode->i_ino))
0226 goto end_rename;
0227
0228 error = -EPERM;
0229 new_inode = d_inode(new_dentry);
0230 new_bh = bfs_find_entry(new_dir, &new_dentry->d_name, &new_de);
0231
0232 if (new_bh && !new_inode) {
0233 brelse(new_bh);
0234 new_bh = NULL;
0235 }
0236 if (!new_bh) {
0237 error = bfs_add_entry(new_dir, &new_dentry->d_name,
0238 old_inode->i_ino);
0239 if (error)
0240 goto end_rename;
0241 }
0242 old_de->ino = 0;
0243 old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir);
0244 mark_inode_dirty(old_dir);
0245 if (new_inode) {
0246 new_inode->i_ctime = current_time(new_inode);
0247 inode_dec_link_count(new_inode);
0248 }
0249 mark_buffer_dirty_inode(old_bh, old_dir);
0250 error = 0;
0251
0252 end_rename:
0253 mutex_unlock(&info->bfs_lock);
0254 brelse(old_bh);
0255 brelse(new_bh);
0256 return error;
0257 }
0258
0259 const struct inode_operations bfs_dir_inops = {
0260 .create = bfs_create,
0261 .lookup = bfs_lookup,
0262 .link = bfs_link,
0263 .unlink = bfs_unlink,
0264 .rename = bfs_rename,
0265 };
0266
0267 static int bfs_add_entry(struct inode *dir, const struct qstr *child, int ino)
0268 {
0269 const unsigned char *name = child->name;
0270 int namelen = child->len;
0271 struct buffer_head *bh;
0272 struct bfs_dirent *de;
0273 int block, sblock, eblock, off, pos;
0274 int i;
0275
0276 dprintf("name=%s, namelen=%d\n", name, namelen);
0277
0278 if (!namelen)
0279 return -ENOENT;
0280 if (namelen > BFS_NAMELEN)
0281 return -ENAMETOOLONG;
0282
0283 sblock = BFS_I(dir)->i_sblock;
0284 eblock = BFS_I(dir)->i_eblock;
0285 for (block = sblock; block <= eblock; block++) {
0286 bh = sb_bread(dir->i_sb, block);
0287 if (!bh)
0288 return -EIO;
0289 for (off = 0; off < BFS_BSIZE; off += BFS_DIRENT_SIZE) {
0290 de = (struct bfs_dirent *)(bh->b_data + off);
0291 if (!de->ino) {
0292 pos = (block - sblock) * BFS_BSIZE + off;
0293 if (pos >= dir->i_size) {
0294 dir->i_size += BFS_DIRENT_SIZE;
0295 dir->i_ctime = current_time(dir);
0296 }
0297 dir->i_mtime = current_time(dir);
0298 mark_inode_dirty(dir);
0299 de->ino = cpu_to_le16((u16)ino);
0300 for (i = 0; i < BFS_NAMELEN; i++)
0301 de->name[i] =
0302 (i < namelen) ? name[i] : 0;
0303 mark_buffer_dirty_inode(bh, dir);
0304 brelse(bh);
0305 return 0;
0306 }
0307 }
0308 brelse(bh);
0309 }
0310 return -ENOSPC;
0311 }
0312
0313 static inline int bfs_namecmp(int len, const unsigned char *name,
0314 const char *buffer)
0315 {
0316 if ((len < BFS_NAMELEN) && buffer[len])
0317 return 0;
0318 return !memcmp(name, buffer, len);
0319 }
0320
0321 static struct buffer_head *bfs_find_entry(struct inode *dir,
0322 const struct qstr *child,
0323 struct bfs_dirent **res_dir)
0324 {
0325 unsigned long block = 0, offset = 0;
0326 struct buffer_head *bh = NULL;
0327 struct bfs_dirent *de;
0328 const unsigned char *name = child->name;
0329 int namelen = child->len;
0330
0331 *res_dir = NULL;
0332 if (namelen > BFS_NAMELEN)
0333 return NULL;
0334
0335 while (block * BFS_BSIZE + offset < dir->i_size) {
0336 if (!bh) {
0337 bh = sb_bread(dir->i_sb, BFS_I(dir)->i_sblock + block);
0338 if (!bh) {
0339 block++;
0340 continue;
0341 }
0342 }
0343 de = (struct bfs_dirent *)(bh->b_data + offset);
0344 offset += BFS_DIRENT_SIZE;
0345 if (le16_to_cpu(de->ino) &&
0346 bfs_namecmp(namelen, name, de->name)) {
0347 *res_dir = de;
0348 return bh;
0349 }
0350 if (offset < bh->b_size)
0351 continue;
0352 brelse(bh);
0353 bh = NULL;
0354 offset = 0;
0355 block++;
0356 }
0357 brelse(bh);
0358 return NULL;
0359 }