1 /*
2 * Copyright (c) 2020 Tomohiro Kusumi <tkusumi@netbsd.org>
3 * Copyright (c) 2020 The DragonFly Project
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The DragonFly Project
7 * by Matthew Dillon <dillon@dragonflybsd.org>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <string.h>
45 #include <fstab.h>
46 #include <assert.h>
47 #include <errno.h>
48 #include <err.h>
49
50 #include <vfs/hammer2/hammer2_disk.h>
51
52 #include "hammer2_subs.h"
53
54 static hammer2_ondisk_t fso;
55 static int hammer2_volumes_initialized;
56
57 static void
hammer2_init_volume(hammer2_volume_t * vol)58 hammer2_init_volume(hammer2_volume_t *vol)
59 {
60 vol->fd = -1;
61 vol->id = -1;
62 vol->offset = (hammer2_off_t)-1;
63 vol->size = (hammer2_off_t)-1;
64 }
65
66 void
hammer2_init_ondisk(hammer2_ondisk_t * fsp)67 hammer2_init_ondisk(hammer2_ondisk_t *fsp)
68 {
69 int i;
70
71 bzero(fsp, sizeof(*fsp));
72 fsp->version = -1;
73 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i)
74 hammer2_init_volume(&fsp->volumes[i]);
75 }
76
77 void
hammer2_install_volume(hammer2_volume_t * vol,int fd,int id,const char * path,hammer2_off_t offset,hammer2_off_t size)78 hammer2_install_volume(hammer2_volume_t *vol, int fd, int id, const char *path,
79 hammer2_off_t offset, hammer2_off_t size)
80 {
81 bzero(vol, sizeof(*vol));
82 vol->fd = fd;
83 vol->id = id;
84 vol->path = strdup(path);
85 vol->offset = offset;
86 vol->size = size;
87 }
88
89 void
hammer2_uninstall_volume(hammer2_volume_t * vol)90 hammer2_uninstall_volume(hammer2_volume_t *vol)
91 {
92 fsync(vol->fd);
93 close(vol->fd);
94 free(vol->path);
95 hammer2_init_volume(vol);
96 }
97
98 /*
99 * Locate a valid volume header. If any of the four volume headers is good,
100 * we have a valid volume header and choose the best one based on mirror_tid.
101 */
102 static int
hammer2_read_volume_header(int fd,const char * path,hammer2_volume_data_t * voldata)103 hammer2_read_volume_header(int fd, const char *path,
104 hammer2_volume_data_t *voldata)
105 {
106 hammer2_volume_data_t vd;
107 hammer2_tid_t mirror_tid = -1;
108 hammer2_off_t size = check_volume(fd);
109 hammer2_crc32_t crc0, crc1;
110 const char *p;
111 int i, zone = -1;
112 ssize_t ret;
113
114 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
115 if (i * HAMMER2_ZONE_BYTES64 >= size)
116 break;
117 if (lseek(fd, i * HAMMER2_ZONE_BYTES64, SEEK_SET) == -1)
118 break;
119 ret = read(fd, &vd, HAMMER2_VOLUME_BYTES);
120 if (ret == -1) {
121 fprintf(stderr, "%s #%d: read %s\n",
122 path, i, strerror(errno));
123 continue;
124 }
125 if (ret != HAMMER2_VOLUME_BYTES) {
126 fprintf(stderr, "%s #%d: read %s\n",
127 path, i, strerror(errno));
128 continue;
129 }
130
131 p = (const char*)&vd;
132 /* verify volume header magic */
133 if ((vd.magic != HAMMER2_VOLUME_ID_HBO) &&
134 (vd.magic != HAMMER2_VOLUME_ID_ABO)) {
135 fprintf(stderr, "%s #%d: bad magic\n", path, i);
136 continue;
137 }
138
139 if (vd.magic == HAMMER2_VOLUME_ID_ABO) {
140 /* XXX: Reversed-endianness filesystem */
141 fprintf(stderr,
142 "%s #%d: reverse-endian filesystem detected",
143 path, i);
144 continue;
145 }
146
147 /* verify volume header CRC's */
148 crc0 = vd.icrc_sects[HAMMER2_VOL_ICRC_SECT0];
149 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRC0_OFF,
150 HAMMER2_VOLUME_ICRC0_SIZE);
151 if (crc0 != crc1) {
152 fprintf(stderr,
153 "%s #%d: volume header crc mismatch "
154 "sect0 %08x/%08x\n",
155 path, i, crc0, crc1);
156 continue;
157 }
158
159 crc0 = vd.icrc_sects[HAMMER2_VOL_ICRC_SECT1];
160 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRC1_OFF,
161 HAMMER2_VOLUME_ICRC1_SIZE);
162 if (crc0 != crc1) {
163 fprintf(stderr,
164 "%s #%d: volume header crc mismatch "
165 "sect1 %08x/%08x",
166 path, i, crc0, crc1);
167 continue;
168 }
169
170 crc0 = vd.icrc_volheader;
171 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRCVH_OFF,
172 HAMMER2_VOLUME_ICRCVH_SIZE);
173 if (crc0 != crc1) {
174 fprintf(stderr,
175 "%s #%d: volume header crc mismatch "
176 "vh %08x/%08x",
177 path, i, crc0, crc1);
178 continue;
179 }
180 if (zone == -1 || mirror_tid < vd.mirror_tid) {
181 bcopy(&vd, voldata, sizeof(vd));
182 mirror_tid = vd.mirror_tid;
183 zone = i;
184 }
185 }
186 return(zone);
187 }
188
189 static void
hammer2_err_uuid_mismatch(uuid_t * uuid1,uuid_t * uuid2,const char * id)190 hammer2_err_uuid_mismatch(uuid_t *uuid1, uuid_t *uuid2, const char *id)
191 {
192 char *p1 = NULL, *p2 = NULL;
193
194 hammer2_uuid_to_str(uuid1, &p1);
195 hammer2_uuid_to_str(uuid2, &p2);
196
197 errx(1, "%s uuid mismatch %s vs %s", id, p1, p2);
198
199 free(p1);
200 free(p2);
201 }
202
203 static void
hammer2_add_volume(const char * path,int rdonly)204 hammer2_add_volume(const char *path, int rdonly)
205 {
206 hammer2_volume_data_t voldata;
207 hammer2_volume_t *vol;
208 struct stat st;
209 int fd, i;
210 uuid_t uuid;
211
212 fd = open(path, rdonly ? O_RDONLY : O_RDWR);
213 if (fd == -1)
214 err(1, "open");
215
216 if (fstat(fd, &st) == -1)
217 err(1, "fstat");
218 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode))
219 errx(1, "Unsupported file type");
220
221 if (hammer2_read_volume_header(fd, path, &voldata) >= 0) {
222 i = voldata.volu_id;
223 if (i < 0 || i >= HAMMER2_MAX_VOLUMES)
224 errx(1, "%s has bad volume id %d", path, i);
225 vol = &fso.volumes[i];
226 if (vol->id != -1)
227 errx(1, "volume id %d already initialized", i);
228 /* all headers must have the same version, nvolumes and uuid */
229 if (!fso.nvolumes) {
230 fso.version = voldata.version;
231 fso.nvolumes = voldata.nvolumes;
232 fso.fsid = voldata.fsid;
233 fso.fstype = voldata.fstype;
234 } else {
235 if (fso.version != (int)voldata.version)
236 errx(1, "Volume version mismatch %d vs %d",
237 fso.version, (int)voldata.version);
238 if (fso.nvolumes != voldata.nvolumes)
239 errx(1, "Volume count mismatch %d vs %d",
240 fso.nvolumes, voldata.nvolumes);
241 uuid = voldata.fsid;
242 if (!uuid_equal(&fso.fsid, &uuid, NULL))
243 hammer2_err_uuid_mismatch(&fso.fsid,
244 &uuid,
245 "fsid");
246 uuid = voldata.fstype;
247 if (!uuid_equal(&fso.fstype, &uuid, NULL))
248 hammer2_err_uuid_mismatch(&fso.fstype,
249 &uuid,
250 "fstype");
251 }
252 /* all per-volume tests passed */
253 hammer2_install_volume(vol, fd, i, path,
254 voldata.volu_loff[i], voldata.volu_size);
255 fso.total_size += vol->size;
256 } else {
257 errx(1, "No valid volume headers found!");
258 }
259 }
260
261 static void
hammer2_verify_volumes_common(const hammer2_ondisk_t * fsp)262 hammer2_verify_volumes_common(const hammer2_ondisk_t *fsp)
263 {
264 const hammer2_volume_t *vol;
265 hammer2_off_t size;
266 struct stat *st;
267 const char *path;
268 int i, j, nvolumes = 0;
269
270 if (fsp->version == -1)
271 errx(1, "Bad volume version %d", fsp->version);
272
273 /* check initialized volume count */
274 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
275 vol = &fsp->volumes[i];
276 if (vol->id != -1)
277 nvolumes++;
278 }
279
280 /* fsp->nvolumes hasn't been verified yet, use nvolumes */
281 st = calloc(nvolumes, sizeof(*st));
282
283 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
284 vol = &fsp->volumes[i];
285 if (vol->id == -1)
286 continue;
287 path = vol->path;
288 /* check volumes are unique */
289 if (stat(path, &st[i]) != 0)
290 errx(1, "Failed to stat %s", path);
291 if (fstat(vol->fd, &st[i]) != 0)
292 errx(1, "Failed to fstat %d", vol->fd);
293 for (j = 0; j < i; ++j) {
294 if ((st[i].st_ino == st[j].st_ino) &&
295 (st[i].st_dev == st[j].st_dev))
296 errx(1, "%s specified more than once", path);
297 }
298 /* check volume fields are initialized */
299 if (vol->fd == -1)
300 errx(1, "%s has bad fd %d", path, vol->fd);
301 if (vol->offset == (hammer2_off_t)-1)
302 errx(1, "%s has bad offset 0x%016jx", path,
303 (intmax_t)vol->offset);
304 if (vol->size == (hammer2_off_t)-1)
305 errx(1, "%s has bad size 0x%016jx", path,
306 (intmax_t)vol->size);
307 /* check volume size vs block device size */
308 size = check_volume(vol->fd);
309 printf("checkvolu header %d %016jx/%016jx\n", i, vol->size, size);
310 if (vol->size > size)
311 errx(1, "%s's size 0x%016jx exceeds device size 0x%016jx",
312 path, (intmax_t)vol->size, size);
313 }
314 free(st);
315 }
316
317 static void
hammer2_verify_volumes_1(hammer2_ondisk_t * fsp,const hammer2_volume_data_t * rootvoldata)318 hammer2_verify_volumes_1(hammer2_ondisk_t *fsp,
319 const hammer2_volume_data_t *rootvoldata)
320 {
321 const hammer2_volume_t *vol;
322 hammer2_off_t off;
323 const char *path;
324 int i, nvolumes = 0;
325
326 /* check initialized volume count */
327 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
328 vol = &fsp->volumes[i];
329 if (vol->id != -1)
330 nvolumes++;
331 }
332 if (nvolumes != 1)
333 errx(1, "Only 1 volume supported");
334 fsp->nvolumes = nvolumes; /* adjust with actual count */
335
336 /* check volume header */
337 if (rootvoldata) {
338 if (rootvoldata->volu_id)
339 errx(1, "Volume id %d must be 0", rootvoldata->volu_id);
340 if (rootvoldata->nvolumes)
341 errx(1, "Volume count %d must be 0",
342 rootvoldata->nvolumes);
343 if (rootvoldata->total_size)
344 errx(1, "Total size 0x%016jx must be 0",
345 (intmax_t)rootvoldata->total_size);
346 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
347 off = rootvoldata->volu_loff[i];
348 if (off)
349 errx(1, "Volume offset[%d] 0x%016jx must be 0",
350 i, (intmax_t)off);
351 }
352 }
353
354 /* check volume */
355 vol = &fsp->volumes[HAMMER2_ROOT_VOLUME];
356 path = vol->path;
357 if (vol->id)
358 errx(1, "%s has non zero id %d", path, vol->id);
359 if (vol->offset)
360 errx(1, "%s has non zero offset 0x%016jx", path,
361 (intmax_t)vol->offset);
362 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64)
363 errx(1, "%s's size is not 0x%016jx aligned", path,
364 (intmax_t)HAMMER2_VOLUME_ALIGN);
365 }
366
367 static void
hammer2_verify_volumes_2(const hammer2_ondisk_t * fsp,const hammer2_volume_data_t * rootvoldata)368 hammer2_verify_volumes_2(const hammer2_ondisk_t *fsp,
369 const hammer2_volume_data_t *rootvoldata)
370 {
371 const hammer2_volume_t *vol;
372 hammer2_off_t off;
373 const char *path;
374 int i, nvolumes = 0;
375
376 /* check initialized volume count */
377 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
378 vol = &fsp->volumes[i];
379 if (vol->id != -1)
380 nvolumes++;
381 }
382 if (fsp->nvolumes != nvolumes)
383 errx(1, "Volume count mismatch %d vs %d",
384 fsp->nvolumes, nvolumes);
385
386 /* check volume header */
387 if (rootvoldata) {
388 if (rootvoldata->volu_id != HAMMER2_ROOT_VOLUME)
389 errx(1, "Volume id %d must be %d",
390 rootvoldata->volu_id, HAMMER2_ROOT_VOLUME);
391 if (rootvoldata->nvolumes != fso.nvolumes)
392 errx(1, "Volume header requires %d devices, %d specified",
393 rootvoldata->nvolumes, fso.nvolumes);
394 if (rootvoldata->total_size != fso.total_size)
395 errx(1, "Total size 0x%016jx does not equal sum of "
396 "volumes 0x%016jx",
397 rootvoldata->total_size, fso.total_size);
398 for (i = 0; i < nvolumes; ++i) {
399 off = rootvoldata->volu_loff[i];
400 if (off == (hammer2_off_t)-1)
401 errx(1, "Volume offset[%d] 0x%016jx must not be -1",
402 i, (intmax_t)off);
403 }
404 for (i = nvolumes; i < HAMMER2_MAX_VOLUMES; ++i) {
405 off = rootvoldata->volu_loff[i];
406 if (off != (hammer2_off_t)-1)
407 errx(1, "Volume offset[%d] 0x%016jx must be -1",
408 i, (intmax_t)off);
409 }
410 }
411
412 /* check volumes */
413 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
414 vol = &fsp->volumes[i];
415 if (vol->id == -1)
416 continue;
417 path = vol->path;
418 /* check offset */
419 if (vol->offset & HAMMER2_FREEMAP_LEVEL1_MASK)
420 errx(1, "%s's offset 0x%016jx not 0x%016jx aligned",
421 path, (intmax_t)vol->offset,
422 HAMMER2_FREEMAP_LEVEL1_SIZE);
423 /* check vs previous volume */
424 if (i) {
425 if (vol->id != (vol-1)->id + 1)
426 errx(1, "%s has inconsistent id %d", path,
427 vol->id);
428 if (vol->offset != (vol-1)->offset + (vol-1)->size)
429 errx(1, "%s has inconsistent offset 0x%016jx",
430 path, (intmax_t)vol->offset);
431 } else { /* first */
432 if (vol->offset)
433 errx(1, "%s has non zero offset 0x%016jx", path,
434 (intmax_t)vol->offset);
435 }
436 /* check size for non-last and last volumes */
437 if (i != fsp->nvolumes - 1) {
438 if (vol->size < HAMMER2_FREEMAP_LEVEL1_SIZE)
439 errx(1, "%s's size must be >= 0x%016jx", path,
440 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE);
441 if (vol->size & HAMMER2_FREEMAP_LEVEL1_MASK)
442 errx(1, "%s's size is not 0x%016jx aligned",
443 path,
444 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE);
445 } else { /* last */
446 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64)
447 errx(1, "%s's size is not 0x%016jx aligned",
448 path, (intmax_t)HAMMER2_VOLUME_ALIGN);
449 }
450 }
451 }
452
453 void
hammer2_verify_volumes(hammer2_ondisk_t * fsp,const hammer2_volume_data_t * rootvoldata)454 hammer2_verify_volumes(hammer2_ondisk_t *fsp,
455 const hammer2_volume_data_t *rootvoldata)
456 {
457 hammer2_verify_volumes_common(fsp);
458 if (fsp->version >= HAMMER2_VOL_VERSION_MULTI_VOLUMES)
459 hammer2_verify_volumes_2(fsp, rootvoldata);
460 else
461 hammer2_verify_volumes_1(fsp, rootvoldata);
462 assert(fsp->nvolumes > 0);
463 }
464
465 void
hammer2_print_volumes(const hammer2_ondisk_t * fsp)466 hammer2_print_volumes(const hammer2_ondisk_t *fsp)
467 {
468 const hammer2_volume_t *vol;
469 int i, n, w = 0;
470
471 for (i = 0; i < fsp->nvolumes; ++i) {
472 vol = &fsp->volumes[i];
473 n = (int)strlen(vol->path);
474 if (n > w)
475 w = n;
476 }
477
478 printf("total %-*.*s 0x%016jx 0x%016jx\n",
479 w, w, "", (intmax_t)0, (intmax_t)fsp->total_size);
480
481 for (i = 0; i < fsp->nvolumes; ++i) {
482 vol = &fsp->volumes[i];
483 printf("volume%-2d %-*.*s 0x%016jx 0x%016jx%s\n",
484 vol->id, w, w, vol->path, (intmax_t)vol->offset,
485 (intmax_t)vol->size,
486 (vol->id == HAMMER2_ROOT_VOLUME ?
487 " (root volume)" : ""));
488 }
489 }
490
491 void
hammer2_init_volumes(const char * blkdevs,int rdonly)492 hammer2_init_volumes(const char *blkdevs, int rdonly)
493 {
494 hammer2_volume_data_t *rootvoldata;
495 char *o, *p, *devpath;
496
497 if (hammer2_volumes_initialized)
498 errx(1, "Already initialized");
499 if (!blkdevs)
500 errx(1, "NULL blkdevs");
501
502 hammer2_init_ondisk(&fso);
503 o = p = strdup(blkdevs);
504 while ((devpath = p) != NULL) {
505 if ((p = strchr(p, ':')) != NULL)
506 *p++ = 0;
507 devpath = getdevpath(devpath, 0);
508 if (strchr(devpath, ':'))
509 hammer2_init_volumes(devpath, rdonly);
510 else
511 hammer2_add_volume(devpath, rdonly);
512 free(devpath);
513 }
514 free(o);
515 hammer2_volumes_initialized = 1;
516
517 rootvoldata = hammer2_read_root_volume_header();
518 hammer2_verify_volumes(&fso, rootvoldata);
519 free(rootvoldata);
520 }
521
522 void
hammer2_cleanup_volumes(void)523 hammer2_cleanup_volumes(void)
524 {
525 hammer2_volume_t *vol;
526 int i;
527
528 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
529 vol = &fso.volumes[i];
530 if (vol->id == -1)
531 continue;
532 hammer2_uninstall_volume(vol);
533 }
534 hammer2_volumes_initialized = 0;
535 }
536
537 typedef void (*callback)(const hammer2_volume_t*, void *data);
538
539 hammer2_volume_t *
hammer2_get_volume(hammer2_off_t offset)540 hammer2_get_volume(hammer2_off_t offset)
541 {
542 hammer2_volume_t *vol;
543 int i;
544
545 assert(hammer2_volumes_initialized == 1);
546 offset &= ~HAMMER2_OFF_MASK_RADIX;
547
548 /* do binary search if users really use this many supported volumes */
549 for (i = 0; i < fso.nvolumes; ++i) {
550 vol = &fso.volumes[i];
551 if ((offset >= vol->offset) &&
552 (offset < vol->offset + vol->size))
553 {
554 return vol;
555 }
556 }
557 return NULL;
558 }
559
560 static int
hammer2_get_volume_attr(hammer2_off_t offset,callback fn,void * data)561 hammer2_get_volume_attr(hammer2_off_t offset, callback fn, void *data)
562 {
563 hammer2_volume_t *vol;
564 int i;
565
566 assert(hammer2_volumes_initialized == 1);
567 offset &= ~HAMMER2_OFF_MASK_RADIX;
568
569 /* do binary search if users really use this many supported volumes */
570 for (i = 0; i < fso.nvolumes; ++i) {
571 vol = &fso.volumes[i];
572 if ((offset >= vol->offset) &&
573 (offset < vol->offset + vol->size)) {
574 fn(vol, data);
575 return(0);
576 }
577 }
578
579 return(-1);
580 }
581
582 /* fd */
583 static void
hammer2_volume_fd_cb(const hammer2_volume_t * vol,void * data)584 hammer2_volume_fd_cb(const hammer2_volume_t *vol, void *data)
585 {
586 *(int*)data = vol->fd;
587 }
588
589 int
hammer2_get_volume_fd(hammer2_off_t offset)590 hammer2_get_volume_fd(hammer2_off_t offset)
591 {
592 int ret = 0;
593
594 if (hammer2_get_volume_attr(offset, hammer2_volume_fd_cb, &ret) < 0)
595 return(-1);
596 return(ret);
597 }
598
599 int
hammer2_get_root_volume_fd(void)600 hammer2_get_root_volume_fd(void)
601 {
602 return(hammer2_get_volume_fd(0));
603 }
604
605 /* id */
606 static void
hammer2_volume_id_cb(const hammer2_volume_t * vol,void * data)607 hammer2_volume_id_cb(const hammer2_volume_t *vol, void *data)
608 {
609 *(int*)data = vol->id;
610 }
611
612 int
hammer2_get_volume_id(hammer2_off_t offset)613 hammer2_get_volume_id(hammer2_off_t offset)
614 {
615 int ret = 0;
616
617 if (hammer2_get_volume_attr(offset, hammer2_volume_id_cb, &ret) < 0)
618 return(-1);
619 return(ret);
620 }
621
622 int
hammer2_get_root_volume_id(void)623 hammer2_get_root_volume_id(void)
624 {
625 return(hammer2_get_volume_id(0));
626 }
627
628 /* path */
629 static void
hammer2_volume_path_cb(const hammer2_volume_t * vol,void * data)630 hammer2_volume_path_cb(const hammer2_volume_t *vol, void *data)
631 {
632 *(const char**)data = vol->path;
633 }
634
635 const char *
hammer2_get_volume_path(hammer2_off_t offset)636 hammer2_get_volume_path(hammer2_off_t offset)
637 {
638 const char *ret = NULL;
639
640 if (hammer2_get_volume_attr(offset, hammer2_volume_path_cb, &ret) < 0)
641 return(NULL);
642 return(ret);
643 }
644
645 const char *
hammer2_get_root_volume_path(void)646 hammer2_get_root_volume_path(void)
647 {
648 return(hammer2_get_volume_path(0));
649 }
650
651 /* offset */
652 static void
hammer2_volume_offset_cb(const hammer2_volume_t * vol,void * data)653 hammer2_volume_offset_cb(const hammer2_volume_t *vol, void *data)
654 {
655 *(hammer2_off_t*)data = vol->offset;
656 }
657
658 hammer2_off_t
hammer2_get_volume_offset(hammer2_off_t offset)659 hammer2_get_volume_offset(hammer2_off_t offset)
660 {
661 hammer2_off_t ret = 0;
662
663 if (hammer2_get_volume_attr(offset, hammer2_volume_offset_cb, &ret) < 0)
664 return(-1);
665 return(ret);
666 }
667
668 hammer2_off_t
hammer2_get_root_volume_offset(void)669 hammer2_get_root_volume_offset(void)
670 {
671 return(hammer2_get_volume_offset(0));
672 }
673
674 /* size */
675 static void
hammer2_volume_size_cb(const hammer2_volume_t * vol,void * data)676 hammer2_volume_size_cb(const hammer2_volume_t *vol, void *data)
677 {
678 *(hammer2_off_t*)data = vol->size;
679 }
680
681 hammer2_off_t
hammer2_get_volume_size(hammer2_off_t offset)682 hammer2_get_volume_size(hammer2_off_t offset)
683 {
684 hammer2_off_t ret = 0;
685
686 if (hammer2_get_volume_attr(offset, hammer2_volume_size_cb, &ret) < 0)
687 return(-1);
688 return(ret);
689 }
690
691 hammer2_off_t
hammer2_get_root_volume_size(void)692 hammer2_get_root_volume_size(void)
693 {
694 return(hammer2_get_volume_size(0));
695 }
696
697 /* total size */
698 hammer2_off_t
hammer2_get_total_size(void)699 hammer2_get_total_size(void)
700 {
701 return(fso.total_size);
702 }
703
704 hammer2_volume_data_t*
hammer2_read_root_volume_header(void)705 hammer2_read_root_volume_header(void)
706 {
707 hammer2_volume_data_t *voldata;
708 int fd = hammer2_get_root_volume_fd();
709 const char *path = hammer2_get_root_volume_path();
710
711 if (fd == -1)
712 return(NULL);
713
714 voldata = calloc(1, sizeof(*voldata));
715 if (hammer2_read_volume_header(fd, path, voldata) >= 0)
716 return(voldata);
717 else
718 errx(1, "Failed to read volume header");
719 }
720