OSDN Git Service

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