1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2000-2003,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_dir2.h" 16 #include "xfs_dir2_priv.h" 17 #include "xfs_trace.h" 18 19 /* 20 * Prototypes for internal functions. 21 */ 22 static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, 23 xfs_dir2_sf_entry_t *sfep, 24 xfs_dir2_data_aoff_t offset, 25 int new_isize); 26 static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, 27 int new_isize); 28 static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, 29 xfs_dir2_sf_entry_t **sfepp, 30 xfs_dir2_data_aoff_t *offsetp); 31 #ifdef DEBUG 32 static void xfs_dir2_sf_check(xfs_da_args_t *args); 33 #else 34 #define xfs_dir2_sf_check(args) 35 #endif /* DEBUG */ 36 37 static void xfs_dir2_sf_toino4(xfs_da_args_t *args); 38 static void xfs_dir2_sf_toino8(xfs_da_args_t *args); 39 40 /* 41 * Given a block directory (dp/block), calculate its size as a shortform (sf) 42 * directory and a header for the sf directory, if it will fit it the 43 * space currently present in the inode. If it won't fit, the output 44 * size is too big (but not accurate). 45 */ 46 int /* size for sf form */ 47 xfs_dir2_block_sfsize( 48 xfs_inode_t *dp, /* incore inode pointer */ 49 xfs_dir2_data_hdr_t *hdr, /* block directory data */ 50 xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ 51 { 52 xfs_dir2_dataptr_t addr; /* data entry address */ 53 xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ 54 xfs_dir2_block_tail_t *btp; /* tail area of the block */ 55 int count; /* shortform entry count */ 56 xfs_dir2_data_entry_t *dep; /* data entry in the block */ 57 int i; /* block entry index */ 58 int i8count; /* count of big-inode entries */ 59 int isdot; /* entry is "." */ 60 int isdotdot; /* entry is ".." */ 61 xfs_mount_t *mp; /* mount structure pointer */ 62 int namelen; /* total name bytes */ 63 xfs_ino_t parent = 0; /* parent inode number */ 64 int size=0; /* total computed size */ 65 int has_ftype; 66 struct xfs_da_geometry *geo; 67 68 mp = dp->i_mount; 69 geo = mp->m_dir_geo; 70 71 /* 72 * if there is a filetype field, add the extra byte to the namelen 73 * for each entry that we see. 74 */ 75 has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0; 76 77 count = i8count = namelen = 0; 78 btp = xfs_dir2_block_tail_p(geo, hdr); 79 blp = xfs_dir2_block_leaf_p(btp); 80 81 /* 82 * Iterate over the block's data entries by using the leaf pointers. 83 */ 84 for (i = 0; i < be32_to_cpu(btp->count); i++) { 85 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR) 86 continue; 87 /* 88 * Calculate the pointer to the entry at hand. 89 */ 90 dep = (xfs_dir2_data_entry_t *)((char *)hdr + 91 xfs_dir2_dataptr_to_off(geo, addr)); 92 /* 93 * Detect . and .., so we can special-case them. 94 * . is not included in sf directories. 95 * .. is included by just the parent inode number. 96 */ 97 isdot = dep->namelen == 1 && dep->name[0] == '.'; 98 isdotdot = 99 dep->namelen == 2 && 100 dep->name[0] == '.' && dep->name[1] == '.'; 101 102 if (!isdot) 103 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; 104 105 /* take into account the file type field */ 106 if (!isdot && !isdotdot) { 107 count++; 108 namelen += dep->namelen + has_ftype; 109 } else if (isdotdot) 110 parent = be64_to_cpu(dep->inumber); 111 /* 112 * Calculate the new size, see if we should give up yet. 113 */ 114 size = xfs_dir2_sf_hdr_size(i8count) + /* header */ 115 count * 3 * sizeof(u8) + /* namelen + offset */ 116 namelen + /* name */ 117 (i8count ? /* inumber */ 118 count * XFS_INO64_SIZE : 119 count * XFS_INO32_SIZE); 120 if (size > XFS_IFORK_DSIZE(dp)) 121 return size; /* size value is a failure */ 122 } 123 /* 124 * Create the output header, if it worked. 125 */ 126 sfhp->count = count; 127 sfhp->i8count = i8count; 128 dp->d_ops->sf_put_parent_ino(sfhp, parent); 129 return size; 130 } 131 132 /* 133 * Convert a block format directory to shortform. 134 * Caller has already checked that it will fit, and built us a header. 135 */ 136 int /* error */ 137 xfs_dir2_block_to_sf( 138 xfs_da_args_t *args, /* operation arguments */ 139 struct xfs_buf *bp, 140 int size, /* shortform directory size */ 141 xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ 142 { 143 xfs_dir2_data_hdr_t *hdr; /* block header */ 144 xfs_dir2_data_entry_t *dep; /* data entry pointer */ 145 xfs_inode_t *dp; /* incore directory inode */ 146 xfs_dir2_data_unused_t *dup; /* unused data pointer */ 147 char *endptr; /* end of data entries */ 148 int error; /* error return value */ 149 int logflags; /* inode logging flags */ 150 xfs_mount_t *mp; /* filesystem mount point */ 151 char *ptr; /* current data pointer */ 152 xfs_dir2_sf_entry_t *sfep; /* shortform entry */ 153 xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */ 154 xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */ 155 156 trace_xfs_dir2_block_to_sf(args); 157 158 dp = args->dp; 159 mp = dp->i_mount; 160 161 /* 162 * allocate a temporary destination buffer the size of the inode 163 * to format the data into. Once we have formatted the data, we 164 * can free the block and copy the formatted data into the inode literal 165 * area. 166 */ 167 dst = kmem_alloc(mp->m_sb.sb_inodesize, 0); 168 hdr = bp->b_addr; 169 170 /* 171 * Copy the header into the newly allocate local space. 172 */ 173 sfp = (xfs_dir2_sf_hdr_t *)dst; 174 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count)); 175 176 /* 177 * Set up to loop over the block's entries. 178 */ 179 ptr = (char *)dp->d_ops->data_entry_p(hdr); 180 endptr = xfs_dir3_data_endp(args->geo, hdr); 181 sfep = xfs_dir2_sf_firstentry(sfp); 182 /* 183 * Loop over the active and unused entries. 184 * Stop when we reach the leaf/tail portion of the block. 185 */ 186 while (ptr < endptr) { 187 /* 188 * If it's unused, just skip over it. 189 */ 190 dup = (xfs_dir2_data_unused_t *)ptr; 191 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 192 ptr += be16_to_cpu(dup->length); 193 continue; 194 } 195 dep = (xfs_dir2_data_entry_t *)ptr; 196 /* 197 * Skip . 198 */ 199 if (dep->namelen == 1 && dep->name[0] == '.') 200 ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); 201 /* 202 * Skip .., but make sure the inode number is right. 203 */ 204 else if (dep->namelen == 2 && 205 dep->name[0] == '.' && dep->name[1] == '.') 206 ASSERT(be64_to_cpu(dep->inumber) == 207 dp->d_ops->sf_get_parent_ino(sfp)); 208 /* 209 * Normal entry, copy it into shortform. 210 */ 211 else { 212 sfep->namelen = dep->namelen; 213 xfs_dir2_sf_put_offset(sfep, 214 (xfs_dir2_data_aoff_t) 215 ((char *)dep - (char *)hdr)); 216 memcpy(sfep->name, dep->name, dep->namelen); 217 dp->d_ops->sf_put_ino(sfp, sfep, 218 be64_to_cpu(dep->inumber)); 219 dp->d_ops->sf_put_ftype(sfep, 220 dp->d_ops->data_get_ftype(dep)); 221 222 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 223 } 224 ptr += dp->d_ops->data_entsize(dep->namelen); 225 } 226 ASSERT((char *)sfep - (char *)sfp == size); 227 228 /* now we are done with the block, we can shrink the inode */ 229 logflags = XFS_ILOG_CORE; 230 error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp); 231 if (error) { 232 ASSERT(error != -ENOSPC); 233 goto out; 234 } 235 236 /* 237 * The buffer is now unconditionally gone, whether 238 * xfs_dir2_shrink_inode worked or not. 239 * 240 * Convert the inode to local format and copy the data in. 241 */ 242 ASSERT(dp->i_df.if_bytes == 0); 243 xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size); 244 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; 245 dp->i_d.di_size = size; 246 247 logflags |= XFS_ILOG_DDATA; 248 xfs_dir2_sf_check(args); 249 out: 250 xfs_trans_log_inode(args->trans, dp, logflags); 251 kmem_free(dst); 252 return error; 253 } 254 255 /* 256 * Add a name to a shortform directory. 257 * There are two algorithms, "easy" and "hard" which we decide on 258 * before changing anything. 259 * Convert to block form if necessary, if the new entry won't fit. 260 */ 261 int /* error */ 262 xfs_dir2_sf_addname( 263 xfs_da_args_t *args) /* operation arguments */ 264 { 265 xfs_inode_t *dp; /* incore directory inode */ 266 int error; /* error return value */ 267 int incr_isize; /* total change in size */ 268 int new_isize; /* di_size after adding name */ 269 int objchange; /* changing to 8-byte inodes */ 270 xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */ 271 int pick; /* which algorithm to use */ 272 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 273 xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */ 274 275 trace_xfs_dir2_sf_addname(args); 276 277 ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT); 278 dp = args->dp; 279 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 280 /* 281 * Make sure the shortform value has some of its header. 282 */ 283 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 284 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 285 return -EIO; 286 } 287 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 288 ASSERT(dp->i_df.if_u1.if_data != NULL); 289 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 290 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); 291 /* 292 * Compute entry (and change in) size. 293 */ 294 incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen); 295 objchange = 0; 296 297 /* 298 * Do we have to change to 8 byte inodes? 299 */ 300 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { 301 /* 302 * Yes, adjust the inode size. old count + (parent + new) 303 */ 304 incr_isize += (sfp->count + 2) * XFS_INO64_DIFF; 305 objchange = 1; 306 } 307 308 new_isize = (int)dp->i_d.di_size + incr_isize; 309 /* 310 * Won't fit as shortform any more (due to size), 311 * or the pick routine says it won't (due to offset values). 312 */ 313 if (new_isize > XFS_IFORK_DSIZE(dp) || 314 (pick = 315 xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { 316 /* 317 * Just checking or no space reservation, it doesn't fit. 318 */ 319 if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) 320 return -ENOSPC; 321 /* 322 * Convert to block form then add the name. 323 */ 324 error = xfs_dir2_sf_to_block(args); 325 if (error) 326 return error; 327 return xfs_dir2_block_addname(args); 328 } 329 /* 330 * Just checking, it fits. 331 */ 332 if (args->op_flags & XFS_DA_OP_JUSTCHECK) 333 return 0; 334 /* 335 * Do it the easy way - just add it at the end. 336 */ 337 if (pick == 1) 338 xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); 339 /* 340 * Do it the hard way - look for a place to insert the new entry. 341 * Convert to 8 byte inode numbers first if necessary. 342 */ 343 else { 344 ASSERT(pick == 2); 345 if (objchange) 346 xfs_dir2_sf_toino8(args); 347 xfs_dir2_sf_addname_hard(args, objchange, new_isize); 348 } 349 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 350 return 0; 351 } 352 353 /* 354 * Add the new entry the "easy" way. 355 * This is copying the old directory and adding the new entry at the end. 356 * Since it's sorted by "offset" we need room after the last offset 357 * that's already there, and then room to convert to a block directory. 358 * This is already checked by the pick routine. 359 */ 360 static void 361 xfs_dir2_sf_addname_easy( 362 xfs_da_args_t *args, /* operation arguments */ 363 xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ 364 xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ 365 int new_isize) /* new directory size */ 366 { 367 int byteoff; /* byte offset in sf dir */ 368 xfs_inode_t *dp; /* incore directory inode */ 369 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 370 371 dp = args->dp; 372 373 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 374 byteoff = (int)((char *)sfep - (char *)sfp); 375 /* 376 * Grow the in-inode space. 377 */ 378 xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen), 379 XFS_DATA_FORK); 380 /* 381 * Need to set up again due to realloc of the inode data. 382 */ 383 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 384 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); 385 /* 386 * Fill in the new entry. 387 */ 388 sfep->namelen = args->namelen; 389 xfs_dir2_sf_put_offset(sfep, offset); 390 memcpy(sfep->name, args->name, sfep->namelen); 391 dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); 392 dp->d_ops->sf_put_ftype(sfep, args->filetype); 393 394 /* 395 * Update the header and inode. 396 */ 397 sfp->count++; 398 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) 399 sfp->i8count++; 400 dp->i_d.di_size = new_isize; 401 xfs_dir2_sf_check(args); 402 } 403 404 /* 405 * Add the new entry the "hard" way. 406 * The caller has already converted to 8 byte inode numbers if necessary, 407 * in which case we need to leave the i8count at 1. 408 * Find a hole that the new entry will fit into, and copy 409 * the first part of the entries, the new entry, and the last part of 410 * the entries. 411 */ 412 /* ARGSUSED */ 413 static void 414 xfs_dir2_sf_addname_hard( 415 xfs_da_args_t *args, /* operation arguments */ 416 int objchange, /* changing inode number size */ 417 int new_isize) /* new directory size */ 418 { 419 int add_datasize; /* data size need for new ent */ 420 char *buf; /* buffer for old */ 421 xfs_inode_t *dp; /* incore directory inode */ 422 int eof; /* reached end of old dir */ 423 int nbytes; /* temp for byte copies */ 424 xfs_dir2_data_aoff_t new_offset; /* next offset value */ 425 xfs_dir2_data_aoff_t offset; /* current offset value */ 426 int old_isize; /* previous di_size */ 427 xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ 428 xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */ 429 xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ 430 xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */ 431 432 /* 433 * Copy the old directory to the stack buffer. 434 */ 435 dp = args->dp; 436 437 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 438 old_isize = (int)dp->i_d.di_size; 439 buf = kmem_alloc(old_isize, 0); 440 oldsfp = (xfs_dir2_sf_hdr_t *)buf; 441 memcpy(oldsfp, sfp, old_isize); 442 /* 443 * Loop over the old directory finding the place we're going 444 * to insert the new entry. 445 * If it's going to end up at the end then oldsfep will point there. 446 */ 447 for (offset = dp->d_ops->data_first_offset, 448 oldsfep = xfs_dir2_sf_firstentry(oldsfp), 449 add_datasize = dp->d_ops->data_entsize(args->namelen), 450 eof = (char *)oldsfep == &buf[old_isize]; 451 !eof; 452 offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen), 453 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep), 454 eof = (char *)oldsfep == &buf[old_isize]) { 455 new_offset = xfs_dir2_sf_get_offset(oldsfep); 456 if (offset + add_datasize <= new_offset) 457 break; 458 } 459 /* 460 * Get rid of the old directory, then allocate space for 461 * the new one. We do this so xfs_idata_realloc won't copy 462 * the data. 463 */ 464 xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); 465 xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); 466 /* 467 * Reset the pointer since the buffer was reallocated. 468 */ 469 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 470 /* 471 * Copy the first part of the directory, including the header. 472 */ 473 nbytes = (int)((char *)oldsfep - (char *)oldsfp); 474 memcpy(sfp, oldsfp, nbytes); 475 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); 476 /* 477 * Fill in the new entry, and update the header counts. 478 */ 479 sfep->namelen = args->namelen; 480 xfs_dir2_sf_put_offset(sfep, offset); 481 memcpy(sfep->name, args->name, sfep->namelen); 482 dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); 483 dp->d_ops->sf_put_ftype(sfep, args->filetype); 484 sfp->count++; 485 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) 486 sfp->i8count++; 487 /* 488 * If there's more left to copy, do that. 489 */ 490 if (!eof) { 491 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 492 memcpy(sfep, oldsfep, old_isize - nbytes); 493 } 494 kmem_free(buf); 495 dp->i_d.di_size = new_isize; 496 xfs_dir2_sf_check(args); 497 } 498 499 /* 500 * Decide if the new entry will fit at all. 501 * If it will fit, pick between adding the new entry to the end (easy) 502 * or somewhere else (hard). 503 * Return 0 (won't fit), 1 (easy), 2 (hard). 504 */ 505 /*ARGSUSED*/ 506 static int /* pick result */ 507 xfs_dir2_sf_addname_pick( 508 xfs_da_args_t *args, /* operation arguments */ 509 int objchange, /* inode # size changes */ 510 xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ 511 xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ 512 { 513 xfs_inode_t *dp; /* incore directory inode */ 514 int holefit; /* found hole it will fit in */ 515 int i; /* entry number */ 516 xfs_dir2_data_aoff_t offset; /* data block offset */ 517 xfs_dir2_sf_entry_t *sfep; /* shortform entry */ 518 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 519 int size; /* entry's data size */ 520 int used; /* data bytes used */ 521 522 dp = args->dp; 523 524 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 525 size = dp->d_ops->data_entsize(args->namelen); 526 offset = dp->d_ops->data_first_offset; 527 sfep = xfs_dir2_sf_firstentry(sfp); 528 holefit = 0; 529 /* 530 * Loop over sf entries. 531 * Keep track of data offset and whether we've seen a place 532 * to insert the new entry. 533 */ 534 for (i = 0; i < sfp->count; i++) { 535 if (!holefit) 536 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); 537 offset = xfs_dir2_sf_get_offset(sfep) + 538 dp->d_ops->data_entsize(sfep->namelen); 539 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 540 } 541 /* 542 * Calculate data bytes used excluding the new entry, if this 543 * was a data block (block form directory). 544 */ 545 used = offset + 546 (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 547 (uint)sizeof(xfs_dir2_block_tail_t); 548 /* 549 * If it won't fit in a block form then we can't insert it, 550 * we'll go back, convert to block, then try the insert and convert 551 * to leaf. 552 */ 553 if (used + (holefit ? 0 : size) > args->geo->blksize) 554 return 0; 555 /* 556 * If changing the inode number size, do it the hard way. 557 */ 558 if (objchange) 559 return 2; 560 /* 561 * If it won't fit at the end then do it the hard way (use the hole). 562 */ 563 if (used + size > args->geo->blksize) 564 return 2; 565 /* 566 * Do it the easy way. 567 */ 568 *sfepp = sfep; 569 *offsetp = offset; 570 return 1; 571 } 572 573 #ifdef DEBUG 574 /* 575 * Check consistency of shortform directory, assert if bad. 576 */ 577 static void 578 xfs_dir2_sf_check( 579 xfs_da_args_t *args) /* operation arguments */ 580 { 581 xfs_inode_t *dp; /* incore directory inode */ 582 int i; /* entry number */ 583 int i8count; /* number of big inode#s */ 584 xfs_ino_t ino; /* entry inode number */ 585 int offset; /* data offset */ 586 xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ 587 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 588 589 dp = args->dp; 590 591 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 592 offset = dp->d_ops->data_first_offset; 593 ino = dp->d_ops->sf_get_parent_ino(sfp); 594 i8count = ino > XFS_DIR2_MAX_SHORT_INUM; 595 596 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); 597 i < sfp->count; 598 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 599 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); 600 ino = dp->d_ops->sf_get_ino(sfp, sfep); 601 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 602 offset = 603 xfs_dir2_sf_get_offset(sfep) + 604 dp->d_ops->data_entsize(sfep->namelen); 605 ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX); 606 } 607 ASSERT(i8count == sfp->i8count); 608 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); 609 ASSERT(offset + 610 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 611 (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize); 612 } 613 #endif /* DEBUG */ 614 615 /* Verify the consistency of an inline directory. */ 616 xfs_failaddr_t 617 xfs_dir2_sf_verify( 618 struct xfs_inode *ip) 619 { 620 struct xfs_mount *mp = ip->i_mount; 621 struct xfs_dir2_sf_hdr *sfp; 622 struct xfs_dir2_sf_entry *sfep; 623 struct xfs_dir2_sf_entry *next_sfep; 624 char *endp; 625 const struct xfs_dir_ops *dops; 626 struct xfs_ifork *ifp; 627 xfs_ino_t ino; 628 int i; 629 int i8count; 630 int offset; 631 int size; 632 int error; 633 uint8_t filetype; 634 635 ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_LOCAL); 636 /* 637 * xfs_iread calls us before xfs_setup_inode sets up ip->d_ops, 638 * so we can only trust the mountpoint to have the right pointer. 639 */ 640 dops = xfs_dir_get_ops(mp, NULL); 641 642 ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); 643 sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data; 644 size = ifp->if_bytes; 645 646 /* 647 * Give up if the directory is way too short. 648 */ 649 if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) || 650 size < xfs_dir2_sf_hdr_size(sfp->i8count)) 651 return __this_address; 652 653 endp = (char *)sfp + size; 654 655 /* Check .. entry */ 656 ino = dops->sf_get_parent_ino(sfp); 657 i8count = ino > XFS_DIR2_MAX_SHORT_INUM; 658 error = xfs_dir_ino_validate(mp, ino); 659 if (error) 660 return __this_address; 661 offset = dops->data_first_offset; 662 663 /* Check all reported entries */ 664 sfep = xfs_dir2_sf_firstentry(sfp); 665 for (i = 0; i < sfp->count; i++) { 666 /* 667 * struct xfs_dir2_sf_entry has a variable length. 668 * Check the fixed-offset parts of the structure are 669 * within the data buffer. 670 */ 671 if (((char *)sfep + sizeof(*sfep)) >= endp) 672 return __this_address; 673 674 /* Don't allow names with known bad length. */ 675 if (sfep->namelen == 0) 676 return __this_address; 677 678 /* 679 * Check that the variable-length part of the structure is 680 * within the data buffer. The next entry starts after the 681 * name component, so nextentry is an acceptable test. 682 */ 683 next_sfep = dops->sf_nextentry(sfp, sfep); 684 if (endp < (char *)next_sfep) 685 return __this_address; 686 687 /* Check that the offsets always increase. */ 688 if (xfs_dir2_sf_get_offset(sfep) < offset) 689 return __this_address; 690 691 /* Check the inode number. */ 692 ino = dops->sf_get_ino(sfp, sfep); 693 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 694 error = xfs_dir_ino_validate(mp, ino); 695 if (error) 696 return __this_address; 697 698 /* Check the file type. */ 699 filetype = dops->sf_get_ftype(sfep); 700 if (filetype >= XFS_DIR3_FT_MAX) 701 return __this_address; 702 703 offset = xfs_dir2_sf_get_offset(sfep) + 704 dops->data_entsize(sfep->namelen); 705 706 sfep = next_sfep; 707 } 708 if (i8count != sfp->i8count) 709 return __this_address; 710 if ((void *)sfep != (void *)endp) 711 return __this_address; 712 713 /* Make sure this whole thing ought to be in local format. */ 714 if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 715 (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) 716 return __this_address; 717 718 return NULL; 719 } 720 721 /* 722 * Create a new (shortform) directory. 723 */ 724 int /* error, always 0 */ 725 xfs_dir2_sf_create( 726 xfs_da_args_t *args, /* operation arguments */ 727 xfs_ino_t pino) /* parent inode number */ 728 { 729 xfs_inode_t *dp; /* incore directory inode */ 730 int i8count; /* parent inode is an 8-byte number */ 731 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 732 int size; /* directory size */ 733 734 trace_xfs_dir2_sf_create(args); 735 736 dp = args->dp; 737 738 ASSERT(dp != NULL); 739 ASSERT(dp->i_d.di_size == 0); 740 /* 741 * If it's currently a zero-length extent file, 742 * convert it to local format. 743 */ 744 if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { 745 dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ 746 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; 747 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); 748 dp->i_df.if_flags |= XFS_IFINLINE; 749 } 750 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 751 ASSERT(dp->i_df.if_bytes == 0); 752 i8count = pino > XFS_DIR2_MAX_SHORT_INUM; 753 size = xfs_dir2_sf_hdr_size(i8count); 754 /* 755 * Make a buffer for the data. 756 */ 757 xfs_idata_realloc(dp, size, XFS_DATA_FORK); 758 /* 759 * Fill in the header, 760 */ 761 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 762 sfp->i8count = i8count; 763 /* 764 * Now can put in the inode number, since i8count is set. 765 */ 766 dp->d_ops->sf_put_parent_ino(sfp, pino); 767 sfp->count = 0; 768 dp->i_d.di_size = size; 769 xfs_dir2_sf_check(args); 770 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 771 return 0; 772 } 773 774 /* 775 * Lookup an entry in a shortform directory. 776 * Returns EEXIST if found, ENOENT if not found. 777 */ 778 int /* error */ 779 xfs_dir2_sf_lookup( 780 xfs_da_args_t *args) /* operation arguments */ 781 { 782 xfs_inode_t *dp; /* incore directory inode */ 783 int i; /* entry index */ 784 int error; 785 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 786 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 787 enum xfs_dacmp cmp; /* comparison result */ 788 xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ 789 790 trace_xfs_dir2_sf_lookup(args); 791 792 xfs_dir2_sf_check(args); 793 dp = args->dp; 794 795 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 796 /* 797 * Bail out if the directory is way too short. 798 */ 799 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 800 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 801 return -EIO; 802 } 803 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 804 ASSERT(dp->i_df.if_u1.if_data != NULL); 805 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 806 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); 807 /* 808 * Special case for . 809 */ 810 if (args->namelen == 1 && args->name[0] == '.') { 811 args->inumber = dp->i_ino; 812 args->cmpresult = XFS_CMP_EXACT; 813 args->filetype = XFS_DIR3_FT_DIR; 814 return -EEXIST; 815 } 816 /* 817 * Special case for .. 818 */ 819 if (args->namelen == 2 && 820 args->name[0] == '.' && args->name[1] == '.') { 821 args->inumber = dp->d_ops->sf_get_parent_ino(sfp); 822 args->cmpresult = XFS_CMP_EXACT; 823 args->filetype = XFS_DIR3_FT_DIR; 824 return -EEXIST; 825 } 826 /* 827 * Loop over all the entries trying to match ours. 828 */ 829 ci_sfep = NULL; 830 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 831 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 832 /* 833 * Compare name and if it's an exact match, return the inode 834 * number. If it's the first case-insensitive match, store the 835 * inode number and continue looking for an exact match. 836 */ 837 cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, 838 sfep->namelen); 839 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { 840 args->cmpresult = cmp; 841 args->inumber = dp->d_ops->sf_get_ino(sfp, sfep); 842 args->filetype = dp->d_ops->sf_get_ftype(sfep); 843 if (cmp == XFS_CMP_EXACT) 844 return -EEXIST; 845 ci_sfep = sfep; 846 } 847 } 848 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); 849 /* 850 * Here, we can only be doing a lookup (not a rename or replace). 851 * If a case-insensitive match was not found, return -ENOENT. 852 */ 853 if (!ci_sfep) 854 return -ENOENT; 855 /* otherwise process the CI match as required by the caller */ 856 error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); 857 return error; 858 } 859 860 /* 861 * Remove an entry from a shortform directory. 862 */ 863 int /* error */ 864 xfs_dir2_sf_removename( 865 xfs_da_args_t *args) 866 { 867 int byteoff; /* offset of removed entry */ 868 xfs_inode_t *dp; /* incore directory inode */ 869 int entsize; /* this entry's size */ 870 int i; /* shortform entry index */ 871 int newsize; /* new inode size */ 872 int oldsize; /* old inode size */ 873 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 874 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 875 876 trace_xfs_dir2_sf_removename(args); 877 878 dp = args->dp; 879 880 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 881 oldsize = (int)dp->i_d.di_size; 882 /* 883 * Bail out if the directory is way too short. 884 */ 885 if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { 886 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 887 return -EIO; 888 } 889 ASSERT(dp->i_df.if_bytes == oldsize); 890 ASSERT(dp->i_df.if_u1.if_data != NULL); 891 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 892 ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count)); 893 /* 894 * Loop over the old directory entries. 895 * Find the one we're deleting. 896 */ 897 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 898 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 899 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 900 XFS_CMP_EXACT) { 901 ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) == 902 args->inumber); 903 break; 904 } 905 } 906 /* 907 * Didn't find it. 908 */ 909 if (i == sfp->count) 910 return -ENOENT; 911 /* 912 * Calculate sizes. 913 */ 914 byteoff = (int)((char *)sfep - (char *)sfp); 915 entsize = dp->d_ops->sf_entsize(sfp, args->namelen); 916 newsize = oldsize - entsize; 917 /* 918 * Copy the part if any after the removed entry, sliding it down. 919 */ 920 if (byteoff + entsize < oldsize) 921 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize, 922 oldsize - (byteoff + entsize)); 923 /* 924 * Fix up the header and file size. 925 */ 926 sfp->count--; 927 dp->i_d.di_size = newsize; 928 /* 929 * Reallocate, making it smaller. 930 */ 931 xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); 932 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 933 /* 934 * Are we changing inode number size? 935 */ 936 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { 937 if (sfp->i8count == 1) 938 xfs_dir2_sf_toino4(args); 939 else 940 sfp->i8count--; 941 } 942 xfs_dir2_sf_check(args); 943 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 944 return 0; 945 } 946 947 /* 948 * Replace the inode number of an entry in a shortform directory. 949 */ 950 int /* error */ 951 xfs_dir2_sf_replace( 952 xfs_da_args_t *args) /* operation arguments */ 953 { 954 xfs_inode_t *dp; /* incore directory inode */ 955 int i; /* entry index */ 956 xfs_ino_t ino=0; /* entry old inode number */ 957 int i8elevated; /* sf_toino8 set i8count=1 */ 958 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 959 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 960 961 trace_xfs_dir2_sf_replace(args); 962 963 dp = args->dp; 964 965 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 966 /* 967 * Bail out if the shortform directory is way too small. 968 */ 969 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 970 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 971 return -EIO; 972 } 973 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 974 ASSERT(dp->i_df.if_u1.if_data != NULL); 975 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 976 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); 977 978 /* 979 * New inode number is large, and need to convert to 8-byte inodes. 980 */ 981 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { 982 int error; /* error return value */ 983 int newsize; /* new inode size */ 984 985 newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF; 986 /* 987 * Won't fit as shortform, convert to block then do replace. 988 */ 989 if (newsize > XFS_IFORK_DSIZE(dp)) { 990 error = xfs_dir2_sf_to_block(args); 991 if (error) { 992 return error; 993 } 994 return xfs_dir2_block_replace(args); 995 } 996 /* 997 * Still fits, convert to 8-byte now. 998 */ 999 xfs_dir2_sf_toino8(args); 1000 i8elevated = 1; 1001 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1002 } else 1003 i8elevated = 0; 1004 1005 ASSERT(args->namelen != 1 || args->name[0] != '.'); 1006 /* 1007 * Replace ..'s entry. 1008 */ 1009 if (args->namelen == 2 && 1010 args->name[0] == '.' && args->name[1] == '.') { 1011 ino = dp->d_ops->sf_get_parent_ino(sfp); 1012 ASSERT(args->inumber != ino); 1013 dp->d_ops->sf_put_parent_ino(sfp, args->inumber); 1014 } 1015 /* 1016 * Normal entry, look for the name. 1017 */ 1018 else { 1019 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 1020 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 1021 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 1022 XFS_CMP_EXACT) { 1023 ino = dp->d_ops->sf_get_ino(sfp, sfep); 1024 ASSERT(args->inumber != ino); 1025 dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); 1026 dp->d_ops->sf_put_ftype(sfep, args->filetype); 1027 break; 1028 } 1029 } 1030 /* 1031 * Didn't find it. 1032 */ 1033 if (i == sfp->count) { 1034 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); 1035 if (i8elevated) 1036 xfs_dir2_sf_toino4(args); 1037 return -ENOENT; 1038 } 1039 } 1040 /* 1041 * See if the old number was large, the new number is small. 1042 */ 1043 if (ino > XFS_DIR2_MAX_SHORT_INUM && 1044 args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { 1045 /* 1046 * And the old count was one, so need to convert to small. 1047 */ 1048 if (sfp->i8count == 1) 1049 xfs_dir2_sf_toino4(args); 1050 else 1051 sfp->i8count--; 1052 } 1053 /* 1054 * See if the old number was small, the new number is large. 1055 */ 1056 if (ino <= XFS_DIR2_MAX_SHORT_INUM && 1057 args->inumber > XFS_DIR2_MAX_SHORT_INUM) { 1058 /* 1059 * add to the i8count unless we just converted to 8-byte 1060 * inodes (which does an implied i8count = 1) 1061 */ 1062 ASSERT(sfp->i8count != 0); 1063 if (!i8elevated) 1064 sfp->i8count++; 1065 } 1066 xfs_dir2_sf_check(args); 1067 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); 1068 return 0; 1069 } 1070 1071 /* 1072 * Convert from 8-byte inode numbers to 4-byte inode numbers. 1073 * The last 8-byte inode number is gone, but the count is still 1. 1074 */ 1075 static void 1076 xfs_dir2_sf_toino4( 1077 xfs_da_args_t *args) /* operation arguments */ 1078 { 1079 char *buf; /* old dir's buffer */ 1080 xfs_inode_t *dp; /* incore directory inode */ 1081 int i; /* entry index */ 1082 int newsize; /* new inode size */ 1083 xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ 1084 xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ 1085 int oldsize; /* old inode size */ 1086 xfs_dir2_sf_entry_t *sfep; /* new sf entry */ 1087 xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ 1088 1089 trace_xfs_dir2_sf_toino4(args); 1090 1091 dp = args->dp; 1092 1093 /* 1094 * Copy the old directory to the buffer. 1095 * Then nuke it from the inode, and add the new buffer to the inode. 1096 * Don't want xfs_idata_realloc copying the data here. 1097 */ 1098 oldsize = dp->i_df.if_bytes; 1099 buf = kmem_alloc(oldsize, 0); 1100 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1101 ASSERT(oldsfp->i8count == 1); 1102 memcpy(buf, oldsfp, oldsize); 1103 /* 1104 * Compute the new inode size. 1105 */ 1106 newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF; 1107 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); 1108 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); 1109 /* 1110 * Reset our pointers, the data has moved. 1111 */ 1112 oldsfp = (xfs_dir2_sf_hdr_t *)buf; 1113 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1114 /* 1115 * Fill in the new header. 1116 */ 1117 sfp->count = oldsfp->count; 1118 sfp->i8count = 0; 1119 dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); 1120 /* 1121 * Copy the entries field by field. 1122 */ 1123 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1124 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1125 i < sfp->count; 1126 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), 1127 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { 1128 sfep->namelen = oldsfep->namelen; 1129 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset)); 1130 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1131 dp->d_ops->sf_put_ino(sfp, sfep, 1132 dp->d_ops->sf_get_ino(oldsfp, oldsfep)); 1133 dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); 1134 } 1135 /* 1136 * Clean up the inode. 1137 */ 1138 kmem_free(buf); 1139 dp->i_d.di_size = newsize; 1140 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 1141 } 1142 1143 /* 1144 * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers. 1145 * The new entry w/ an 8-byte inode number is not there yet; we leave with 1146 * i8count set to 1, but no corresponding 8-byte entry. 1147 */ 1148 static void 1149 xfs_dir2_sf_toino8( 1150 xfs_da_args_t *args) /* operation arguments */ 1151 { 1152 char *buf; /* old dir's buffer */ 1153 xfs_inode_t *dp; /* incore directory inode */ 1154 int i; /* entry index */ 1155 int newsize; /* new inode size */ 1156 xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ 1157 xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ 1158 int oldsize; /* old inode size */ 1159 xfs_dir2_sf_entry_t *sfep; /* new sf entry */ 1160 xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ 1161 1162 trace_xfs_dir2_sf_toino8(args); 1163 1164 dp = args->dp; 1165 1166 /* 1167 * Copy the old directory to the buffer. 1168 * Then nuke it from the inode, and add the new buffer to the inode. 1169 * Don't want xfs_idata_realloc copying the data here. 1170 */ 1171 oldsize = dp->i_df.if_bytes; 1172 buf = kmem_alloc(oldsize, 0); 1173 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1174 ASSERT(oldsfp->i8count == 0); 1175 memcpy(buf, oldsfp, oldsize); 1176 /* 1177 * Compute the new inode size (nb: entry count + 1 for parent) 1178 */ 1179 newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF; 1180 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); 1181 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); 1182 /* 1183 * Reset our pointers, the data has moved. 1184 */ 1185 oldsfp = (xfs_dir2_sf_hdr_t *)buf; 1186 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1187 /* 1188 * Fill in the new header. 1189 */ 1190 sfp->count = oldsfp->count; 1191 sfp->i8count = 1; 1192 dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); 1193 /* 1194 * Copy the entries field by field. 1195 */ 1196 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1197 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1198 i < sfp->count; 1199 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), 1200 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { 1201 sfep->namelen = oldsfep->namelen; 1202 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset)); 1203 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1204 dp->d_ops->sf_put_ino(sfp, sfep, 1205 dp->d_ops->sf_get_ino(oldsfp, oldsfep)); 1206 dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); 1207 } 1208 /* 1209 * Clean up the inode. 1210 */ 1211 kmem_free(buf); 1212 dp->i_d.di_size = newsize; 1213 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 1214 } 1215