]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/dir2.c
xfs_scrub_all: escape service names consistently
[thirdparty/xfsprogs-dev.git] / db / dir2.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "bit.h"
9 #include "type.h"
10 #include "faddr.h"
11 #include "fprint.h"
12 #include "field.h"
13 #include "dir2.h"
14 #include "init.h"
15 #include "output.h"
16
17 static int dir2_block_hdr_count(void *obj, int startoff);
18 static int dir2_block_leaf_count(void *obj, int startoff);
19 static int dir2_block_leaf_offset(void *obj, int startoff, int idx);
20 static int dir2_block_tail_count(void *obj, int startoff);
21 static int dir2_block_tail_offset(void *obj, int startoff, int idx);
22 static int dir2_block_u_count(void *obj, int startoff);
23 static int dir2_block_u_offset(void *obj, int startoff, int idx);
24 static int dir2_data_union_freetag_count(void *obj, int startoff);
25 static int dir2_data_union_inumber_count(void *obj, int startoff);
26 static int dir2_data_union_length_count(void *obj, int startoff);
27 static int dir2_data_union_name_count(void *obj, int startoff);
28 static int dir2_data_union_namelen_count(void *obj, int startoff);
29 static int dir2_data_union_tag_count(void *obj, int startoff);
30 static int dir2_data_union_tag_offset(void *obj, int startoff, int idx);
31 static int dir2_data_hdr_count(void *obj, int startoff);
32 static int dir2_data_u_count(void *obj, int startoff);
33 static int dir2_data_u_offset(void *obj, int startoff, int idx);
34 static int dir2_free_bests_count(void *obj, int startoff);
35 static int dir2_free_hdr_count(void *obj, int startoff);
36 static int dir2_leaf_bests_count(void *obj, int startoff);
37 static int dir2_leaf_bests_offset(void *obj, int startoff, int idx);
38 static int dir2_leaf_ents_count(void *obj, int startoff);
39 static int dir2_leaf_hdr_count(void *obj, int startoff);
40 static int dir2_leaf_tail_count(void *obj, int startoff);
41 static int dir2_leaf_tail_offset(void *obj, int startoff, int idx);
42 static int dir2_node_btree_count(void *obj, int startoff);
43 static int dir2_node_hdr_count(void *obj, int startoff);
44
45 const field_t dir2_hfld[] = {
46 { "", FLDT_DIR2, OI(0), C1, 0, TYP_NONE },
47 { NULL }
48 };
49
50 #define BOFF(f) bitize(offsetof(struct xfs_dir2_data_hdr, f))
51 #define DOFF(f) bitize(offsetof(struct xfs_dir2_data_hdr, f))
52 #define FOFF(f) bitize(offsetof(struct xfs_dir2_free, f))
53 #define LOFF(f) bitize(offsetof(struct xfs_dir2_leaf, f))
54 #define NOFF(f) bitize(offsetof(struct xfs_da_intnode, f))
55 const field_t dir2_flds[] = {
56 { "bhdr", FLDT_DIR2_DATA_HDR, OI(BOFF(magic)), dir2_block_hdr_count,
57 FLD_COUNT, TYP_NONE },
58 { "bu", FLDT_DIR2_DATA_UNION, dir2_block_u_offset, dir2_block_u_count,
59 FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
60 { "bleaf", FLDT_DIR2_LEAF_ENTRY, dir2_block_leaf_offset,
61 dir2_block_leaf_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
62 { "btail", FLDT_DIR2_BLOCK_TAIL, dir2_block_tail_offset,
63 dir2_block_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
64 { "dhdr", FLDT_DIR2_DATA_HDR, OI(DOFF(magic)), dir2_data_hdr_count,
65 FLD_COUNT, TYP_NONE },
66 { "du", FLDT_DIR2_DATA_UNION, dir2_data_u_offset, dir2_data_u_count,
67 FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
68 { "lhdr", FLDT_DIR2_LEAF_HDR, OI(LOFF(hdr)), dir2_leaf_hdr_count,
69 FLD_COUNT, TYP_NONE },
70 { "lbests", FLDT_DIR2_DATA_OFF, dir2_leaf_bests_offset,
71 dir2_leaf_bests_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
72 { "lents", FLDT_DIR2_LEAF_ENTRY, OI(LOFF(__ents)), dir2_leaf_ents_count,
73 FLD_ARRAY|FLD_COUNT, TYP_NONE },
74 { "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset,
75 dir2_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
76 { "nhdr", FLDT_DA_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count,
77 FLD_COUNT, TYP_NONE },
78 { "nbtree", FLDT_DA_NODE_ENTRY, OI(NOFF(__btree)), dir2_node_btree_count,
79 FLD_ARRAY|FLD_COUNT, TYP_NONE },
80 { "fhdr", FLDT_DIR2_FREE_HDR, OI(FOFF(hdr)), dir2_free_hdr_count,
81 FLD_COUNT, TYP_NONE },
82 { "fbests", FLDT_DIR2_DATA_OFFNZ, OI(FOFF(bests)),
83 dir2_free_bests_count, FLD_ARRAY|FLD_COUNT, TYP_NONE },
84 { NULL }
85 };
86
87 #define BTOFF(f) bitize(offsetof(xfs_dir2_block_tail_t, f))
88 const field_t dir2_block_tail_flds[] = {
89 { "count", FLDT_UINT32D, OI(BTOFF(count)), C1, 0, TYP_NONE },
90 { "stale", FLDT_UINT32D, OI(BTOFF(stale)), C1, 0, TYP_NONE },
91 { NULL }
92 };
93
94 #define DFOFF(f) bitize(offsetof(xfs_dir2_data_free_t, f))
95 const field_t dir2_data_free_flds[] = {
96 { "offset", FLDT_DIR2_DATA_OFF, OI(DFOFF(offset)), C1, 0, TYP_NONE },
97 { "length", FLDT_DIR2_DATA_OFF, OI(DFOFF(length)), C1, 0, TYP_NONE },
98 { NULL }
99 };
100
101 #define DHOFF(f) bitize(offsetof(xfs_dir2_data_hdr_t, f))
102 const field_t dir2_data_hdr_flds[] = {
103 { "magic", FLDT_UINT32X, OI(DHOFF(magic)), C1, 0, TYP_NONE },
104 { "bestfree", FLDT_DIR2_DATA_FREE, OI(DHOFF(bestfree)),
105 CI(XFS_DIR2_DATA_FD_COUNT), FLD_ARRAY, TYP_NONE },
106 { NULL }
107 };
108
109 #define DEOFF(f) bitize(offsetof(xfs_dir2_data_entry_t, f))
110 #define DUOFF(f) bitize(offsetof(xfs_dir2_data_unused_t, f))
111 const field_t dir2_data_union_flds[] = {
112 { "freetag", FLDT_UINT16X, OI(DUOFF(freetag)),
113 dir2_data_union_freetag_count, FLD_COUNT, TYP_NONE },
114 { "inumber", FLDT_INO, OI(DEOFF(inumber)),
115 dir2_data_union_inumber_count, FLD_COUNT, TYP_INODE },
116 { "length", FLDT_DIR2_DATA_OFF, OI(DUOFF(length)),
117 dir2_data_union_length_count, FLD_COUNT, TYP_NONE },
118 { "namelen", FLDT_UINT8D, OI(DEOFF(namelen)),
119 dir2_data_union_namelen_count, FLD_COUNT, TYP_NONE },
120 { "name", FLDT_CHARNS, OI(DEOFF(name)), dir2_data_union_name_count,
121 FLD_COUNT, TYP_NONE },
122 { "tag", FLDT_DIR2_DATA_OFF, dir2_data_union_tag_offset,
123 dir2_data_union_tag_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
124 { NULL }
125 };
126
127 #define LEOFF(f) bitize(offsetof(xfs_dir2_leaf_entry_t, f))
128 const field_t dir2_leaf_entry_flds[] = {
129 { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE },
130 { "address", FLDT_UINT32X, OI(LEOFF(address)), C1, 0, TYP_NONE },
131 { NULL }
132 };
133
134 #define LHOFF(f) bitize(offsetof(xfs_dir2_leaf_hdr_t, f))
135 const field_t dir2_leaf_hdr_flds[] = {
136 { "info", FLDT_DA_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE },
137 { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE },
138 { "stale", FLDT_UINT16D, OI(LHOFF(stale)), C1, 0, TYP_NONE },
139 { NULL }
140 };
141
142 #define LTOFF(f) bitize(offsetof(xfs_dir2_leaf_tail_t, f))
143 const field_t dir2_leaf_tail_flds[] = {
144 { "bestcount", FLDT_UINT32D, OI(LTOFF(bestcount)), C1, 0, TYP_NONE },
145 { NULL }
146 };
147
148 #define FHOFF(f) bitize(offsetof(xfs_dir2_free_hdr_t, f))
149 const field_t dir2_free_hdr_flds[] = {
150 { "magic", FLDT_UINT32X, OI(FHOFF(magic)), C1, 0, TYP_NONE },
151 { "firstdb", FLDT_INT32D, OI(FHOFF(firstdb)), C1, 0, TYP_NONE },
152 { "nvalid", FLDT_INT32D, OI(FHOFF(nvalid)), C1, 0, TYP_NONE },
153 { "nused", FLDT_INT32D, OI(FHOFF(nused)), C1, 0, TYP_NONE },
154 { NULL }
155 };
156
157 #define DBOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f))
158 const field_t da_blkinfo_flds[] = {
159 { "forw", FLDT_DIRBLOCK, OI(DBOFF(forw)), C1, 0, TYP_INODATA },
160 { "back", FLDT_DIRBLOCK, OI(DBOFF(back)), C1, 0, TYP_INODATA },
161 { "magic", FLDT_UINT16X, OI(DBOFF(magic)), C1, 0, TYP_NONE },
162 { "pad", FLDT_UINT16X, OI(DBOFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
163 { NULL }
164 };
165
166 #define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f))
167 const field_t da_node_entry_flds[] = {
168 { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE },
169 { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA },
170 { NULL }
171 };
172
173 #define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f))
174 const field_t da_node_hdr_flds[] = {
175 { "info", FLDT_DA_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE },
176 { "count", FLDT_UINT16D, OI(HOFF(__count)), C1, 0, TYP_NONE },
177 { "level", FLDT_UINT16D, OI(HOFF(__level)), C1, 0, TYP_NONE },
178 { NULL }
179 };
180
181 /*
182 * Worker functions shared between either dir2/dir3 or block/data formats
183 */
184 static int
185 __dir2_block_tail_offset(
186 struct xfs_dir2_data_hdr *block,
187 int startoff,
188 int idx)
189 {
190 struct xfs_dir2_block_tail *btp;
191
192 ASSERT(startoff == 0);
193 ASSERT(idx == 0);
194 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
195 return bitize((int)((char *)btp - (char *)block));
196 }
197
198 static int
199 __dir2_data_entries_count(
200 char *ptr,
201 char *endptr)
202 {
203 int i;
204
205 for (i = 0; ptr < endptr; i++) {
206 struct xfs_dir2_data_entry *dep;
207 struct xfs_dir2_data_unused *dup;
208
209 dup = (xfs_dir2_data_unused_t *)ptr;
210 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG)
211 ptr += be16_to_cpu(dup->length);
212 else {
213 dep = (xfs_dir2_data_entry_t *)ptr;
214 ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
215 }
216 }
217 return i;
218 }
219
220 static char *
221 __dir2_data_entry_offset(
222 char *ptr,
223 char *endptr,
224 int idx)
225 {
226 int i;
227
228 for (i = 0; i < idx; i++) {
229 struct xfs_dir2_data_entry *dep;
230 struct xfs_dir2_data_unused *dup;
231
232 ASSERT(ptr < endptr);
233 dup = (xfs_dir2_data_unused_t *)ptr;
234 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG)
235 ptr += be16_to_cpu(dup->length);
236 else {
237 dep = (xfs_dir2_data_entry_t *)ptr;
238 ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
239 }
240 }
241 return ptr;
242 }
243
244 /*
245 * Block format functions
246 */
247 static int
248 dir2_block_hdr_count(
249 void *obj,
250 int startoff)
251 {
252 struct xfs_dir2_data_hdr *block = obj;
253
254 ASSERT(startoff == 0);
255 return be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC;
256 }
257
258 static int
259 dir3_block_hdr_count(
260 void *obj,
261 int startoff)
262 {
263 struct xfs_dir2_data_hdr *block = obj;
264
265 ASSERT(startoff == 0);
266 return be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC;
267 }
268
269 static int
270 dir2_block_leaf_count(
271 void *obj,
272 int startoff)
273 {
274 struct xfs_dir2_data_hdr *block = obj;
275 struct xfs_dir2_block_tail *btp;
276
277 ASSERT(startoff == 0);
278 if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC &&
279 be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC)
280 return 0;
281 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
282 return be32_to_cpu(btp->count);
283 }
284
285 static int
286 dir2_block_leaf_offset(
287 void *obj,
288 int startoff,
289 int idx)
290 {
291 struct xfs_dir2_data_hdr *block = obj;
292 struct xfs_dir2_block_tail *btp;
293 struct xfs_dir2_leaf_entry *lep;
294
295 ASSERT(startoff == 0);
296 ASSERT(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC ||
297 be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC);
298 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
299 lep = xfs_dir2_block_leaf_p(btp) + idx;
300 return bitize((int)((char *)lep - (char *)block));
301 }
302
303 static int
304 dir2_block_tail_count(
305 void *obj,
306 int startoff)
307 {
308 struct xfs_dir2_data_hdr *block = obj;
309
310 ASSERT(startoff == 0);
311 return be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC;
312 }
313
314 static int
315 dir3_block_tail_count(
316 void *obj,
317 int startoff)
318 {
319 struct xfs_dir2_data_hdr *block = obj;
320
321 ASSERT(startoff == 0);
322 return be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC;
323 }
324
325 static int
326 dir2_block_tail_offset(
327 void *obj,
328 int startoff,
329 int idx)
330 {
331 struct xfs_dir2_data_hdr *block = obj;
332
333 ASSERT(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC ||
334 be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC);
335 return __dir2_block_tail_offset(block, startoff, idx);
336 }
337
338 static int
339 dir2_block_u_count(
340 void *obj,
341 int startoff)
342 {
343 struct xfs_dir2_data_hdr *block = obj;
344 struct xfs_dir2_block_tail *btp;
345
346 ASSERT(startoff == 0);
347 if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC &&
348 be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC)
349 return 0;
350
351 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
352 return __dir2_data_entries_count(
353 (char *)obj + mp->m_dir_geo->data_entry_offset,
354 (char *)xfs_dir2_block_leaf_p(btp));
355 }
356
357 static int
358 dir2_block_u_offset(
359 void *obj,
360 int startoff,
361 int idx)
362 {
363 struct xfs_dir2_data_hdr *block = obj;
364 struct xfs_dir2_block_tail *btp;
365 char *ptr;
366
367 ASSERT(startoff == 0);
368 ASSERT(be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC ||
369 be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC);
370 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
371 ptr = __dir2_data_entry_offset(
372 (char *)obj + mp->m_dir_geo->data_entry_offset,
373 (char *)xfs_dir2_block_leaf_p(btp), idx);
374 return bitize((int)(ptr - (char *)block));
375 }
376
377 /*
378 * Data block format functions
379 */
380 static int
381 dir2_data_union_freetag_count(
382 void *obj,
383 int startoff)
384 {
385 xfs_dir2_data_unused_t *dup;
386 char *end;
387
388 ASSERT(bitoffs(startoff) == 0);
389 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
390 end = (char *)&dup->freetag + sizeof(dup->freetag);
391 return end <= (char *)obj + mp->m_dir_geo->blksize &&
392 be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG;
393 }
394
395 static int
396 dir2_data_union_inumber_count(
397 void *obj,
398 int startoff)
399 {
400 xfs_dir2_data_entry_t *dep;
401 xfs_dir2_data_unused_t *dup;
402 char *end;
403
404 ASSERT(bitoffs(startoff) == 0);
405 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
406 dep = (xfs_dir2_data_entry_t *)dup;
407 end = (char *)&dep->inumber + sizeof(dep->inumber);
408 return end <= (char *)obj + mp->m_dir_geo->blksize &&
409 be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG;
410 }
411
412 static int
413 dir2_data_union_length_count(
414 void *obj,
415 int startoff)
416 {
417 xfs_dir2_data_unused_t *dup;
418 char *end;
419
420 ASSERT(bitoffs(startoff) == 0);
421 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
422 end = (char *)&dup->length + sizeof(dup->length);
423 return end <= (char *)obj + mp->m_dir_geo->blksize &&
424 be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG;
425 }
426
427 static int
428 dir2_data_union_name_count(
429 void *obj,
430 int startoff)
431 {
432 xfs_dir2_data_entry_t *dep;
433 xfs_dir2_data_unused_t *dup;
434 char *end;
435
436 ASSERT(bitoffs(startoff) == 0);
437 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
438 dep = (xfs_dir2_data_entry_t *)dup;
439 end = (char *)&dep->namelen + sizeof(dep->namelen);
440 if (end >= (char *)obj + mp->m_dir_geo->blksize ||
441 be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG)
442 return 0;
443 end = (char *)&dep->name[0] + dep->namelen;
444 return end <= (char *)obj + mp->m_dir_geo->blksize ? dep->namelen : 0;
445 }
446
447 static int
448 dir2_data_union_namelen_count(
449 void *obj,
450 int startoff)
451 {
452 xfs_dir2_data_entry_t *dep;
453 xfs_dir2_data_unused_t *dup;
454 char *end;
455
456 ASSERT(bitoffs(startoff) == 0);
457 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
458 dep = (xfs_dir2_data_entry_t *)dup;
459 end = (char *)&dep->namelen + sizeof(dep->namelen);
460 return end <= (char *)obj + mp->m_dir_geo->blksize &&
461 be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG;
462 }
463
464 static int
465 dir2_data_union_tag_count(
466 void *obj,
467 int startoff)
468 {
469 xfs_dir2_data_entry_t *dep;
470 xfs_dir2_data_unused_t *dup;
471 char *end;
472 __be16 *tagp;
473
474 ASSERT(bitoffs(startoff) == 0);
475 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
476 dep = (xfs_dir2_data_entry_t *)dup;
477 end = (char *)&dup->freetag + sizeof(dup->freetag);
478 if (end > (char *)obj + mp->m_dir_geo->blksize)
479 return 0;
480 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
481 end = (char *)&dup->length + sizeof(dup->length);
482 if (end > (char *)obj + mp->m_dir_geo->blksize)
483 return 0;
484 tagp = xfs_dir2_data_unused_tag_p(dup);
485 } else {
486 end = (char *)&dep->namelen + sizeof(dep->namelen);
487 if (end > (char *)obj + mp->m_dir_geo->blksize)
488 return 0;
489 tagp = libxfs_dir2_data_entry_tag_p(mp, dep);
490 }
491 end = (char *)tagp + sizeof(*tagp);
492 return end <= (char *)obj + mp->m_dir_geo->blksize;
493 }
494
495 static int
496 dir2_data_union_tag_offset(
497 void *obj,
498 int startoff,
499 int idx)
500 {
501 xfs_dir2_data_entry_t *dep;
502 xfs_dir2_data_unused_t *dup;
503
504 ASSERT(bitoffs(startoff) == 0);
505 ASSERT(idx == 0);
506 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
507 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG)
508 return bitize((int)((char *)xfs_dir2_data_unused_tag_p(dup) -
509 (char *)dup));
510 dep = (xfs_dir2_data_entry_t *)dup;
511 return bitize((int)((char *)libxfs_dir2_data_entry_tag_p(mp, dep) -
512 (char *)dep));
513 }
514
515 static int
516 dir2_data_hdr_count(
517 void *obj,
518 int startoff)
519 {
520 struct xfs_dir2_data_hdr *data = obj;
521
522 ASSERT(startoff == 0);
523 return be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC;
524 }
525
526 static int
527 dir3_data_hdr_count(
528 void *obj,
529 int startoff)
530 {
531 struct xfs_dir2_data_hdr *data = obj;
532
533 ASSERT(startoff == 0);
534 return be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC;
535 }
536
537 static int
538 dir2_data_u_count(
539 void *obj,
540 int startoff)
541 {
542 struct xfs_dir2_data_hdr *data = obj;
543
544 ASSERT(startoff == 0);
545 if (be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC &&
546 be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC)
547 return 0;
548
549 return __dir2_data_entries_count(
550 (char *)data + mp->m_dir_geo->data_entry_offset,
551 (char *)data + mp->m_dir_geo->blksize);
552 }
553
554 static int
555 dir2_data_u_offset(
556 void *obj,
557 int startoff,
558 int idx)
559 {
560 struct xfs_dir2_data_hdr *data = obj;
561 char *ptr;
562
563 ASSERT(startoff == 0);
564 ASSERT(be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC ||
565 be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC);
566 ptr = __dir2_data_entry_offset(
567 (char *)data + mp->m_dir_geo->data_entry_offset,
568 (char *)data + mp->m_dir_geo->blksize, idx);
569 return bitize((int)(ptr - (char *)data));
570 }
571
572 int
573 dir2_data_union_size(
574 void *obj,
575 int startoff,
576 int idx)
577 {
578 xfs_dir2_data_entry_t *dep;
579 xfs_dir2_data_unused_t *dup;
580
581 ASSERT(bitoffs(startoff) == 0);
582 ASSERT(idx == 0);
583 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
584 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG)
585 return bitize(be16_to_cpu(dup->length));
586 else {
587 dep = (xfs_dir2_data_entry_t *)dup;
588 return bitize(libxfs_dir2_data_entsize(mp, dep->namelen));
589 }
590 }
591
592 static int
593 dir3_data_union_ftype_offset(
594 void *obj,
595 int startoff,
596 int idx)
597 {
598 xfs_dir2_data_entry_t *dep;
599 xfs_dir2_data_unused_t *dup;
600
601 ASSERT(bitoffs(startoff) == 0);
602 ASSERT(idx == 0);
603 dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff));
604 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG)
605 return bitize((int)((char *)xfs_dir2_data_unused_tag_p(dup) -
606 (char *)dup));
607 dep = (xfs_dir2_data_entry_t *)dup;
608 return bitize((int)((char *)&dep->name[dep->namelen] - (char *)dep));
609 }
610
611 /*
612 * Free block functions
613 */
614 static int
615 dir2_free_bests_count(
616 void *obj,
617 int startoff)
618 {
619 struct xfs_dir2_free *free = obj;
620
621 ASSERT(startoff == 0);
622 if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC)
623 return 0;
624 return be32_to_cpu(free->hdr.nvalid);
625 }
626
627 static int
628 dir3_free_bests_count(
629 void *obj,
630 int startoff)
631 {
632 struct xfs_dir3_free *free = obj;
633
634 ASSERT(startoff == 0);
635 if (be32_to_cpu(free->hdr.hdr.magic) != XFS_DIR3_FREE_MAGIC)
636 return 0;
637 return be32_to_cpu(free->hdr.nvalid);
638 }
639
640 static int
641 dir2_free_hdr_count(
642 void *obj,
643 int startoff)
644 {
645 struct xfs_dir2_free *free = obj;
646
647 ASSERT(startoff == 0);
648 return be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC;
649 }
650
651 static int
652 dir3_free_hdr_count(
653 void *obj,
654 int startoff)
655 {
656 struct xfs_dir3_free *free = obj;
657
658 ASSERT(startoff == 0);
659 return be32_to_cpu(free->hdr.hdr.magic) == XFS_DIR3_FREE_MAGIC;
660 }
661
662 /*
663 * Leaf block functions
664 */
665 static int
666 dir2_leaf_bests_count(
667 void *obj,
668 int startoff)
669 {
670 struct xfs_dir2_leaf *leaf = obj;
671 struct xfs_dir2_leaf_tail *ltp;
672
673 ASSERT(startoff == 0);
674 if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC &&
675 be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR3_LEAF1_MAGIC)
676 return 0;
677 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
678 return be32_to_cpu(ltp->bestcount);
679 }
680
681 static int
682 dir2_leaf_bests_offset(
683 void *obj,
684 int startoff,
685 int idx)
686 {
687 struct xfs_dir2_leaf *leaf = obj;
688 struct xfs_dir2_leaf_tail *ltp;
689 __be16 *lbp;
690
691 ASSERT(startoff == 0);
692 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC ||
693 be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR3_LEAF1_MAGIC);
694 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
695 lbp = xfs_dir2_leaf_bests_p(ltp) + idx;
696 return bitize((int)((char *)lbp - (char *)leaf));
697 }
698
699 static int
700 dir2_leaf_ents_count(
701 void *obj,
702 int startoff)
703 {
704 struct xfs_dir2_leaf *leaf = obj;
705
706 ASSERT(startoff == 0);
707 if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC &&
708 be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC)
709 return 0;
710 return be16_to_cpu(leaf->hdr.count);
711 }
712
713 static int
714 dir3_leaf_ents_count(
715 void *obj,
716 int startoff)
717 {
718 struct xfs_dir3_leaf *leaf = obj;
719
720 ASSERT(startoff == 0);
721 if (be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_DIR3_LEAF1_MAGIC &&
722 be16_to_cpu(leaf->hdr.info.hdr.magic) != XFS_DIR3_LEAFN_MAGIC)
723 return 0;
724 return be16_to_cpu(leaf->hdr.count);
725 }
726
727 static int
728 dir2_leaf_hdr_count(
729 void *obj,
730 int startoff)
731 {
732 struct xfs_dir2_leaf *leaf = obj;
733
734 ASSERT(startoff == 0);
735 return be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC ||
736 be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC;
737 }
738
739 static int
740 dir3_leaf_hdr_count(
741 void *obj,
742 int startoff)
743 {
744 struct xfs_dir3_leaf *leaf = obj;
745
746 ASSERT(startoff == 0);
747 return be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_DIR3_LEAF1_MAGIC ||
748 be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_DIR3_LEAFN_MAGIC;
749 }
750
751 static int
752 dir2_leaf_tail_count(
753 void *obj,
754 int startoff)
755 {
756 struct xfs_dir2_leaf *leaf = obj;
757
758 ASSERT(startoff == 0);
759 return be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC;
760 }
761
762 static int
763 dir3_leaf_tail_count(
764 void *obj,
765 int startoff)
766 {
767 struct xfs_dir3_leaf *leaf = obj;
768
769 ASSERT(startoff == 0);
770 return be16_to_cpu(leaf->hdr.info.hdr.magic) == XFS_DIR3_LEAF1_MAGIC;
771 }
772
773 static int
774 dir2_leaf_tail_offset(
775 void *obj,
776 int startoff,
777 int idx)
778 {
779 struct xfs_dir2_leaf *leaf = obj;
780 struct xfs_dir2_leaf_tail *ltp;
781
782 ASSERT(startoff == 0);
783 ASSERT(idx == 0);
784 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC ||
785 be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR3_LEAF1_MAGIC);
786 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
787 return bitize((int)((char *)ltp - (char *)leaf));
788 }
789
790 /*
791 * Node format functions
792 */
793 static int
794 dir2_node_btree_count(
795 void *obj,
796 int startoff)
797 {
798 xfs_da_intnode_t *node = obj;
799
800 ASSERT(startoff == 0);
801 if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC)
802 return 0;
803 return be16_to_cpu(node->hdr.__count);
804 }
805
806 static int
807 dir3_node_btree_count(
808 void *obj,
809 int startoff)
810 {
811 struct xfs_da3_intnode *node = obj;
812
813 ASSERT(startoff == 0);
814 if (be16_to_cpu(node->hdr.info.hdr.magic) != XFS_DA3_NODE_MAGIC)
815 return 0;
816 return be16_to_cpu(node->hdr.__count);
817 }
818
819 static int
820 dir2_node_hdr_count(
821 void *obj,
822 int startoff)
823 {
824 struct xfs_da_intnode *node = obj;
825
826 ASSERT(startoff == 0);
827 return be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC;
828 }
829
830 static int
831 dir3_node_hdr_count(
832 void *obj,
833 int startoff)
834 {
835 struct xfs_da3_intnode *node = obj;
836
837 ASSERT(startoff == 0);
838 return be16_to_cpu(node->hdr.info.hdr.magic) == XFS_DA3_NODE_MAGIC;
839 }
840
841 int
842 dir2_size(
843 void *obj,
844 int startoff,
845 int idx)
846 {
847 return bitize(mp->m_dir_geo->blksize);
848 }
849
850 /*
851 * CRC enabled structure definitions
852 */
853 const field_t dir3_hfld[] = {
854 { "", FLDT_DIR3, OI(0), C1, 0, TYP_NONE },
855 { NULL }
856 };
857
858 #define B3OFF(f) bitize(offsetof(struct xfs_dir3_data_hdr, f))
859 #define D3OFF(f) bitize(offsetof(struct xfs_dir3_data_hdr, f))
860 #define F3OFF(f) bitize(offsetof(struct xfs_dir3_free, f))
861 #define L3OFF(f) bitize(offsetof(struct xfs_dir3_leaf, f))
862 #define N3OFF(f) bitize(offsetof(struct xfs_da3_intnode, f))
863 const field_t dir3_flds[] = {
864 { "bhdr", FLDT_DIR3_DATA_HDR, OI(B3OFF(hdr)), dir3_block_hdr_count,
865 FLD_COUNT, TYP_NONE },
866 { "bu", FLDT_DIR3_DATA_UNION, dir2_block_u_offset, dir2_block_u_count,
867 FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
868 { "bleaf", FLDT_DIR2_LEAF_ENTRY, dir2_block_leaf_offset,
869 dir2_block_leaf_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
870 { "btail", FLDT_DIR2_BLOCK_TAIL, dir2_block_tail_offset,
871 dir3_block_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
872 { "dhdr", FLDT_DIR3_DATA_HDR, OI(D3OFF(hdr)), dir3_data_hdr_count,
873 FLD_COUNT, TYP_NONE },
874 { "du", FLDT_DIR3_DATA_UNION, dir2_data_u_offset, dir2_data_u_count,
875 FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
876 { "lhdr", FLDT_DIR3_LEAF_HDR, OI(L3OFF(hdr)), dir3_leaf_hdr_count,
877 FLD_COUNT, TYP_NONE },
878 { "lbests", FLDT_DIR2_DATA_OFF, dir2_leaf_bests_offset,
879 dir2_leaf_bests_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE },
880 { "lents", FLDT_DIR2_LEAF_ENTRY, OI(L3OFF(__ents)), dir3_leaf_ents_count,
881 FLD_ARRAY|FLD_COUNT, TYP_NONE },
882 { "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset,
883 dir3_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
884 { "nhdr", FLDT_DA3_NODE_HDR, OI(N3OFF(hdr)), dir3_node_hdr_count,
885 FLD_COUNT, TYP_NONE },
886 { "nbtree", FLDT_DA_NODE_ENTRY, OI(N3OFF(__btree)), dir3_node_btree_count,
887 FLD_ARRAY|FLD_COUNT, TYP_NONE },
888 { "fhdr", FLDT_DIR3_FREE_HDR, OI(F3OFF(hdr)), dir3_free_hdr_count,
889 FLD_COUNT, TYP_NONE },
890 { "fbests", FLDT_DIR2_DATA_OFFNZ, OI(F3OFF(bests)),
891 dir3_free_bests_count, FLD_ARRAY|FLD_COUNT, TYP_NONE },
892 { NULL }
893 };
894
895 #define D3EOFF(f) bitize(offsetof(xfs_dir2_data_entry_t, f))
896 #define D3UOFF(f) bitize(offsetof(xfs_dir2_data_unused_t, f))
897 const field_t dir3_data_union_flds[] = {
898 { "freetag", FLDT_UINT16X, OI(D3UOFF(freetag)),
899 dir2_data_union_freetag_count, FLD_COUNT, TYP_NONE },
900 { "inumber", FLDT_INO, OI(D3EOFF(inumber)),
901 dir2_data_union_inumber_count, FLD_COUNT, TYP_INODE },
902 { "length", FLDT_DIR2_DATA_OFF, OI(D3UOFF(length)),
903 dir2_data_union_length_count, FLD_COUNT, TYP_NONE },
904 { "namelen", FLDT_UINT8D, OI(D3EOFF(namelen)),
905 dir2_data_union_namelen_count, FLD_COUNT, TYP_NONE },
906 { "name", FLDT_CHARNS, OI(D3EOFF(name)), dir2_data_union_name_count,
907 FLD_COUNT, TYP_NONE },
908 { "filetype", FLDT_UINT8D, dir3_data_union_ftype_offset, C1,
909 FLD_OFFSET, TYP_NONE },
910 { "tag", FLDT_DIR2_DATA_OFF, dir2_data_union_tag_offset,
911 dir2_data_union_tag_count, FLD_OFFSET|FLD_COUNT, TYP_NONE },
912 { NULL }
913 };
914
915 #define DBH3OFF(f) bitize(offsetof(struct xfs_dir3_blk_hdr, f))
916 const field_t dir3_blkhdr_flds[] = {
917 { "magic", FLDT_UINT32X, OI(DBH3OFF(magic)), C1, 0, TYP_NONE },
918 { "crc", FLDT_CRC, OI(DBH3OFF(crc)), C1, 0, TYP_NONE },
919 { "bno", FLDT_DFSBNO, OI(DBH3OFF(blkno)), C1, 0, TYP_BMAPBTD },
920 { "lsn", FLDT_UINT64X, OI(DBH3OFF(lsn)), C1, 0, TYP_NONE },
921 { "uuid", FLDT_UUID, OI(DBH3OFF(uuid)), C1, 0, TYP_NONE },
922 { "owner", FLDT_INO, OI(DBH3OFF(owner)), C1, 0, TYP_NONE },
923 { NULL }
924 };
925
926 #define DH3OFF(f) bitize(offsetof(struct xfs_dir3_data_hdr, f))
927 const field_t dir3_data_hdr_flds[] = {
928 { "hdr", FLDT_DIR3_BLKHDR, OI(DH3OFF(hdr)), C1, 0, TYP_NONE },
929 { "bestfree", FLDT_DIR2_DATA_FREE, OI(DH3OFF(best_free)),
930 CI(XFS_DIR2_DATA_FD_COUNT), FLD_ARRAY, TYP_NONE },
931 { "pad", FLDT_UINT32X, OI(DH3OFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
932 { NULL }
933 };
934
935 #define LH3OFF(f) bitize(offsetof(struct xfs_dir3_leaf_hdr, f))
936 const field_t dir3_leaf_hdr_flds[] = {
937 { "info", FLDT_DA3_BLKINFO, OI(LH3OFF(info)), C1, 0, TYP_NONE },
938 { "count", FLDT_UINT16D, OI(LH3OFF(count)), C1, 0, TYP_NONE },
939 { "stale", FLDT_UINT16D, OI(LH3OFF(stale)), C1, 0, TYP_NONE },
940 { "pad", FLDT_UINT32X, OI(LH3OFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
941 { NULL }
942 };
943
944 #define FH3OFF(f) bitize(offsetof(struct xfs_dir3_free_hdr, f))
945 const field_t dir3_free_hdr_flds[] = {
946 { "hdr", FLDT_DIR3_BLKHDR, OI(FH3OFF(hdr)), C1, 0, TYP_NONE },
947 { "firstdb", FLDT_INT32D, OI(FH3OFF(firstdb)), C1, 0, TYP_NONE },
948 { "nvalid", FLDT_INT32D, OI(FH3OFF(nvalid)), C1, 0, TYP_NONE },
949 { "nused", FLDT_INT32D, OI(FH3OFF(nused)), C1, 0, TYP_NONE },
950 { "pad", FLDT_UINT32X, OI(FH3OFF(pad)), C1, FLD_SKIPALL, TYP_NONE },
951 { NULL }
952 };
953
954
955 #define DB3OFF(f) bitize(offsetof(struct xfs_da3_blkinfo, f))
956 const field_t da3_blkinfo_flds[] = {
957 { "hdr", FLDT_DA_BLKINFO, OI(DB3OFF(hdr)), C1, 0, TYP_NONE },
958 { "crc", FLDT_CRC, OI(DB3OFF(crc)), C1, 0, TYP_NONE },
959 { "bno", FLDT_DFSBNO, OI(DB3OFF(blkno)), C1, 0, TYP_BMAPBTD },
960 { "lsn", FLDT_UINT64X, OI(DB3OFF(lsn)), C1, 0, TYP_NONE },
961 { "uuid", FLDT_UUID, OI(DB3OFF(uuid)), C1, 0, TYP_NONE },
962 { "owner", FLDT_INO, OI(DB3OFF(owner)), C1, 0, TYP_NONE },
963 { NULL }
964 };
965
966 #define H3OFF(f) bitize(offsetof(struct xfs_da3_node_hdr, f))
967 const field_t da3_node_hdr_flds[] = {
968 { "info", FLDT_DA3_BLKINFO, OI(H3OFF(info)), C1, 0, TYP_NONE },
969 { "count", FLDT_UINT16D, OI(H3OFF(__count)), C1, 0, TYP_NONE },
970 { "level", FLDT_UINT16D, OI(H3OFF(__level)), C1, 0, TYP_NONE },
971 { "pad", FLDT_UINT32X, OI(H3OFF(__pad32)), C1, FLD_SKIPALL, TYP_NONE },
972 { NULL }
973 };
974
975 /* Set the CRC. */
976 void
977 xfs_dir3_set_crc(
978 struct xfs_buf *bp)
979 {
980 __be32 magic32;
981 __be16 magic16;
982
983 magic32 = *(__be32 *)bp->b_addr;
984 magic16 = ((struct xfs_da_blkinfo *)bp->b_addr)->magic;
985
986 switch (magic32) {
987 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
988 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
989 xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF);
990 return;
991 case cpu_to_be32(XFS_DIR3_FREE_MAGIC):
992 xfs_buf_update_cksum(bp, XFS_DIR3_FREE_CRC_OFF);
993 return;
994 default:
995 break;
996 }
997
998 switch (magic16) {
999 case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC):
1000 case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC):
1001 xfs_buf_update_cksum(bp, XFS_DIR3_LEAF_CRC_OFF);
1002 return;
1003 case cpu_to_be16(XFS_DA3_NODE_MAGIC):
1004 xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF);
1005 return;
1006 default:
1007 dbprintf(_("Unknown directory buffer type! %x %x\n"), magic32, magic16);
1008 break;
1009 }
1010 }
1011
1012 /*
1013 * Special read verifier for directory buffers. Detect the magic number
1014 * appropriately and set the correct verifier and call it.
1015 */
1016 static void
1017 xfs_dir3_db_read_verify(
1018 struct xfs_buf *bp)
1019 {
1020 __be32 magic32;
1021 __be16 magic16;
1022
1023 magic32 = *(__be32 *)bp->b_addr;
1024 magic16 = ((struct xfs_da_blkinfo *)bp->b_addr)->magic;
1025
1026 switch (magic32) {
1027 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
1028 bp->b_ops = &xfs_dir3_block_buf_ops;
1029 goto verify;
1030 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
1031 bp->b_ops = &xfs_dir3_data_buf_ops;
1032 goto verify;
1033 case cpu_to_be32(XFS_DIR3_FREE_MAGIC):
1034 bp->b_ops = &xfs_dir3_free_buf_ops;
1035 goto verify;
1036 default:
1037 break;
1038 }
1039
1040 switch (magic16) {
1041 case cpu_to_be16(XFS_DIR3_LEAF1_MAGIC):
1042 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
1043 break;
1044 case cpu_to_be16(XFS_DIR3_LEAFN_MAGIC):
1045 bp->b_ops = &xfs_dir3_leafn_buf_ops;
1046 break;
1047 case cpu_to_be16(XFS_DA3_NODE_MAGIC):
1048 bp->b_ops = &xfs_da3_node_buf_ops;
1049 break;
1050 default:
1051 dbprintf(_("Unknown directory buffer type!\n"));
1052 xfs_buf_ioerror(bp, -EFSCORRUPTED);
1053 return;
1054 }
1055 verify:
1056 bp->b_ops->verify_read(bp);
1057 }
1058
1059 static void
1060 xfs_dir3_db_write_verify(
1061 struct xfs_buf *bp)
1062 {
1063 dbprintf(_("Writing unknown directory buffer type!\n"));
1064 xfs_buf_ioerror(bp, -EFSCORRUPTED);
1065 }
1066
1067 const struct xfs_buf_ops xfs_dir3_db_buf_ops = {
1068 .name = "xfs_dir3",
1069 .verify_read = xfs_dir3_db_read_verify,
1070 .verify_write = xfs_dir3_db_write_verify,
1071 };