1
2
3
4
5
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_mount.h"
13#include "xfs_inode.h"
14#include "xfs_trans.h"
15#include "xfs_bmap.h"
16#include "xfs_dir2.h"
17#include "xfs_dir2_priv.h"
18#include "xfs_errortag.h"
19#include "xfs_error.h"
20#include "xfs_trace.h"
21
22struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
23
24
25
26
27unsigned char
28xfs_mode_to_ftype(
29 int mode)
30{
31 switch (mode & S_IFMT) {
32 case S_IFREG:
33 return XFS_DIR3_FT_REG_FILE;
34 case S_IFDIR:
35 return XFS_DIR3_FT_DIR;
36 case S_IFCHR:
37 return XFS_DIR3_FT_CHRDEV;
38 case S_IFBLK:
39 return XFS_DIR3_FT_BLKDEV;
40 case S_IFIFO:
41 return XFS_DIR3_FT_FIFO;
42 case S_IFSOCK:
43 return XFS_DIR3_FT_SOCK;
44 case S_IFLNK:
45 return XFS_DIR3_FT_SYMLINK;
46 default:
47 return XFS_DIR3_FT_UNKNOWN;
48 }
49}
50
51
52
53
54
55xfs_dahash_t
56xfs_ascii_ci_hashname(
57 struct xfs_name *name)
58{
59 xfs_dahash_t hash;
60 int i;
61
62 for (i = 0, hash = 0; i < name->len; i++)
63 hash = tolower(name->name[i]) ^ rol32(hash, 7);
64
65 return hash;
66}
67
68enum xfs_dacmp
69xfs_ascii_ci_compname(
70 struct xfs_da_args *args,
71 const unsigned char *name,
72 int len)
73{
74 enum xfs_dacmp result;
75 int i;
76
77 if (args->namelen != len)
78 return XFS_CMP_DIFFERENT;
79
80 result = XFS_CMP_EXACT;
81 for (i = 0; i < len; i++) {
82 if (args->name[i] == name[i])
83 continue;
84 if (tolower(args->name[i]) != tolower(name[i]))
85 return XFS_CMP_DIFFERENT;
86 result = XFS_CMP_CASE;
87 }
88
89 return result;
90}
91
92int
93xfs_da_mount(
94 struct xfs_mount *mp)
95{
96 struct xfs_da_geometry *dageo;
97
98
99 ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
100 ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
101
102 mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
103 KM_MAYFAIL);
104 mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
105 KM_MAYFAIL);
106 if (!mp->m_dir_geo || !mp->m_attr_geo) {
107 kmem_free(mp->m_dir_geo);
108 kmem_free(mp->m_attr_geo);
109 return -ENOMEM;
110 }
111
112
113 dageo = mp->m_dir_geo;
114 dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
115 dageo->fsblog = mp->m_sb.sb_blocklog;
116 dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
117 dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
118 if (xfs_sb_version_hascrc(&mp->m_sb)) {
119 dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);
120 dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);
121 dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);
122 dageo->data_entry_offset =
123 sizeof(struct xfs_dir3_data_hdr);
124 } else {
125 dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);
126 dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);
127 dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);
128 dageo->data_entry_offset =
129 sizeof(struct xfs_dir2_data_hdr);
130 }
131 dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /
132 sizeof(struct xfs_dir2_leaf_entry);
133 dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /
134 sizeof(xfs_dir2_data_off_t);
135
136 dageo->data_first_offset = dageo->data_entry_offset +
137 xfs_dir2_data_entsize(mp, 1) +
138 xfs_dir2_data_entsize(mp, 2);
139
140
141
142
143
144 dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
145 dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
146 dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
147 dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
148 (uint)sizeof(xfs_da_node_entry_t);
149 dageo->magicpct = (dageo->blksize * 37) / 100;
150
151
152 dageo = mp->m_attr_geo;
153 dageo->blklog = mp->m_sb.sb_blocklog;
154 dageo->fsblog = mp->m_sb.sb_blocklog;
155 dageo->blksize = 1 << dageo->blklog;
156 dageo->fsbcount = 1;
157 dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
158 dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
159 (uint)sizeof(xfs_da_node_entry_t);
160 dageo->magicpct = (dageo->blksize * 37) / 100;
161 return 0;
162}
163
164void
165xfs_da_unmount(
166 struct xfs_mount *mp)
167{
168 kmem_free(mp->m_dir_geo);
169 kmem_free(mp->m_attr_geo);
170}
171
172
173
174
175int
176xfs_dir_isempty(
177 xfs_inode_t *dp)
178{
179 xfs_dir2_sf_hdr_t *sfp;
180
181 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
182 if (dp->i_d.di_size == 0)
183 return 1;
184 if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
185 return 0;
186 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
187 return !sfp->count;
188}
189
190
191
192
193int
194xfs_dir_ino_validate(
195 xfs_mount_t *mp,
196 xfs_ino_t ino)
197{
198 bool ino_ok = xfs_verify_dir_ino(mp, ino);
199
200 if (XFS_IS_CORRUPT(mp, !ino_ok) ||
201 XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {
202 xfs_warn(mp, "Invalid inode number 0x%Lx",
203 (unsigned long long) ino);
204 return -EFSCORRUPTED;
205 }
206 return 0;
207}
208
209
210
211
212int
213xfs_dir_init(
214 xfs_trans_t *tp,
215 xfs_inode_t *dp,
216 xfs_inode_t *pdp)
217{
218 struct xfs_da_args *args;
219 int error;
220
221 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
222 error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
223 if (error)
224 return error;
225
226 args = kmem_zalloc(sizeof(*args), KM_NOFS);
227 if (!args)
228 return -ENOMEM;
229
230 args->geo = dp->i_mount->m_dir_geo;
231 args->dp = dp;
232 args->trans = tp;
233 error = xfs_dir2_sf_create(args, pdp->i_ino);
234 kmem_free(args);
235 return error;
236}
237
238
239
240
241
242int
243xfs_dir_createname(
244 struct xfs_trans *tp,
245 struct xfs_inode *dp,
246 struct xfs_name *name,
247 xfs_ino_t inum,
248 xfs_extlen_t total)
249{
250 struct xfs_da_args *args;
251 int rval;
252 int v;
253
254 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
255
256 if (inum) {
257 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
258 if (rval)
259 return rval;
260 XFS_STATS_INC(dp->i_mount, xs_dir_create);
261 }
262
263 args = kmem_zalloc(sizeof(*args), KM_NOFS);
264 if (!args)
265 return -ENOMEM;
266
267 args->geo = dp->i_mount->m_dir_geo;
268 args->name = name->name;
269 args->namelen = name->len;
270 args->filetype = name->type;
271 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
272 args->inumber = inum;
273 args->dp = dp;
274 args->total = total;
275 args->whichfork = XFS_DATA_FORK;
276 args->trans = tp;
277 args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
278 if (!inum)
279 args->op_flags |= XFS_DA_OP_JUSTCHECK;
280
281 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
282 rval = xfs_dir2_sf_addname(args);
283 goto out_free;
284 }
285
286 rval = xfs_dir2_isblock(args, &v);
287 if (rval)
288 goto out_free;
289 if (v) {
290 rval = xfs_dir2_block_addname(args);
291 goto out_free;
292 }
293
294 rval = xfs_dir2_isleaf(args, &v);
295 if (rval)
296 goto out_free;
297 if (v)
298 rval = xfs_dir2_leaf_addname(args);
299 else
300 rval = xfs_dir2_node_addname(args);
301
302out_free:
303 kmem_free(args);
304 return rval;
305}
306
307
308
309
310
311int
312xfs_dir_cilookup_result(
313 struct xfs_da_args *args,
314 const unsigned char *name,
315 int len)
316{
317 if (args->cmpresult == XFS_CMP_DIFFERENT)
318 return -ENOENT;
319 if (args->cmpresult != XFS_CMP_CASE ||
320 !(args->op_flags & XFS_DA_OP_CILOOKUP))
321 return -EEXIST;
322
323 args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
324 if (!args->value)
325 return -ENOMEM;
326
327 memcpy(args->value, name, len);
328 args->valuelen = len;
329 return -EEXIST;
330}
331
332
333
334
335
336
337
338int
339xfs_dir_lookup(
340 xfs_trans_t *tp,
341 xfs_inode_t *dp,
342 struct xfs_name *name,
343 xfs_ino_t *inum,
344 struct xfs_name *ci_name)
345{
346 struct xfs_da_args *args;
347 int rval;
348 int v;
349 int lock_mode;
350
351 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
352 XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
353
354
355
356
357
358
359
360
361
362 args = kmem_zalloc(sizeof(*args), KM_NOFS);
363 args->geo = dp->i_mount->m_dir_geo;
364 args->name = name->name;
365 args->namelen = name->len;
366 args->filetype = name->type;
367 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
368 args->dp = dp;
369 args->whichfork = XFS_DATA_FORK;
370 args->trans = tp;
371 args->op_flags = XFS_DA_OP_OKNOENT;
372 if (ci_name)
373 args->op_flags |= XFS_DA_OP_CILOOKUP;
374
375 lock_mode = xfs_ilock_data_map_shared(dp);
376 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
377 rval = xfs_dir2_sf_lookup(args);
378 goto out_check_rval;
379 }
380
381 rval = xfs_dir2_isblock(args, &v);
382 if (rval)
383 goto out_free;
384 if (v) {
385 rval = xfs_dir2_block_lookup(args);
386 goto out_check_rval;
387 }
388
389 rval = xfs_dir2_isleaf(args, &v);
390 if (rval)
391 goto out_free;
392 if (v)
393 rval = xfs_dir2_leaf_lookup(args);
394 else
395 rval = xfs_dir2_node_lookup(args);
396
397out_check_rval:
398 if (rval == -EEXIST)
399 rval = 0;
400 if (!rval) {
401 *inum = args->inumber;
402 if (ci_name) {
403 ci_name->name = args->value;
404 ci_name->len = args->valuelen;
405 }
406 }
407out_free:
408 xfs_iunlock(dp, lock_mode);
409 kmem_free(args);
410 return rval;
411}
412
413
414
415
416int
417xfs_dir_removename(
418 struct xfs_trans *tp,
419 struct xfs_inode *dp,
420 struct xfs_name *name,
421 xfs_ino_t ino,
422 xfs_extlen_t total)
423{
424 struct xfs_da_args *args;
425 int rval;
426 int v;
427
428 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
429 XFS_STATS_INC(dp->i_mount, xs_dir_remove);
430
431 args = kmem_zalloc(sizeof(*args), KM_NOFS);
432 if (!args)
433 return -ENOMEM;
434
435 args->geo = dp->i_mount->m_dir_geo;
436 args->name = name->name;
437 args->namelen = name->len;
438 args->filetype = name->type;
439 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
440 args->inumber = ino;
441 args->dp = dp;
442 args->total = total;
443 args->whichfork = XFS_DATA_FORK;
444 args->trans = tp;
445
446 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
447 rval = xfs_dir2_sf_removename(args);
448 goto out_free;
449 }
450
451 rval = xfs_dir2_isblock(args, &v);
452 if (rval)
453 goto out_free;
454 if (v) {
455 rval = xfs_dir2_block_removename(args);
456 goto out_free;
457 }
458
459 rval = xfs_dir2_isleaf(args, &v);
460 if (rval)
461 goto out_free;
462 if (v)
463 rval = xfs_dir2_leaf_removename(args);
464 else
465 rval = xfs_dir2_node_removename(args);
466out_free:
467 kmem_free(args);
468 return rval;
469}
470
471
472
473
474int
475xfs_dir_replace(
476 struct xfs_trans *tp,
477 struct xfs_inode *dp,
478 struct xfs_name *name,
479 xfs_ino_t inum,
480 xfs_extlen_t total)
481{
482 struct xfs_da_args *args;
483 int rval;
484 int v;
485
486 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
487
488 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
489 if (rval)
490 return rval;
491
492 args = kmem_zalloc(sizeof(*args), KM_NOFS);
493 if (!args)
494 return -ENOMEM;
495
496 args->geo = dp->i_mount->m_dir_geo;
497 args->name = name->name;
498 args->namelen = name->len;
499 args->filetype = name->type;
500 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
501 args->inumber = inum;
502 args->dp = dp;
503 args->total = total;
504 args->whichfork = XFS_DATA_FORK;
505 args->trans = tp;
506
507 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
508 rval = xfs_dir2_sf_replace(args);
509 goto out_free;
510 }
511
512 rval = xfs_dir2_isblock(args, &v);
513 if (rval)
514 goto out_free;
515 if (v) {
516 rval = xfs_dir2_block_replace(args);
517 goto out_free;
518 }
519
520 rval = xfs_dir2_isleaf(args, &v);
521 if (rval)
522 goto out_free;
523 if (v)
524 rval = xfs_dir2_leaf_replace(args);
525 else
526 rval = xfs_dir2_node_replace(args);
527out_free:
528 kmem_free(args);
529 return rval;
530}
531
532
533
534
535int
536xfs_dir_canenter(
537 xfs_trans_t *tp,
538 xfs_inode_t *dp,
539 struct xfs_name *name)
540{
541 return xfs_dir_createname(tp, dp, name, 0, 0);
542}
543
544
545
546
547
548
549
550
551
552
553
554int
555xfs_dir2_grow_inode(
556 struct xfs_da_args *args,
557 int space,
558 xfs_dir2_db_t *dbp)
559{
560 struct xfs_inode *dp = args->dp;
561 struct xfs_mount *mp = dp->i_mount;
562 xfs_fileoff_t bno;
563 int count;
564 int error;
565
566 trace_xfs_dir2_grow_inode(args, space);
567
568
569
570
571 bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
572 count = args->geo->fsbcount;
573
574 error = xfs_da_grow_inode_int(args, &bno, count);
575 if (error)
576 return error;
577
578 *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
579
580
581
582
583 if (space == XFS_DIR2_DATA_SPACE) {
584 xfs_fsize_t size;
585
586 size = XFS_FSB_TO_B(mp, bno + count);
587 if (size > dp->i_d.di_size) {
588 dp->i_d.di_size = size;
589 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
590 }
591 }
592 return 0;
593}
594
595
596
597
598int
599xfs_dir2_isblock(
600 struct xfs_da_args *args,
601 int *vp)
602{
603 xfs_fileoff_t last;
604 int rval;
605
606 if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
607 return rval;
608 rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
609 if (XFS_IS_CORRUPT(args->dp->i_mount,
610 rval != 0 &&
611 args->dp->i_d.di_size != args->geo->blksize))
612 return -EFSCORRUPTED;
613 *vp = rval;
614 return 0;
615}
616
617
618
619
620int
621xfs_dir2_isleaf(
622 struct xfs_da_args *args,
623 int *vp)
624{
625 xfs_fileoff_t last;
626 int rval;
627
628 if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
629 return rval;
630 *vp = last == args->geo->leafblk + args->geo->fsbcount;
631 return 0;
632}
633
634
635
636
637
638
639int
640xfs_dir2_shrink_inode(
641 struct xfs_da_args *args,
642 xfs_dir2_db_t db,
643 struct xfs_buf *bp)
644{
645 xfs_fileoff_t bno;
646 xfs_dablk_t da;
647 int done;
648 struct xfs_inode *dp;
649 int error;
650 struct xfs_mount *mp;
651 struct xfs_trans *tp;
652
653 trace_xfs_dir2_shrink_inode(args, db);
654
655 dp = args->dp;
656 mp = dp->i_mount;
657 tp = args->trans;
658 da = xfs_dir2_db_to_da(args->geo, db);
659
660
661 error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
662 if (error) {
663
664
665
666
667
668
669
670
671
672
673
674
675 return error;
676 }
677 ASSERT(done);
678
679
680
681 xfs_trans_binval(tp, bp);
682
683
684
685 if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
686 return 0;
687
688
689
690 if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
691 return 0;
692 bno = da;
693 if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
694
695
696
697 return error;
698 }
699 if (db == args->geo->datablk)
700 ASSERT(bno == 0);
701 else
702 ASSERT(bno > 0);
703
704
705
706 dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
707 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
708 return 0;
709}
710
711
712bool
713xfs_dir2_namecheck(
714 const void *name,
715 size_t length)
716{
717
718
719
720
721 if (length >= MAXNAMELEN)
722 return false;
723
724
725 return !memchr(name, '/', length) && !memchr(name, 0, length);
726}
727
728xfs_dahash_t
729xfs_dir2_hashname(
730 struct xfs_mount *mp,
731 struct xfs_name *name)
732{
733 if (unlikely(xfs_sb_version_hasasciici(&mp->m_sb)))
734 return xfs_ascii_ci_hashname(name);
735 return xfs_da_hashname(name->name, name->len);
736}
737
738enum xfs_dacmp
739xfs_dir2_compname(
740 struct xfs_da_args *args,
741 const unsigned char *name,
742 int len)
743{
744 if (unlikely(xfs_sb_version_hasasciici(&args->dp->i_mount->m_sb)))
745 return xfs_ascii_ci_compname(args, name, len);
746 return xfs_da_compname(args, name, len);
747}
748