OSDN Git Service

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