]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/inode.c
xfs: zero length symlinks are not valid
[thirdparty/xfsprogs-dev.git] / db / inode.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "command.h"
9 #include "type.h"
10 #include "faddr.h"
11 #include "fprint.h"
12 #include "field.h"
13 #include "inode.h"
14 #include "io.h"
15 #include "print.h"
16 #include "block.h"
17 #include "bit.h"
18 #include "output.h"
19 #include "init.h"
20
21 static int inode_a_bmbt_count(void *obj, int startoff);
22 static int inode_a_bmx_count(void *obj, int startoff);
23 static int inode_a_count(void *obj, int startoff);
24 static int inode_a_offset(void *obj, int startoff, int idx);
25 static int inode_a_sfattr_count(void *obj, int startoff);
26 static int inode_core_nlinkv2_count(void *obj, int startoff);
27 static int inode_core_onlink_count(void *obj, int startoff);
28 static int inode_core_projid_count(void *obj, int startoff);
29 static int inode_core_nlinkv1_count(void *obj, int startoff);
30 static int inode_f(int argc, char **argv);
31 static int inode_u_offset(void *obj, int startoff, int idx);
32 static int inode_u_bmbt_count(void *obj, int startoff);
33 static int inode_u_bmx_count(void *obj, int startoff);
34 static int inode_u_c_count(void *obj, int startoff);
35 static int inode_u_dev_count(void *obj, int startoff);
36 static int inode_u_muuid_count(void *obj, int startoff);
37 static int inode_u_sfdir2_count(void *obj, int startoff);
38 static int inode_u_sfdir3_count(void *obj, int startoff);
39 static int inode_u_symlink_count(void *obj, int startoff);
40
41 static const cmdinfo_t inode_cmd =
42 { "inode", NULL, inode_f, 0, 1, 1, "[inode#]",
43 "set current inode", NULL };
44
45 const field_t inode_hfld[] = {
46 { "", FLDT_INODE, OI(0), C1, 0, TYP_NONE },
47 { NULL }
48 };
49 const field_t inode_crc_hfld[] = {
50 { "", FLDT_INODE_CRC, OI(0), C1, 0, TYP_NONE },
51 { NULL }
52 };
53
54 /* XXX: fix this up! */
55 #define OFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
56 const field_t inode_flds[] = {
57 { "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE },
58 { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0,
59 TYP_INODE },
60 { "u", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE },
61 { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count,
62 FLD_COUNT|FLD_OFFSET, TYP_NONE },
63 { NULL }
64 };
65 const field_t inode_crc_flds[] = {
66 { "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE },
67 { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0,
68 TYP_INODE },
69 { "v3", FLDT_DINODE_V3, OI(OFF(magic)), C1, 0, TYP_NONE },
70 { "u3", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE },
71 { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count,
72 FLD_COUNT|FLD_OFFSET, TYP_NONE },
73 { NULL }
74 };
75
76
77 #define COFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
78 const field_t inode_core_flds[] = {
79 { "magic", FLDT_UINT16X, OI(COFF(magic)), C1, 0, TYP_NONE },
80 { "mode", FLDT_UINT16O, OI(COFF(mode)), C1, 0, TYP_NONE },
81 { "version", FLDT_INT8D, OI(COFF(version)), C1, 0, TYP_NONE },
82 { "format", FLDT_DINODE_FMT, OI(COFF(format)), C1, 0, TYP_NONE },
83 { "nlinkv1", FLDT_UINT16D, OI(COFF(onlink)), inode_core_nlinkv1_count,
84 FLD_COUNT, TYP_NONE },
85 { "nlinkv2", FLDT_UINT32D, OI(COFF(nlink)), inode_core_nlinkv2_count,
86 FLD_COUNT, TYP_NONE },
87 { "onlink", FLDT_UINT16D, OI(COFF(onlink)), inode_core_onlink_count,
88 FLD_COUNT, TYP_NONE },
89 { "projid_lo", FLDT_UINT16D, OI(COFF(projid_lo)),
90 inode_core_projid_count, FLD_COUNT, TYP_NONE },
91 { "projid_hi", FLDT_UINT16D, OI(COFF(projid_hi)),
92 inode_core_projid_count, FLD_COUNT, TYP_NONE },
93 { "pad", FLDT_UINT8X, OI(OFF(pad)), CI(6), FLD_ARRAY|FLD_SKIPALL, TYP_NONE },
94 { "uid", FLDT_UINT32D, OI(COFF(uid)), C1, 0, TYP_NONE },
95 { "gid", FLDT_UINT32D, OI(COFF(gid)), C1, 0, TYP_NONE },
96 { "flushiter", FLDT_UINT16D, OI(COFF(flushiter)), C1, 0, TYP_NONE },
97 { "atime", FLDT_TIMESTAMP, OI(COFF(atime)), C1, 0, TYP_NONE },
98 { "mtime", FLDT_TIMESTAMP, OI(COFF(mtime)), C1, 0, TYP_NONE },
99 { "ctime", FLDT_TIMESTAMP, OI(COFF(ctime)), C1, 0, TYP_NONE },
100 { "size", FLDT_FSIZE, OI(COFF(size)), C1, 0, TYP_NONE },
101 { "nblocks", FLDT_DRFSBNO, OI(COFF(nblocks)), C1, 0, TYP_NONE },
102 { "extsize", FLDT_EXTLEN, OI(COFF(extsize)), C1, 0, TYP_NONE },
103 { "nextents", FLDT_EXTNUM, OI(COFF(nextents)), C1, 0, TYP_NONE },
104 { "naextents", FLDT_AEXTNUM, OI(COFF(anextents)), C1, 0, TYP_NONE },
105 { "forkoff", FLDT_UINT8D, OI(COFF(forkoff)), C1, 0, TYP_NONE },
106 { "aformat", FLDT_DINODE_FMT, OI(COFF(aformat)), C1, 0, TYP_NONE },
107 { "dmevmask", FLDT_UINT32X, OI(COFF(dmevmask)), C1, 0, TYP_NONE },
108 { "dmstate", FLDT_UINT16D, OI(COFF(dmstate)), C1, 0, TYP_NONE },
109 { "flags", FLDT_UINT16X, OI(COFF(flags)), C1, FLD_SKIPALL, TYP_NONE },
110 { "newrtbm", FLDT_UINT1,
111 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NEWRTBM_BIT - 1), C1,
112 0, TYP_NONE },
113 { "prealloc", FLDT_UINT1,
114 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PREALLOC_BIT - 1), C1,
115 0, TYP_NONE },
116 { "realtime", FLDT_UINT1,
117 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_REALTIME_BIT - 1), C1,
118 0, TYP_NONE },
119 { "immutable", FLDT_UINT1,
120 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_IMMUTABLE_BIT-1), C1,
121 0, TYP_NONE },
122 { "append", FLDT_UINT1,
123 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_APPEND_BIT - 1), C1,
124 0, TYP_NONE },
125 { "sync", FLDT_UINT1,
126 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_SYNC_BIT - 1), C1,
127 0, TYP_NONE },
128 { "noatime", FLDT_UINT1,
129 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOATIME_BIT - 1), C1,
130 0, TYP_NONE },
131 { "nodump", FLDT_UINT1,
132 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODUMP_BIT - 1), C1,
133 0, TYP_NONE },
134 { "rtinherit", FLDT_UINT1,
135 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_RTINHERIT_BIT-1), C1,
136 0, TYP_NONE },
137 { "projinherit", FLDT_UINT1,
138 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PROJINHERIT_BIT-1), C1,
139 0, TYP_NONE },
140 { "nosymlinks", FLDT_UINT1,
141 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOSYMLINKS_BIT-1), C1,
142 0, TYP_NONE },
143 { "extsz", FLDT_UINT1,
144 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSIZE_BIT-1), C1,
145 0, TYP_NONE },
146 { "extszinherit", FLDT_UINT1,
147 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSZINHERIT_BIT-1), C1,
148 0, TYP_NONE },
149 { "nodefrag", FLDT_UINT1,
150 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODEFRAG_BIT-1), C1,
151 0, TYP_NONE },
152 { "filestream", FLDT_UINT1,
153 OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_FILESTREAM_BIT-1), C1,
154 0, TYP_NONE },
155 { "gen", FLDT_UINT32D, OI(COFF(gen)), C1, 0, TYP_NONE },
156 { NULL }
157 };
158
159 const field_t inode_v3_flds[] = {
160 { "crc", FLDT_CRC, OI(COFF(crc)), C1, 0, TYP_NONE },
161 { "change_count", FLDT_UINT64D, OI(COFF(changecount)), C1, 0, TYP_NONE },
162 { "lsn", FLDT_UINT64X, OI(COFF(lsn)), C1, 0, TYP_NONE },
163 { "flags2", FLDT_UINT64X, OI(COFF(flags2)), C1, 0, TYP_NONE },
164 { "cowextsize", FLDT_EXTLEN, OI(COFF(cowextsize)), C1, 0, TYP_NONE },
165 { "pad2", FLDT_UINT8X, OI(OFF(pad2)), CI(12), FLD_ARRAY|FLD_SKIPALL, TYP_NONE },
166 { "crtime", FLDT_TIMESTAMP, OI(COFF(crtime)), C1, 0, TYP_NONE },
167 { "inumber", FLDT_INO, OI(COFF(ino)), C1, 0, TYP_NONE },
168 { "uuid", FLDT_UUID, OI(COFF(uuid)), C1, 0, TYP_NONE },
169 { "reflink", FLDT_UINT1,
170 OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_REFLINK_BIT-1), C1,
171 0, TYP_NONE },
172 { "cowextsz", FLDT_UINT1,
173 OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_COWEXTSIZE_BIT-1), C1,
174 0, TYP_NONE },
175 { NULL }
176 };
177
178
179 #define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f))
180 const field_t timestamp_flds[] = {
181 { "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
182 { "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
183 { NULL }
184 };
185
186 const field_t inode_u_flds[] = {
187 { "bmbt", FLDT_BMROOTD, NULL, inode_u_bmbt_count, FLD_COUNT, TYP_NONE },
188 { "bmx", FLDT_BMAPBTDREC, NULL, inode_u_bmx_count, FLD_ARRAY|FLD_COUNT,
189 TYP_NONE },
190 { "c", FLDT_CHARNS, NULL, inode_u_c_count, FLD_COUNT, TYP_NONE },
191 { "dev", FLDT_DEV, NULL, inode_u_dev_count, FLD_COUNT, TYP_NONE },
192 { "muuid", FLDT_UUID, NULL, inode_u_muuid_count, FLD_COUNT, TYP_NONE },
193 { "sfdir2", FLDT_DIR2SF, NULL, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE },
194 { "sfdir3", FLDT_DIR3SF, NULL, inode_u_sfdir3_count, FLD_COUNT, TYP_NONE },
195 { "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT,
196 TYP_NONE },
197 { NULL }
198 };
199
200 const field_t inode_a_flds[] = {
201 { "bmbt", FLDT_BMROOTA, NULL, inode_a_bmbt_count, FLD_COUNT, TYP_NONE },
202 { "bmx", FLDT_BMAPBTAREC, NULL, inode_a_bmx_count, FLD_ARRAY|FLD_COUNT,
203 TYP_NONE },
204 { "sfattr", FLDT_ATTRSHORT, NULL, inode_a_sfattr_count, FLD_COUNT,
205 TYP_NONE },
206 { NULL }
207 };
208
209 static const char *dinode_fmt_name[] =
210 { "dev", "local", "extents", "btree", "uuid" };
211 static const int dinode_fmt_name_size =
212 sizeof(dinode_fmt_name) / sizeof(dinode_fmt_name[0]);
213
214 /*ARGSUSED*/
215 int
216 fp_dinode_fmt(
217 void *obj,
218 int bit,
219 int count,
220 char *fmtstr,
221 int size,
222 int arg,
223 int base,
224 int array)
225 {
226 int bitpos;
227 xfs_dinode_fmt_t f;
228 int i;
229
230 for (i = 0, bitpos = bit; i < count; i++, bitpos += size) {
231 f = (xfs_dinode_fmt_t)getbitval(obj, bitpos, size, BVUNSIGNED);
232 if (array)
233 dbprintf("%d:", i + base);
234 if (f < 0 || f >= dinode_fmt_name_size)
235 dbprintf("%d", (int)f);
236 else
237 dbprintf("%d (%s)", (int)f, dinode_fmt_name[(int)f]);
238 if (i < count - 1)
239 dbprintf(" ");
240 }
241 return 1;
242 }
243
244 static int
245 inode_a_bmbt_count(
246 void *obj,
247 int startoff)
248 {
249 xfs_dinode_t *dip;
250
251 ASSERT(bitoffs(startoff) == 0);
252 ASSERT(obj == iocur_top->data);
253 dip = obj;
254 if (!XFS_DFORK_Q(dip))
255 return 0;
256 ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
257 return dip->di_aformat == XFS_DINODE_FMT_BTREE;
258 }
259
260 static int
261 inode_a_bmx_count(
262 void *obj,
263 int startoff)
264 {
265 xfs_dinode_t *dip;
266
267 ASSERT(bitoffs(startoff) == 0);
268 ASSERT(obj == iocur_top->data);
269 dip = obj;
270 if (!XFS_DFORK_Q(dip))
271 return 0;
272 ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
273 return dip->di_aformat == XFS_DINODE_FMT_EXTENTS ?
274 be16_to_cpu(dip->di_anextents) : 0;
275 }
276
277 static int
278 inode_a_count(
279 void *obj,
280 int startoff)
281 {
282 xfs_dinode_t *dip;
283
284 ASSERT(startoff == 0);
285 dip = obj;
286 return XFS_DFORK_Q(dip);
287 }
288
289 static int
290 inode_a_offset(
291 void *obj,
292 int startoff,
293 int idx)
294 {
295 xfs_dinode_t *dip;
296
297 ASSERT(startoff == 0);
298 ASSERT(idx == 0);
299 dip = obj;
300 ASSERT(XFS_DFORK_Q(dip));
301 return bitize((int)((char *)XFS_DFORK_APTR(dip) - (char *)dip));
302 }
303
304 static int
305 inode_a_sfattr_count(
306 void *obj,
307 int startoff)
308 {
309 xfs_dinode_t *dip;
310
311 ASSERT(bitoffs(startoff) == 0);
312 ASSERT(obj == iocur_top->data);
313 dip = obj;
314 if (!XFS_DFORK_Q(dip))
315 return 0;
316 ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
317 return dip->di_aformat == XFS_DINODE_FMT_LOCAL;
318 }
319
320 int
321 inode_a_size(
322 void *obj,
323 int startoff,
324 int idx)
325 {
326 xfs_attr_shortform_t *asf;
327 xfs_dinode_t *dip;
328
329 ASSERT(startoff == 0);
330 ASSERT(idx == 0);
331 dip = obj;
332 switch (dip->di_aformat) {
333 case XFS_DINODE_FMT_LOCAL:
334 asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
335 return bitize(be16_to_cpu(asf->hdr.totsize));
336 case XFS_DINODE_FMT_EXTENTS:
337 return (int)be16_to_cpu(dip->di_anextents) *
338 bitsz(xfs_bmbt_rec_t);
339 case XFS_DINODE_FMT_BTREE:
340 return bitize((int)XFS_DFORK_ASIZE(dip, mp));
341 default:
342 return 0;
343 }
344 }
345
346 static int
347 inode_core_nlinkv1_count(
348 void *obj,
349 int startoff)
350 {
351 xfs_dinode_t *dic;
352
353 ASSERT(startoff == 0);
354 ASSERT(obj == iocur_top->data);
355 dic = obj;
356 return dic->di_version == 1;
357 }
358
359 static int
360 inode_core_nlinkv2_count(
361 void *obj,
362 int startoff)
363 {
364 xfs_dinode_t *dic;
365
366 ASSERT(startoff == 0);
367 ASSERT(obj == iocur_top->data);
368 dic = obj;
369 return dic->di_version >= 2;
370 }
371
372 static int
373 inode_core_onlink_count(
374 void *obj,
375 int startoff)
376 {
377 xfs_dinode_t *dic;
378
379 ASSERT(startoff == 0);
380 ASSERT(obj == iocur_top->data);
381 dic = obj;
382 return dic->di_version >= 2;
383 }
384
385 static int
386 inode_core_projid_count(
387 void *obj,
388 int startoff)
389 {
390 xfs_dinode_t *dic;
391
392 ASSERT(startoff == 0);
393 ASSERT(obj == iocur_top->data);
394 dic = obj;
395 return dic->di_version >= 2;
396 }
397
398 static int
399 inode_f(
400 int argc,
401 char **argv)
402 {
403 xfs_ino_t ino;
404 char *p;
405
406 if (argc > 1) {
407 ino = strtoull(argv[1], &p, 0);
408 if (*p != '\0') {
409 dbprintf(_("bad value for inode number %s\n"), argv[1]);
410 return 0;
411 }
412 set_cur_inode(ino);
413 } else if (iocur_top->ino == NULLFSINO)
414 dbprintf(_("no current inode\n"));
415 else
416 dbprintf(_("current inode number is %lld\n"), iocur_top->ino);
417 return 0;
418 }
419
420 void
421 inode_init(void)
422 {
423 add_command(&inode_cmd);
424 }
425
426 typnm_t
427 inode_next_type(void)
428 {
429 switch (iocur_top->mode & S_IFMT) {
430 case S_IFDIR:
431 return TYP_DIR2;
432 case S_IFLNK:
433 return TYP_SYMLINK;
434 case S_IFREG:
435 if (iocur_top->ino == mp->m_sb.sb_rbmino)
436 return TYP_RTBITMAP;
437 else if (iocur_top->ino == mp->m_sb.sb_rsumino)
438 return TYP_RTSUMMARY;
439 else if (iocur_top->ino == mp->m_sb.sb_uquotino ||
440 iocur_top->ino == mp->m_sb.sb_gquotino ||
441 iocur_top->ino == mp->m_sb.sb_pquotino)
442 return TYP_DQBLK;
443 else
444 return TYP_DATA;
445 default:
446 return TYP_NONE;
447 }
448 }
449
450 int
451 inode_size(
452 void *obj,
453 int startoff,
454 int idx)
455 {
456 return bitize(mp->m_sb.sb_inodesize);
457 }
458
459 static int
460 inode_u_offset(
461 void *obj,
462 int startoff,
463 int idx)
464 {
465 xfs_dinode_t *dip;
466
467 ASSERT(startoff == 0);
468 ASSERT(idx == 0);
469 dip = obj;
470 return bitize((int)((char *)XFS_DFORK_DPTR(dip) - (char *)dip));
471 }
472
473 static int
474 inode_u_bmbt_count(
475 void *obj,
476 int startoff)
477 {
478 xfs_dinode_t *dip;
479
480 ASSERT(bitoffs(startoff) == 0);
481 ASSERT(obj == iocur_top->data);
482 dip = obj;
483 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
484 return dip->di_format == XFS_DINODE_FMT_BTREE;
485 }
486
487 static int
488 inode_u_bmx_count(
489 void *obj,
490 int startoff)
491 {
492 xfs_dinode_t *dip;
493
494 ASSERT(bitoffs(startoff) == 0);
495 ASSERT(obj == iocur_top->data);
496 dip = obj;
497 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
498 return dip->di_format == XFS_DINODE_FMT_EXTENTS ?
499 be32_to_cpu(dip->di_nextents) : 0;
500 }
501
502 static int
503 inode_u_c_count(
504 void *obj,
505 int startoff)
506 {
507 xfs_dinode_t *dip;
508
509 ASSERT(bitoffs(startoff) == 0);
510 ASSERT(obj == iocur_top->data);
511 dip = obj;
512 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
513 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
514 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG ?
515 (int)be64_to_cpu(dip->di_size) : 0;
516 }
517
518 static int
519 inode_u_dev_count(
520 void *obj,
521 int startoff)
522 {
523 xfs_dinode_t *dip;
524
525 ASSERT(bitoffs(startoff) == 0);
526 ASSERT(obj == iocur_top->data);
527 dip = obj;
528 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
529 return dip->di_format == XFS_DINODE_FMT_DEV;
530 }
531
532 static int
533 inode_u_muuid_count(
534 void *obj,
535 int startoff)
536 {
537 xfs_dinode_t *dip;
538
539 ASSERT(bitoffs(startoff) == 0);
540 ASSERT(obj == iocur_top->data);
541 dip = obj;
542 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
543 return dip->di_format == XFS_DINODE_FMT_UUID;
544 }
545
546 static int
547 inode_u_sfdir2_count(
548 void *obj,
549 int startoff)
550 {
551 xfs_dinode_t *dip;
552
553 ASSERT(bitoffs(startoff) == 0);
554 ASSERT(obj == iocur_top->data);
555 dip = obj;
556 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
557 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
558 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR &&
559 !xfs_sb_version_hasftype(&mp->m_sb);
560 }
561
562 static int
563 inode_u_sfdir3_count(
564 void *obj,
565 int startoff)
566 {
567 xfs_dinode_t *dip;
568
569 ASSERT(bitoffs(startoff) == 0);
570 ASSERT(obj == iocur_top->data);
571 dip = obj;
572 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
573 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
574 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR &&
575 xfs_sb_version_hasftype(&mp->m_sb);
576 }
577
578 int
579 inode_u_size(
580 void *obj,
581 int startoff,
582 int idx)
583 {
584 xfs_dinode_t *dip;
585
586 ASSERT(startoff == 0);
587 ASSERT(idx == 0);
588 dip = obj;
589 switch (dip->di_format) {
590 case XFS_DINODE_FMT_DEV:
591 return bitsz(xfs_dev_t);
592 case XFS_DINODE_FMT_LOCAL:
593 return bitize((int)be64_to_cpu(dip->di_size));
594 case XFS_DINODE_FMT_EXTENTS:
595 return (int)be32_to_cpu(dip->di_nextents) *
596 bitsz(xfs_bmbt_rec_t);
597 case XFS_DINODE_FMT_BTREE:
598 return bitize((int)XFS_DFORK_DSIZE(dip, mp));
599 case XFS_DINODE_FMT_UUID:
600 return bitsz(uuid_t);
601 default:
602 return 0;
603 }
604 }
605
606 static int
607 inode_u_symlink_count(
608 void *obj,
609 int startoff)
610 {
611 xfs_dinode_t *dip;
612
613 ASSERT(bitoffs(startoff) == 0);
614 ASSERT(obj == iocur_top->data);
615 dip = obj;
616 ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
617 return dip->di_format == XFS_DINODE_FMT_LOCAL &&
618 (be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFLNK ?
619 (int)be64_to_cpu(dip->di_size) : 0;
620 }
621
622 /*
623 * We are now using libxfs for our IO backend, so we should always try to use
624 * inode cluster buffers rather than filesystem block sized buffers for reading
625 * inodes. This means that we always use the same buffers as libxfs operations
626 * does, and that avoids buffer cache issues caused by overlapping buffers. This
627 * can be seen clearly when trying to read the root inode. Much of this logic is
628 * similar to libxfs_imap().
629 */
630 void
631 set_cur_inode(
632 xfs_ino_t ino)
633 {
634 xfs_agblock_t agbno;
635 xfs_agino_t agino;
636 xfs_agnumber_t agno;
637 xfs_dinode_t *dip;
638 int offset;
639 int numblks = blkbb;
640 xfs_agblock_t cluster_agbno;
641
642
643 agno = XFS_INO_TO_AGNO(mp, ino);
644 agino = XFS_INO_TO_AGINO(mp, ino);
645 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
646 offset = XFS_AGINO_TO_OFFSET(mp, agino);
647 if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
648 offset >= mp->m_sb.sb_inopblock ||
649 XFS_AGINO_TO_INO(mp, agno, agino) != ino) {
650 dbprintf(_("bad inode number %lld\n"), ino);
651 return;
652 }
653 cur_agno = agno;
654
655 if (mp->m_inode_cluster_size > mp->m_sb.sb_blocksize &&
656 mp->m_inoalign_mask) {
657 xfs_agblock_t chunk_agbno;
658 xfs_agblock_t offset_agbno;
659 int blks_per_cluster;
660
661 blks_per_cluster = mp->m_inode_cluster_size >>
662 mp->m_sb.sb_blocklog;
663 offset_agbno = agbno & mp->m_inoalign_mask;
664 chunk_agbno = agbno - offset_agbno;
665 cluster_agbno = chunk_agbno +
666 ((offset_agbno / blks_per_cluster) * blks_per_cluster);
667 offset += ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock);
668 numblks = XFS_FSB_TO_BB(mp, blks_per_cluster);
669 } else
670 cluster_agbno = agbno;
671
672 /*
673 * First set_cur to the block with the inode
674 * then use off_cur to get the right part of the buffer.
675 */
676 ASSERT(typtab[TYP_INODE].typnm == TYP_INODE);
677
678 /* ingore ring update here, do it explicitly below */
679 set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, cluster_agbno),
680 numblks, DB_RING_IGN, NULL);
681 off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
682 if (!iocur_top->data)
683 return;
684 dip = iocur_top->data;
685 iocur_top->ino_buf = 1;
686 iocur_top->ino = ino;
687 iocur_top->mode = be16_to_cpu(dip->di_mode);
688 if ((iocur_top->mode & S_IFMT) == S_IFDIR)
689 iocur_top->dirino = ino;
690
691 if (xfs_sb_version_hascrc(&mp->m_sb)) {
692 iocur_top->ino_crc_ok = libxfs_verify_cksum((char *)dip,
693 mp->m_sb.sb_inodesize,
694 XFS_DINODE_CRC_OFF);
695 if (!iocur_top->ino_crc_ok)
696 dbprintf(
697 _("Metadata CRC error detected for ino %lld\n"),
698 ino);
699 }
700
701 /* track updated info in ring */
702 ring_add();
703 }
704
705 void
706 xfs_inode_set_crc(
707 struct xfs_buf *bp)
708 {
709 ASSERT(iocur_top->ino_buf);
710 ASSERT(iocur_top->bp == bp);
711
712 libxfs_dinode_calc_crc(mp, iocur_top->data);
713 iocur_top->ino_crc_ok = 1;
714 }