]> git.saurik.com Git - apple/hfs.git/blame_incremental - CopyHFSMeta/DeviceWrapper.c
hfs-195.tar.gz
[apple/hfs.git] / CopyHFSMeta / DeviceWrapper.c
... / ...
CommitLineData
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <err.h>
7#include <errno.h>
8#include <sys/stat.h>
9#include <sys/fcntl.h>
10#include <sys/disk.h>
11
12#include "hfsmeta.h"
13
14/*
15 * Functions to wrap around a device.
16 */
17#define MIN(a, b) \
18 ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \
19 __a < __b ? __a : __b; })
20
21struct DeviceWrapperContext {
22 char *pathname;
23 size_t blockSize;
24 off_t devSize;
25 int fd;
26};
27
28static int
29noClean(struct IOWrapper *ctx)
30{
31 // Conceivably, we could erase the entire device
32 return 0;
33}
34
35static ssize_t
36doRead(struct IOWrapper *ctx, off_t start, void *buffer, off_t len)
37{
38 // For now, just do a pread
39 struct DeviceWrapperContext *dctx = (struct DeviceWrapperContext*)ctx->context;
40
41 return pread(dctx->fd, buffer, (size_t)len, start);
42}
43
44static ssize_t
45writeExtent(struct IOWrapper *context, DeviceInfo_t *devp, off_t start, off_t len, void (^bp)(off_t))
46{
47 const size_t bufSize = 1024 * 1024;
48 struct DeviceWrapperContext *ctx = (struct DeviceWrapperContext*)context->context;
49 uint8_t buffer[bufSize];
50 off_t total = 0;
51
52 if (debug) printf("Writing extent <%lld, %lld> to device %s", start, len, ctx->pathname);
53
54 while (total < len) {
55 ssize_t nread;
56 size_t amt = MIN(bufSize, len - total);
57 nread = pread(devp->fd, buffer, amt, start + total);
58 if (nread == -1) {
59 warn("Cannot read from device at offset %lld", start + total);
60 return -1;
61 }
62 (void)pwrite(ctx->fd, (char*)buffer, nread, start + total);
63 bp(nread);
64 total += nread;
65 }
66 return 0;
67}
68
69/*
70 * Device files can't have progress information stored, so we don't do anything.
71 */
72static off_t
73GetProgress(struct IOWrapper *context)
74{
75 return 0;
76}
77static void
78SetProgress(struct IOWrapper *context, off_t progr)
79{
80 return;
81}
82
83struct IOWrapper *
84InitDeviceWrapper(const char *path, DeviceInfo_t *devp)
85{
86 struct DeviceWrapperContext ctx = { 0 };
87 struct DeviceWrapperContext *retctx = NULL;
88 IOWrapper_t *retval = NULL;
89 struct stat sb;
90 uint64_t blockCount;
91 char rawname[strlen(path) + 2]; // /dev/disk5 -> /dev/rdisk5
92
93 if (strncmp(path, "/dev/disk", 9) == 0) {
94 // Need to make it into a raw device name
95 sprintf(rawname, "/dev/rdisk%s", path + 9);
96 } else {
97 strcpy(rawname, path);
98 }
99
100 if (lstat(rawname, &sb) == -1) {
101 warn("cannot examine raw device %s", rawname);
102 goto done;
103 }
104 if ((sb.st_mode & S_IFMT) != S_IFCHR) {
105 warnx("device %s is not a raw device", rawname);
106 goto done;
107 }
108
109 ctx.pathname = strdup(rawname);
110
111 ctx.fd = open(rawname, O_RDWR);
112 if (ctx.fd == -1) {
113 warn("Cannot open device %s for reading and writing", rawname);
114 goto done;
115 }
116
117 if (ioctl(ctx.fd, DKIOCGETBLOCKSIZE, &ctx.blockSize) == -1) {
118 ctx.blockSize = 512; // A reasonable default
119 }
120 if (ioctl(ctx.fd, DKIOCGETBLOCKCOUNT, &blockCount) == -1) {
121 warn("Cannot block count for device %s", rawname);
122 goto done;
123 }
124 ctx.devSize = ctx.blockSize * blockCount;
125
126 if (ctx.devSize != devp->size) {
127 warnx("Device %s is not the same size (%lld) as source device (%lld)", rawname, ctx.devSize, devp->size);
128 goto done;
129 }
130
131 ctx.pathname = strdup(rawname);
132 retctx = malloc(sizeof(ctx));
133 if (retctx == NULL) {
134 warn("Cannot allocate space for device context");
135 goto done;
136 }
137 *retctx = ctx;
138 retval = malloc(sizeof(*retval));
139 if (retval == NULL) {
140 warn("Cannot allocate space for device wrapper");
141 goto done;
142 }
143 retval->context = retctx;
144 retval->reader = &doRead;
145 retval->writer = &writeExtent;
146 retval->getprog = &GetProgress;
147 retval->setprog = &SetProgress;
148 retval->cleanup = &noClean;
149
150done:
151 return retval;
152}