]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_dir2.c
xfsprogs: Release v6.7.0
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_dir2.c
CommitLineData
37b3b4d6 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18 5 */
9c799827 6#include "libxfs_priv.h"
b626fb59 7#include "xfs_fs.h"
27846843 8#include "xfs_shared.h"
b626fb59
DC
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_mount.h"
b626fb59
DC
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"
2cf10e4c 18#include "xfs_errortag.h"
b626fb59 19#include "xfs_trace.h"
2bd0ea18 20
f040050e
DW
21const struct xfs_name xfs_name_dotdot = {
22 .name = (const unsigned char *)"..",
23 .len = 2,
24 .type = XFS_DIR3_FT_DIR,
25};
494434d7 26
aaca101b 27/*
3297e0ca 28 * Convert inode mode to directory entry filetype
aaca101b 29 */
16c101bb
DW
30unsigned char
31xfs_mode_to_ftype(
32 int mode)
3297e0ca
AG
33{
34 switch (mode & S_IFMT) {
35 case S_IFREG:
36 return XFS_DIR3_FT_REG_FILE;
37 case S_IFDIR:
38 return XFS_DIR3_FT_DIR;
39 case S_IFCHR:
40 return XFS_DIR3_FT_CHRDEV;
41 case S_IFBLK:
42 return XFS_DIR3_FT_BLKDEV;
43 case S_IFIFO:
44 return XFS_DIR3_FT_FIFO;
45 case S_IFSOCK:
46 return XFS_DIR3_FT_SOCK;
47 case S_IFLNK:
48 return XFS_DIR3_FT_SYMLINK;
49 default:
50 return XFS_DIR3_FT_UNKNOWN;
51 }
52}
51ca7008
BN
53
54/*
5e656dbb
BN
55 * ASCII case-insensitive (ie. A-Z) support for directories that was
56 * used in IRIX.
51ca7008 57 */
e169cc9b 58xfs_dahash_t
51ca7008 59xfs_ascii_ci_hashname(
c331b654 60 const struct xfs_name *name)
51ca7008 61{
c331b654
DW
62 xfs_dahash_t hash;
63 int i;
51ca7008 64
5e656dbb 65 for (i = 0, hash = 0; i < name->len; i++)
bd970a73 66 hash = xfs_ascii_ci_xfrm(name->name[i]) ^ rol32(hash, 7);
51ca7008
BN
67
68 return hash;
69}
70
e169cc9b 71enum xfs_dacmp
51ca7008 72xfs_ascii_ci_compname(
e169cc9b
CH
73 struct xfs_da_args *args,
74 const unsigned char *name,
75 int len)
51ca7008 76{
e169cc9b
CH
77 enum xfs_dacmp result;
78 int i;
51ca7008 79
5e656dbb 80 if (args->namelen != len)
51ca7008
BN
81 return XFS_CMP_DIFFERENT;
82
83 result = XFS_CMP_EXACT;
5e656dbb
BN
84 for (i = 0; i < len; i++) {
85 if (args->name[i] == name[i])
51ca7008 86 continue;
bd970a73
DW
87 if (xfs_ascii_ci_xfrm(args->name[i]) !=
88 xfs_ascii_ci_xfrm(name[i]))
51ca7008
BN
89 return XFS_CMP_DIFFERENT;
90 result = XFS_CMP_CASE;
91 }
92
93 return result;
94}
95
ff105f75
DC
96int
97xfs_da_mount(
98 struct xfs_mount *mp)
2bd0ea18 99{
ff105f75 100 struct xfs_da_geometry *dageo;
ed59338e
DC
101
102
ff105f75 103 ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
fdef0e8b 104 ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
ff105f75 105
ff105f75 106 mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
6cd1e6db 107 KM_MAYFAIL);
ff105f75 108 mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
6cd1e6db 109 KM_MAYFAIL);
ff105f75
DC
110 if (!mp->m_dir_geo || !mp->m_attr_geo) {
111 kmem_free(mp->m_dir_geo);
112 kmem_free(mp->m_attr_geo);
12b53197 113 return -ENOMEM;
ff105f75
DC
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;
fdef0e8b 120 dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
ff105f75 121 dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
94541a16 122 if (xfs_has_crc(mp)) {
52be9b6a 123 dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);
99e7b975 124 dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);
6006410b 125 dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);
58a1d356
CH
126 dageo->data_entry_offset =
127 sizeof(struct xfs_dir3_data_hdr);
99e7b975 128 } else {
52be9b6a 129 dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);
99e7b975 130 dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);
6006410b 131 dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);
58a1d356
CH
132 dageo->data_entry_offset =
133 sizeof(struct xfs_dir2_data_hdr);
99e7b975 134 }
d106a3e0
CH
135 dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /
136 sizeof(struct xfs_dir2_leaf_entry);
ae3cd5b1
CH
137 dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /
138 sizeof(xfs_dir2_data_off_t);
ff105f75 139
58a1d356
CH
140 dageo->data_first_offset = dageo->data_entry_offset +
141 xfs_dir2_data_entsize(mp, 1) +
142 xfs_dir2_data_entsize(mp, 2);
143
ff105f75
DC
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);
52be9b6a 151 dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
ed59338e 152 (uint)sizeof(xfs_da_node_entry_t);
f0683d63
CB
153 dageo->max_extents = (XFS_DIR2_MAX_SPACES * XFS_DIR2_SPACE_SIZE) >>
154 mp->m_sb.sb_blocklog;
ff105f75
DC
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;
52be9b6a
CH
163 dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
164 dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
ed59338e 165 (uint)sizeof(xfs_da_node_entry_t);
f0683d63
CB
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
ff105f75 172 dageo->magicpct = (dageo->blksize * 37) / 100;
ff105f75
DC
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);
2bd0ea18
NS
182}
183
5e656dbb
BN
184/*
185 * Return 1 if directory contains only "." and "..".
186 */
187int
188xfs_dir_isempty(
189 xfs_inode_t *dp)
190{
a2ceac1f 191 xfs_dir2_sf_hdr_t *sfp;
5e656dbb 192
e37bf53c 193 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
509dcb4b 194 if (dp->i_disk_size == 0) /* might happen during shutdown. */
5e656dbb 195 return 1;
eae3e30d 196 if (dp->i_disk_size > xfs_inode_data_fork_size(dp))
5e656dbb 197 return 0;
a2ceac1f
DC
198 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
199 return !sfp->count;
5e656dbb
BN
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{
be3bf25c
DW
210 bool ino_ok = xfs_verify_dir_ino(mp, ino);
211
bc73da84
DW
212 if (XFS_IS_CORRUPT(mp, !ino_ok) ||
213 XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {
a2ceac1f 214 xfs_warn(mp, "Invalid inode number 0x%Lx",
5e656dbb 215 (unsigned long long) ino);
12b53197 216 return -EFSCORRUPTED;
5e656dbb
BN
217 }
218 return 0;
219}
220
2bd0ea18
NS
221/*
222 * Initialize a directory with its "." and ".." entries.
223 */
5e656dbb
BN
224int
225xfs_dir_init(
226 xfs_trans_t *tp,
227 xfs_inode_t *dp,
228 xfs_inode_t *pdp)
2bd0ea18 229{
ff105f75 230 struct xfs_da_args *args;
5e656dbb 231 int error;
2bd0ea18 232
e37bf53c 233 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
ff105f75
DC
234 error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
235 if (error)
2bd0ea18 236 return error;
ff105f75 237
6cd1e6db 238 args = kmem_zalloc(sizeof(*args), KM_NOFS);
ff105f75 239 if (!args)
12b53197 240 return -ENOMEM;
ff105f75
DC
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;
2bd0ea18
NS
248}
249
250/*
5a35bf2c
DC
251 * Enter a name in a directory, or check for available space.
252 * If inum is 0, only the available space test is performed.
2bd0ea18 253 */
5e656dbb
BN
254int
255xfs_dir_createname(
a50d2ab0
BF
256 struct xfs_trans *tp,
257 struct xfs_inode *dp,
c331b654 258 const struct xfs_name *name,
2bd0ea18 259 xfs_ino_t inum, /* new entry inode number */
2bd0ea18
NS
260 xfs_extlen_t total) /* bmap's total block count */
261{
ff105f75 262 struct xfs_da_args *args;
5e656dbb 263 int rval;
1a3bfffe 264 bool v;
2bd0ea18 265
e37bf53c 266 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
44be3822 267
5a35bf2c
DC
268 if (inum) {
269 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
270 if (rval)
271 return rval;
79896434 272 XFS_STATS_INC(dp->i_mount, xs_dir_create);
5a35bf2c 273 }
5e656dbb 274
6cd1e6db 275 args = kmem_zalloc(sizeof(*args), KM_NOFS);
ff105f75 276 if (!args)
12b53197 277 return -ENOMEM;
ff105f75
DC
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;
e169cc9b 283 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
ff105f75
DC
284 args->inumber = inum;
285 args->dp = dp;
ff105f75
DC
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;
5a35bf2c
DC
290 if (!inum)
291 args->op_flags |= XFS_DA_OP_JUSTCHECK;
ff105f75 292
d967a68d 293 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
ff105f75
DC
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);
2bd0ea18 311 else
ff105f75
DC
312 rval = xfs_dir2_node_addname(args);
313
314out_free:
315 kmem_free(args);
2bd0ea18
NS
316 return rval;
317}
318
5e656dbb
BN
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,
56b2de80 326 const unsigned char *name,
5e656dbb
BN
327 int len)
328{
329 if (args->cmpresult == XFS_CMP_DIFFERENT)
12b53197 330 return -ENOENT;
5e656dbb
BN
331 if (args->cmpresult != XFS_CMP_CASE ||
332 !(args->op_flags & XFS_DA_OP_CILOOKUP))
12b53197 333 return -EEXIST;
5e656dbb 334
56b2de80 335 args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
5e656dbb 336 if (!args->value)
12b53197 337 return -ENOMEM;
5e656dbb
BN
338
339 memcpy(args->value, name, len);
340 args->valuelen = len;
12b53197 341 return -EEXIST;
5e656dbb
BN
342}
343
2bd0ea18
NS
344/*
345 * Lookup a name in a directory, give back the inode number.
5e656dbb
BN
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.
2bd0ea18 348 */
5e656dbb
BN
349
350int
351xfs_dir_lookup(
c331b654
DW
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 */
2bd0ea18 357{
c331b654
DW
358 struct xfs_da_args *args;
359 int rval;
1a3bfffe 360 bool v;
c331b654 361 int lock_mode;
2bd0ea18 362
e37bf53c 363 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
79896434 364 XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
a95cf252 365
ff105f75
DC
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 */
6cd1e6db 374 args = kmem_zalloc(sizeof(*args), KM_NOFS);
ff105f75
DC
375 args->geo = dp->i_mount->m_dir_geo;
376 args->name = name->name;
377 args->namelen = name->len;
378 args->filetype = name->type;
e169cc9b 379 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
ff105f75
DC
380 args->dp = dp;
381 args->whichfork = XFS_DATA_FORK;
382 args->trans = tp;
383 args->op_flags = XFS_DA_OP_OKNOENT;
5e656dbb 384 if (ci_name)
ff105f75 385 args->op_flags |= XFS_DA_OP_CILOOKUP;
5e656dbb 386
7ebb7646 387 lock_mode = xfs_ilock_data_map_shared(dp);
d967a68d 388 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
ff105f75
DC
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);
2bd0ea18 406 else
ff105f75
DC
407 rval = xfs_dir2_node_lookup(args);
408
409out_check_rval:
12b53197 410 if (rval == -EEXIST)
2bd0ea18 411 rval = 0;
5e656dbb 412 if (!rval) {
ff105f75 413 *inum = args->inumber;
5e656dbb 414 if (ci_name) {
ff105f75
DC
415 ci_name->name = args->value;
416 ci_name->len = args->valuelen;
5e656dbb
BN
417 }
418 }
ff105f75 419out_free:
7ebb7646 420 xfs_iunlock(dp, lock_mode);
ff105f75 421 kmem_free(args);
2bd0ea18
NS
422 return rval;
423}
424
425/*
426 * Remove an entry from a directory.
427 */
5e656dbb
BN
428int
429xfs_dir_removename(
a50d2ab0
BF
430 struct xfs_trans *tp,
431 struct xfs_inode *dp,
432 struct xfs_name *name,
433 xfs_ino_t ino,
a50d2ab0 434 xfs_extlen_t total) /* bmap's total block count */
2bd0ea18 435{
a50d2ab0
BF
436 struct xfs_da_args *args;
437 int rval;
1a3bfffe 438 bool v;
2bd0ea18 439
e37bf53c 440 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
79896434 441 XFS_STATS_INC(dp->i_mount, xs_dir_remove);
5e656dbb 442
6cd1e6db 443 args = kmem_zalloc(sizeof(*args), KM_NOFS);
ff105f75 444 if (!args)
12b53197 445 return -ENOMEM;
ff105f75
DC
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;
e169cc9b 451 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
ff105f75
DC
452 args->inumber = ino;
453 args->dp = dp;
ff105f75
DC
454 args->total = total;
455 args->whichfork = XFS_DATA_FORK;
456 args->trans = tp;
457
d967a68d 458 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
ff105f75
DC
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);
2bd0ea18 476 else
ff105f75
DC
477 rval = xfs_dir2_node_removename(args);
478out_free:
479 kmem_free(args);
2bd0ea18
NS
480 return rval;
481}
482
483/*
484 * Replace the inode number of a directory entry.
485 */
5e656dbb
BN
486int
487xfs_dir_replace(
a50d2ab0
BF
488 struct xfs_trans *tp,
489 struct xfs_inode *dp,
c331b654 490 const struct xfs_name *name, /* name of entry to replace */
a50d2ab0 491 xfs_ino_t inum, /* new inode number */
a50d2ab0 492 xfs_extlen_t total) /* bmap's total block count */
2bd0ea18 493{
a50d2ab0
BF
494 struct xfs_da_args *args;
495 int rval;
1a3bfffe 496 bool v;
2bd0ea18 497
e37bf53c 498 ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
a95cf252 499
ff105f75
DC
500 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
501 if (rval)
2bd0ea18 502 return rval;
5e656dbb 503
6cd1e6db 504 args = kmem_zalloc(sizeof(*args), KM_NOFS);
ff105f75 505 if (!args)
12b53197 506 return -ENOMEM;
ff105f75
DC
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;
e169cc9b 512 args->hashval = xfs_dir2_hashname(dp->i_mount, name);
ff105f75
DC
513 args->inumber = inum;
514 args->dp = dp;
ff105f75
DC
515 args->total = total;
516 args->whichfork = XFS_DATA_FORK;
517 args->trans = tp;
518
d967a68d 519 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
ff105f75
DC
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);
2bd0ea18 537 else
ff105f75
DC
538 rval = xfs_dir2_node_replace(args);
539out_free:
540 kmem_free(args);
2bd0ea18
NS
541 return rval;
542}
543
4a34b33d
DC
544/*
545 * See if this entry can be added to the directory without allocating space.
4a34b33d
DC
546 */
547int
548xfs_dir_canenter(
549 xfs_trans_t *tp,
550 xfs_inode_t *dp,
5a35bf2c 551 struct xfs_name *name) /* name of entry to add */
4a34b33d 552{
015bc82e 553 return xfs_dir_createname(tp, dp, name, 0, 0);
4a34b33d
DC
554}
555
2bd0ea18
NS
556/*
557 * Utility routines.
558 */
559
560/*
561 * Add a block to the directory.
a2ceac1f
DC
562 *
563 * This routine is for data and free blocks, not leaf/node blocks which are
564 * handled by xfs_da_grow_inode.
2bd0ea18 565 */
5e656dbb 566int
2bd0ea18 567xfs_dir2_grow_inode(
a2ceac1f
DC
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 */
2bd0ea18 571{
a2ceac1f
DC
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;
56b2de80
DC
577
578 trace_xfs_dir2_grow_inode(args, space);
2bd0ea18 579
2bd0ea18
NS
580 /*
581 * Set lowest possible block in the space requested.
582 */
583 bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
ff105f75 584 count = args->geo->fsbcount;
2bd0ea18 585
a2ceac1f
DC
586 error = xfs_da_grow_inode_int(args, &bno, count);
587 if (error)
588 return error;
56b2de80 589
ff105f75 590 *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
56b2de80 591
2bd0ea18
NS
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);
509dcb4b
CH
599 if (size > dp->i_disk_size) {
600 dp->i_disk_size = size;
a2ceac1f 601 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
2bd0ea18
NS
602 }
603 }
604 return 0;
605}
606
607/*
608 * See if the directory is a single-block form directory.
609 */
5e656dbb 610int
2bd0ea18 611xfs_dir2_isblock(
ff105f75 612 struct xfs_da_args *args,
1a3bfffe 613 bool *isblock)
2bd0ea18 614{
1a3bfffe
SZ
615 struct xfs_mount *mp = args->dp->i_mount;
616 xfs_fileoff_t eof;
617 int error;
2bd0ea18 618
1a3bfffe
SZ
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))
3cfabff6 629 return -EFSCORRUPTED;
2bd0ea18
NS
630 return 0;
631}
632
633/*
634 * See if the directory is a single-leaf form directory.
635 */
5e656dbb 636int
2bd0ea18 637xfs_dir2_isleaf(
ff105f75 638 struct xfs_da_args *args,
1a3bfffe 639 bool *isleaf)
2bd0ea18 640{
1a3bfffe
SZ
641 xfs_fileoff_t eof;
642 int error;
2bd0ea18 643
1a3bfffe
SZ
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;
2bd0ea18
NS
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(
a50d2ab0
BF
663 struct xfs_da_args *args,
664 xfs_dir2_db_t db,
665 struct xfs_buf *bp)
2bd0ea18 666{
a50d2ab0
BF
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;
2bd0ea18 674
56b2de80
DC
675 trace_xfs_dir2_shrink_inode(args, db);
676
2bd0ea18
NS
677 dp = args->dp;
678 mp = dp->i_mount;
679 tp = args->trans;
ff105f75 680 da = xfs_dir2_db_to_da(args->geo, db);
db9cba4e
DC
681
682 /* Unmap the fsblock(s). */
d3c5f3dd 683 error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
db9cba4e 684 if (error) {
2bd0ea18 685 /*
db9cba4e
DC
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.
2bd0ea18
NS
696 */
697 return error;
698 }
699 ASSERT(done);
700 /*
701 * Invalidate the buffer from the transaction.
702 */
a2ceac1f 703 xfs_trans_binval(tp, bp);
2bd0ea18
NS
704 /*
705 * If it's not a data block, we're done.
706 */
ff105f75 707 if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
2bd0ea18
NS
708 return 0;
709 /*
710 * If the block isn't the last one in the directory, we're done.
711 */
509dcb4b 712 if (dp->i_disk_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
2bd0ea18
NS
713 return 0;
714 bno = da;
0e266570 715 if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
2bd0ea18
NS
716 /*
717 * This can't really happen unless there's kernel corruption.
718 */
719 return error;
720 }
ff105f75 721 if (db == args->geo->datablk)
2bd0ea18
NS
722 ASSERT(bno == 0);
723 else
724 ASSERT(bno > 0);
725 /*
726 * Set the size to the new last block.
727 */
509dcb4b 728 dp->i_disk_size = XFS_FSB_TO_B(mp, bno);
2bd0ea18
NS
729 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
730 return 0;
731}
d2b2d412
DW
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}
846e459c
DW
749
750xfs_dahash_t
751xfs_dir2_hashname(
752 struct xfs_mount *mp,
c331b654 753 const struct xfs_name *name)
846e459c 754{
94541a16 755 if (unlikely(xfs_has_asciici(mp)))
846e459c
DW
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{
94541a16 766 if (unlikely(xfs_has_asciici(args->dp->i_mount)))
846e459c
DW
767 return xfs_ascii_ci_compname(args, name, len);
768 return xfs_da_compname(args, name, len);
769}