1#include <stdio.h>
2#include <stdlib.h>
3#include <errno.h>
4
5#include "iterate_hfs_metadata.h"
6#include "../CopyHFSMeta/Data.h"
7#include "../CopyHFSMeta/hfsmeta.h"
8
9/*
10 * These variables are used by the CopyHFSMeta routines, so we have to define them
11 */
12
13__private_extern__ int debug = 0;
14__private_extern__ int verbose = 0;
15__private_extern__ int printProgress = 0;
16
17/*
18 * This is essentially the guts of CopyHFSMeta, only without
19 * the ability to write out to a sparse bundle.  It also always
20 * wants to get the "other" metadata (symlinks and large EA extents).
21 *
22 * For each extent it finds, it calls the passed-in function pointer,
23 * with the start and length.
24 *
25 * It will go through and get the symlink and EA extents first, and
26 * then go through the rest of the extents.  It does not attempt any
27 * sorting past that.
28 */
29int
30iterate_hfs_metadata(char *device, int (*handle_extent)(int fd, off_t start, off_t length, void *ctx), void *context_ptr)
31{
32	struct DeviceInfo *devp = NULL;
33	struct VolumeDescriptor *vdp = NULL;
34	VolumeObjects_t *vop = NULL;
35	int retval = 0;
36
37	devp = OpenDevice(device, 0);
38	if (devp == NULL) {
39		retval = errno;
40		goto done;
41	}
42
43	vdp = VolumeInfo(devp);
44	if (vdp == NULL) {
45		retval = errno;
46		goto done;
47	}
48
49	if (CompareVolumeHeaders(vdp) == -1) {
50		retval = EINVAL;
51		goto done;
52	}
53
54	vop = InitVolumeObject(devp, vdp);
55	if (vop == NULL) {
56		retval = errno;
57		goto done;
58	}
59
60	/*
61	 * These guys don't have an error.  Probably
62	 * a mistake.
63	 */
64	AddHeaders(vop, 1);
65	AddJournal(vop);
66	AddFileExtents(vop);
67
68	/*
69	 * By this point, vop has all of the system metadata.
70	 * The only metadata we don't have would be symlinks (from
71	 * the catalog file), and extended attribute fork extents
72	 * (from the attributes file).  We get those with
73	 * FindOtherMetadata().
74	 */
75	retval = FindOtherMetadata(vop, ^(int fid __unused, off_t start, off_t len) {
76			return (*handle_extent)(devp->fd, start, len, context_ptr);
77		});
78
79	if (retval != 0)
80		goto done;
81
82	/*
83	 * Now, we've handled all of the other metadata, so we need
84	 * to go through the rest of our metadata, which is in vop.
85	 */
86	ExtentList_t *extList;
87	for (extList = vop->list;
88	     extList;
89	     extList = extList->next) {
90		size_t index;
91
92		for (index = 0; index < extList->count; index++) {
93			retval = (*handle_extent)(devp->fd, extList->extents[index].base, extList->extents[index].length, context_ptr);
94			if (retval != 0)
95				goto done;
96		}
97	}
98
99done:
100	if (vop) {
101		ReleaseVolumeObjects(vop);
102	} else {
103		if (vdp) {
104			ReleaseVolumeDescriptor(vdp);
105		}
106		if (devp) {
107			ReleaseDeviceInfo(devp);
108		}
109	}
110
111	return retval;
112
113}
114