xref: /onnv-gate/usr/src/lib/libparted/common/libparted/fs/fat/bootsector.c (revision 9663:ace9a2ac3683)
1 /*
2     libparted
3     Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Free Software Foundation, Inc.
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <config.h>
20 #include "fat.h"
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 
30 /* Reads in the boot sector (superblock), and does a minimum of sanity
31  * checking.  The goals are:
32  *	- to detect fat file systems, even if they are damaged [i.e. not
33  * return an error / throw an exception]
34  *	- to fail detection if there's not enough information for
35  * fat_boot_sector_probe_type() to work (or possibly crash on a divide-by-zero)
36  */
37 int
fat_boot_sector_read(FatBootSector * bs,const PedGeometry * geom)38 fat_boot_sector_read (FatBootSector* bs, const PedGeometry *geom)
39 {
40 	PED_ASSERT (bs != NULL, return 0);
41 	PED_ASSERT (geom != NULL, return 0);
42 
43 	if (!ped_geometry_read (geom, bs, 0, 1))
44 		return 0;
45 
46 	if (PED_LE16_TO_CPU (bs->boot_sign) != 0xAA55) {
47 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
48 			_("File system has an invalid signature for a FAT "
49 			  "file system."));
50 		return 0;
51 	}
52 
53 	if (!bs->system_id[0]) {
54 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
55 			_("File system has an invalid signature for a FAT "
56 			  "file system."));
57 		return 0;
58 	}
59 
60 	if (!bs->sector_size
61             || PED_LE16_TO_CPU (bs->sector_size) % PED_SECTOR_SIZE_DEFAULT) {
62 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
63 			_("File system has an invalid sector size for a FAT "
64 			  "file system."));
65 		return 0;
66 	}
67 
68 	if (!bs->cluster_size) {
69 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
70 			_("File system has an invalid cluster size for a FAT "
71 			  "file system."));
72 		return 0;
73 	}
74 
75 	if (!bs->reserved) {
76 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
77 			_("File system has an invalid number of reserved "
78 			  "sectors for a FAT file system."));
79 		return 0;
80 	}
81 
82 	if (bs->fats < 1 || bs->fats > 4) {
83 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
84 			_("File system has an invalid number of FATs."));
85 		return 0;
86 	}
87 
88 	return 1;
89 }
90 
91 /*
92     Don't trust the FAT12, FAT16 or FAT32 label string.
93  */
94 FatType
fat_boot_sector_probe_type(const FatBootSector * bs,const PedGeometry * geom)95 fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom)
96 {
97 	PedSector	logical_sector_size;
98 	PedSector	first_cluster_sector;
99 	FatCluster	cluster_count;
100 
101 	if (!PED_LE16_TO_CPU (bs->dir_entries))
102 		return FAT_TYPE_FAT32;
103 
104 	logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
105 
106 	first_cluster_sector
107 		= PED_LE16_TO_CPU (bs->reserved) * logical_sector_size
108 		  + 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size
109 		  + PED_LE16_TO_CPU (bs->dir_entries)
110 			/ (512 / sizeof (FatDirEntry));
111 	cluster_count = (geom->length - first_cluster_sector)
112 			/ bs->cluster_size / logical_sector_size;
113 	if (cluster_count > MAX_FAT12_CLUSTERS)
114 		return FAT_TYPE_FAT16;
115 	else
116 		return FAT_TYPE_FAT12;
117 }
118 
119 /* Analyses the boot sector, and sticks appropriate numbers in
120    fs->type_specific.
121 
122    Note: you need to subtract (2 * cluster_sectors) off cluster offset,
123    because the first cluster is number 2.  (0 and 1 are not real clusters,
124    and referencing them is a bug)
125  */
126 int
fat_boot_sector_analyse(FatBootSector * bs,PedFileSystem * fs)127 fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs)
128 {
129 	FatSpecific*		fs_info = FAT_SPECIFIC (fs);
130 	int			fat_entry_size;
131 
132 	PED_ASSERT (bs != NULL, return 0);
133 
134 	if (PED_LE16_TO_CPU (bs->sector_size) != 512) {
135 		if (ped_exception_throw (
136 			PED_EXCEPTION_BUG,
137 			PED_EXCEPTION_IGNORE_CANCEL,
138 			_("This file system has a logical sector size of %d.  "
139 			"GNU Parted is known not to work properly with sector "
140 			"sizes other than 512 bytes."),
141 			(int) PED_LE16_TO_CPU (bs->sector_size))
142 				!= PED_EXCEPTION_IGNORE)
143 			return 0;
144 	}
145 
146 	fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
147 
148 	fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track);
149 	fs_info->heads = PED_LE16_TO_CPU (bs->heads);
150 	if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63
151 	    || fs_info->heads < 1 || fs_info->heads > 255) {
152 		PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom;
153 		int cyl_count = 0;
154 
155 		if (fs_info->heads > 0 && fs_info->sectors_per_track > 0)
156 			cyl_count = fs->geom->dev->length / fs_info->heads
157 					/ fs_info->sectors_per_track;
158 
159 		switch (ped_exception_throw (
160 			PED_EXCEPTION_ERROR,
161 			PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE
162 			+ PED_EXCEPTION_CANCEL,
163 			_("The file system's CHS geometry is (%d, %d, %d), "
164 			  "which is invalid.  The partition table's CHS "
165 			  "geometry is (%d, %d, %d).  If you select Ignore, "
166 			  "the file system's CHS geometry will be left "
167 			  "unchanged.  If you select Fix, the file system's "
168 			  "CHS geometry will be set to match the partition "
169 			  "table's CHS geometry."),
170 			 cyl_count, fs_info->heads, fs_info->sectors_per_track,
171 			 bios_geom->cylinders, bios_geom->heads,
172 			 bios_geom->sectors)) {
173 
174 		case PED_EXCEPTION_FIX:
175 			fs_info->sectors_per_track = bios_geom->sectors;
176 			fs_info->heads = bios_geom->heads;
177 			bs->secs_track
178 				= PED_CPU_TO_LE16 (fs_info->sectors_per_track);
179 			bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
180 			if (!fat_boot_sector_write (bs, fs))
181 				return 0;
182 			break;
183 
184 		case PED_EXCEPTION_CANCEL:
185 			return 0;
186 
187 		case PED_EXCEPTION_IGNORE:
188 			break;
189 
190                 default:
191                         break;
192 		}
193 	}
194 
195 	if (bs->sectors)
196 		fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors)
197 						* fs_info->logical_sector_size;
198 	else
199 		fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count)
200 						* fs_info->logical_sector_size;
201 
202 	fs_info->fat_table_count = bs->fats;
203 	fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries);
204 	fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved)
205 					* fs_info->logical_sector_size;
206 	fs_info->cluster_sectors = bs->cluster_size
207 				   * fs_info->logical_sector_size;
208 	fs_info->cluster_size = fs_info->cluster_sectors * 512;
209 
210 	if (fs_info->logical_sector_size == 0) {
211 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
212 			_("FAT boot sector says logical sector size is 0.  "
213 			  "This is weird. "));
214 		return 0;
215 	}
216 	if (fs_info->fat_table_count == 0) {
217 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
218 			_("FAT boot sector says there are no FAT tables.  This "
219 			  "is weird. "));
220 		return 0;
221 	}
222 	if (fs_info->cluster_sectors == 0) {
223 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
224 			_("FAT boot sector says clusters are 0 sectors.  This "
225 			  "is weird. "));
226 		return 0;
227 	}
228 
229 	fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom);
230 	if (fs_info->fat_type == FAT_TYPE_FAT12) {
231 		ped_exception_throw (
232 			PED_EXCEPTION_NO_FEATURE,
233 			PED_EXCEPTION_CANCEL,
234 			_("File system is FAT12, which is unsupported."));
235 		return 0;
236 	}
237 	if (fs_info->fat_type == FAT_TYPE_FAT16) {
238 		fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length)
239 				       * fs_info->logical_sector_size;
240 		fs_info->serial_number
241 			= PED_LE32_TO_CPU (bs->u.fat16.serial_number);
242 		fs_info->root_cluster = 0;
243 		fs_info->root_dir_offset
244 			= fs_info->fat_offset
245 			  + fs_info->fat_sectors * fs_info->fat_table_count;
246 		fs_info->root_dir_sector_count
247 			= fs_info->root_dir_entry_count * sizeof (FatDirEntry)
248 			  / (512 * fs_info->logical_sector_size);
249 		fs_info->cluster_offset
250 			= fs_info->root_dir_offset
251 			  + fs_info->root_dir_sector_count;
252 	}
253 	if (fs_info->fat_type == FAT_TYPE_FAT32) {
254 		fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
255 					* fs_info->logical_sector_size;
256 		fs_info->serial_number
257 			= PED_LE32_TO_CPU (bs->u.fat32.serial_number);
258 		fs_info->info_sector_offset
259 		    = PED_LE16_TO_CPU (fs_info->boot_sector.u.fat32.info_sector)
260 			  * fs_info->logical_sector_size;
261 		fs_info->boot_sector_backup_offset
262 		  = PED_LE16_TO_CPU (fs_info->boot_sector.u.fat32.backup_sector)
263 			  * fs_info->logical_sector_size;
264 		fs_info->root_cluster
265 			= PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster);
266 		fs_info->root_dir_offset = 0;
267 		fs_info->root_dir_sector_count = 0;
268 		fs_info->cluster_offset
269 			= fs_info->fat_offset
270 			  + fs_info->fat_sectors * fs_info->fat_table_count;
271 	}
272 
273 	fs_info->cluster_count
274 		= (fs_info->sector_count - fs_info->cluster_offset)
275 		  / fs_info->cluster_sectors;
276 
277 	fat_entry_size = fat_table_entry_size (fs_info->fat_type);
278 	if (fs_info->cluster_count + 2
279 			> fs_info->fat_sectors * 512 / fat_entry_size)
280 		fs_info->cluster_count
281 			= fs_info->fat_sectors * 512 / fat_entry_size - 2;
282 
283 	fs_info->dir_entries_per_cluster
284 		= fs_info->cluster_size / sizeof (FatDirEntry);
285 	return 1;
286 }
287 
288 #ifndef DISCOVER_ONLY
289 int
fat_boot_sector_set_boot_code(FatBootSector * bs)290 fat_boot_sector_set_boot_code (FatBootSector* bs)
291 {
292 	PED_ASSERT (bs != NULL, return 0);
293 
294 	memset (bs, 0, 512);
295 	memcpy (bs->boot_jump, FAT_BOOT_JUMP, 3);
296 	memcpy (bs->u.fat32.boot_code, FAT_BOOT_CODE, FAT_BOOT_CODE_LENGTH);
297 	return 1;
298 }
299 
300 int
fat_boot_sector_generate(FatBootSector * bs,const PedFileSystem * fs)301 fat_boot_sector_generate (FatBootSector* bs, const PedFileSystem* fs)
302 {
303 	FatSpecific*	fs_info = FAT_SPECIFIC (fs);
304 
305 	PED_ASSERT (bs != NULL, return 0);
306 
307 	memcpy (bs->system_id, "MSWIN4.1", 8);
308 	bs->sector_size = PED_CPU_TO_LE16 (fs_info->logical_sector_size * 512);
309 	bs->cluster_size = fs_info->cluster_sectors
310 				/ fs_info->logical_sector_size;
311 	bs->reserved = PED_CPU_TO_LE16 (fs_info->fat_offset
312 					/ fs_info->logical_sector_size);
313 	bs->fats = fs_info->fat_table_count;
314 
315 	bs->dir_entries = (fs_info->fat_type == FAT_TYPE_FAT16)
316 			  ? PED_CPU_TO_LE16 (fs_info->root_dir_entry_count)
317 			  : 0;
318 
319 	if (fs_info->sector_count / fs_info->logical_sector_size > 0xffff
320 		|| fs_info->fat_type == FAT_TYPE_FAT32) {
321 		bs->sectors = 0;
322 		bs->sector_count = PED_CPU_TO_LE32 (fs_info->sector_count
323 						/ fs_info->logical_sector_size);
324 	} else {
325 		bs->sectors = PED_CPU_TO_LE16 (fs_info->sector_count
326 					       / fs_info->logical_sector_size);
327 		bs->sector_count = 0;
328 	}
329 
330 	bs->media = 0xf8;
331 
332 	bs->secs_track = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
333 	bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
334 	bs->hidden = PED_CPU_TO_LE32 (fs->geom->start);
335 
336 	if (fs_info->fat_type == FAT_TYPE_FAT32) {
337 		bs->fat_length = 0;
338 		bs->u.fat32.fat_length = PED_CPU_TO_LE32 (fs_info->fat_sectors
339 						/ fs_info->logical_sector_size);
340 		bs->u.fat32.flags = 0;	/* FIXME: what the hell are these? */
341 		bs->u.fat32.version = 0;  /* must be 0, for Win98 bootstrap */
342 		bs->u.fat32.root_dir_cluster
343 			= PED_CPU_TO_LE32 (fs_info->root_cluster);
344 		bs->u.fat32.info_sector
345 			= PED_CPU_TO_LE16 (fs_info->info_sector_offset
346 					   / fs_info->logical_sector_size);
347 		bs->u.fat32.backup_sector
348 			= PED_CPU_TO_LE16 (fs_info->boot_sector_backup_offset
349 					   / fs_info->logical_sector_size);
350 
351 		bs->u.fat32.drive_num = 0x80;	/* _ALWAYS_ 0x80.  silly DOS */
352 
353 		memset (bs->u.fat32.empty_1, 0, 12);
354 
355 		bs->u.fat32.ext_signature = 0x29;
356 		bs->u.fat32.serial_number
357 			= PED_CPU_TO_LE32 (fs_info->serial_number);
358 		memcpy (bs->u.fat32.volume_name, "NO NAME    ", 11);
359 		memcpy (bs->u.fat32.fat_name, "FAT32   ", 8);
360 	} else {
361 		bs->fat_length
362 			= PED_CPU_TO_LE16 (fs_info->fat_sectors
363 					   / fs_info->logical_sector_size);
364 
365 		bs->u.fat16.drive_num = 0x80;	/* _ALWAYS_ 0x80.  silly DOS */
366 
367 		bs->u.fat16.ext_signature = 0x29;
368 		bs->u.fat16.serial_number
369 			= PED_CPU_TO_LE32 (fs_info->serial_number);
370 		memcpy (bs->u.fat16.volume_name, "NO NAME    ", 11);
371 		memcpy (bs->u.fat16.fat_name, "FAT16   ", 8);
372 	}
373 
374 	bs->boot_sign = PED_CPU_TO_LE16 (0xaa55);
375 
376 	return 1;
377 }
378 
379 int
fat_boot_sector_write(const FatBootSector * bs,PedFileSystem * fs)380 fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs)
381 {
382 	FatSpecific*	fs_info = FAT_SPECIFIC (fs);
383 
384 	PED_ASSERT (bs != NULL, return 0);
385 
386 	if (!ped_geometry_write (fs->geom, bs, 0, 1))
387 		return 0;
388 	if (fs_info->fat_type == FAT_TYPE_FAT32) {
389 		if (!ped_geometry_write (fs->geom, bs,
390 					 fs_info->boot_sector_backup_offset, 1))
391 			return 0;
392 	}
393 	return ped_geometry_sync (fs->geom);
394 }
395 
396 int
fat_info_sector_read(FatInfoSector * is,const PedFileSystem * fs)397 fat_info_sector_read (FatInfoSector* is, const PedFileSystem* fs)
398 {
399 	FatSpecific*	fs_info = FAT_SPECIFIC (fs);
400 	int		status;
401 
402 	PED_ASSERT (is != NULL, return 0);
403 
404 	if (!ped_geometry_read (fs->geom, is, fs_info->info_sector_offset, 1))
405 		return 0;
406 
407 	if (PED_LE32_TO_CPU (is->signature_2) != FAT32_INFO_MAGIC2) {
408 		status = ped_exception_throw (PED_EXCEPTION_WARNING,
409 				PED_EXCEPTION_IGNORE_CANCEL,
410 				_("The information sector has the wrong "
411 				"signature (%x).  Select cancel for now, "
412 				"and send in a bug report.  If you're "
413 				"desperate, it's probably safe to ignore."),
414 				PED_LE32_TO_CPU (is->signature_2));
415 		if (status == PED_EXCEPTION_CANCEL) return 0;
416 	}
417 	return 1;
418 }
419 
420 int
fat_info_sector_generate(FatInfoSector * is,const PedFileSystem * fs)421 fat_info_sector_generate (FatInfoSector* is, const PedFileSystem* fs)
422 {
423 	FatSpecific*	fs_info = FAT_SPECIFIC (fs);
424 
425 	PED_ASSERT (is != NULL, return 0);
426 
427 	fat_table_count_stats (fs_info->fat);
428 
429 	memset (is, 0, 512);
430 
431 	is->signature_1 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC1);
432 	is->signature_2 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC2);
433 	is->free_clusters = PED_CPU_TO_LE32 (fs_info->fat->free_cluster_count);
434 	is->next_cluster = PED_CPU_TO_LE32 (fs_info->fat->last_alloc);
435 	is->signature_3 = PED_CPU_TO_LE16 (FAT32_INFO_MAGIC3);
436 
437 	return 1;
438 }
439 
440 int
fat_info_sector_write(const FatInfoSector * is,PedFileSystem * fs)441 fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs)
442 {
443 	FatSpecific*	fs_info = FAT_SPECIFIC (fs);
444 
445 	PED_ASSERT (is != NULL, return 0);
446 
447 	if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1))
448 		return 0;
449 	return ped_geometry_sync (fs->geom);
450 }
451 #endif /* !DISCOVER_ONLY */
452 
453