]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/bmap.c
libxfs: update to match 3.19-rc1 kernel code
[thirdparty/xfsprogs-dev.git] / db / bmap.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 <xfs/libxfs.h>
20 #include "command.h"
21 #include "type.h"
22 #include "fprint.h"
23 #include "faddr.h"
24 #include "field.h"
25 #include "bmap.h"
26 #include "io.h"
27 #include "inode.h"
28 #include "output.h"
29 #include "init.h"
30
31 static int bmap_f(int argc, char **argv);
32 static int bmap_one_extent(xfs_bmbt_rec_t *ep,
33 xfs_fileoff_t *offp, xfs_fileoff_t eoff,
34 int *idxp, bmap_ext_t *bep);
35 static xfs_fsblock_t select_child(xfs_fileoff_t off, xfs_bmbt_key_t *kp,
36 xfs_bmbt_ptr_t *pp, int nrecs);
37
38 static const cmdinfo_t bmap_cmd =
39 { "bmap", NULL, bmap_f, 0, 3, 0, N_("[-ad] [block [len]]"),
40 N_("show block map for current file"), NULL };
41
42 void
43 bmap(
44 xfs_fileoff_t offset,
45 xfs_filblks_t len,
46 int whichfork,
47 int *nexp,
48 bmap_ext_t *bep)
49 {
50 struct xfs_btree_block *block;
51 xfs_fsblock_t bno;
52 xfs_fileoff_t curoffset;
53 xfs_dinode_t *dip;
54 xfs_fileoff_t eoffset;
55 xfs_bmbt_rec_t *ep;
56 xfs_dinode_fmt_t fmt;
57 int fsize;
58 xfs_bmbt_key_t *kp;
59 int n;
60 int nex;
61 xfs_fsblock_t nextbno;
62 int nextents;
63 xfs_bmbt_ptr_t *pp;
64 xfs_bmdr_block_t *rblock;
65 typnm_t typ;
66 xfs_bmbt_rec_t *xp;
67
68 push_cur();
69 set_cur_inode(iocur_top->ino);
70 nex = *nexp;
71 *nexp = 0;
72 ASSERT(nex > 0);
73 dip = iocur_top->data;
74 n = 0;
75 eoffset = offset + len - 1;
76 curoffset = offset;
77 fmt = (xfs_dinode_fmt_t)XFS_DFORK_FORMAT(dip, whichfork);
78 typ = whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA;
79 ASSERT(typtab[typ].typnm == typ);
80 ASSERT(fmt == XFS_DINODE_FMT_LOCAL || fmt == XFS_DINODE_FMT_EXTENTS ||
81 fmt == XFS_DINODE_FMT_BTREE);
82 if (fmt == XFS_DINODE_FMT_EXTENTS) {
83 nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
84 xp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork);
85 for (ep = xp; ep < &xp[nextents] && n < nex; ep++) {
86 if (!bmap_one_extent(ep, &curoffset, eoffset, &n, bep))
87 break;
88 }
89 } else if (fmt == XFS_DINODE_FMT_BTREE) {
90 push_cur();
91 rblock = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
92 fsize = XFS_DFORK_SIZE(dip, mp, whichfork);
93 pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
94 kp = XFS_BMDR_KEY_ADDR(rblock, 1);
95 bno = select_child(curoffset, kp, pp,
96 be16_to_cpu(rblock->bb_numrecs));
97 for (;;) {
98 set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno),
99 blkbb, DB_RING_IGN, NULL);
100 block = (struct xfs_btree_block *)iocur_top->data;
101 if (be16_to_cpu(block->bb_level) == 0)
102 break;
103 pp = XFS_BMBT_PTR_ADDR(mp, block, 1,
104 xfs_bmbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0));
105 kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
106 bno = select_child(curoffset, kp, pp,
107 be16_to_cpu(block->bb_numrecs));
108 }
109 for (;;) {
110 nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
111 nextents = be16_to_cpu(block->bb_numrecs);
112 xp = (xfs_bmbt_rec_t *)
113 XFS_BMBT_REC_ADDR(mp, block, 1);
114 for (ep = xp; ep < &xp[nextents] && n < nex; ep++) {
115 if (!bmap_one_extent(ep, &curoffset, eoffset,
116 &n, bep)) {
117 nextbno = NULLFSBLOCK;
118 break;
119 }
120 }
121 bno = nextbno;
122 if (bno == NULLFSBLOCK)
123 break;
124 set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno),
125 blkbb, DB_RING_IGN, NULL);
126 block = (struct xfs_btree_block *)iocur_top->data;
127 }
128 pop_cur();
129 }
130 pop_cur();
131 *nexp = n;
132 }
133
134 static int
135 bmap_f(
136 int argc,
137 char **argv)
138 {
139 int afork = 0;
140 bmap_ext_t be;
141 int c;
142 xfs_fileoff_t co, cosave;
143 int dfork = 0;
144 xfs_dinode_t *dip;
145 xfs_fileoff_t eo;
146 xfs_filblks_t len;
147 int nex;
148 char *p;
149 int whichfork;
150
151 if (iocur_top->ino == NULLFSINO) {
152 dbprintf(_("no current inode\n"));
153 return 0;
154 }
155 optind = 0;
156 if (argc) while ((c = getopt(argc, argv, "ad")) != EOF) {
157 switch (c) {
158 case 'a':
159 afork = 1;
160 break;
161 case 'd':
162 dfork = 1;
163 break;
164 default:
165 dbprintf(_("bad option for bmap command\n"));
166 return 0;
167 }
168 }
169 if (afork + dfork == 0) {
170 push_cur();
171 set_cur_inode(iocur_top->ino);
172 dip = iocur_top->data;
173 if (be32_to_cpu(dip->di_nextents))
174 dfork = 1;
175 if (be16_to_cpu(dip->di_anextents))
176 afork = 1;
177 pop_cur();
178 }
179 if (optind < argc) {
180 co = (xfs_fileoff_t)strtoull(argv[optind], &p, 0);
181 if (*p != '\0') {
182 dbprintf(_("bad block number for bmap %s\n"),
183 argv[optind]);
184 return 0;
185 }
186 optind++;
187 if (optind < argc) {
188 len = (xfs_filblks_t)strtoull(argv[optind], &p, 0);
189 if (*p != '\0') {
190 dbprintf(_("bad len for bmap %s\n"), argv[optind]);
191 return 0;
192 }
193 eo = co + len - 1;
194 } else
195 eo = co;
196 } else {
197 co = 0;
198 eo = -1;
199 }
200 cosave = co;
201 for (whichfork = XFS_DATA_FORK;
202 whichfork <= XFS_ATTR_FORK;
203 whichfork++) {
204 if (whichfork == XFS_DATA_FORK && !dfork)
205 continue;
206 if (whichfork == XFS_ATTR_FORK && !afork)
207 continue;
208 for (;;) {
209 nex = 1;
210 bmap(co, eo - co + 1, whichfork, &nex, &be);
211 if (nex == 0)
212 break;
213 dbprintf(_("%s offset %lld startblock %llu (%u/%u) count "
214 "%llu flag %u\n"),
215 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
216 be.startoff, be.startblock,
217 XFS_FSB_TO_AGNO(mp, be.startblock),
218 XFS_FSB_TO_AGBNO(mp, be.startblock),
219 be.blockcount, be.flag);
220 co = be.startoff + be.blockcount;
221 }
222 co = cosave;
223 }
224 return 0;
225 }
226
227 void
228 bmap_init(void)
229 {
230 add_command(&bmap_cmd);
231 }
232
233 static int
234 bmap_one_extent(
235 xfs_bmbt_rec_t *ep,
236 xfs_fileoff_t *offp,
237 xfs_fileoff_t eoff,
238 int *idxp,
239 bmap_ext_t *bep)
240 {
241 xfs_filblks_t c;
242 xfs_fileoff_t curoffset;
243 int f;
244 int idx;
245 xfs_fileoff_t o;
246 xfs_fsblock_t s;
247
248 convert_extent(ep, &o, &s, &c, &f);
249 curoffset = *offp;
250 idx = *idxp;
251 if (o + c <= curoffset)
252 return 1;
253 if (o > eoff)
254 return 0;
255 if (o < curoffset) {
256 c -= curoffset - o;
257 s += curoffset - o;
258 o = curoffset;
259 }
260 if (o + c - 1 > eoff)
261 c -= (o + c - 1) - eoff;
262 bep[idx].startoff = o;
263 bep[idx].startblock = s;
264 bep[idx].blockcount = c;
265 bep[idx].flag = f;
266 *idxp = idx + 1;
267 *offp = o + c;
268 return 1;
269 }
270
271 void
272 convert_extent(
273 xfs_bmbt_rec_t *rp,
274 xfs_fileoff_t *op,
275 xfs_fsblock_t *sp,
276 xfs_filblks_t *cp,
277 int *fp)
278 {
279 struct xfs_bmbt_irec irec;
280
281 libxfs_bmbt_disk_get_all(rp, &irec);
282 *fp = irec.br_state == XFS_EXT_UNWRITTEN;
283 *op = irec.br_startoff;
284 *sp = irec.br_startblock;
285 *cp = irec.br_blockcount;
286 }
287
288 void
289 make_bbmap(
290 bbmap_t *bbmap,
291 int nex,
292 bmap_ext_t *bmp)
293 {
294 int i;
295
296 for (i = 0; i < nex; i++) {
297 bbmap->b[i].bm_bn = XFS_FSB_TO_DADDR(mp, bmp[i].startblock);
298 bbmap->b[i].bm_len = XFS_FSB_TO_BB(mp, bmp[i].blockcount);
299 }
300 bbmap->nmaps = nex;
301 }
302
303 static xfs_fsblock_t
304 select_child(
305 xfs_fileoff_t off,
306 xfs_bmbt_key_t *kp,
307 xfs_bmbt_ptr_t *pp,
308 int nrecs)
309 {
310 int i;
311
312 for (i = 0; i < nrecs; i++) {
313 if (be64_to_cpu(kp[i].br_startoff) == off)
314 return be64_to_cpu(pp[i]);
315 if (be64_to_cpu(kp[i].br_startoff) > off) {
316 if (i == 0)
317 return be64_to_cpu(pp[i]);
318 else
319 return be64_to_cpu(pp[i - 1]);
320 }
321 }
322 return be64_to_cpu(pp[nrecs - 1]);
323 }