1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_types.h"
21#include "xfs_log.h"
22#include "xfs_inum.h"
23#include "xfs_trans.h"
24#include "xfs_sb.h"
25#include "xfs_ag.h"
26#include "xfs_dir2.h"
27#include "xfs_dmapi.h"
28#include "xfs_mount.h"
29#include "xfs_da_btree.h"
30#include "xfs_bmap_btree.h"
31#include "xfs_dir2_sf.h"
32#include "xfs_attr_sf.h"
33#include "xfs_dinode.h"
34#include "xfs_inode.h"
35#include "xfs_inode_item.h"
36#include "xfs_error.h"
37#include "xfs_dir2_data.h"
38#include "xfs_dir2_leaf.h"
39#include "xfs_dir2_block.h"
40#include "xfs_dir2_trace.h"
41
42
43
44
45static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
46 xfs_dir2_sf_entry_t *sfep,
47 xfs_dir2_data_aoff_t offset,
48 int new_isize);
49static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
50 int new_isize);
51static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
52 xfs_dir2_sf_entry_t **sfepp,
53 xfs_dir2_data_aoff_t *offsetp);
54#ifdef DEBUG
55static void xfs_dir2_sf_check(xfs_da_args_t *args);
56#else
57#define xfs_dir2_sf_check(args)
58#endif
59#if XFS_BIG_INUMS
60static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
61static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
62#endif
63
64
65
66
67
68
69
70int
71xfs_dir2_block_sfsize(
72 xfs_inode_t *dp,
73 xfs_dir2_block_t *block,
74 xfs_dir2_sf_hdr_t *sfhp)
75{
76 xfs_dir2_dataptr_t addr;
77 xfs_dir2_leaf_entry_t *blp;
78 xfs_dir2_block_tail_t *btp;
79 int count;
80 xfs_dir2_data_entry_t *dep;
81 int i;
82 int i8count;
83 int isdot;
84 int isdotdot;
85 xfs_mount_t *mp;
86 int namelen;
87 xfs_ino_t parent = 0;
88 int size=0;
89
90 mp = dp->i_mount;
91
92 count = i8count = namelen = 0;
93 btp = xfs_dir2_block_tail_p(mp, block);
94 blp = xfs_dir2_block_leaf_p(btp);
95
96
97
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
104
105 dep = (xfs_dir2_data_entry_t *)
106 ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
107
108
109
110
111
112 isdot = dep->namelen == 1 && dep->name[0] == '.';
113 isdotdot =
114 dep->namelen == 2 &&
115 dep->name[0] == '.' && dep->name[1] == '.';
116#if XFS_BIG_INUMS
117 if (!isdot)
118 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
119#endif
120 if (!isdot && !isdotdot) {
121 count++;
122 namelen += dep->namelen;
123 } else if (isdotdot)
124 parent = be64_to_cpu(dep->inumber);
125
126
127
128 size = xfs_dir2_sf_hdr_size(i8count) +
129 count +
130 count * (uint)sizeof(xfs_dir2_sf_off_t) +
131 namelen +
132 (i8count ?
133 (uint)sizeof(xfs_dir2_ino8_t) * count :
134 (uint)sizeof(xfs_dir2_ino4_t) * count);
135 if (size > XFS_IFORK_DSIZE(dp))
136 return size;
137 }
138
139
140
141 sfhp->count = count;
142 sfhp->i8count = i8count;
143 xfs_dir2_sf_put_inumber((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
144 return size;
145}
146
147
148
149
150
151int
152xfs_dir2_block_to_sf(
153 xfs_da_args_t *args,
154 xfs_dabuf_t *bp,
155 int size,
156 xfs_dir2_sf_hdr_t *sfhp)
157{
158 xfs_dir2_block_t *block;
159 xfs_dir2_block_tail_t *btp;
160 xfs_dir2_data_entry_t *dep;
161 xfs_inode_t *dp;
162 xfs_dir2_data_unused_t *dup;
163 char *endptr;
164 int error;
165 int logflags;
166 xfs_mount_t *mp;
167 char *ptr;
168 xfs_dir2_sf_entry_t *sfep;
169 xfs_dir2_sf_t *sfp;
170 xfs_ino_t temp;
171
172 xfs_dir2_trace_args_sb("block_to_sf", args, size, bp);
173 dp = args->dp;
174 mp = dp->i_mount;
175
176
177
178
179
180 block = kmem_alloc(mp->m_dirblksize, KM_SLEEP);
181 memcpy(block, bp->data, mp->m_dirblksize);
182 logflags = XFS_ILOG_CORE;
183 if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
184 ASSERT(error != ENOSPC);
185 goto out;
186 }
187
188
189
190
191
192
193 dp->i_df.if_flags &= ~XFS_IFEXTENTS;
194 dp->i_df.if_flags |= XFS_IFINLINE;
195 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
196 ASSERT(dp->i_df.if_bytes == 0);
197 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
198 logflags |= XFS_ILOG_DDATA;
199
200
201
202 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
203 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
204 dp->i_d.di_size = size;
205
206
207
208 btp = xfs_dir2_block_tail_p(mp, block);
209 ptr = (char *)block->u;
210 endptr = (char *)xfs_dir2_block_leaf_p(btp);
211 sfep = xfs_dir2_sf_firstentry(sfp);
212
213
214
215
216 while (ptr < endptr) {
217
218
219
220 dup = (xfs_dir2_data_unused_t *)ptr;
221 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
222 ptr += be16_to_cpu(dup->length);
223 continue;
224 }
225 dep = (xfs_dir2_data_entry_t *)ptr;
226
227
228
229 if (dep->namelen == 1 && dep->name[0] == '.')
230 ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
231
232
233
234 else if (dep->namelen == 2 &&
235 dep->name[0] == '.' && dep->name[1] == '.')
236 ASSERT(be64_to_cpu(dep->inumber) ==
237 xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));
238
239
240
241 else {
242 sfep->namelen = dep->namelen;
243 xfs_dir2_sf_put_offset(sfep,
244 (xfs_dir2_data_aoff_t)
245 ((char *)dep - (char *)block));
246 memcpy(sfep->name, dep->name, dep->namelen);
247 temp = be64_to_cpu(dep->inumber);
248 xfs_dir2_sf_put_inumber(sfp, &temp,
249 xfs_dir2_sf_inumberp(sfep));
250 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
251 }
252 ptr += xfs_dir2_data_entsize(dep->namelen);
253 }
254 ASSERT((char *)sfep - (char *)sfp == size);
255 xfs_dir2_sf_check(args);
256out:
257 xfs_trans_log_inode(args->trans, dp, logflags);
258 kmem_free(block);
259 return error;
260}
261
262
263
264
265
266
267
268int
269xfs_dir2_sf_addname(
270 xfs_da_args_t *args)
271{
272 int add_entsize;
273 xfs_inode_t *dp;
274 int error;
275 int incr_isize;
276 int new_isize;
277 int objchange;
278 xfs_dir2_data_aoff_t offset = 0;
279 int old_isize;
280 int pick;
281 xfs_dir2_sf_t *sfp;
282 xfs_dir2_sf_entry_t *sfep = NULL;
283
284 xfs_dir2_trace_args("sf_addname", args);
285 ASSERT(xfs_dir2_sf_lookup(args) == ENOENT);
286 dp = args->dp;
287 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
288
289
290
291 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
292 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
293 return XFS_ERROR(EIO);
294 }
295 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
296 ASSERT(dp->i_df.if_u1.if_data != NULL);
297 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
298 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
299
300
301
302 add_entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
303 incr_isize = add_entsize;
304 objchange = 0;
305#if XFS_BIG_INUMS
306
307
308
309 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) {
310
311
312
313 add_entsize +=
314 (uint)sizeof(xfs_dir2_ino8_t) -
315 (uint)sizeof(xfs_dir2_ino4_t);
316 incr_isize +=
317 (sfp->hdr.count + 2) *
318 ((uint)sizeof(xfs_dir2_ino8_t) -
319 (uint)sizeof(xfs_dir2_ino4_t));
320 objchange = 1;
321 }
322#endif
323 old_isize = (int)dp->i_d.di_size;
324 new_isize = old_isize + incr_isize;
325
326
327
328
329 if (new_isize > XFS_IFORK_DSIZE(dp) ||
330 (pick =
331 xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
332
333
334
335 if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
336 return XFS_ERROR(ENOSPC);
337
338
339
340 error = xfs_dir2_sf_to_block(args);
341 if (error)
342 return error;
343 return xfs_dir2_block_addname(args);
344 }
345
346
347
348 if (args->op_flags & XFS_DA_OP_JUSTCHECK)
349 return 0;
350
351
352
353 if (pick == 1)
354 xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize);
355
356
357
358
359 else {
360 ASSERT(pick == 2);
361#if XFS_BIG_INUMS
362 if (objchange)
363 xfs_dir2_sf_toino8(args);
364#endif
365 xfs_dir2_sf_addname_hard(args, objchange, new_isize);
366 }
367 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
368 return 0;
369}
370
371
372
373
374
375
376
377
378static void
379xfs_dir2_sf_addname_easy(
380 xfs_da_args_t *args,
381 xfs_dir2_sf_entry_t *sfep,
382 xfs_dir2_data_aoff_t offset,
383 int new_isize)
384{
385 int byteoff;
386 xfs_inode_t *dp;
387 xfs_dir2_sf_t *sfp;
388
389 dp = args->dp;
390
391 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
392 byteoff = (int)((char *)sfep - (char *)sfp);
393
394
395
396 xfs_idata_realloc(dp, xfs_dir2_sf_entsize_byname(sfp, args->namelen),
397 XFS_DATA_FORK);
398
399
400
401 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
402 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
403
404
405
406 sfep->namelen = args->namelen;
407 xfs_dir2_sf_put_offset(sfep, offset);
408 memcpy(sfep->name, args->name, sfep->namelen);
409 xfs_dir2_sf_put_inumber(sfp, &args->inumber,
410 xfs_dir2_sf_inumberp(sfep));
411
412
413
414 sfp->hdr.count++;
415#if XFS_BIG_INUMS
416 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
417 sfp->hdr.i8count++;
418#endif
419 dp->i_d.di_size = new_isize;
420 xfs_dir2_sf_check(args);
421}
422
423
424
425
426
427
428
429
430
431
432static void
433xfs_dir2_sf_addname_hard(
434 xfs_da_args_t *args,
435 int objchange,
436 int new_isize)
437{
438 int add_datasize;
439 char *buf;
440 xfs_inode_t *dp;
441 int eof;
442 int nbytes;
443 xfs_dir2_data_aoff_t new_offset;
444 xfs_dir2_data_aoff_t offset;
445 int old_isize;
446 xfs_dir2_sf_entry_t *oldsfep;
447 xfs_dir2_sf_t *oldsfp;
448 xfs_dir2_sf_entry_t *sfep;
449 xfs_dir2_sf_t *sfp;
450
451
452
453
454 dp = args->dp;
455
456 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
457 old_isize = (int)dp->i_d.di_size;
458 buf = kmem_alloc(old_isize, KM_SLEEP);
459 oldsfp = (xfs_dir2_sf_t *)buf;
460 memcpy(oldsfp, sfp, old_isize);
461
462
463
464
465
466 for (offset = XFS_DIR2_DATA_FIRST_OFFSET,
467 oldsfep = xfs_dir2_sf_firstentry(oldsfp),
468 add_datasize = xfs_dir2_data_entsize(args->namelen),
469 eof = (char *)oldsfep == &buf[old_isize];
470 !eof;
471 offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen),
472 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep),
473 eof = (char *)oldsfep == &buf[old_isize]) {
474 new_offset = xfs_dir2_sf_get_offset(oldsfep);
475 if (offset + add_datasize <= new_offset)
476 break;
477 }
478
479
480
481
482
483 xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
484 xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
485
486
487
488 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
489
490
491
492 nbytes = (int)((char *)oldsfep - (char *)oldsfp);
493 memcpy(sfp, oldsfp, nbytes);
494 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
495
496
497
498 sfep->namelen = args->namelen;
499 xfs_dir2_sf_put_offset(sfep, offset);
500 memcpy(sfep->name, args->name, sfep->namelen);
501 xfs_dir2_sf_put_inumber(sfp, &args->inumber,
502 xfs_dir2_sf_inumberp(sfep));
503 sfp->hdr.count++;
504#if XFS_BIG_INUMS
505 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
506 sfp->hdr.i8count++;
507#endif
508
509
510
511 if (!eof) {
512 sfep = xfs_dir2_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
522
523
524
525
526
527static int
528xfs_dir2_sf_addname_pick(
529 xfs_da_args_t *args,
530 int objchange,
531 xfs_dir2_sf_entry_t **sfepp,
532 xfs_dir2_data_aoff_t *offsetp)
533{
534 xfs_inode_t *dp;
535 int holefit;
536 int i;
537 xfs_mount_t *mp;
538 xfs_dir2_data_aoff_t offset;
539 xfs_dir2_sf_entry_t *sfep;
540 xfs_dir2_sf_t *sfp;
541 int size;
542 int used;
543
544 dp = args->dp;
545 mp = dp->i_mount;
546
547 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
548 size = xfs_dir2_data_entsize(args->namelen);
549 offset = XFS_DIR2_DATA_FIRST_OFFSET;
550 sfep = xfs_dir2_sf_firstentry(sfp);
551 holefit = 0;
552
553
554
555
556
557 for (i = 0; i < sfp->hdr.count; i++) {
558 if (!holefit)
559 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
560 offset = xfs_dir2_sf_get_offset(sfep) +
561 xfs_dir2_data_entsize(sfep->namelen);
562 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
563 }
564
565
566
567
568 used = offset +
569 (sfp->hdr.count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
570 (uint)sizeof(xfs_dir2_block_tail_t);
571
572
573
574
575
576 if (used + (holefit ? 0 : size) > mp->m_dirblksize)
577 return 0;
578
579
580
581#if XFS_BIG_INUMS
582 if (objchange) {
583 return 2;
584 }
585#else
586 ASSERT(objchange == 0);
587#endif
588
589
590
591 if (used + size > mp->m_dirblksize)
592 return 2;
593
594
595
596 *sfepp = sfep;
597 *offsetp = offset;
598 return 1;
599}
600
601#ifdef DEBUG
602
603
604
605static void
606xfs_dir2_sf_check(
607 xfs_da_args_t *args)
608{
609 xfs_inode_t *dp;
610 int i;
611 int i8count;
612 xfs_ino_t ino;
613 int offset;
614 xfs_dir2_sf_entry_t *sfep;
615 xfs_dir2_sf_t *sfp;
616
617 dp = args->dp;
618
619 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
620 offset = XFS_DIR2_DATA_FIRST_OFFSET;
621 ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
622 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
623
624 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
625 i < sfp->hdr.count;
626 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
627 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
628 ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
629 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
630 offset =
631 xfs_dir2_sf_get_offset(sfep) +
632 xfs_dir2_data_entsize(sfep->namelen);
633 }
634 ASSERT(i8count == sfp->hdr.i8count);
635 ASSERT(XFS_BIG_INUMS || i8count == 0);
636 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
637 ASSERT(offset +
638 (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
639 (uint)sizeof(xfs_dir2_block_tail_t) <=
640 dp->i_mount->m_dirblksize);
641}
642#endif
643
644
645
646
647int
648xfs_dir2_sf_create(
649 xfs_da_args_t *args,
650 xfs_ino_t pino)
651{
652 xfs_inode_t *dp;
653 int i8count;
654 xfs_dir2_sf_t *sfp;
655 int size;
656
657 xfs_dir2_trace_args_i("sf_create", args, pino);
658 dp = args->dp;
659
660 ASSERT(dp != NULL);
661 ASSERT(dp->i_d.di_size == 0);
662
663
664
665
666 if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) {
667 dp->i_df.if_flags &= ~XFS_IFEXTENTS;
668 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
669 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
670 dp->i_df.if_flags |= XFS_IFINLINE;
671 }
672 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
673 ASSERT(dp->i_df.if_bytes == 0);
674 i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
675 size = xfs_dir2_sf_hdr_size(i8count);
676
677
678
679 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
680
681
682
683 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
684 sfp->hdr.i8count = i8count;
685
686
687
688 xfs_dir2_sf_put_inumber(sfp, &pino, &sfp->hdr.parent);
689 sfp->hdr.count = 0;
690 dp->i_d.di_size = size;
691 xfs_dir2_sf_check(args);
692 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
693 return 0;
694}
695
696int
697xfs_dir2_sf_getdents(
698 xfs_inode_t *dp,
699 void *dirent,
700 xfs_off_t *offset,
701 filldir_t filldir)
702{
703 int i;
704 xfs_mount_t *mp;
705 xfs_dir2_dataptr_t off;
706 xfs_dir2_sf_entry_t *sfep;
707 xfs_dir2_sf_t *sfp;
708 xfs_dir2_dataptr_t dot_offset;
709 xfs_dir2_dataptr_t dotdot_offset;
710 xfs_ino_t ino;
711
712 mp = dp->i_mount;
713
714 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
715
716
717
718 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
719 ASSERT(XFS_FORCED_SHUTDOWN(mp));
720 return XFS_ERROR(EIO);
721 }
722
723 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
724 ASSERT(dp->i_df.if_u1.if_data != NULL);
725
726 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
727
728 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
729
730
731
732
733 if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk)
734 return 0;
735
736
737
738
739
740
741
742 dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
743 XFS_DIR2_DATA_DOT_OFFSET);
744 dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
745 XFS_DIR2_DATA_DOTDOT_OFFSET);
746
747
748
749
750 if (*offset <= dot_offset) {
751 ino = dp->i_ino;
752#if XFS_BIG_INUMS
753 ino += mp->m_inoadd;
754#endif
755 if (filldir(dirent, ".", 1, dot_offset, ino, DT_DIR)) {
756 *offset = dot_offset;
757 return 0;
758 }
759 }
760
761
762
763
764 if (*offset <= dotdot_offset) {
765 ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
766#if XFS_BIG_INUMS
767 ino += mp->m_inoadd;
768#endif
769 if (filldir(dirent, "..", 2, dotdot_offset, ino, DT_DIR)) {
770 *offset = dotdot_offset;
771 return 0;
772 }
773 }
774
775
776
777
778 sfep = xfs_dir2_sf_firstentry(sfp);
779 for (i = 0; i < sfp->hdr.count; i++) {
780 off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
781 xfs_dir2_sf_get_offset(sfep));
782
783 if (*offset > off) {
784 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
785 continue;
786 }
787
788 ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
789#if XFS_BIG_INUMS
790 ino += mp->m_inoadd;
791#endif
792
793 if (filldir(dirent, sfep->name, sfep->namelen,
794 off, ino, DT_UNKNOWN)) {
795 *offset = off;
796 return 0;
797 }
798 sfep = xfs_dir2_sf_nextentry(sfp, sfep);
799 }
800
801 *offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
802 return 0;
803}
804
805
806
807
808
809int
810xfs_dir2_sf_lookup(
811 xfs_da_args_t *args)
812{
813 xfs_inode_t *dp;
814 int i;
815 int error;
816 xfs_dir2_sf_entry_t *sfep;
817 xfs_dir2_sf_t *sfp;
818 enum xfs_dacmp cmp;
819 xfs_dir2_sf_entry_t *ci_sfep;
820
821 xfs_dir2_trace_args("sf_lookup", args);
822 xfs_dir2_sf_check(args);
823 dp = args->dp;
824
825 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
826
827
828
829 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
830 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
831 return XFS_ERROR(EIO);
832 }
833 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
834 ASSERT(dp->i_df.if_u1.if_data != NULL);
835 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
836 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
837
838
839
840 if (args->namelen == 1 && args->name[0] == '.') {
841 args->inumber = dp->i_ino;
842 args->cmpresult = XFS_CMP_EXACT;
843 return XFS_ERROR(EEXIST);
844 }
845
846
847
848 if (args->namelen == 2 &&
849 args->name[0] == '.' && args->name[1] == '.') {
850 args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
851 args->cmpresult = XFS_CMP_EXACT;
852 return XFS_ERROR(EEXIST);
853 }
854
855
856
857 ci_sfep = NULL;
858 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
859 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
860
861
862
863
864
865 cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name,
866 sfep->namelen);
867 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
868 args->cmpresult = cmp;
869 args->inumber = xfs_dir2_sf_get_inumber(sfp,
870 xfs_dir2_sf_inumberp(sfep));
871 if (cmp == XFS_CMP_EXACT)
872 return XFS_ERROR(EEXIST);
873 ci_sfep = sfep;
874 }
875 }
876 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
877
878
879
880
881 if (!ci_sfep)
882 return XFS_ERROR(ENOENT);
883
884 error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
885 return XFS_ERROR(error);
886}
887
888
889
890
891int
892xfs_dir2_sf_removename(
893 xfs_da_args_t *args)
894{
895 int byteoff;
896 xfs_inode_t *dp;
897 int entsize;
898 int i;
899 int newsize;
900 int oldsize;
901 xfs_dir2_sf_entry_t *sfep;
902 xfs_dir2_sf_t *sfp;
903
904 xfs_dir2_trace_args("sf_removename", args);
905 dp = args->dp;
906
907 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
908 oldsize = (int)dp->i_d.di_size;
909
910
911
912 if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) {
913 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
914 return XFS_ERROR(EIO);
915 }
916 ASSERT(dp->i_df.if_bytes == oldsize);
917 ASSERT(dp->i_df.if_u1.if_data != NULL);
918 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
919 ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
920
921
922
923
924 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count;
925 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
926 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
927 XFS_CMP_EXACT) {
928 ASSERT(xfs_dir2_sf_get_inumber(sfp,
929 xfs_dir2_sf_inumberp(sfep)) ==
930 args->inumber);
931 break;
932 }
933 }
934
935
936
937 if (i == sfp->hdr.count)
938 return XFS_ERROR(ENOENT);
939
940
941
942 byteoff = (int)((char *)sfep - (char *)sfp);
943 entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
944 newsize = oldsize - entsize;
945
946
947
948 if (byteoff + entsize < oldsize)
949 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
950 oldsize - (byteoff + entsize));
951
952
953
954 sfp->hdr.count--;
955 dp->i_d.di_size = newsize;
956
957
958
959 xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
960 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
961#if XFS_BIG_INUMS
962
963
964
965 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
966 if (sfp->hdr.i8count == 1)
967 xfs_dir2_sf_toino4(args);
968 else
969 sfp->hdr.i8count--;
970 }
971#endif
972 xfs_dir2_sf_check(args);
973 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
974 return 0;
975}
976
977
978
979
980int
981xfs_dir2_sf_replace(
982 xfs_da_args_t *args)
983{
984 xfs_inode_t *dp;
985 int i;
986#if XFS_BIG_INUMS || defined(DEBUG)
987 xfs_ino_t ino=0;
988#endif
989#if XFS_BIG_INUMS
990 int i8elevated;
991#endif
992 xfs_dir2_sf_entry_t *sfep;
993 xfs_dir2_sf_t *sfp;
994
995 xfs_dir2_trace_args("sf_replace", args);
996 dp = args->dp;
997
998 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
999
1000
1001
1002 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
1003 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
1004 return XFS_ERROR(EIO);
1005 }
1006 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
1007 ASSERT(dp->i_df.if_u1.if_data != NULL);
1008 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1009 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
1010#if XFS_BIG_INUMS
1011
1012
1013
1014 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) {
1015 int error;
1016 int newsize;
1017
1018 newsize =
1019 dp->i_df.if_bytes +
1020 (sfp->hdr.count + 1) *
1021 ((uint)sizeof(xfs_dir2_ino8_t) -
1022 (uint)sizeof(xfs_dir2_ino4_t));
1023
1024
1025
1026 if (newsize > XFS_IFORK_DSIZE(dp)) {
1027 error = xfs_dir2_sf_to_block(args);
1028 if (error) {
1029 return error;
1030 }
1031 return xfs_dir2_block_replace(args);
1032 }
1033
1034
1035
1036 xfs_dir2_sf_toino8(args);
1037 i8elevated = 1;
1038 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1039 } else
1040 i8elevated = 0;
1041#endif
1042 ASSERT(args->namelen != 1 || args->name[0] != '.');
1043
1044
1045
1046 if (args->namelen == 2 &&
1047 args->name[0] == '.' && args->name[1] == '.') {
1048#if XFS_BIG_INUMS || defined(DEBUG)
1049 ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
1050 ASSERT(args->inumber != ino);
1051#endif
1052 xfs_dir2_sf_put_inumber(sfp, &args->inumber, &sfp->hdr.parent);
1053 }
1054
1055
1056
1057 else {
1058 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
1059 i < sfp->hdr.count;
1060 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
1061 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
1062 XFS_CMP_EXACT) {
1063#if XFS_BIG_INUMS || defined(DEBUG)
1064 ino = xfs_dir2_sf_get_inumber(sfp,
1065 xfs_dir2_sf_inumberp(sfep));
1066 ASSERT(args->inumber != ino);
1067#endif
1068 xfs_dir2_sf_put_inumber(sfp, &args->inumber,
1069 xfs_dir2_sf_inumberp(sfep));
1070 break;
1071 }
1072 }
1073
1074
1075
1076 if (i == sfp->hdr.count) {
1077 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
1078#if XFS_BIG_INUMS
1079 if (i8elevated)
1080 xfs_dir2_sf_toino4(args);
1081#endif
1082 return XFS_ERROR(ENOENT);
1083 }
1084 }
1085#if XFS_BIG_INUMS
1086
1087
1088
1089 if (ino > XFS_DIR2_MAX_SHORT_INUM &&
1090 args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
1091
1092
1093
1094 if (sfp->hdr.i8count == 1)
1095 xfs_dir2_sf_toino4(args);
1096 else
1097 sfp->hdr.i8count--;
1098 }
1099
1100
1101
1102 if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
1103 args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1104
1105
1106
1107
1108 ASSERT(sfp->hdr.i8count != 0);
1109 if (!i8elevated)
1110 sfp->hdr.i8count++;
1111 }
1112#endif
1113 xfs_dir2_sf_check(args);
1114 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
1115 return 0;
1116}
1117
1118#if XFS_BIG_INUMS
1119
1120
1121
1122
1123static void
1124xfs_dir2_sf_toino4(
1125 xfs_da_args_t *args)
1126{
1127 char *buf;
1128 xfs_inode_t *dp;
1129 int i;
1130 xfs_ino_t ino;
1131 int newsize;
1132 xfs_dir2_sf_entry_t *oldsfep;
1133 xfs_dir2_sf_t *oldsfp;
1134 int oldsize;
1135 xfs_dir2_sf_entry_t *sfep;
1136 xfs_dir2_sf_t *sfp;
1137
1138 xfs_dir2_trace_args("sf_toino4", args);
1139 dp = args->dp;
1140
1141
1142
1143
1144
1145
1146 oldsize = dp->i_df.if_bytes;
1147 buf = kmem_alloc(oldsize, KM_SLEEP);
1148 oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1149 ASSERT(oldsfp->hdr.i8count == 1);
1150 memcpy(buf, oldsfp, oldsize);
1151
1152
1153
1154 newsize =
1155 oldsize -
1156 (oldsfp->hdr.count + 1) *
1157 ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t));
1158 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1159 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1160
1161
1162
1163 oldsfp = (xfs_dir2_sf_t *)buf;
1164 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1165
1166
1167
1168 sfp->hdr.count = oldsfp->hdr.count;
1169 sfp->hdr.i8count = 0;
1170 ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
1171 xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
1172
1173
1174
1175 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1176 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1177 i < sfp->hdr.count;
1178 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
1179 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
1180 sfep->namelen = oldsfep->namelen;
1181 sfep->offset = oldsfep->offset;
1182 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1183 ino = xfs_dir2_sf_get_inumber(oldsfp,
1184 xfs_dir2_sf_inumberp(oldsfep));
1185 xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
1186 }
1187
1188
1189
1190 kmem_free(buf);
1191 dp->i_d.di_size = newsize;
1192 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1193}
1194
1195
1196
1197
1198
1199
1200static void
1201xfs_dir2_sf_toino8(
1202 xfs_da_args_t *args)
1203{
1204 char *buf;
1205 xfs_inode_t *dp;
1206 int i;
1207 xfs_ino_t ino;
1208 int newsize;
1209 xfs_dir2_sf_entry_t *oldsfep;
1210 xfs_dir2_sf_t *oldsfp;
1211 int oldsize;
1212 xfs_dir2_sf_entry_t *sfep;
1213 xfs_dir2_sf_t *sfp;
1214
1215 xfs_dir2_trace_args("sf_toino8", args);
1216 dp = args->dp;
1217
1218
1219
1220
1221
1222
1223 oldsize = dp->i_df.if_bytes;
1224 buf = kmem_alloc(oldsize, KM_SLEEP);
1225 oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1226 ASSERT(oldsfp->hdr.i8count == 0);
1227 memcpy(buf, oldsfp, oldsize);
1228
1229
1230
1231 newsize =
1232 oldsize +
1233 (oldsfp->hdr.count + 1) *
1234 ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t));
1235 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1236 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1237
1238
1239
1240 oldsfp = (xfs_dir2_sf_t *)buf;
1241 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
1242
1243
1244
1245 sfp->hdr.count = oldsfp->hdr.count;
1246 sfp->hdr.i8count = 1;
1247 ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
1248 xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
1249
1250
1251
1252 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1253 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1254 i < sfp->hdr.count;
1255 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
1256 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
1257 sfep->namelen = oldsfep->namelen;
1258 sfep->offset = oldsfep->offset;
1259 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1260 ino = xfs_dir2_sf_get_inumber(oldsfp,
1261 xfs_dir2_sf_inumberp(oldsfep));
1262 xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
1263 }
1264
1265
1266
1267 kmem_free(buf);
1268 dp->i_d.di_size = newsize;
1269 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1270}
1271#endif