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 13 typedef int (*toupper_t)(int); 14 15 static int affs_toupper(int ch); 16 static int affs_hash_dentry(const struct dentry *, struct qstr *); 17 static int affs_compare_dentry(const struct dentry *dentry, 18 unsigned int len, const char *str, const struct qstr *name); 19 static int affs_intl_toupper(int ch); 20 static int affs_intl_hash_dentry(const struct dentry *, struct qstr *); 21 static int affs_intl_compare_dentry(const struct dentry *dentry, 22 unsigned int len, const char *str, const struct qstr *name); 23 24 const struct dentry_operations affs_dentry_operations = { 25 .d_hash = affs_hash_dentry, 26 .d_compare = affs_compare_dentry, 27 }; 28 29 const 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 37 static int 38 affs_toupper(int ch) 39 { 40 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; 41 } 42 43 /* International toupper() for DOS\3 ("international") */ 44 45 static int 46 affs_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 53 static inline toupper_t 54 affs_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 */ 63 static inline int 64 __affs_hash_dentry(const struct dentry *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(dentry); 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 84 static int 85 affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) 86 { 87 return __affs_hash_dentry(dentry, qstr, affs_toupper, 88 affs_nofilenametruncate(dentry)); 89 90 } 91 92 static int 93 affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr) 94 { 95 return __affs_hash_dentry(dentry, qstr, affs_intl_toupper, 96 affs_nofilenametruncate(dentry)); 97 98 } 99 100 static 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 133 static int 134 affs_compare_dentry(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(dentry)); 140 } 141 142 static int 143 affs_intl_compare_dentry(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(dentry)); 148 149 } 150 151 /* 152 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. 153 */ 154 155 static inline int 156 affs_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 174 int 175 affs_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 187 static struct buffer_head * 188 affs_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 216 struct dentry * 217 affs_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 250 int 251 affs_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 259 int 260 affs_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 290 int 291 affs_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 319 int 320 affs_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 328 int 329 affs_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_nohighmem(inode); 348 inode->i_data.a_ops = &affs_symlink_aops; 349 inode->i_mode = S_IFLNK | 0777; 350 mode_to_prot(inode); 351 352 error = -EIO; 353 bh = affs_bread(sb, inode->i_ino); 354 if (!bh) 355 goto err; 356 i = 0; 357 p = (char *)AFFS_HEAD(bh)->table; 358 lc = '/'; 359 if (*symname == '/') { 360 struct affs_sb_info *sbi = AFFS_SB(sb); 361 while (*symname == '/') 362 symname++; 363 spin_lock(&sbi->symlink_lock); 364 while (sbi->s_volume[i]) /* Cannot overflow */ 365 *p++ = sbi->s_volume[i++]; 366 spin_unlock(&sbi->symlink_lock); 367 } 368 while (i < maxlen && (c = *symname++)) { 369 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') { 370 *p++ = '/'; 371 i++; 372 symname += 2; 373 lc = '/'; 374 } else if (c == '.' && lc == '/' && *symname == '/') { 375 symname++; 376 lc = '/'; 377 } else { 378 *p++ = c; 379 lc = c; 380 i++; 381 } 382 if (lc == '/') 383 while (*symname == '/') 384 symname++; 385 } 386 *p = 0; 387 mark_buffer_dirty_inode(bh, inode); 388 affs_brelse(bh); 389 mark_inode_dirty(inode); 390 391 error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK); 392 if (error) 393 goto err; 394 395 return 0; 396 397 err: 398 clear_nlink(inode); 399 mark_inode_dirty(inode); 400 iput(inode); 401 return error; 402 } 403 404 int 405 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) 406 { 407 struct inode *inode = d_inode(old_dentry); 408 409 pr_debug("%s(%lu, %lu, \"%pd\")\n", __func__, inode->i_ino, dir->i_ino, 410 dentry); 411 412 return affs_add_entry(dir, inode, dentry, ST_LINKFILE); 413 } 414 415 int 416 affs_rename(struct inode *old_dir, struct dentry *old_dentry, 417 struct inode *new_dir, struct dentry *new_dentry, 418 unsigned int flags) 419 { 420 struct super_block *sb = old_dir->i_sb; 421 struct buffer_head *bh = NULL; 422 int retval; 423 424 if (flags & ~RENAME_NOREPLACE) 425 return -EINVAL; 426 427 pr_debug("%s(old=%lu,\"%pd\" to new=%lu,\"%pd\")\n", __func__, 428 old_dir->i_ino, old_dentry, new_dir->i_ino, new_dentry); 429 430 retval = affs_check_name(new_dentry->d_name.name, 431 new_dentry->d_name.len, 432 affs_nofilenametruncate(old_dentry)); 433 434 if (retval) 435 return retval; 436 437 /* Unlink destination if it already exists */ 438 if (d_really_is_positive(new_dentry)) { 439 retval = affs_remove_header(new_dentry); 440 if (retval) 441 return retval; 442 } 443 444 bh = affs_bread(sb, d_inode(old_dentry)->i_ino); 445 if (!bh) 446 return -EIO; 447 448 /* Remove header from its parent directory. */ 449 affs_lock_dir(old_dir); 450 retval = affs_remove_hash(old_dir, bh); 451 affs_unlock_dir(old_dir); 452 if (retval) 453 goto done; 454 455 /* And insert it into the new directory with the new name. */ 456 affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry); 457 affs_fix_checksum(sb, bh); 458 affs_lock_dir(new_dir); 459 retval = affs_insert_hash(new_dir, bh); 460 affs_unlock_dir(new_dir); 461 /* TODO: move it back to old_dir, if error? */ 462 463 done: 464 mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir); 465 affs_brelse(bh); 466 return retval; 467 } 468