OSDN Git Service

Updated GPL license boilerplate.
[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 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
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
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
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
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
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
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
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
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
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