2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
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.
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.
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
19 #include <xfs/libxfs.h>
33 static int inode_a_bmbt_count(void *obj
, int startoff
);
34 static int inode_a_bmx_count(void *obj
, int startoff
);
35 static int inode_a_count(void *obj
, int startoff
);
36 static int inode_a_offset(void *obj
, int startoff
, int idx
);
37 static int inode_a_sfattr_count(void *obj
, int startoff
);
38 static int inode_core_nlinkv2_count(void *obj
, int startoff
);
39 static int inode_core_onlink_count(void *obj
, int startoff
);
40 static int inode_core_projid_count(void *obj
, int startoff
);
41 static int inode_core_nlinkv1_count(void *obj
, int startoff
);
42 static int inode_f(int argc
, char **argv
);
43 static int inode_u_bmbt_count(void *obj
, int startoff
);
44 static int inode_u_bmx_count(void *obj
, int startoff
);
45 static int inode_u_c_count(void *obj
, int startoff
);
46 static int inode_u_dev_count(void *obj
, int startoff
);
47 static int inode_u_muuid_count(void *obj
, int startoff
);
48 static int inode_u_sfdir_count(void *obj
, int startoff
);
49 static int inode_u_sfdir2_count(void *obj
, int startoff
);
50 static int inode_u_symlink_count(void *obj
, int startoff
);
52 static const cmdinfo_t inode_cmd
=
53 { "inode", NULL
, inode_f
, 0, 1, 1, "[inode#]",
54 "set current inode", NULL
};
56 const field_t inode_hfld
[] = {
57 { "", FLDT_INODE
, OI(0), C1
, 0, TYP_NONE
},
61 #define OFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
62 const field_t inode_flds
[] = {
63 { "core", FLDT_DINODE_CORE
, OI(OFF(core
)), C1
, 0, TYP_NONE
},
64 { "next_unlinked", FLDT_AGINO
, OI(OFF(next_unlinked
)), C1
, 0,
66 { "u", FLDT_DINODE_U
, OI(OFF(u
)), C1
, 0, TYP_NONE
},
67 { "a", FLDT_DINODE_A
, inode_a_offset
, inode_a_count
,
68 FLD_COUNT
|FLD_OFFSET
, TYP_NONE
},
72 #define COFF(f) bitize(offsetof(xfs_dinode_core_t, di_ ## f))
73 const field_t inode_core_flds
[] = {
74 { "magic", FLDT_UINT16X
, OI(COFF(magic
)), C1
, 0, TYP_NONE
},
75 { "mode", FLDT_UINT16O
, OI(COFF(mode
)), C1
, 0, TYP_NONE
},
76 { "version", FLDT_INT8D
, OI(COFF(version
)), C1
, 0, TYP_NONE
},
77 { "format", FLDT_DINODE_FMT
, OI(COFF(format
)), C1
, 0, TYP_NONE
},
78 { "nlinkv1", FLDT_UINT16D
, OI(COFF(onlink
)), inode_core_nlinkv1_count
,
79 FLD_COUNT
, TYP_NONE
},
80 { "nlinkv2", FLDT_UINT32D
, OI(COFF(nlink
)), inode_core_nlinkv2_count
,
81 FLD_COUNT
, TYP_NONE
},
82 { "onlink", FLDT_UINT16D
, OI(COFF(onlink
)), inode_core_onlink_count
,
83 FLD_COUNT
, TYP_NONE
},
84 { "projid", FLDT_UINT16D
, OI(COFF(projid
)), inode_core_projid_count
,
85 FLD_COUNT
, TYP_NONE
},
86 { "uid", FLDT_UINT32D
, OI(COFF(uid
)), C1
, 0, TYP_NONE
},
87 { "gid", FLDT_UINT32D
, OI(COFF(gid
)), C1
, 0, TYP_NONE
},
88 { "flushiter", FLDT_UINT16D
, OI(COFF(flushiter
)), C1
, 0, TYP_NONE
},
89 { "atime", FLDT_TIMESTAMP
, OI(COFF(atime
)), C1
, 0, TYP_NONE
},
90 { "mtime", FLDT_TIMESTAMP
, OI(COFF(mtime
)), C1
, 0, TYP_NONE
},
91 { "ctime", FLDT_TIMESTAMP
, OI(COFF(ctime
)), C1
, 0, TYP_NONE
},
92 { "size", FLDT_FSIZE
, OI(COFF(size
)), C1
, 0, TYP_NONE
},
93 { "nblocks", FLDT_DRFSBNO
, OI(COFF(nblocks
)), C1
, 0, TYP_NONE
},
94 { "extsize", FLDT_EXTLEN
, OI(COFF(extsize
)), C1
, 0, TYP_NONE
},
95 { "nextents", FLDT_EXTNUM
, OI(COFF(nextents
)), C1
, 0, TYP_NONE
},
96 { "naextents", FLDT_AEXTNUM
, OI(COFF(anextents
)), C1
, 0, TYP_NONE
},
97 { "forkoff", FLDT_UINT8D
, OI(COFF(forkoff
)), C1
, 0, TYP_NONE
},
98 { "aformat", FLDT_DINODE_FMT
, OI(COFF(aformat
)), C1
, 0, TYP_NONE
},
99 { "dmevmask", FLDT_UINT32X
, OI(COFF(dmevmask
)), C1
, 0, TYP_NONE
},
100 { "dmstate", FLDT_UINT16D
, OI(COFF(dmstate
)), C1
, 0, TYP_NONE
},
101 { "flags", FLDT_UINT16X
, OI(COFF(flags
)), C1
, FLD_SKIPALL
, TYP_NONE
},
102 { "newrtbm", FLDT_UINT1
,
103 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_NEWRTBM_BIT
- 1), C1
,
105 { "prealloc", FLDT_UINT1
,
106 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_PREALLOC_BIT
- 1), C1
,
108 { "realtime", FLDT_UINT1
,
109 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_REALTIME_BIT
- 1), C1
,
111 { "immutable", FLDT_UINT1
,
112 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_IMMUTABLE_BIT
-1), C1
,
114 { "append", FLDT_UINT1
,
115 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_APPEND_BIT
- 1), C1
,
117 { "sync", FLDT_UINT1
,
118 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_SYNC_BIT
- 1), C1
,
120 { "noatime", FLDT_UINT1
,
121 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_NOATIME_BIT
- 1), C1
,
123 { "nodump", FLDT_UINT1
,
124 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_NODUMP_BIT
- 1), C1
,
126 { "rtinherit", FLDT_UINT1
,
127 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_RTINHERIT_BIT
-1), C1
,
129 { "projinherit", FLDT_UINT1
,
130 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_PROJINHERIT_BIT
-1),C1
,
132 { "nosymlinks", FLDT_UINT1
,
133 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_NOSYMLINKS_BIT
-1), C1
,
135 { "extsz", FLDT_UINT1
,
136 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_EXTSIZE_BIT
-1),C1
,
138 { "extszinherit", FLDT_UINT1
,
139 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_EXTSZINHERIT_BIT
-1),C1
,
141 { "nodefrag", FLDT_UINT1
,
142 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_NODEFRAG_BIT
-1),C1
,
144 { "filestream", FLDT_UINT1
,
145 OI(COFF(flags
) + bitsz(__uint16_t
) - XFS_DIFLAG_FILESTREAM_BIT
-1),C1
,
147 { "gen", FLDT_UINT32D
, OI(COFF(gen
)), C1
, 0, TYP_NONE
},
151 #define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f))
152 const field_t timestamp_flds
[] = {
153 { "sec", FLDT_TIME
, OI(TOFF(sec
)), C1
, 0, TYP_NONE
},
154 { "nsec", FLDT_NSEC
, OI(TOFF(nsec
)), C1
, 0, TYP_NONE
},
158 const field_t inode_u_flds
[] = {
159 { "bmbt", FLDT_BMROOTD
, NULL
, inode_u_bmbt_count
, FLD_COUNT
, TYP_NONE
},
160 { "bmx", FLDT_BMAPBTDREC
, NULL
, inode_u_bmx_count
, FLD_ARRAY
|FLD_COUNT
,
162 { "c", FLDT_CHARNS
, NULL
, inode_u_c_count
, FLD_COUNT
, TYP_NONE
},
163 { "dev", FLDT_DEV
, NULL
, inode_u_dev_count
, FLD_COUNT
, TYP_NONE
},
164 { "muuid", FLDT_UUID
, NULL
, inode_u_muuid_count
, FLD_COUNT
, TYP_NONE
},
165 { "sfdir", FLDT_DIRSHORT
, NULL
, inode_u_sfdir_count
, FLD_COUNT
, TYP_NONE
},
166 { "sfdir2", FLDT_DIR2SF
, NULL
, inode_u_sfdir2_count
, FLD_COUNT
, TYP_NONE
},
167 { "symlink", FLDT_CHARNS
, NULL
, inode_u_symlink_count
, FLD_COUNT
,
172 const field_t inode_a_flds
[] = {
173 { "bmbt", FLDT_BMROOTA
, NULL
, inode_a_bmbt_count
, FLD_COUNT
, TYP_NONE
},
174 { "bmx", FLDT_BMAPBTAREC
, NULL
, inode_a_bmx_count
, FLD_ARRAY
|FLD_COUNT
,
176 { "sfattr", FLDT_ATTRSHORT
, NULL
, inode_a_sfattr_count
, FLD_COUNT
,
181 static const char *dinode_fmt_name
[] =
182 { "dev", "local", "extents", "btree", "uuid" };
183 static const int dinode_fmt_name_size
=
184 sizeof(dinode_fmt_name
) / sizeof(dinode_fmt_name
[0]);
202 for (i
= 0, bitpos
= bit
; i
< count
; i
++, bitpos
+= size
) {
203 f
= (xfs_dinode_fmt_t
)getbitval(obj
, bitpos
, size
, BVSIGNED
);
205 dbprintf("%d:", i
+ base
);
206 if (f
< 0 || f
>= dinode_fmt_name_size
)
207 dbprintf("%d", (int)f
);
209 dbprintf("%d (%s)", (int)f
, dinode_fmt_name
[(int)f
]);
223 ASSERT(bitoffs(startoff
) == 0);
224 ASSERT(obj
== iocur_top
->data
);
226 if (!XFS_DFORK_Q(dip
))
228 ASSERT((char *)XFS_DFORK_APTR(dip
) - (char *)dip
== byteize(startoff
));
229 return dip
->di_core
.di_aformat
== XFS_DINODE_FMT_BTREE
;
239 ASSERT(bitoffs(startoff
) == 0);
240 ASSERT(obj
== iocur_top
->data
);
242 if (!XFS_DFORK_Q(dip
))
244 ASSERT((char *)XFS_DFORK_APTR(dip
) - (char *)dip
== byteize(startoff
));
245 return dip
->di_core
.di_aformat
== XFS_DINODE_FMT_EXTENTS
?
246 be16_to_cpu(dip
->di_core
.di_anextents
) : 0;
256 ASSERT(startoff
== 0);
258 return XFS_DFORK_Q(dip
);
269 ASSERT(startoff
== 0);
272 ASSERT(XFS_DFORK_Q(dip
));
273 return bitize((int)((char *)XFS_DFORK_APTR(dip
) - (char *)dip
));
277 inode_a_sfattr_count(
283 ASSERT(bitoffs(startoff
) == 0);
284 ASSERT(obj
== iocur_top
->data
);
286 if (!XFS_DFORK_Q(dip
))
288 ASSERT((char *)XFS_DFORK_APTR(dip
) - (char *)dip
== byteize(startoff
));
289 return dip
->di_core
.di_aformat
== XFS_DINODE_FMT_LOCAL
;
298 xfs_attr_shortform_t
*asf
;
301 ASSERT(startoff
== 0);
304 switch (dip
->di_core
.di_aformat
) {
305 case XFS_DINODE_FMT_LOCAL
:
306 asf
= (xfs_attr_shortform_t
*)XFS_DFORK_APTR(dip
);
307 return bitize(be16_to_cpu(asf
->hdr
.totsize
));
308 case XFS_DINODE_FMT_EXTENTS
:
309 return (int)be16_to_cpu(dip
->di_core
.di_anextents
) *
310 bitsz(xfs_bmbt_rec_t
);
311 case XFS_DINODE_FMT_BTREE
:
312 return bitize((int)XFS_DFORK_ASIZE(dip
, mp
));
319 inode_core_nlinkv1_count(
323 xfs_dinode_core_t
*dic
;
325 ASSERT(startoff
== 0);
326 ASSERT(obj
== iocur_top
->data
);
328 return dic
->di_version
== XFS_DINODE_VERSION_1
;
332 inode_core_nlinkv2_count(
336 xfs_dinode_core_t
*dic
;
338 ASSERT(startoff
== 0);
339 ASSERT(obj
== iocur_top
->data
);
341 return dic
->di_version
== XFS_DINODE_VERSION_2
;
345 inode_core_onlink_count(
349 xfs_dinode_core_t
*dic
;
351 ASSERT(startoff
== 0);
352 ASSERT(obj
== iocur_top
->data
);
354 return dic
->di_version
== XFS_DINODE_VERSION_2
;
358 inode_core_projid_count(
362 xfs_dinode_core_t
*dic
;
364 ASSERT(startoff
== 0);
365 ASSERT(obj
== iocur_top
->data
);
367 return dic
->di_version
== XFS_DINODE_VERSION_2
;
379 ino
= strtoull(argv
[1], &p
, 0);
381 dbprintf(_("bad value for inode number %s\n"), argv
[1]);
385 } else if (iocur_top
->ino
== NULLFSINO
)
386 dbprintf(_("no current inode\n"));
388 dbprintf(_("current inode number is %lld\n"), iocur_top
->ino
);
395 add_command(&inode_cmd
);
399 inode_next_type(void)
401 switch (iocur_top
->mode
& S_IFMT
) {
403 return xfs_sb_version_hasdirv2(&mp
->m_sb
) ? TYP_DIR2
: TYP_DIR
;
407 if (iocur_top
->ino
== mp
->m_sb
.sb_rbmino
)
409 else if (iocur_top
->ino
== mp
->m_sb
.sb_rsumino
)
410 return TYP_RTSUMMARY
;
411 else if (iocur_top
->ino
== mp
->m_sb
.sb_uquotino
||
412 iocur_top
->ino
== mp
->m_sb
.sb_gquotino
)
427 return bitize(mp
->m_sb
.sb_inodesize
);
437 ASSERT(bitoffs(startoff
) == 0);
438 ASSERT(obj
== iocur_top
->data
);
440 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
441 return dip
->di_core
.di_format
== XFS_DINODE_FMT_BTREE
;
451 ASSERT(bitoffs(startoff
) == 0);
452 ASSERT(obj
== iocur_top
->data
);
454 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
455 return dip
->di_core
.di_format
== XFS_DINODE_FMT_EXTENTS
?
456 be32_to_cpu(dip
->di_core
.di_nextents
) : 0;
466 ASSERT(bitoffs(startoff
) == 0);
467 ASSERT(obj
== iocur_top
->data
);
469 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
470 return dip
->di_core
.di_format
== XFS_DINODE_FMT_LOCAL
&&
471 (be16_to_cpu(dip
->di_core
.di_mode
) & S_IFMT
) == S_IFREG
?
472 (int)be64_to_cpu(dip
->di_core
.di_size
) : 0;
482 ASSERT(bitoffs(startoff
) == 0);
483 ASSERT(obj
== iocur_top
->data
);
485 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
486 return dip
->di_core
.di_format
== XFS_DINODE_FMT_DEV
;
496 ASSERT(bitoffs(startoff
) == 0);
497 ASSERT(obj
== iocur_top
->data
);
499 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
500 return dip
->di_core
.di_format
== XFS_DINODE_FMT_UUID
;
510 ASSERT(bitoffs(startoff
) == 0);
511 ASSERT(obj
== iocur_top
->data
);
513 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
514 return dip
->di_core
.di_format
== XFS_DINODE_FMT_LOCAL
&&
515 (be16_to_cpu(dip
->di_core
.di_mode
) & S_IFMT
) == S_IFDIR
516 && !xfs_sb_version_hasdirv2(&mp
->m_sb
);
520 inode_u_sfdir2_count(
526 ASSERT(bitoffs(startoff
) == 0);
527 ASSERT(obj
== iocur_top
->data
);
529 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
530 return dip
->di_core
.di_format
== XFS_DINODE_FMT_LOCAL
&&
531 (be16_to_cpu(dip
->di_core
.di_mode
) & S_IFMT
) == S_IFDIR
&&
532 xfs_sb_version_hasdirv2(&mp
->m_sb
);
543 ASSERT(startoff
== 0);
546 switch (dip
->di_core
.di_format
) {
547 case XFS_DINODE_FMT_DEV
:
548 return bitsz(xfs_dev_t
);
549 case XFS_DINODE_FMT_LOCAL
:
550 return bitize((int)be64_to_cpu(dip
->di_core
.di_size
));
551 case XFS_DINODE_FMT_EXTENTS
:
552 return (int)be32_to_cpu(dip
->di_core
.di_nextents
) *
553 bitsz(xfs_bmbt_rec_t
);
554 case XFS_DINODE_FMT_BTREE
:
555 return bitize((int)XFS_DFORK_DSIZE(dip
, mp
));
556 case XFS_DINODE_FMT_UUID
:
557 return bitsz(uuid_t
);
564 inode_u_symlink_count(
570 ASSERT(bitoffs(startoff
) == 0);
571 ASSERT(obj
== iocur_top
->data
);
573 ASSERT((char *)&dip
->di_u
- (char *)dip
== byteize(startoff
));
574 return dip
->di_core
.di_format
== XFS_DINODE_FMT_LOCAL
&&
575 (be16_to_cpu(dip
->di_core
.di_mode
) & S_IFMT
) == S_IFLNK
?
576 (int)be64_to_cpu(dip
->di_core
.di_size
) : 0;
589 agno
= XFS_INO_TO_AGNO(mp
, ino
);
590 agino
= XFS_INO_TO_AGINO(mp
, ino
);
591 agbno
= XFS_AGINO_TO_AGBNO(mp
, agino
);
592 offset
= XFS_AGINO_TO_OFFSET(mp
, agino
);
593 if (agno
>= mp
->m_sb
.sb_agcount
|| agbno
>= mp
->m_sb
.sb_agblocks
||
594 offset
>= mp
->m_sb
.sb_inopblock
||
595 XFS_AGINO_TO_INO(mp
, agno
, agino
) != ino
) {
596 dbprintf(_("bad inode number %lld\n"), ino
);
601 * First set_cur to the block with the inode
602 * then use off_cur to get the right part of the buffer.
604 ASSERT(typtab
[TYP_INODE
].typnm
== TYP_INODE
);
606 /* ingore ring update here, do it explicitly below */
607 set_cur(&typtab
[TYP_INODE
], XFS_AGB_TO_DADDR(mp
, agno
, agbno
),
608 blkbb
, DB_RING_IGN
, NULL
);
609 off_cur(offset
<< mp
->m_sb
.sb_inodelog
, mp
->m_sb
.sb_inodesize
);
610 dip
= iocur_top
->data
;
611 iocur_top
->ino
= ino
;
612 iocur_top
->mode
= be16_to_cpu(dip
->di_core
.di_mode
);
613 if ((iocur_top
->mode
& S_IFMT
) == S_IFDIR
)
614 iocur_top
->dirino
= ino
;
616 /* track updated info in ring */