Loading...
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
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
22const struct xfs_name xfs_name_dotdot = {
23 .name = (const unsigned char *)"..",
24 .len = 2,
25 .type = XFS_DIR3_FT_DIR,
26};
27
28/*
29 * Convert inode mode to directory entry filetype
30 */
31unsigned char
32xfs_mode_to_ftype(
33 int mode)
34{
35 switch (mode & S_IFMT) {
36 case S_IFREG:
37 return XFS_DIR3_FT_REG_FILE;
38 case S_IFDIR:
39 return XFS_DIR3_FT_DIR;
40 case S_IFCHR:
41 return XFS_DIR3_FT_CHRDEV;
42 case S_IFBLK:
43 return XFS_DIR3_FT_BLKDEV;
44 case S_IFIFO:
45 return XFS_DIR3_FT_FIFO;
46 case S_IFSOCK:
47 return XFS_DIR3_FT_SOCK;
48 case S_IFLNK:
49 return XFS_DIR3_FT_SYMLINK;
50 default:
51 return XFS_DIR3_FT_UNKNOWN;
52 }
53}
54
55/*
56 * ASCII case-insensitive (ie. A-Z) support for directories that was
57 * used in IRIX.
58 */
59xfs_dahash_t
60xfs_ascii_ci_hashname(
61 const struct xfs_name *name)
62{
63 xfs_dahash_t hash;
64 int i;
65
66 for (i = 0, hash = 0; i < name->len; i++)
67 hash = tolower(name->name[i]) ^ rol32(hash, 7);
68
69 return hash;
70}
71
72enum xfs_dacmp
73xfs_ascii_ci_compname(
74 struct xfs_da_args *args,
75 const unsigned char *name,
76 int len)
77{
78 enum xfs_dacmp result;
79 int i;
80
81 if (args->namelen != len)
82 return XFS_CMP_DIFFERENT;
83
84 result = XFS_CMP_EXACT;
85 for (i = 0; i < len; i++) {
86 if (args->name[i] == name[i])
87 continue;
88 if (tolower(args->name[i]) != tolower(name[i]))
89 return XFS_CMP_DIFFERENT;
90 result = XFS_CMP_CASE;
91 }
92
93 return result;
94}
95
96int
97xfs_da_mount(
98 struct xfs_mount *mp)
99{
100 struct xfs_da_geometry *dageo;
101
102
103 ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
104 ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
105
106 mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
107 KM_MAYFAIL);
108 mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
109 KM_MAYFAIL);
110 if (!mp->m_dir_geo || !mp->m_attr_geo) {
111 kmem_free(mp->m_dir_geo);
112 kmem_free(mp->m_attr_geo);
113 return -ENOMEM;
114 }
115
116 /* set up directory geometry */
117 dageo = mp->m_dir_geo;
118 dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
119 dageo->fsblog = mp->m_sb.sb_blocklog;
120 dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
121 dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
122 if (xfs_has_crc(mp)) {
123 dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);
124 dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);
125 dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);
126 dageo->data_entry_offset =
127 sizeof(struct xfs_dir3_data_hdr);
128 } else {
129 dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);
130 dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);
131 dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);
132 dageo->data_entry_offset =
133 sizeof(struct xfs_dir2_data_hdr);
134 }
135 dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /
136 sizeof(struct xfs_dir2_leaf_entry);
137 dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /
138 sizeof(xfs_dir2_data_off_t);
139
140 dageo->data_first_offset = dageo->data_entry_offset +
141 xfs_dir2_data_entsize(mp, 1) +
142 xfs_dir2_data_entsize(mp, 2);
143
144 /*
145 * Now we've set up the block conversion variables, we can calculate the
146 * segment block constants using the geometry structure.
147 */
148 dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
149 dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
150 dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
151 dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
152 (uint)sizeof(xfs_da_node_entry_t);
153 dageo->max_extents = (XFS_DIR2_MAX_SPACES * XFS_DIR2_SPACE_SIZE) >>
154 mp->m_sb.sb_blocklog;
155 dageo->magicpct = (dageo->blksize * 37) / 100;
156
157 /* set up attribute geometry - single fsb only */
158 dageo = mp->m_attr_geo;
159 dageo->blklog = mp->m_sb.sb_blocklog;
160 dageo->fsblog = mp->m_sb.sb_blocklog;
161 dageo->blksize = 1 << dageo->blklog;
162 dageo->fsbcount = 1;
163 dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
164 dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
165 (uint)sizeof(xfs_da_node_entry_t);
166
167 if (xfs_has_large_extent_counts(mp))
168 dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_LARGE;
169 else
170 dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_SMALL;
171
172 dageo->magicpct = (dageo->blksize * 37) / 100;
173 return 0;
174}
175
176void
177xfs_da_unmount(
178 struct xfs_mount *mp)
179{
180 kmem_free(mp->m_dir_geo);
181 kmem_free(mp->m_attr_geo);
182}
183
184/*
185 * Return 1 if directory contains only "." and "..".
186 */
187int
188xfs_dir_isempty(
189 xfs_inode_t *dp)
190{
191 xfs_dir2_sf_hdr_t *sfp;
192
193 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
194 if (dp->i_disk_size == 0) /* might happen during shutdown. */
195 return 1;
196 if (dp->i_disk_size > xfs_inode_data_fork_size(dp))
197 return 0;
198 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
199 return !sfp->count;
200}
201
202/*
203 * Validate a given inode number.
204 */
205int
206xfs_dir_ino_validate(
207 xfs_mount_t *mp,
208 xfs_ino_t ino)
209{
210 bool ino_ok = xfs_verify_dir_ino(mp, ino);
211
212 if (XFS_IS_CORRUPT(mp, !ino_ok) ||
213 XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {
214 xfs_warn(mp, "Invalid inode number 0x%Lx",
215 (unsigned long long) ino);
216 return -EFSCORRUPTED;
217 }
218 return 0;
219}
220
221/*
222 * Initialize a directory with its "." and ".." entries.
223 */
224int
225xfs_dir_init(
226 xfs_trans_t *tp,
227 xfs_inode_t *dp,
228 xfs_inode_t *pdp)
229{
230 struct xfs_da_args *args;
231 int error;
232
233 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
234 error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
235 if (error)
236 return error;
237
238 args = kmem_zalloc(sizeof(*args), KM_NOFS);
239 if (!args)
240 return -ENOMEM;
241
242 args->geo = dp->i_mount->m_dir_geo;
243 args->dp = dp;
244 args->trans = tp;
245 error = xfs_dir2_sf_create(args, pdp->i_ino);
246 kmem_free(args);
247 return error;
248}
249
250/*
251 * Enter a name in a directory, or check for available space.
252 * If inum is 0, only the available space test is performed.
253 */
254int
255xfs_dir_createname(
256 struct xfs_trans *tp,
257 struct xfs_inode *dp,
258 const struct xfs_name *name,
259 xfs_ino_t inum, /* new entry inode number */
260 xfs_extlen_t total) /* bmap's total block count */
261{
262 struct xfs_da_args *args;
263 int rval;
264 bool v;
265
266 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
267
268 if (inum) {
269 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
270 if (rval)
271 return rval;
272 XFS_STATS_INC(dp->i_mount, xs_dir_create);
273 }
274
275 args = kmem_zalloc(sizeof(*args), KM_NOFS);
276 if (!args)
277 return -ENOMEM;
278
279 args->geo = dp->i_mount->m_dir_geo;
280 args->name = name->name;
281 args->namelen = name->len;
282 args->filetype = name->type;
283 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
284 args->inumber = inum;
285 args->dp = dp;
286 args->total = total;
287 args->whichfork = XFS_DATA_FORK;
288 args->trans = tp;
289 args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
290 if (!inum)
291 args->op_flags |= XFS_DA_OP_JUSTCHECK;
292
293 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
294 rval = xfs_dir2_sf_addname(args);
295 goto out_free;
296 }
297
298 rval = xfs_dir2_isblock(args, &v);
299 if (rval)
300 goto out_free;
301 if (v) {
302 rval = xfs_dir2_block_addname(args);
303 goto out_free;
304 }
305
306 rval = xfs_dir2_isleaf(args, &v);
307 if (rval)
308 goto out_free;
309 if (v)
310 rval = xfs_dir2_leaf_addname(args);
311 else
312 rval = xfs_dir2_node_addname(args);
313
314out_free:
315 kmem_free(args);
316 return rval;
317}
318
319/*
320 * If doing a CI lookup and case-insensitive match, dup actual name into
321 * args.value. Return EEXIST for success (ie. name found) or an error.
322 */
323int
324xfs_dir_cilookup_result(
325 struct xfs_da_args *args,
326 const unsigned char *name,
327 int len)
328{
329 if (args->cmpresult == XFS_CMP_DIFFERENT)
330 return -ENOENT;
331 if (args->cmpresult != XFS_CMP_CASE ||
332 !(args->op_flags & XFS_DA_OP_CILOOKUP))
333 return -EEXIST;
334
335 args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
336 if (!args->value)
337 return -ENOMEM;
338
339 memcpy(args->value, name, len);
340 args->valuelen = len;
341 return -EEXIST;
342}
343
344/*
345 * Lookup a name in a directory, give back the inode number.
346 * If ci_name is not NULL, returns the actual name in ci_name if it differs
347 * to name, or ci_name->name is set to NULL for an exact match.
348 */
349
350int
351xfs_dir_lookup(
352 struct xfs_trans *tp,
353 struct xfs_inode *dp,
354 const struct xfs_name *name,
355 xfs_ino_t *inum, /* out: inode number */
356 struct xfs_name *ci_name) /* out: actual name if CI match */
357{
358 struct xfs_da_args *args;
359 int rval;
360 bool v;
361 int lock_mode;
362
363 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
364 XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
365
366 /*
367 * We need to use KM_NOFS here so that lockdep will not throw false
368 * positive deadlock warnings on a non-transactional lookup path. It is
369 * safe to recurse into inode recalim in that case, but lockdep can't
370 * easily be taught about it. Hence KM_NOFS avoids having to add more
371 * lockdep Doing this avoids having to add a bunch of lockdep class
372 * annotations into the reclaim path for the ilock.
373 */
374 args = kmem_zalloc(sizeof(*args), KM_NOFS);
375 args->geo = dp->i_mount->m_dir_geo;
376 args->name = name->name;
377 args->namelen = name->len;
378 args->filetype = name->type;
379 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
380 args->dp = dp;
381 args->whichfork = XFS_DATA_FORK;
382 args->trans = tp;
383 args->op_flags = XFS_DA_OP_OKNOENT;
384 if (ci_name)
385 args->op_flags |= XFS_DA_OP_CILOOKUP;
386
387 lock_mode = xfs_ilock_data_map_shared(dp);
388 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
389 rval = xfs_dir2_sf_lookup(args);
390 goto out_check_rval;
391 }
392
393 rval = xfs_dir2_isblock(args, &v);
394 if (rval)
395 goto out_free;
396 if (v) {
397 rval = xfs_dir2_block_lookup(args);
398 goto out_check_rval;
399 }
400
401 rval = xfs_dir2_isleaf(args, &v);
402 if (rval)
403 goto out_free;
404 if (v)
405 rval = xfs_dir2_leaf_lookup(args);
406 else
407 rval = xfs_dir2_node_lookup(args);
408
409out_check_rval:
410 if (rval == -EEXIST)
411 rval = 0;
412 if (!rval) {
413 *inum = args->inumber;
414 if (ci_name) {
415 ci_name->name = args->value;
416 ci_name->len = args->valuelen;
417 }
418 }
419out_free:
420 xfs_iunlock(dp, lock_mode);
421 kmem_free(args);
422 return rval;
423}
424
425/*
426 * Remove an entry from a directory.
427 */
428int
429xfs_dir_removename(
430 struct xfs_trans *tp,
431 struct xfs_inode *dp,
432 struct xfs_name *name,
433 xfs_ino_t ino,
434 xfs_extlen_t total) /* bmap's total block count */
435{
436 struct xfs_da_args *args;
437 int rval;
438 bool v;
439
440 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
441 XFS_STATS_INC(dp->i_mount, xs_dir_remove);
442
443 args = kmem_zalloc(sizeof(*args), KM_NOFS);
444 if (!args)
445 return -ENOMEM;
446
447 args->geo = dp->i_mount->m_dir_geo;
448 args->name = name->name;
449 args->namelen = name->len;
450 args->filetype = name->type;
451 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
452 args->inumber = ino;
453 args->dp = dp;
454 args->total = total;
455 args->whichfork = XFS_DATA_FORK;
456 args->trans = tp;
457
458 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
459 rval = xfs_dir2_sf_removename(args);
460 goto out_free;
461 }
462
463 rval = xfs_dir2_isblock(args, &v);
464 if (rval)
465 goto out_free;
466 if (v) {
467 rval = xfs_dir2_block_removename(args);
468 goto out_free;
469 }
470
471 rval = xfs_dir2_isleaf(args, &v);
472 if (rval)
473 goto out_free;
474 if (v)
475 rval = xfs_dir2_leaf_removename(args);
476 else
477 rval = xfs_dir2_node_removename(args);
478out_free:
479 kmem_free(args);
480 return rval;
481}
482
483/*
484 * Replace the inode number of a directory entry.
485 */
486int
487xfs_dir_replace(
488 struct xfs_trans *tp,
489 struct xfs_inode *dp,
490 const struct xfs_name *name, /* name of entry to replace */
491 xfs_ino_t inum, /* new inode number */
492 xfs_extlen_t total) /* bmap's total block count */
493{
494 struct xfs_da_args *args;
495 int rval;
496 bool v;
497
498 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
499
500 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
501 if (rval)
502 return rval;
503
504 args = kmem_zalloc(sizeof(*args), KM_NOFS);
505 if (!args)
506 return -ENOMEM;
507
508 args->geo = dp->i_mount->m_dir_geo;
509 args->name = name->name;
510 args->namelen = name->len;
511 args->filetype = name->type;
512 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
513 args->inumber = inum;
514 args->dp = dp;
515 args->total = total;
516 args->whichfork = XFS_DATA_FORK;
517 args->trans = tp;
518
519 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
520 rval = xfs_dir2_sf_replace(args);
521 goto out_free;
522 }
523
524 rval = xfs_dir2_isblock(args, &v);
525 if (rval)
526 goto out_free;
527 if (v) {
528 rval = xfs_dir2_block_replace(args);
529 goto out_free;
530 }
531
532 rval = xfs_dir2_isleaf(args, &v);
533 if (rval)
534 goto out_free;
535 if (v)
536 rval = xfs_dir2_leaf_replace(args);
537 else
538 rval = xfs_dir2_node_replace(args);
539out_free:
540 kmem_free(args);
541 return rval;
542}
543
544/*
545 * See if this entry can be added to the directory without allocating space.
546 */
547int
548xfs_dir_canenter(
549 xfs_trans_t *tp,
550 xfs_inode_t *dp,
551 struct xfs_name *name) /* name of entry to add */
552{
553 return xfs_dir_createname(tp, dp, name, 0, 0);
554}
555
556/*
557 * Utility routines.
558 */
559
560/*
561 * Add a block to the directory.
562 *
563 * This routine is for data and free blocks, not leaf/node blocks which are
564 * handled by xfs_da_grow_inode.
565 */
566int
567xfs_dir2_grow_inode(
568 struct xfs_da_args *args,
569 int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */
570 xfs_dir2_db_t *dbp) /* out: block number added */
571{
572 struct xfs_inode *dp = args->dp;
573 struct xfs_mount *mp = dp->i_mount;
574 xfs_fileoff_t bno; /* directory offset of new block */
575 int count; /* count of filesystem blocks */
576 int error;
577
578 trace_xfs_dir2_grow_inode(args, space);
579
580 /*
581 * Set lowest possible block in the space requested.
582 */
583 bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
584 count = args->geo->fsbcount;
585
586 error = xfs_da_grow_inode_int(args, &bno, count);
587 if (error)
588 return error;
589
590 *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
591
592 /*
593 * Update file's size if this is the data space and it grew.
594 */
595 if (space == XFS_DIR2_DATA_SPACE) {
596 xfs_fsize_t size; /* directory file (data) size */
597
598 size = XFS_FSB_TO_B(mp, bno + count);
599 if (size > dp->i_disk_size) {
600 dp->i_disk_size = size;
601 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
602 }
603 }
604 return 0;
605}
606
607/*
608 * See if the directory is a single-block form directory.
609 */
610int
611xfs_dir2_isblock(
612 struct xfs_da_args *args,
613 bool *isblock)
614{
615 struct xfs_mount *mp = args->dp->i_mount;
616 xfs_fileoff_t eof;
617 int error;
618
619 error = xfs_bmap_last_offset(args->dp, &eof, XFS_DATA_FORK);
620 if (error)
621 return error;
622
623 *isblock = false;
624 if (XFS_FSB_TO_B(mp, eof) != args->geo->blksize)
625 return 0;
626
627 *isblock = true;
628 if (XFS_IS_CORRUPT(mp, args->dp->i_disk_size != args->geo->blksize))
629 return -EFSCORRUPTED;
630 return 0;
631}
632
633/*
634 * See if the directory is a single-leaf form directory.
635 */
636int
637xfs_dir2_isleaf(
638 struct xfs_da_args *args,
639 bool *isleaf)
640{
641 xfs_fileoff_t eof;
642 int error;
643
644 error = xfs_bmap_last_offset(args->dp, &eof, XFS_DATA_FORK);
645 if (error)
646 return error;
647
648 *isleaf = false;
649 if (eof != args->geo->leafblk + args->geo->fsbcount)
650 return 0;
651
652 *isleaf = true;
653 return 0;
654}
655
656/*
657 * Remove the given block from the directory.
658 * This routine is used for data and free blocks, leaf/node are done
659 * by xfs_da_shrink_inode.
660 */
661int
662xfs_dir2_shrink_inode(
663 struct xfs_da_args *args,
664 xfs_dir2_db_t db,
665 struct xfs_buf *bp)
666{
667 xfs_fileoff_t bno; /* directory file offset */
668 xfs_dablk_t da; /* directory file offset */
669 int done; /* bunmap is finished */
670 struct xfs_inode *dp;
671 int error;
672 struct xfs_mount *mp;
673 struct xfs_trans *tp;
674
675 trace_xfs_dir2_shrink_inode(args, db);
676
677 dp = args->dp;
678 mp = dp->i_mount;
679 tp = args->trans;
680 da = xfs_dir2_db_to_da(args->geo, db);
681
682 /* Unmap the fsblock(s). */
683 error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
684 if (error) {
685 /*
686 * ENOSPC actually can happen if we're in a removename with no
687 * space reservation, and the resulting block removal would
688 * cause a bmap btree split or conversion from extents to btree.
689 * This can only happen for un-fragmented directory blocks,
690 * since you need to be punching out the middle of an extent.
691 * In this case we need to leave the block in the file, and not
692 * binval it. So the block has to be in a consistent empty
693 * state and appropriately logged. We don't free up the buffer,
694 * the caller can tell it hasn't happened since it got an error
695 * back.
696 */
697 return error;
698 }
699 ASSERT(done);
700 /*
701 * Invalidate the buffer from the transaction.
702 */
703 xfs_trans_binval(tp, bp);
704 /*
705 * If it's not a data block, we're done.
706 */
707 if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
708 return 0;
709 /*
710 * If the block isn't the last one in the directory, we're done.
711 */
712 if (dp->i_disk_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
713 return 0;
714 bno = da;
715 if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
716 /*
717 * This can't really happen unless there's kernel corruption.
718 */
719 return error;
720 }
721 if (db == args->geo->datablk)
722 ASSERT(bno == 0);
723 else
724 ASSERT(bno > 0);
725 /*
726 * Set the size to the new last block.
727 */
728 dp->i_disk_size = XFS_FSB_TO_B(mp, bno);
729 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
730 return 0;
731}
732
733/* Returns true if the directory entry name is valid. */
734bool
735xfs_dir2_namecheck(
736 const void *name,
737 size_t length)
738{
739 /*
740 * MAXNAMELEN includes the trailing null, but (name/length) leave it
741 * out, so use >= for the length check.
742 */
743 if (length >= MAXNAMELEN)
744 return false;
745
746 /* There shouldn't be any slashes or nulls here */
747 return !memchr(name, '/', length) && !memchr(name, 0, length);
748}
749
750xfs_dahash_t
751xfs_dir2_hashname(
752 struct xfs_mount *mp,
753 const struct xfs_name *name)
754{
755 if (unlikely(xfs_has_asciici(mp)))
756 return xfs_ascii_ci_hashname(name);
757 return xfs_da_hashname(name->name, name->len);
758}
759
760enum xfs_dacmp
761xfs_dir2_compname(
762 struct xfs_da_args *args,
763 const unsigned char *name,
764 int len)
765{
766 if (unlikely(xfs_has_asciici(args->dp->i_mount)))
767 return xfs_ascii_ci_compname(args, name, len);
768 return xfs_da_compname(args, name, len);
769}
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
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 * Convert inode mode to directory entry filetype
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 * ASCII case-insensitive (ie. A-Z) support for directories that was
53 * used in IRIX.
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 /* set up directory geometry */
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 * Now we've set up the block conversion variables, we can calculate the
142 * segment block constants using the geometry structure.
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 /* set up attribute geometry - single fsb only */
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 * Return 1 if directory contains only "." and "..".
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) /* might happen during shutdown. */
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 * Validate a given inode number.
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 * Initialize a directory with its "." and ".." entries.
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 * Enter a name in a directory, or check for available space.
240 * If inum is 0, only the available space test is performed.
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, /* new entry inode number */
248 xfs_extlen_t total) /* bmap's total block count */
249{
250 struct xfs_da_args *args;
251 int rval;
252 int v; /* type-checking value */
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_df.if_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 * If doing a CI lookup and case-insensitive match, dup actual name into
309 * args.value. Return EEXIST for success (ie. name found) or an error.
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 * Lookup a name in a directory, give back the inode number.
334 * If ci_name is not NULL, returns the actual name in ci_name if it differs
335 * to name, or ci_name->name is set to NULL for an exact match.
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, /* out: inode number */
344 struct xfs_name *ci_name) /* out: actual name if CI match */
345{
346 struct xfs_da_args *args;
347 int rval;
348 int v; /* type-checking value */
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 * We need to use KM_NOFS here so that lockdep will not throw false
356 * positive deadlock warnings on a non-transactional lookup path. It is
357 * safe to recurse into inode recalim in that case, but lockdep can't
358 * easily be taught about it. Hence KM_NOFS avoids having to add more
359 * lockdep Doing this avoids having to add a bunch of lockdep class
360 * annotations into the reclaim path for the ilock.
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_df.if_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 * Remove an entry from a directory.
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) /* bmap's total block count */
423{
424 struct xfs_da_args *args;
425 int rval;
426 int v; /* type-checking value */
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_df.if_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 * Replace the inode number of a directory entry.
473 */
474int
475xfs_dir_replace(
476 struct xfs_trans *tp,
477 struct xfs_inode *dp,
478 struct xfs_name *name, /* name of entry to replace */
479 xfs_ino_t inum, /* new inode number */
480 xfs_extlen_t total) /* bmap's total block count */
481{
482 struct xfs_da_args *args;
483 int rval;
484 int v; /* type-checking value */
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_df.if_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 * See if this entry can be added to the directory without allocating space.
534 */
535int
536xfs_dir_canenter(
537 xfs_trans_t *tp,
538 xfs_inode_t *dp,
539 struct xfs_name *name) /* name of entry to add */
540{
541 return xfs_dir_createname(tp, dp, name, 0, 0);
542}
543
544/*
545 * Utility routines.
546 */
547
548/*
549 * Add a block to the directory.
550 *
551 * This routine is for data and free blocks, not leaf/node blocks which are
552 * handled by xfs_da_grow_inode.
553 */
554int
555xfs_dir2_grow_inode(
556 struct xfs_da_args *args,
557 int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */
558 xfs_dir2_db_t *dbp) /* out: block number added */
559{
560 struct xfs_inode *dp = args->dp;
561 struct xfs_mount *mp = dp->i_mount;
562 xfs_fileoff_t bno; /* directory offset of new block */
563 int count; /* count of filesystem blocks */
564 int error;
565
566 trace_xfs_dir2_grow_inode(args, space);
567
568 /*
569 * Set lowest possible block in the space requested.
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 * Update file's size if this is the data space and it grew.
582 */
583 if (space == XFS_DIR2_DATA_SPACE) {
584 xfs_fsize_t size; /* directory file (data) 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 * See if the directory is a single-block form directory.
597 */
598int
599xfs_dir2_isblock(
600 struct xfs_da_args *args,
601 int *vp) /* out: 1 is block, 0 is not block */
602{
603 xfs_fileoff_t last; /* last file offset */
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 * See if the directory is a single-leaf form directory.
619 */
620int
621xfs_dir2_isleaf(
622 struct xfs_da_args *args,
623 int *vp) /* out: 1 is block, 0 is not block */
624{
625 xfs_fileoff_t last; /* last file offset */
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 * Remove the given block from the directory.
636 * This routine is used for data and free blocks, leaf/node are done
637 * by xfs_da_shrink_inode.
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; /* directory file offset */
646 xfs_dablk_t da; /* directory file offset */
647 int done; /* bunmap is finished */
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 /* Unmap the fsblock(s). */
661 error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
662 if (error) {
663 /*
664 * ENOSPC actually can happen if we're in a removename with no
665 * space reservation, and the resulting block removal would
666 * cause a bmap btree split or conversion from extents to btree.
667 * This can only happen for un-fragmented directory blocks,
668 * since you need to be punching out the middle of an extent.
669 * In this case we need to leave the block in the file, and not
670 * binval it. So the block has to be in a consistent empty
671 * state and appropriately logged. We don't free up the buffer,
672 * the caller can tell it hasn't happened since it got an error
673 * back.
674 */
675 return error;
676 }
677 ASSERT(done);
678 /*
679 * Invalidate the buffer from the transaction.
680 */
681 xfs_trans_binval(tp, bp);
682 /*
683 * If it's not a data block, we're done.
684 */
685 if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
686 return 0;
687 /*
688 * If the block isn't the last one in the directory, we're done.
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 * This can't really happen unless there's kernel corruption.
696 */
697 return error;
698 }
699 if (db == args->geo->datablk)
700 ASSERT(bno == 0);
701 else
702 ASSERT(bno > 0);
703 /*
704 * Set the size to the new last block.
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/* Returns true if the directory entry name is valid. */
712bool
713xfs_dir2_namecheck(
714 const void *name,
715 size_t length)
716{
717 /*
718 * MAXNAMELEN includes the trailing null, but (name/length) leave it
719 * out, so use >= for the length check.
720 */
721 if (length >= MAXNAMELEN)
722 return false;
723
724 /* There shouldn't be any slashes or nulls here */
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}