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