]> git.saurik.com Git - apple/hfs.git/blob - fstyp_hfs/fstyp_hfs.c
hfs-366.50.19.tar.gz
[apple/hfs.git] / fstyp_hfs / fstyp_hfs.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/disk.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <sys/stat.h>
32
33 #define HFS_VOLHDR_OFFSET 1024 /* technote 1150 */
34 #define HFS_VOLHDR_SIZE 512 /* technote 1150 */
35
36 #define E_OPENDEV -1
37 #define E_READ -5
38
39 void usage(void);
40 char *rawname(char *name);
41 char *unrawname(char *name);
42 int checkVolHdr(const unsigned char *volhdr);
43 char *blockcheck(char *origname);
44
45 char *progname;
46
47 /*
48 * perhaps check the alternate volume header as well
49
50 * prefer to use raw device. TODO: suppose block device is valid but
51 * the corresponding raw device is not valid, then we fail. this is
52 * probably no the desired behavior.
53 */
54
55 int
56 main(int argc, char **argv)
57 {
58 unsigned char volhdr[HFS_VOLHDR_SIZE] = {0};
59 int fd, retval;
60 char *devname;
61
62 fd = -1;
63 retval = 0;
64
65 if ((progname = strrchr(*argv, '/')))
66 ++progname;
67 else
68 progname = *argv;
69
70 if (argc != 2) {
71 usage();
72 } else {
73 devname = blockcheck(argv[1]);
74
75 if (devname != NULL) {
76 if ((fd = open(devname, O_RDONLY, 0)) < 0) {
77 retval = E_OPENDEV;
78 } else if (pread(fd, volhdr, HFS_VOLHDR_SIZE, HFS_VOLHDR_OFFSET) != HFS_VOLHDR_SIZE) {
79 retval = E_READ;
80 } else {
81 retval = checkVolHdr(volhdr);
82 }
83
84 if (-1 != fd) {
85 close(fd);
86 fd = -1;
87 }
88 }
89 }
90
91 return retval;
92 }
93
94 void
95 usage(void)
96 {
97 fprintf(stdout, "usage: %s device\n", progname);
98 return;
99 }
100
101 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
102 char *
103 rawname(char *name)
104 {
105 static char rawbuf[32];
106 char *dp;
107
108 (void) memset(rawbuf, 0, sizeof(rawbuf));
109
110 /* find the last "/" in a path, like /dev/disk2 */
111 if ((dp = strrchr(name, '/')) == 0)
112 return NULL;
113
114 /* temporarily replace the last "/" with a NUL */
115 *dp = 0;
116
117 /* copy name, with the "/" removed into 'rawbuf' */
118 (void) strlcpy(rawbuf, name, sizeof(rawbuf));
119
120 /* replace the "/" back */
121 *dp = '/';
122
123 /* Now add the "/r" to make it a raw device */
124 (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
125
126 /* then copy the rest of the string (after the /) into place */
127 (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
128
129 return (rawbuf);
130 }
131
132 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
133 char *
134 unrawname(char *name)
135 {
136 char *dp;
137 struct stat stb;
138
139 if ((dp = strrchr(name, '/')) == 0)
140 return (name);
141 if (stat(name, &stb) < 0)
142 return (name);
143 if ((stb.st_mode & S_IFMT) != S_IFCHR)
144 return (name);
145 if (dp[1] != 'r')
146 return (name);
147 (void) strcpy(&dp[1], &dp[2]);
148
149 return (name);
150 }
151
152 /*
153 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
154 * 1) remove "hotroot"
155 * 2) if error, return NULL
156 * 3) if not a char device, return NULL (effectively, this is treated
157 * as error even if accessing the block device might have been OK)
158 */
159 char *
160 blockcheck(char *origname)
161 {
162 struct stat stblock, stchar;
163 char *newname, *raw;
164 int retried;
165
166 retried = 0;
167 newname = origname;
168 retry:
169 if (stat(newname, &stblock) < 0) {
170 perror(newname);
171 fprintf(stderr, "Can't stat %s\n", newname);
172 return NULL;
173 }
174 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
175 raw = rawname(newname);
176 if (stat(raw, &stchar) < 0) {
177 perror(raw);
178 fprintf(stderr, "Can't stat %s\n", raw);
179 return NULL;
180 }
181 if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
182 return (raw);
183 } else {
184 fprintf(stderr, "%s is not a character device\n", raw);
185 return NULL;
186 }
187 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
188 newname = unrawname(newname);
189 retried++;
190 goto retry;
191 }
192 /* not a block or character device */
193 return NULL;
194 }
195
196 /*
197 * (sanity) check the volume header in volhdr
198 *
199 * return 1 if volhdr is an HFS volhdr, 0 otherwise
200 */
201 int
202 checkVolHdr(const unsigned char *volhdr)
203 {
204 int retval;
205
206 retval = 0;
207
208 if (strncmp((const char *)volhdr, "H+", 2) == 0) {
209 /* technote 1150: H+ is version 4 */
210 retval = (volhdr[3] == 4);
211 } else if (strncmp((const char *)volhdr, "HX", 2) == 0) {
212 /* technote 1150: HX is version 5 */
213 retval = (volhdr[3] == 5);
214 }
215 return retval;
216 }