1/* 2 * linux/fs/affs/namei.c 3 * 4 * (c) 1996 Hans-Joachim Widmaier - Rewritten 5 * 6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 7 * 8 * (C) 1991 Linus Torvalds - minix filesystem 9 */ 10 11#include "affs.h" 12 13typedef int (*toupper_t)(int); 14 15static int affs_toupper(int ch); 16static int affs_hash_dentry(const struct dentry *, struct qstr *); 17static int affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry, 18 unsigned int len, const char *str, const struct qstr *name); 19static int affs_intl_toupper(int ch); 20static int affs_intl_hash_dentry(const struct dentry *, struct qstr *); 21static int affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry, 22 unsigned int len, const char *str, const struct qstr *name); 23 24const struct dentry_operations affs_dentry_operations = { 25 .d_hash = affs_hash_dentry, 26 .d_compare = affs_compare_dentry, 27}; 28 29const struct dentry_operations affs_intl_dentry_operations = { 30 .d_hash = affs_intl_hash_dentry, 31 .d_compare = affs_intl_compare_dentry, 32}; 33 34 35/* Simple toupper() for DOS\1 */ 36 37static int 38affs_toupper(int ch) 39{ 40 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; 41} 42 43/* International toupper() for DOS\3 ("international") */ 44 45static int 46affs_intl_toupper(int ch) 47{ 48 return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0 49 && ch <= 0xFE && ch != 0xF7) ? 50 ch - ('a' - 'A') : ch; 51} 52 53static inline toupper_t 54affs_get_toupper(struct super_block *sb) 55{ 56 return affs_test_opt(AFFS_SB(sb)->s_flags, SF_INTL) ? 57 affs_intl_toupper : affs_toupper; 58} 59 60/* 61 * Note: the dentry argument is the parent dentry. 62 */ 63static inline int 64__affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) 65{ 66 const u8 *name = qstr->name; 67 unsigned long hash; 68 int retval; 69 u32 len; 70 71 retval = affs_check_name(qstr->name, qstr->len, notruncate); 72 if (retval) 73 return retval; 74 75 hash = init_name_hash(); 76 len = min(qstr->len, AFFSNAMEMAX); 77 for (; len > 0; name++, len--) 78 hash = partial_name_hash(toupper(*name), hash); 79 qstr->hash = end_name_hash(hash); 80 81 return 0; 82} 83 84static int 85affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) 86{ 87 return __affs_hash_dentry(qstr, affs_toupper, 88 affs_nofilenametruncate(dentry)); 89 90} 91 92static int 93affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr) 94{ 95 return __affs_hash_dentry(qstr, affs_intl_toupper, 96 affs_nofilenametruncate(dentry)); 97 98} 99 100static inline int __affs_compare_dentry(unsigned int len, 101 const char *str, const struct qstr *name, toupper_t toupper, 102 bool notruncate) 103{ 104 const u8 *aname = str; 105 const u8 *bname = name->name; 106 107 /* 108 * 'str' is the name of an already existing dentry, so the name 109 * must be valid. 'name' must be validated first. 110 */ 111 112 if (affs_check_name(name->name, name->len, notruncate)) 113 return 1; 114 115 /* 116 * If the names are longer than the allowed 30 chars, 117 * the excess is ignored, so their length may differ. 118 */ 119 if (len >= AFFSNAMEMAX) { 120 if (name->len < AFFSNAMEMAX) 121 return 1; 122 len = AFFSNAMEMAX; 123 } else if (len != name->len) 124 return 1; 125 126 for (; len > 0; len--) 127 if (toupper(*aname++) != toupper(*bname++)) 128 return 1; 129 130 return 0; 131} 132 133static int 134affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry, 135 unsigned int len, const char *str, const struct qstr *name) 136{ 137 138 return __affs_compare_dentry(len, str, name, affs_toupper, 139 affs_nofilenametruncate(parent)); 140} 141 142static int 143affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry, 144 unsigned int len, const char *str, const struct qstr *name) 145{ 146 return __affs_compare_dentry(len, str, name, affs_intl_toupper, 147 affs_nofilenametruncate(parent)); 148 149} 150 151/* 152 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. 153 */ 154 155static inline int 156affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper) 157{ 158 const u8 *name = dentry->d_name.name; 159 int len = dentry->d_name.len; 160 161 if (len >= AFFSNAMEMAX) { 162 if (*name2 < AFFSNAMEMAX) 163 return 0; 164 len = AFFSNAMEMAX; 165 } else if (len != *name2) 166 return 0; 167 168 for (name2++; len > 0; len--) 169 if (toupper(*name++) != toupper(*name2++)) 170 return 0; 171 return 1; 172} 173 174int 175affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len) 176{ 177 toupper_t toupper = affs_get_toupper(sb); 178 u32 hash; 179 180 hash = len = min(len, AFFSNAMEMAX); 181 for (; len > 0; len--) 182 hash = (hash * 13 + toupper(*name++)) & 0x7ff; 183 184 return hash % AFFS_SB(sb)->s_hashsize; 185} 186 187static struct buffer_head * 188affs_find_entry(struct inode *dir, struct dentry *dentry) 189{ 190 struct super_block *sb = dir->i_sb; 191 struct buffer_head *bh; 192 toupper_t toupper = affs_get_toupper(sb); 193 u32 key; 194 195 pr_debug("%s(\"%pd\")\n", __func__, dentry); 196 197 bh = affs_bread(sb, dir->i_ino); 198 if (!bh) 199 return ERR_PTR(-EIO); 200 201 key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]); 202 203 for (;;) { 204 affs_brelse(bh); 205 if (key == 0) 206 return NULL; 207 bh = affs_bread(sb, key); 208 if (!bh) 209 return ERR_PTR(-EIO); 210 if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper)) 211 return bh; 212 key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain); 213 } 214} 215 216struct dentry * 217affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 218{ 219 struct super_block *sb = dir->i_sb; 220 struct buffer_head *bh; 221 struct inode *inode = NULL; 222 223 pr_debug("%s(\"%pd\")\n", __func__, dentry); 224 225 affs_lock_dir(dir); 226 bh = affs_find_entry(dir, dentry); 227 affs_unlock_dir(dir); 228 if (IS_ERR(bh)) 229 return ERR_CAST(bh); 230 if (bh) { 231 u32 ino = bh->b_blocknr; 232 233 /* store the real header ino in d_fsdata for faster lookups */ 234 dentry->d_fsdata = (void *)(long)ino; 235 switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) { 236 //link to dirs disabled 237 //case ST_LINKDIR: 238 case ST_LINKFILE: 239 ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original); 240 } 241 affs_brelse(bh); 242 inode = affs_iget(sb, ino); 243 if (IS_ERR(inode)) 244 return ERR_CAST(inode); 245 } 246 d_add(dentry, inode); 247 return NULL; 248} 249 250int 251affs_unlink(struct inode *dir, struct dentry *dentry) 252{ 253 pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, 254 d_inode(dentry)->i_ino, dentry); 255 256 return affs_remove_header(dentry); 257} 258 259int 260affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) 261{ 262 struct super_block *sb = dir->i_sb; 263 struct inode *inode; 264 int error; 265 266 pr_debug("%s(%lu,\"%pd\",0%ho)\n", 267 __func__, dir->i_ino, dentry, mode); 268 269 inode = affs_new_inode(dir); 270 if (!inode) 271 return -ENOSPC; 272 273 inode->i_mode = mode; 274 mode_to_prot(inode); 275 mark_inode_dirty(inode); 276 277 inode->i_op = &affs_file_inode_operations; 278 inode->i_fop = &affs_file_operations; 279 inode->i_mapping->a_ops = affs_test_opt(AFFS_SB(sb)->s_flags, SF_OFS) ? 280 &affs_aops_ofs : &affs_aops; 281 error = affs_add_entry(dir, inode, dentry, ST_FILE); 282 if (error) { 283 clear_nlink(inode); 284 iput(inode); 285 return error; 286 } 287 return 0; 288} 289 290int 291affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 292{ 293 struct inode *inode; 294 int error; 295 296 pr_debug("%s(%lu,\"%pd\",0%ho)\n", 297 __func__, dir->i_ino, dentry, mode); 298 299 inode = affs_new_inode(dir); 300 if (!inode) 301 return -ENOSPC; 302 303 inode->i_mode = S_IFDIR | mode; 304 mode_to_prot(inode); 305 306 inode->i_op = &affs_dir_inode_operations; 307 inode->i_fop = &affs_dir_operations; 308 309 error = affs_add_entry(dir, inode, dentry, ST_USERDIR); 310 if (error) { 311 clear_nlink(inode); 312 mark_inode_dirty(inode); 313 iput(inode); 314 return error; 315 } 316 return 0; 317} 318 319int 320affs_rmdir(struct inode *dir, struct dentry *dentry) 321{ 322 pr_debug("%s(dir=%lu, %lu \"%pd\")\n", __func__, dir->i_ino, 323 d_inode(dentry)->i_ino, dentry); 324 325 return affs_remove_header(dentry); 326} 327 328int 329affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 330{ 331 struct super_block *sb = dir->i_sb; 332 struct buffer_head *bh; 333 struct inode *inode; 334 char *p; 335 int i, maxlen, error; 336 char c, lc; 337 338 pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n", 339 __func__, dir->i_ino, dentry, symname); 340 341 maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1; 342 inode = affs_new_inode(dir); 343 if (!inode) 344 return -ENOSPC; 345 346 inode->i_op = &affs_symlink_inode_operations; 347 inode->i_data.a_ops = &affs_symlink_aops; 348 inode->i_mode = S_IFLNK | 0777; 349 mode_to_prot(inode); 350 351 error = -EIO; 352 bh = affs_bread(sb, inode->i_ino); 353 if (!bh) 354 goto err; 355 i = 0; 356 p = (char *)AFFS_HEAD(bh)->table; 357 lc = '/'; 358 if (*symname == '/') { 359 struct affs_sb_info *sbi = AFFS_SB(sb); 360 while (*symname == '/') 361 symname++; 362 spin_lock(&sbi->symlink_lock); 363 while (sbi->s_volume[i]) /* Cannot overflow */ 364 *p++ = sbi->s_volume[i++]; 365 spin_unlock(&sbi->symlink_lock); 366 } 367 while (i < maxlen && (c = *symname++)) { 368 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { 369 *p++ = '/'; 370 i++; 371 symname += 2; 372 lc = '/'; 373 } else if (c == '.' && lc == '/' && *symname == '/') { 374 symname++; 375 lc = '/'; 376 } else { 377 *p++ = c; 378 lc = c; 379 i++; 380 } 381 if (lc == '/') 382 while (*symname == '/') 383 symname++; 384 } 385 *p = 0; 386 mark_buffer_dirty_inode(bh, inode); 387 affs_brelse(bh); 388 mark_inode_dirty(inode); 389 390 error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK); 391 if (error) 392 goto err; 393 394 return 0; 395 396err: 397 clear_nlink(inode); 398 mark_inode_dirty(inode); 399 iput(inode); 400 return error; 401} 402 403int 404affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) 405{ 406 struct inode *inode = d_inode(old_dentry); 407 408 pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino, 409 dentry); 410 411 return affs_add_entry(dir, inode, dentry, ST_LINKFILE); 412} 413 414int 415affs_rename(struct inode *old_dir, struct dentry *old_dentry, 416 struct inode *new_dir, struct dentry *new_dentry) 417{ 418 struct super_block *sb = old_dir->i_sb; 419 struct buffer_head *bh = NULL; 420 int retval; 421 422 pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, 423 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); 424 425 retval = affs_check_name(new_dentry->d_name.name, 426 new_dentry->d_name.len, 427 affs_nofilenametruncate(old_dentry)); 428 429 if (retval) 430 return retval; 431 432 /* Unlink destination if it already exists */ 433 if (d_really_is_positive(new_dentry)) { 434 retval = affs_remove_header(new_dentry); 435 if (retval) 436 return retval; 437 } 438 439 bh = affs_bread(sb, d_inode(old_dentry)->i_ino); 440 if (!bh) 441 return -EIO; 442 443 /* Remove header from its parent directory. */ 444 affs_lock_dir(old_dir); 445 retval = affs_remove_hash(old_dir, bh); 446 affs_unlock_dir(old_dir); 447 if (retval) 448 goto done; 449 450 /* And insert it into the new directory with the new name. */ 451 affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry); 452 affs_fix_checksum(sb, bh); 453 affs_lock_dir(new_dir); 454 retval = affs_insert_hash(new_dir, bh); 455 affs_unlock_dir(new_dir); 456 /* TODO: move it back to old_dir, if error? */ 457 458done: 459 mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir); 460 affs_brelse(bh); 461 return retval; 462} 463