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