0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "affs.h"
0013 #include <linux/exportfs.h>
0014
0015 typedef int (*toupper_t)(int);
0016
0017
0018
0019 static int
0020 affs_toupper(int ch)
0021 {
0022 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
0023 }
0024
0025
0026
0027 static int
0028 affs_intl_toupper(int ch)
0029 {
0030 return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
0031 && ch <= 0xFE && ch != 0xF7) ?
0032 ch - ('a' - 'A') : ch;
0033 }
0034
0035 static inline toupper_t
0036 affs_get_toupper(struct super_block *sb)
0037 {
0038 return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ?
0039 affs_intl_toupper : affs_toupper;
0040 }
0041
0042
0043
0044
0045 static inline int
0046 __affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
0047 {
0048 const u8 *name = qstr->name;
0049 unsigned long hash;
0050 int retval;
0051 u32 len;
0052
0053 retval = affs_check_name(qstr->name, qstr->len, notruncate);
0054 if (retval)
0055 return retval;
0056
0057 hash = init_name_hash(dentry);
0058 len = min(qstr->len, AFFSNAMEMAX);
0059 for (; len > 0; name++, len--)
0060 hash = partial_name_hash(toupper(*name), hash);
0061 qstr->hash = end_name_hash(hash);
0062
0063 return 0;
0064 }
0065
0066 static int
0067 affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
0068 {
0069 return __affs_hash_dentry(dentry, qstr, affs_toupper,
0070 affs_nofilenametruncate(dentry));
0071
0072 }
0073
0074 static int
0075 affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
0076 {
0077 return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
0078 affs_nofilenametruncate(dentry));
0079
0080 }
0081
0082 static inline int __affs_compare_dentry(unsigned int len,
0083 const char *str, const struct qstr *name, toupper_t toupper,
0084 bool notruncate)
0085 {
0086 const u8 *aname = str;
0087 const u8 *bname = name->name;
0088
0089
0090
0091
0092
0093
0094 if (affs_check_name(name->name, name->len, notruncate))
0095 return 1;
0096
0097
0098
0099
0100
0101 if (len >= AFFSNAMEMAX) {
0102 if (name->len < AFFSNAMEMAX)
0103 return 1;
0104 len = AFFSNAMEMAX;
0105 } else if (len != name->len)
0106 return 1;
0107
0108 for (; len > 0; len--)
0109 if (toupper(*aname++) != toupper(*bname++))
0110 return 1;
0111
0112 return 0;
0113 }
0114
0115 static int
0116 affs_compare_dentry(const struct dentry *dentry,
0117 unsigned int len, const char *str, const struct qstr *name)
0118 {
0119
0120 return __affs_compare_dentry(len, str, name, affs_toupper,
0121 affs_nofilenametruncate(dentry));
0122 }
0123
0124 static int
0125 affs_intl_compare_dentry(const struct dentry *dentry,
0126 unsigned int len, const char *str, const struct qstr *name)
0127 {
0128 return __affs_compare_dentry(len, str, name, affs_intl_toupper,
0129 affs_nofilenametruncate(dentry));
0130
0131 }
0132
0133
0134
0135
0136
0137 static inline int
0138 affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
0139 {
0140 const u8 *name = dentry->d_name.name;
0141 int len = dentry->d_name.len;
0142
0143 if (len >= AFFSNAMEMAX) {
0144 if (*name2 < AFFSNAMEMAX)
0145 return 0;
0146 len = AFFSNAMEMAX;
0147 } else if (len != *name2)
0148 return 0;
0149
0150 for (name2++; len > 0; len--)
0151 if (toupper(*name++) != toupper(*name2++))
0152 return 0;
0153 return 1;
0154 }
0155
0156 int
0157 affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
0158 {
0159 toupper_t toupper = affs_get_toupper(sb);
0160 u32 hash;
0161
0162 hash = len = min(len, AFFSNAMEMAX);
0163 for (; len > 0; len--)
0164 hash = (hash * 13 + toupper(*name++)) & 0x7ff;
0165
0166 return hash % AFFS_SB(sb)->s_hashsize;
0167 }
0168
0169 static struct buffer_head *
0170 affs_find_entry(struct inode *dir, struct dentry *dentry)
0171 {
0172 struct super_block *sb = dir->i_sb;
0173 struct buffer_head *bh;
0174 toupper_t toupper = affs_get_toupper(sb);
0175 u32 key;
0176
0177 pr_debug("%s(\"%pd\")\n", __func__, dentry);
0178
0179 bh = affs_bread(sb, dir->i_ino);
0180 if (!bh)
0181 return ERR_PTR(-EIO);
0182
0183 key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
0184
0185 for (;;) {
0186 affs_brelse(bh);
0187 if (key == 0)
0188 return NULL;
0189 bh = affs_bread(sb, key);
0190 if (!bh)
0191 return ERR_PTR(-EIO);
0192 if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
0193 return bh;
0194 key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
0195 }
0196 }
0197
0198 struct dentry *
0199 affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
0200 {
0201 struct super_block *sb = dir->i_sb;
0202 struct buffer_head *bh;
0203 struct inode *inode = NULL;
0204 struct dentry *res;
0205
0206 pr_debug("%s(\"%pd\")\n", __func__, dentry);
0207
0208 affs_lock_dir(dir);
0209 bh = affs_find_entry(dir, dentry);
0210 if (IS_ERR(bh)) {
0211 affs_unlock_dir(dir);
0212 return ERR_CAST(bh);
0213 }
0214 if (bh) {
0215 u32 ino = bh->b_blocknr;
0216
0217
0218 dentry->d_fsdata = (void *)(long)ino;
0219 switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
0220
0221
0222 case ST_LINKFILE:
0223 ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
0224 }
0225 affs_brelse(bh);
0226 inode = affs_iget(sb, ino);
0227 }
0228 res = d_splice_alias(inode, dentry);
0229 if (!IS_ERR_OR_NULL(res))
0230 res->d_fsdata = dentry->d_fsdata;
0231 affs_unlock_dir(dir);
0232 return res;
0233 }
0234
0235 int
0236 affs_unlink(struct inode *dir, struct dentry *dentry)
0237 {
0238 pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
0239 d_inode(dentry)->i_ino, dentry);
0240
0241 return affs_remove_header(dentry);
0242 }
0243
0244 int
0245 affs_create(struct user_namespace *mnt_userns, struct inode *dir,
0246 struct dentry *dentry, umode_t mode, bool excl)
0247 {
0248 struct super_block *sb = dir->i_sb;
0249 struct inode *inode;
0250 int error;
0251
0252 pr_debug("%s(%lu,\"%pd\",0%ho)\n",
0253 __func__, dir->i_ino, dentry, mode);
0254
0255 inode = affs_new_inode(dir);
0256 if (!inode)
0257 return -ENOSPC;
0258
0259 inode->i_mode = mode;
0260 affs_mode_to_prot(inode);
0261 mark_inode_dirty(inode);
0262
0263 inode->i_op = &affs_file_inode_operations;
0264 inode->i_fop = &affs_file_operations;
0265 inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ?
0266 &affs_aops_ofs : &affs_aops;
0267 error = affs_add_entry(dir, inode, dentry, ST_FILE);
0268 if (error) {
0269 clear_nlink(inode);
0270 iput(inode);
0271 return error;
0272 }
0273 return 0;
0274 }
0275
0276 int
0277 affs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
0278 struct dentry *dentry, umode_t mode)
0279 {
0280 struct inode *inode;
0281 int error;
0282
0283 pr_debug("%s(%lu,\"%pd\",0%ho)\n",
0284 __func__, dir->i_ino, dentry, mode);
0285
0286 inode = affs_new_inode(dir);
0287 if (!inode)
0288 return -ENOSPC;
0289
0290 inode->i_mode = S_IFDIR | mode;
0291 affs_mode_to_prot(inode);
0292
0293 inode->i_op = &affs_dir_inode_operations;
0294 inode->i_fop = &affs_dir_operations;
0295
0296 error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
0297 if (error) {
0298 clear_nlink(inode);
0299 mark_inode_dirty(inode);
0300 iput(inode);
0301 return error;
0302 }
0303 return 0;
0304 }
0305
0306 int
0307 affs_rmdir(struct inode *dir, struct dentry *dentry)
0308 {
0309 pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino,
0310 d_inode(dentry)->i_ino, dentry);
0311
0312 return affs_remove_header(dentry);
0313 }
0314
0315 int
0316 affs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
0317 struct dentry *dentry, const char *symname)
0318 {
0319 struct super_block *sb = dir->i_sb;
0320 struct buffer_head *bh;
0321 struct inode *inode;
0322 char *p;
0323 int i, maxlen, error;
0324 char c, lc;
0325
0326 pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
0327 __func__, dir->i_ino, dentry, symname);
0328
0329 maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
0330 inode = affs_new_inode(dir);
0331 if (!inode)
0332 return -ENOSPC;
0333
0334 inode->i_op = &affs_symlink_inode_operations;
0335 inode_nohighmem(inode);
0336 inode->i_data.a_ops = &affs_symlink_aops;
0337 inode->i_mode = S_IFLNK | 0777;
0338 affs_mode_to_prot(inode);
0339
0340 error = -EIO;
0341 bh = affs_bread(sb, inode->i_ino);
0342 if (!bh)
0343 goto err;
0344 i = 0;
0345 p = (char *)AFFS_HEAD(bh)->table;
0346 lc = '/';
0347 if (*symname == '/') {
0348 struct affs_sb_info *sbi = AFFS_SB(sb);
0349 while (*symname == '/')
0350 symname++;
0351 spin_lock(&sbi->symlink_lock);
0352 while (sbi->s_volume[i])
0353 *p++ = sbi->s_volume[i++];
0354 spin_unlock(&sbi->symlink_lock);
0355 }
0356 while (i < maxlen && (c = *symname++)) {
0357 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
0358 *p++ = '/';
0359 i++;
0360 symname += 2;
0361 lc = '/';
0362 } else if (c == '.' && lc == '/' && *symname == '/') {
0363 symname++;
0364 lc = '/';
0365 } else {
0366 *p++ = c;
0367 lc = c;
0368 i++;
0369 }
0370 if (lc == '/')
0371 while (*symname == '/')
0372 symname++;
0373 }
0374 *p = 0;
0375 inode->i_size = i + 1;
0376 mark_buffer_dirty_inode(bh, inode);
0377 affs_brelse(bh);
0378 mark_inode_dirty(inode);
0379
0380 error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
0381 if (error)
0382 goto err;
0383
0384 return 0;
0385
0386 err:
0387 clear_nlink(inode);
0388 mark_inode_dirty(inode);
0389 iput(inode);
0390 return error;
0391 }
0392
0393 int
0394 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
0395 {
0396 struct inode *inode = d_inode(old_dentry);
0397
0398 pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino,
0399 dentry);
0400
0401 return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
0402 }
0403
0404 static int
0405 affs_rename(struct inode *old_dir, struct dentry *old_dentry,
0406 struct inode *new_dir, struct dentry *new_dentry)
0407 {
0408 struct super_block *sb = old_dir->i_sb;
0409 struct buffer_head *bh = NULL;
0410 int retval;
0411
0412 retval = affs_check_name(new_dentry->d_name.name,
0413 new_dentry->d_name.len,
0414 affs_nofilenametruncate(old_dentry));
0415
0416 if (retval)
0417 return retval;
0418
0419
0420 if (d_really_is_positive(new_dentry)) {
0421 retval = affs_remove_header(new_dentry);
0422 if (retval)
0423 return retval;
0424 }
0425
0426 bh = affs_bread(sb, d_inode(old_dentry)->i_ino);
0427 if (!bh)
0428 return -EIO;
0429
0430
0431 affs_lock_dir(old_dir);
0432 retval = affs_remove_hash(old_dir, bh);
0433 affs_unlock_dir(old_dir);
0434 if (retval)
0435 goto done;
0436
0437
0438 affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
0439 affs_fix_checksum(sb, bh);
0440 affs_lock_dir(new_dir);
0441 retval = affs_insert_hash(new_dir, bh);
0442 affs_unlock_dir(new_dir);
0443
0444
0445 done:
0446 mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
0447 affs_brelse(bh);
0448 return retval;
0449 }
0450
0451 static int
0452 affs_xrename(struct inode *old_dir, struct dentry *old_dentry,
0453 struct inode *new_dir, struct dentry *new_dentry)
0454 {
0455
0456 struct super_block *sb = old_dir->i_sb;
0457 struct buffer_head *bh_old = NULL;
0458 struct buffer_head *bh_new = NULL;
0459 int retval;
0460
0461 bh_old = affs_bread(sb, d_inode(old_dentry)->i_ino);
0462 if (!bh_old)
0463 return -EIO;
0464
0465 bh_new = affs_bread(sb, d_inode(new_dentry)->i_ino);
0466 if (!bh_new) {
0467 affs_brelse(bh_old);
0468 return -EIO;
0469 }
0470
0471
0472 affs_lock_dir(old_dir);
0473 retval = affs_remove_hash(old_dir, bh_old);
0474 affs_unlock_dir(old_dir);
0475 if (retval)
0476 goto done;
0477
0478
0479 affs_lock_dir(new_dir);
0480 retval = affs_remove_hash(new_dir, bh_new);
0481 affs_unlock_dir(new_dir);
0482 if (retval)
0483 goto done;
0484
0485
0486 affs_copy_name(AFFS_TAIL(sb, bh_old)->name, new_dentry);
0487 affs_fix_checksum(sb, bh_old);
0488 affs_lock_dir(new_dir);
0489 retval = affs_insert_hash(new_dir, bh_old);
0490 affs_unlock_dir(new_dir);
0491
0492
0493 affs_copy_name(AFFS_TAIL(sb, bh_new)->name, old_dentry);
0494 affs_fix_checksum(sb, bh_new);
0495 affs_lock_dir(old_dir);
0496 retval = affs_insert_hash(old_dir, bh_new);
0497 affs_unlock_dir(old_dir);
0498 done:
0499 mark_buffer_dirty_inode(bh_old, new_dir);
0500 mark_buffer_dirty_inode(bh_new, old_dir);
0501 affs_brelse(bh_old);
0502 affs_brelse(bh_new);
0503 return retval;
0504 }
0505
0506 int affs_rename2(struct user_namespace *mnt_userns, struct inode *old_dir,
0507 struct dentry *old_dentry, struct inode *new_dir,
0508 struct dentry *new_dentry, unsigned int flags)
0509 {
0510
0511 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
0512 return -EINVAL;
0513
0514 pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__,
0515 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry);
0516
0517 if (flags & RENAME_EXCHANGE)
0518 return affs_xrename(old_dir, old_dentry, new_dir, new_dentry);
0519
0520 return affs_rename(old_dir, old_dentry, new_dir, new_dentry);
0521 }
0522
0523 static struct dentry *affs_get_parent(struct dentry *child)
0524 {
0525 struct inode *parent;
0526 struct buffer_head *bh;
0527
0528 bh = affs_bread(child->d_sb, d_inode(child)->i_ino);
0529 if (!bh)
0530 return ERR_PTR(-EIO);
0531
0532 parent = affs_iget(child->d_sb,
0533 be32_to_cpu(AFFS_TAIL(child->d_sb, bh)->parent));
0534 brelse(bh);
0535 if (IS_ERR(parent))
0536 return ERR_CAST(parent);
0537
0538 return d_obtain_alias(parent);
0539 }
0540
0541 static struct inode *affs_nfs_get_inode(struct super_block *sb, u64 ino,
0542 u32 generation)
0543 {
0544 struct inode *inode;
0545
0546 if (!affs_validblock(sb, ino))
0547 return ERR_PTR(-ESTALE);
0548
0549 inode = affs_iget(sb, ino);
0550 if (IS_ERR(inode))
0551 return ERR_CAST(inode);
0552
0553 return inode;
0554 }
0555
0556 static struct dentry *affs_fh_to_dentry(struct super_block *sb, struct fid *fid,
0557 int fh_len, int fh_type)
0558 {
0559 return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
0560 affs_nfs_get_inode);
0561 }
0562
0563 static struct dentry *affs_fh_to_parent(struct super_block *sb, struct fid *fid,
0564 int fh_len, int fh_type)
0565 {
0566 return generic_fh_to_parent(sb, fid, fh_len, fh_type,
0567 affs_nfs_get_inode);
0568 }
0569
0570 const struct export_operations affs_export_ops = {
0571 .fh_to_dentry = affs_fh_to_dentry,
0572 .fh_to_parent = affs_fh_to_parent,
0573 .get_parent = affs_get_parent,
0574 };
0575
0576 const struct dentry_operations affs_dentry_operations = {
0577 .d_hash = affs_hash_dentry,
0578 .d_compare = affs_compare_dentry,
0579 };
0580
0581 const struct dentry_operations affs_intl_dentry_operations = {
0582 .d_hash = affs_intl_hash_dentry,
0583 .d_compare = affs_intl_compare_dentry,
0584 };