OSDN Git Service

Avoid compiler warnings with gcc -Wall -Wshadow.
[android-x86/external-parted.git] / libparted / fs / fat / bootsector.c
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 2 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, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
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
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 || PED_LE16_TO_CPU (bs->sector_size) % 512) {
61                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
62                         _("File system has an invalid sector size for a FAT "
63                           "file system."));
64                 return 0;
65         }
66
67         if (!bs->cluster_size) {
68                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
69                         _("File system has an invalid cluster size for a FAT "
70                           "file system."));
71                 return 0;
72         }
73
74         if (!bs->reserved) {
75                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
76                         _("File system has an invalid number of reserved "
77                           "sectors for a FAT file system."));
78                 return 0;
79         }
80
81         if (bs->fats < 1 || bs->fats > 4) {
82                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
83                         _("File system has an invalid number of FATs."));
84                 return 0;
85         }
86
87         return 1;
88 }
89
90 /*
91     Don't trust the FAT12, FAT16 or FAT32 label string.
92  */
93 FatType
94 fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom)
95 {
96         PedSector       logical_sector_size;
97         PedSector       first_cluster_sector;
98         FatCluster      cluster_count;
99
100         if (!PED_LE16_TO_CPU (bs->dir_entries))
101                 return FAT_TYPE_FAT32;
102
103         logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
104
105         first_cluster_sector
106                 = PED_LE16_TO_CPU (bs->reserved) * logical_sector_size
107                   + 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size
108                   + PED_LE16_TO_CPU (bs->dir_entries)
109                         / (512 / sizeof (FatDirEntry));
110         cluster_count = (geom->length - first_cluster_sector)
111                         / bs->cluster_size / logical_sector_size;
112         if (cluster_count > MAX_FAT12_CLUSTERS)
113                 return FAT_TYPE_FAT16;
114         else
115                 return FAT_TYPE_FAT12;
116 }
117
118 /* Analyses the boot sector, and sticks appropriate numbers in
119    fs->type_specific.
120
121    Note: you need to subtract (2 * cluster_sectors) off cluster offset,
122    because the first cluster is number 2.  (0 and 1 are not real clusters,
123    and referencing them is a bug)
124  */
125 int
126 fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs)
127 {
128         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
129         int                     fat_entry_size;
130
131         PED_ASSERT (bs != NULL, return 0);
132         
133         if (PED_LE16_TO_CPU (bs->sector_size) != 512) {
134                 if (ped_exception_throw (
135                         PED_EXCEPTION_BUG,
136                         PED_EXCEPTION_IGNORE_CANCEL,
137                         _("This file system has a logical sector size of %d.  "
138                         "GNU Parted is known not to work properly with sector "
139                         "sizes other than 512 bytes."),
140                         (int) PED_LE16_TO_CPU (bs->sector_size))
141                                 != PED_EXCEPTION_IGNORE)
142                         return 0;
143         }
144
145         fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
146
147         fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track);
148         fs_info->heads = PED_LE16_TO_CPU (bs->heads);
149         if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63
150             || fs_info->heads < 1 || fs_info->heads > 255) {
151                 PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom;
152                 int cyl_count = 0;
153
154                 if (fs_info->heads > 0 && fs_info->sectors_per_track > 0)
155                         cyl_count = fs->geom->dev->length / fs_info->heads
156                                         / fs_info->sectors_per_track;
157
158                 switch (ped_exception_throw (
159                         PED_EXCEPTION_ERROR,
160                         PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE
161                         + PED_EXCEPTION_CANCEL,
162                         _("The file system's CHS geometry is (%d, %d, %d), "
163                           "which is invalid.  The partition table's CHS "
164                           "geometry is (%d, %d, %d).  If you select Ignore, "
165                           "the file system's CHS geometry will be left "
166                           "unchanged.  If you select Fix, the file system's "
167                           "CHS geometry will be set to match the partition "
168                           "table's CHS geometry."),
169                          cyl_count, fs_info->heads, fs_info->sectors_per_track,
170                          bios_geom->cylinders, bios_geom->heads,
171                          bios_geom->sectors)) {
172
173                 case PED_EXCEPTION_FIX:
174                         fs_info->sectors_per_track = bios_geom->sectors;
175                         fs_info->heads = bios_geom->heads;
176                         bs->secs_track
177                                 = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
178                         bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
179                         if (!fat_boot_sector_write (bs, fs))
180                                 return 0;
181                         break;
182
183                 case PED_EXCEPTION_CANCEL:
184                         return 0;
185
186                 case PED_EXCEPTION_IGNORE:
187                         break;
188
189                 default:
190                         break;
191                 }
192         }
193
194         if (bs->sectors)
195                 fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors)
196                                                 * fs_info->logical_sector_size;
197         else
198                 fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count)
199                                                 * fs_info->logical_sector_size;
200
201         fs_info->fat_table_count = bs->fats;
202         fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries);
203         fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved)
204                                         * fs_info->logical_sector_size;
205         fs_info->cluster_sectors = bs->cluster_size
206                                    * fs_info->logical_sector_size;
207         fs_info->cluster_size = fs_info->cluster_sectors * 512;
208
209         if (fs_info->logical_sector_size == 0) {
210                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
211                         _("FAT boot sector says logical sector size is 0.  "
212                           "This is weird. "));
213                 return 0;
214         }
215         if (fs_info->fat_table_count == 0) {
216                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
217                         _("FAT boot sector says there are no FAT tables.  This "
218                           "is weird. "));
219                 return 0;
220         }
221         if (fs_info->cluster_sectors == 0) {
222                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
223                         _("FAT boot sector says clusters are 0 sectors.  This "
224                           "is weird. "));
225                 return 0;
226         }
227
228         fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom);
229         if (fs_info->fat_type == FAT_TYPE_FAT12) {
230                 ped_exception_throw (
231                         PED_EXCEPTION_NO_FEATURE,
232                         PED_EXCEPTION_CANCEL,
233                         _("File system is FAT12, which is unsupported."));
234                 return 0;
235         }
236         if (fs_info->fat_type == FAT_TYPE_FAT16) {
237                 fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length)
238                                        * fs_info->logical_sector_size;
239                 fs_info->serial_number
240                         = PED_LE32_TO_CPU (bs->u.fat16.serial_number);
241                 fs_info->root_cluster = 0;
242                 fs_info->root_dir_offset
243                         = fs_info->fat_offset
244                           + fs_info->fat_sectors * fs_info->fat_table_count;
245                 fs_info->root_dir_sector_count
246                         = fs_info->root_dir_entry_count * sizeof (FatDirEntry)
247                           / (512 * fs_info->logical_sector_size);
248                 fs_info->cluster_offset
249                         = fs_info->root_dir_offset
250                           + fs_info->root_dir_sector_count;
251         }
252         if (fs_info->fat_type == FAT_TYPE_FAT32) {
253                 fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
254                                         * fs_info->logical_sector_size;
255                 fs_info->serial_number
256                         = PED_LE32_TO_CPU (bs->u.fat32.serial_number);
257                 fs_info->info_sector_offset
258                     = PED_LE16_TO_CPU (fs_info->boot_sector.u.fat32.info_sector)
259                           * fs_info->logical_sector_size;
260                 fs_info->boot_sector_backup_offset
261                   = PED_LE16_TO_CPU (fs_info->boot_sector.u.fat32.backup_sector)
262                           * fs_info->logical_sector_size;
263                 fs_info->root_cluster
264                         = PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster);
265                 fs_info->root_dir_offset = 0;
266                 fs_info->root_dir_sector_count = 0;
267                 fs_info->cluster_offset
268                         = fs_info->fat_offset
269                           + fs_info->fat_sectors * fs_info->fat_table_count;
270         }
271
272         fs_info->cluster_count
273                 = (fs_info->sector_count - fs_info->cluster_offset)
274                   / fs_info->cluster_sectors;
275
276         fat_entry_size = fat_table_entry_size (fs_info->fat_type);
277         if (fs_info->cluster_count + 2
278                         > fs_info->fat_sectors * 512 / fat_entry_size)
279                 fs_info->cluster_count
280                         = fs_info->fat_sectors * 512 / fat_entry_size - 2;
281
282         fs_info->dir_entries_per_cluster
283                 = fs_info->cluster_size / sizeof (FatDirEntry);
284         return 1;
285 }
286
287 #ifndef DISCOVER_ONLY
288 int
289 fat_boot_sector_set_boot_code (FatBootSector* bs)
290 {
291         PED_ASSERT (bs != NULL, return 0);
292
293         memset (bs, 0, 512);
294         memcpy (bs->boot_jump, FAT_BOOT_JUMP, 3);
295         memcpy (bs->u.fat32.boot_code, FAT_BOOT_CODE, FAT_BOOT_CODE_LENGTH);
296         return 1;
297 }
298
299 int
300 fat_boot_sector_generate (FatBootSector* bs, const PedFileSystem* fs)
301 {
302         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
303
304         PED_ASSERT (bs != NULL, return 0);
305
306         memcpy (bs->system_id, "MSWIN4.1", 8);
307         bs->sector_size = PED_CPU_TO_LE16 (fs_info->logical_sector_size * 512);
308         bs->cluster_size = fs_info->cluster_sectors
309                                 / fs_info->logical_sector_size;
310         bs->reserved = PED_CPU_TO_LE16 (fs_info->fat_offset
311                                         / fs_info->logical_sector_size);
312         bs->fats = fs_info->fat_table_count;
313
314         bs->dir_entries = (fs_info->fat_type == FAT_TYPE_FAT16)
315                           ? PED_CPU_TO_LE16 (fs_info->root_dir_entry_count)
316                           : 0;
317
318         if (fs_info->sector_count / fs_info->logical_sector_size > 0xffff
319                 || fs_info->fat_type == FAT_TYPE_FAT32) {
320                 bs->sectors = 0;
321                 bs->sector_count = PED_CPU_TO_LE32 (fs_info->sector_count
322                                                 / fs_info->logical_sector_size);
323         } else {
324                 bs->sectors = PED_CPU_TO_LE16 (fs_info->sector_count
325                                                / fs_info->logical_sector_size);
326                 bs->sector_count = 0;
327         }
328
329         bs->media = 0xf8;
330
331         bs->secs_track = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
332         bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
333         bs->hidden = PED_CPU_TO_LE32 (fs->geom->start);
334
335         if (fs_info->fat_type == FAT_TYPE_FAT32) {
336                 bs->fat_length = 0;
337                 bs->u.fat32.fat_length = PED_CPU_TO_LE32 (fs_info->fat_sectors
338                                                 / fs_info->logical_sector_size);
339                 bs->u.fat32.flags = 0;  /* FIXME: what the hell are these? */
340                 bs->u.fat32.version = 0;  /* must be 0, for Win98 bootstrap */
341                 bs->u.fat32.root_dir_cluster
342                         = PED_CPU_TO_LE32 (fs_info->root_cluster);
343                 bs->u.fat32.info_sector
344                         = PED_CPU_TO_LE16 (fs_info->info_sector_offset
345                                            / fs_info->logical_sector_size);
346                 bs->u.fat32.backup_sector
347                         = PED_CPU_TO_LE16 (fs_info->boot_sector_backup_offset
348                                            / fs_info->logical_sector_size);
349
350                 bs->u.fat32.drive_num = 0x80;   /* _ALWAYS_ 0x80.  silly DOS */
351
352                 memset (bs->u.fat32.empty_1, 0, 12);
353
354                 bs->u.fat32.ext_signature = 0x29;
355                 bs->u.fat32.serial_number
356                         = PED_CPU_TO_LE32 (fs_info->serial_number);
357                 memcpy (bs->u.fat32.volume_name, "NO NAME    ", 11);
358                 memcpy (bs->u.fat32.fat_name, "FAT32   ", 8);
359         } else {
360                 bs->fat_length
361                         = PED_CPU_TO_LE16 (fs_info->fat_sectors
362                                            / fs_info->logical_sector_size);
363
364                 bs->u.fat16.drive_num = 0x80;   /* _ALWAYS_ 0x80.  silly DOS */
365
366                 bs->u.fat16.ext_signature = 0x29;
367                 bs->u.fat16.serial_number
368                         = PED_CPU_TO_LE32 (fs_info->serial_number);
369                 memcpy (bs->u.fat16.volume_name, "NO NAME    ", 11);
370                 memcpy (bs->u.fat16.fat_name, "FAT16   ", 8);
371         }
372
373         bs->boot_sign = PED_CPU_TO_LE16 (0xaa55);
374
375         return 1;
376 }
377
378 int
379 fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs)
380 {
381         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
382
383         PED_ASSERT (bs != NULL, return 0);
384
385         if (!ped_geometry_write (fs->geom, bs, 0, 1))
386                 return 0;
387         if (fs_info->fat_type == FAT_TYPE_FAT32) {
388                 if (!ped_geometry_write (fs->geom, bs,
389                                          fs_info->boot_sector_backup_offset, 1))
390                         return 0;
391         }
392         return ped_geometry_sync (fs->geom);
393 }
394
395 int
396 fat_info_sector_read (FatInfoSector* is, const PedFileSystem* fs)
397 {
398         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
399         int             status;
400
401         PED_ASSERT (is != NULL, return 0);
402         
403         if (!ped_geometry_read (fs->geom, is, fs_info->info_sector_offset, 1))
404                 return 0;
405
406         if (PED_LE32_TO_CPU (is->signature_2) != FAT32_INFO_MAGIC2) {
407                 status = ped_exception_throw (PED_EXCEPTION_WARNING,
408                                 PED_EXCEPTION_IGNORE_CANCEL,
409                                 _("The information sector has the wrong "
410                                 "signature (%x).  Select cancel for now, "
411                                 "and send in a bug report.  If you're "
412                                 "desperate, it's probably safe to ignore."),
413                                 PED_LE32_TO_CPU (is->signature_2));
414                 if (status == PED_EXCEPTION_CANCEL) return 0;
415         }
416         return 1;
417 }
418
419 int
420 fat_info_sector_generate (FatInfoSector* is, const PedFileSystem* fs)
421 {
422         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
423
424         PED_ASSERT (is != NULL, return 0);
425         
426         fat_table_count_stats (fs_info->fat);
427
428         memset (is, 0, 512);
429
430         is->signature_1 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC1);
431         is->signature_2 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC2);
432         is->free_clusters = PED_CPU_TO_LE32 (fs_info->fat->free_cluster_count);
433         is->next_cluster = PED_CPU_TO_LE32 (fs_info->fat->last_alloc);
434         is->signature_3 = PED_CPU_TO_LE16 (FAT32_INFO_MAGIC3);
435
436         return 1;
437 }
438
439 int
440 fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs)
441 {
442         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
443
444         PED_ASSERT (is != NULL, return 0);
445         
446         if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1))
447                 return 0;
448         return ped_geometry_sync (fs->geom);
449 }
450 #endif /* !DISCOVER_ONLY */
451