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