]> git.saurik.com Git - apple/hfs.git/blob - fstyp_hfs/fstyp_hfs.c
884f955cf3f2c7db8ff6bb0b8da988f7850d7913
[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 if ((dp = strrchr(name, '/')) == 0)
109 return (0);
110 *dp = 0;
111 (void) strcpy(rawbuf, name);
112 *dp = '/';
113 (void) strcat(rawbuf, "/r");
114 (void) strcat(rawbuf, &dp[1]);
115
116 return (rawbuf);
117 }
118
119 /* copied from diskdev_cmds/fsck_hfs/utilities.c */
120 char *
121 unrawname(char *name)
122 {
123 char *dp;
124 struct stat stb;
125
126 if ((dp = strrchr(name, '/')) == 0)
127 return (name);
128 if (stat(name, &stb) < 0)
129 return (name);
130 if ((stb.st_mode & S_IFMT) != S_IFCHR)
131 return (name);
132 if (dp[1] != 'r')
133 return (name);
134 (void) strcpy(&dp[1], &dp[2]);
135
136 return (name);
137 }
138
139 /*
140 * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
141 * 1) remove "hotroot"
142 * 2) if error, return NULL
143 * 3) if not a char device, return NULL (effectively, this is treated
144 * as error even if accessing the block device might have been OK)
145 */
146 char *
147 blockcheck(char *origname)
148 {
149 struct stat stblock, stchar;
150 char *newname, *raw;
151 int retried;
152
153 retried = 0;
154 newname = origname;
155 retry:
156 if (stat(newname, &stblock) < 0) {
157 perror(newname);
158 fprintf(stderr, "Can't stat %s\n", newname);
159 return NULL;
160 }
161 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
162 raw = rawname(newname);
163 if (stat(raw, &stchar) < 0) {
164 perror(raw);
165 fprintf(stderr, "Can't stat %s\n", raw);
166 return NULL;
167 }
168 if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
169 return (raw);
170 } else {
171 fprintf(stderr, "%s is not a character device\n", raw);
172 return NULL;
173 }
174 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
175 newname = unrawname(newname);
176 retried++;
177 goto retry;
178 }
179 /* not a block or character device */
180 return NULL;
181 }
182
183 /*
184 * (sanity) check the volume header in volhdr
185 *
186 * return 1 if volhdr is an HFS volhdr, 0 otherwise
187 */
188 int
189 checkVolHdr(const unsigned char *volhdr)
190 {
191 int retval;
192
193 retval = 0;
194
195 if (strncmp((const char *)volhdr, "H+", 2) == 0) {
196 /* technote 1150: H+ is version 4 */
197 retval = (volhdr[3] == 4);
198 } else if (strncmp((const char *)volhdr, "HX", 2) == 0) {
199 /* technote 1150: HX is version 5 */
200 retval = (volhdr[3] == 5);
201 }
202 return retval;
203 }