File: | src/sbin/fsck_msdos/boot.c |
Warning: | line 65, column 7 Although the value stored to 'o' is used in the enclosing expression, the value is never actually read from 'o' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: boot.c,v 1.24 2016/10/10 00:34:50 bluhm Exp $ */ |
2 | /* $NetBSD: boot.c,v 1.5 1997/10/17 11:19:23 ws Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (C) 1995, 1997 Wolfgang Solfrank |
6 | * Copyright (c) 1995 Martin Husemann |
7 | * |
8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions |
10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/param.h> /* DEV_BSIZE powerof2 */ |
30 | #include <sys/disklabel.h> |
31 | |
32 | #include <stdlib.h> |
33 | #include <string.h> |
34 | #include <ctype.h> |
35 | #include <stdio.h> |
36 | #include <unistd.h> |
37 | |
38 | #include "ext.h" |
39 | |
40 | int |
41 | readboot(int dosfs, struct bootblock *boot) |
42 | { |
43 | u_char *block = NULL((void *)0); |
44 | u_char *fsinfo = NULL((void *)0); |
45 | u_char *backup = NULL((void *)0); |
46 | int ret = FSOK0, secsize = lab.d_secsize, fsinfosz; |
47 | off_t o; |
48 | ssize_t n; |
49 | |
50 | if (secsize < DOSBOOTBLOCKSIZE512) { |
51 | xperror("sector size < DOSBOOTBLOCKSIZE"); |
52 | goto fail; |
53 | } |
54 | if (DOSBOOTBLOCKSIZE512 != DEV_BSIZE(1 << 9)) { |
55 | xperror("DOSBOOTBLOCKSIZE != DEV_BSIZE"); |
56 | goto fail; |
57 | } |
58 | |
59 | block = malloc(secsize); |
60 | if (block == NULL((void *)0)) { |
61 | xperror("could not malloc boot block"); |
62 | goto fail; |
63 | } |
64 | |
65 | if ((o = lseek(dosfs, 0, SEEK_SET0)) == -1) { |
Although the value stored to 'o' is used in the enclosing expression, the value is never actually read from 'o' | |
66 | xperror("could not seek boot block"); |
67 | goto fail; |
68 | } |
69 | |
70 | n = read(dosfs, block, secsize); |
71 | if (n == -1 || n != secsize) { |
72 | xperror("could not read boot block"); |
73 | goto fail; |
74 | } |
75 | |
76 | if (block[510] != 0x55 || block[511] != 0xaa) { |
77 | pfatal("Invalid signature in boot block: %02x%02x\n", |
78 | block[511], block[510]); |
79 | } |
80 | |
81 | memset(boot, 0, sizeof *boot); |
82 | boot->ValidFat = -1; |
83 | |
84 | /* decode bios parameter block */ |
85 | boot->BytesPerSec = block[11] + (block[12] << 8); |
86 | if (boot->BytesPerSec == 0 || boot->BytesPerSec != secsize) { |
87 | pfatal("Invalid sector size: %u\n", boot->BytesPerSec); |
88 | goto fail; |
89 | } |
90 | boot->SecPerClust = block[13]; |
91 | if (boot->SecPerClust == 0 || !powerof2(boot->SecPerClust)((((boot->SecPerClust)-1)&(boot->SecPerClust))==0)) { |
92 | pfatal("Invalid cluster size: %u\n", boot->SecPerClust); |
93 | goto fail; |
94 | } |
95 | boot->ResSectors = block[14] + (block[15] << 8); |
96 | boot->FATs = block[16]; |
97 | if (boot->FATs == 0) { |
98 | pfatal("Invalid number of FATs: %u\n", boot->FATs); |
99 | goto fail; |
100 | } |
101 | boot->RootDirEnts = block[17] + (block[18] << 8); |
102 | boot->Sectors = block[19] + (block[20] << 8); |
103 | boot->Media = block[21]; |
104 | boot->FATsmall = block[22] + (block[23] << 8); |
105 | boot->SecPerTrack = block[24] + (block[25] << 8); |
106 | boot->Heads = block[26] + (block[27] << 8); |
107 | boot->HiddenSecs = block[28] + (block[29] << 8) + (block[30] << 16) + (block[31] << 24); |
108 | boot->HugeSectors = block[32] + (block[33] << 8) + (block[34] << 16) + (block[35] << 24); |
109 | |
110 | boot->FATsecs = boot->FATsmall; |
111 | |
112 | if (!boot->RootDirEnts) { |
113 | boot->flags |= FAT321; |
114 | boot->FATsecs = block[36] + (block[37] << 8) |
115 | + (block[38] << 16) + (block[39] << 24); |
116 | if (block[40] & 0x80) |
117 | boot->ValidFat = block[40] & 0x0f; |
118 | |
119 | /* check version number: */ |
120 | if (block[42] || block[43]) { |
121 | /* Correct? XXX */ |
122 | pfatal("Unknown filesystem version: %x.%x\n", |
123 | block[43], block[42]); |
124 | goto fail; |
125 | } |
126 | boot->RootCl = block[44] + (block[45] << 8) |
127 | + (block[46] << 16) + (block[47] << 24); |
128 | boot->FSInfo = block[48] + (block[49] << 8); |
129 | boot->Backup = block[50] + (block[51] << 8); |
130 | |
131 | o = lseek(dosfs, boot->FSInfo * secsize, SEEK_SET0); |
132 | if (o == -1 || o != boot->FSInfo * secsize) { |
133 | xperror("could not seek fsinfo block"); |
134 | goto fail; |
135 | } |
136 | |
137 | if ((2 * DOSBOOTBLOCKSIZE512) < secsize) |
138 | fsinfosz = secsize; |
139 | else |
140 | fsinfosz = 2 * secsize; |
141 | fsinfo = malloc(fsinfosz); |
142 | if (fsinfo == NULL((void *)0)) { |
143 | xperror("could not malloc fsinfo"); |
144 | goto fail; |
145 | } |
146 | n = read(dosfs, fsinfo, fsinfosz); |
147 | if (n == -1 || n != fsinfosz) { |
148 | xperror("could not read fsinfo block"); |
149 | goto fail; |
150 | } |
151 | |
152 | if (memcmp(fsinfo, "RRaA", 4) |
153 | || memcmp(fsinfo + 0x1e4, "rrAa", 4) |
154 | || fsinfo[0x1fc] |
155 | || fsinfo[0x1fd] |
156 | || fsinfo[0x1fe] != 0x55 |
157 | || fsinfo[0x1ff] != 0xaa |
158 | || fsinfo[0x3fc] |
159 | || fsinfo[0x3fd] |
160 | || fsinfo[0x3fe] != 0x55 |
161 | || fsinfo[0x3ff] != 0xaa) { |
162 | pwarn("Invalid signature in fsinfo block\n"); |
163 | if (ask(0, "fix")) { |
164 | memcpy(fsinfo, "RRaA", 4); |
165 | memcpy(fsinfo + 0x1e4, "rrAa", 4); |
166 | fsinfo[0x1fc] = fsinfo[0x1fd] = 0; |
167 | fsinfo[0x1fe] = 0x55; |
168 | fsinfo[0x1ff] = 0xaa; |
169 | fsinfo[0x3fc] = fsinfo[0x3fd] = 0; |
170 | fsinfo[0x3fe] = 0x55; |
171 | fsinfo[0x3ff] = 0xaa; |
172 | |
173 | o = lseek(dosfs, boot->FSInfo * secsize, |
174 | SEEK_SET0); |
175 | if (o == -1 || o != boot->FSInfo * secsize) { |
176 | xperror("Unable to seek FSInfo"); |
177 | goto fail; |
178 | } |
179 | n = write(dosfs, fsinfo, fsinfosz); |
180 | if (n == -1 || n != fsinfosz) { |
181 | xperror("Unable to write FSInfo"); |
182 | goto fail; |
183 | } |
184 | ret = FSBOOTMOD1; |
185 | } else |
186 | boot->FSInfo = 0; |
187 | } |
188 | if (boot->FSInfo) { |
189 | boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8) |
190 | + (fsinfo[0x1ea] << 16) |
191 | + (fsinfo[0x1eb] << 24); |
192 | boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8) |
193 | + (fsinfo[0x1ee] << 16) |
194 | + (fsinfo[0x1ef] << 24); |
195 | } |
196 | |
197 | o = lseek(dosfs, boot->Backup * secsize, SEEK_SET0); |
198 | if (o == -1 || o != boot->Backup * secsize) { |
199 | xperror("could not seek backup bootblock"); |
200 | goto fail; |
201 | } |
202 | backup = malloc(2 * secsize); /* In case we check fsinfo. */ |
203 | if (backup == NULL((void *)0)) { |
204 | xperror("could not malloc backup boot block"); |
205 | goto fail; |
206 | } |
207 | n = read(dosfs, backup, secsize); |
208 | if (n == -1 || n != secsize) { |
209 | xperror("could not read backup bootblock"); |
210 | goto fail; |
211 | } |
212 | |
213 | /* |
214 | * Check that the backup boot block matches the primary one. |
215 | * We don't check every byte, since some vendor utilities |
216 | * seem to overwrite the boot code when they feel like it, |
217 | * without changing the backup block. Specifically, we check |
218 | * the two-byte signature at the end, the BIOS parameter |
219 | * block (which starts after the 3-byte JMP and the 8-byte |
220 | * OEM name/version) and the filesystem information that |
221 | * follows the BPB (bsBPB[53] and bsExt[26] for FAT32, so we |
222 | * check 79 bytes). |
223 | */ |
224 | if (backup[510] != 0x55 || backup[511] != 0xaa) { |
225 | pfatal("Invalid signature in backup boot block: %02x%02x\n", backup[511], backup[510]); |
226 | } |
227 | if (memcmp(block + 11, backup + 11, 79)) { |
228 | pfatal("backup doesn't compare to primary bootblock\n"); |
229 | goto fail; |
230 | } |
231 | /* Check backup FSInfo? XXX */ |
232 | } |
233 | |
234 | if (boot->FATsecs == 0) { |
235 | pfatal("Invalid number of FAT sectors: %u\n", boot->FATsecs); |
236 | goto fail; |
237 | } |
238 | |
239 | boot->ClusterOffset = (boot->RootDirEnts * 32 + secsize - 1) |
240 | / secsize |
241 | + boot->ResSectors |
242 | + boot->FATs * boot->FATsecs |
243 | - CLUST_FIRST2 * boot->SecPerClust; |
244 | |
245 | if (boot->Sectors) { |
246 | boot->HugeSectors = 0; |
247 | boot->NumSectors = boot->Sectors; |
248 | } else |
249 | boot->NumSectors = boot->HugeSectors; |
250 | |
251 | if (boot->ClusterOffset > boot->NumSectors) { |
252 | pfatal("Cluster offset too large (%u clusters)\n", |
253 | boot->ClusterOffset); |
254 | goto fail; |
255 | } |
256 | boot->NumClusters = (boot->NumSectors - boot->ClusterOffset) / boot->SecPerClust; |
257 | |
258 | if (boot->flags&FAT321) |
259 | boot->ClustMask = CLUST32_MASK0xfffffff; |
260 | else if (boot->NumClusters < (CLUST_RSRVD0xfffffff6&CLUST12_MASK0xfff)) |
261 | boot->ClustMask = CLUST12_MASK0xfff; |
262 | else if (boot->NumClusters < (CLUST_RSRVD0xfffffff6&CLUST16_MASK0xffff)) |
263 | boot->ClustMask = CLUST16_MASK0xffff; |
264 | else { |
265 | pfatal("Filesystem too big (%u clusters) for non-FAT32 partition\n", |
266 | boot->NumClusters); |
267 | goto fail; |
268 | } |
269 | |
270 | switch (boot->ClustMask) { |
271 | case CLUST32_MASK0xfffffff: |
272 | boot->NumFatEntries = (boot->FATsecs * secsize) / 4; |
273 | break; |
274 | case CLUST16_MASK0xffff: |
275 | boot->NumFatEntries = (boot->FATsecs * secsize) / 2; |
276 | break; |
277 | default: |
278 | boot->NumFatEntries = (boot->FATsecs * secsize * 2) / 3; |
279 | break; |
280 | } |
281 | |
282 | if (boot->NumFatEntries < boot->NumClusters) { |
283 | pfatal("FAT size too small, %u entries won't fit into %u sectors\n", |
284 | boot->NumClusters, boot->FATsecs); |
285 | goto fail; |
286 | } |
287 | boot->ClusterSize = boot->SecPerClust * secsize; |
288 | |
289 | boot->NumFiles = 1; |
290 | boot->NumFree = 0; |
291 | |
292 | free(backup); |
293 | free(block); |
294 | free(fsinfo); |
295 | return ret; |
296 | fail: |
297 | free(backup); |
298 | free(block); |
299 | free(fsinfo); |
300 | return FSFATAL16; |
301 | } |
302 | |
303 | int |
304 | writefsinfo(int dosfs, struct bootblock *boot) |
305 | { |
306 | u_char *fsinfo = NULL((void *)0); |
307 | int secsize = lab.d_secsize, fsinfosz; |
308 | off_t o; |
309 | ssize_t n; |
310 | |
311 | if ((2 * DOSBOOTBLOCKSIZE512) < secsize) |
312 | fsinfosz = secsize; |
313 | else |
314 | fsinfosz = 2 * secsize; |
315 | |
316 | fsinfo = malloc(fsinfosz); |
317 | if (fsinfo == NULL((void *)0)) { |
318 | xperror("could not malloc fsinfo block"); |
319 | goto fail; |
320 | } |
321 | |
322 | o = lseek(dosfs, boot->FSInfo * secsize, SEEK_SET0); |
323 | if (o == -1 || o != boot->FSInfo * secsize) { |
324 | xperror("could not seek fsinfo block"); |
325 | goto fail; |
326 | } |
327 | |
328 | n = read(dosfs, fsinfo, fsinfosz); |
329 | if (n == -1 || n != fsinfosz) { |
330 | xperror("could not read fsinfo block"); |
331 | goto fail; |
332 | } |
333 | |
334 | fsinfo[0x1e8] = (u_char)boot->FSFree; |
335 | fsinfo[0x1e9] = (u_char)(boot->FSFree >> 8); |
336 | fsinfo[0x1ea] = (u_char)(boot->FSFree >> 16); |
337 | fsinfo[0x1eb] = (u_char)(boot->FSFree >> 24); |
338 | fsinfo[0x1ec] = (u_char)boot->FSNext; |
339 | fsinfo[0x1ed] = (u_char)(boot->FSNext >> 8); |
340 | fsinfo[0x1ee] = (u_char)(boot->FSNext >> 16); |
341 | fsinfo[0x1ef] = (u_char)(boot->FSNext >> 24); |
342 | |
343 | o = lseek(dosfs, o, SEEK_SET0); |
344 | if (o == -1 || o != boot->FSInfo * boot->BytesPerSec) { |
345 | xperror("Unable to seek FSInfo"); |
346 | goto fail; |
347 | } |
348 | n = write(dosfs, fsinfo, fsinfosz); |
349 | if (n == -1 || n != fsinfosz) { |
350 | xperror("Unable to write FSInfo"); |
351 | goto fail; |
352 | } |
353 | |
354 | free(fsinfo); |
355 | |
356 | /* |
357 | * Technically, we should return FSBOOTMOD here. |
358 | * |
359 | * However, since Win95 OSR2 (the first M$ OS that has |
360 | * support for FAT32) doesn't maintain the FSINFO block |
361 | * correctly, it has to be fixed pretty often. |
362 | * |
363 | * Therefore, we handle the FSINFO block only informally, |
364 | * fixing it if necessary, but otherwise ignoring the |
365 | * fact that it was incorrect. |
366 | */ |
367 | return 0; |
368 | fail: |
369 | free(fsinfo); |
370 | return FSFATAL16; |
371 | } |