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