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