OSDN Git Service

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