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