OSDN Git Service

maint: update copyrights in r/
[android-x86/external-parted.git] / libparted / fs / r / fat / fat.c
1 /*
2     libparted
3     Copyright (C) 1998-2001, 2007-2012 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 <string.h>
21 #include <uuid/uuid.h>
22
23 #include "fat.h"
24 #include "calc.h"
25
26 PedFileSystem*
27 fat_alloc (const PedGeometry* geom)
28 {
29         PedFileSystem*          fs;
30
31         fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
32         if (!fs)
33                 goto error;
34
35         fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
36         if (!fs->type_specific)
37                 goto error_free_fs;
38
39         fs->geom = ped_geometry_duplicate (geom);
40         if (!fs->geom)
41                 goto error_free_type_specific;
42
43         fs->checked = 0;
44         return fs;
45
46 error_free_type_specific:
47         free (fs->type_specific);
48 error_free_fs:
49         free (fs);
50 error:
51         return NULL;
52 }
53
54 /* Requires the boot sector to be analysed */
55 int
56 fat_alloc_buffers (PedFileSystem* fs)
57 {
58         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
59
60         fs_info->buffer_sectors = BUFFER_SIZE;
61         fs_info->buffer = ped_malloc (fs_info->buffer_sectors * 512);
62         if (!fs_info->buffer)
63                 goto error;
64
65         fs_info->cluster_info = ped_malloc (fs_info->cluster_count + 2);
66         if (!fs_info->cluster_info)
67                 goto error_free_buffer;
68
69         return 1;
70
71 error_free_buffer:
72         free (fs_info->buffer);
73 error:
74         return 0;
75 };
76
77 void
78 fat_free_buffers (PedFileSystem* fs)
79 {
80         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
81
82         free (fs_info->cluster_info);
83         free (fs_info->buffer);
84 }
85
86 void
87 fat_free (PedFileSystem* fs)
88 {
89         ped_geometry_destroy (fs->geom);
90         free (fs->type_specific);
91         free (fs);
92 }
93
94 int
95 fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors)
96 {
97         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
98
99         PED_ASSERT (fs_info->cluster_sectors % frag_sectors == 0
100                         && frag_sectors <= fs_info->cluster_sectors);
101
102         fs_info->frag_size = frag_sectors * 512;
103         fs_info->frag_sectors = frag_sectors;
104         fs_info->buffer_frags = fs_info->buffer_sectors / frag_sectors;
105         fs_info->cluster_frags = fs_info->cluster_sectors / frag_sectors;
106         fs_info->frag_count = fs_info->cluster_count * fs_info->cluster_frags;
107
108         return 1;
109 }
110
111 PedGeometry*
112 fat_probe (PedGeometry* geom, FatType* fat_type)
113 {
114         PedFileSystem*          fs;
115         FatSpecific*            fs_info;
116         PedGeometry*            result;
117
118         fs = fat_alloc (geom);
119         if (!fs)
120                 goto error;
121         fs_info = (FatSpecific*) fs->type_specific;
122
123         if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
124                 goto error_free_fs;
125         if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
126                 goto error_free_fs;
127
128         *fat_type = fs_info->fat_type;
129         result = ped_geometry_new (geom->dev, geom->start,
130                                    fs_info->sector_count);
131
132         fat_free (fs);
133         return result;
134
135 error_free_fs:
136         fat_free (fs);
137 error:
138         return NULL;
139 }
140
141 PedGeometry*
142 fat_probe_fat16 (PedGeometry* geom)
143 {
144         FatType         fat_type;
145         PedGeometry*    probed_geom = fat_probe (geom, &fat_type);
146
147         if (probed_geom) {
148                 if (fat_type == FAT_TYPE_FAT16)
149                         return probed_geom;
150                 ped_geometry_destroy (probed_geom);
151         }
152         return NULL;
153 }
154
155 PedGeometry*
156 fat_probe_fat32 (PedGeometry* geom)
157 {
158         FatType         fat_type;
159         PedGeometry*    probed_geom = fat_probe (geom, &fat_type);
160
161         if (probed_geom) {
162                 if (fat_type == FAT_TYPE_FAT32)
163                         return probed_geom;
164                 ped_geometry_destroy (probed_geom);
165         }
166         return NULL;
167 }
168
169 #ifndef DISCOVER_ONLY
170 int
171 fat_clobber (PedGeometry* geom)
172 {
173         FatBootSector           boot_sector;
174
175         if (!fat_boot_sector_read (&boot_sector, geom))
176                 return 1;
177
178         boot_sector.system_id[0] = 0;
179         boot_sector.boot_sign = 0;
180         if (boot_sector.u.fat16.fat_name[0] == 'F')
181                 boot_sector.u.fat16.fat_name[0] = 0;
182         if (boot_sector.u.fat32.fat_name[0] == 'F')
183                 boot_sector.u.fat32.fat_name[0] = 0;
184
185         return ped_geometry_write (geom, &boot_sector, 0, 1);
186 }
187
188 static int
189 _init_fats (PedFileSystem* fs)
190 {
191         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
192         FatCluster      table_size;
193
194         table_size = fs_info->fat_sectors * 512
195                      / fat_table_entry_size (fs_info->fat_type);
196         fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
197         if (!fs_info->fat)
198                 goto error;
199
200         if (!fat_table_read (fs_info->fat, fs, 0))
201                 goto error_free_fat;
202
203         return 1;
204
205 error_free_fat:
206         fat_table_destroy (fs_info->fat);
207 error:
208         return 0;
209 }
210
211 PedFileSystem*
212 fat_open (PedGeometry* geom)
213 {
214         PedFileSystem*          fs;
215         FatSpecific*            fs_info;
216
217         fs = fat_alloc (geom);
218         if (!fs)
219                 goto error;
220         fs_info = (FatSpecific*) fs->type_specific;
221
222         if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
223                 goto error_free_fs;
224         if (!fat_boot_sector_analyse (&fs_info->boot_sector, fs))
225                 goto error_free_fs;
226         fs->type = (fs_info->fat_type == FAT_TYPE_FAT16)
227                                 ? &fat16_type
228                                 : &fat32_type;
229         if (fs_info->fat_type == FAT_TYPE_FAT32) {
230                 if (!fat_info_sector_read (&fs_info->info_sector, fs))
231                         goto error_free_fs;
232         }
233
234         if (!_init_fats (fs))
235                 goto error_free_fs;
236         if (!fat_alloc_buffers (fs))
237                 goto error_free_fat_table;
238         if (!fat_collect_cluster_info (fs))
239                 goto error_free_buffers;
240
241         return fs;
242
243 error_free_buffers:
244         fat_free_buffers (fs);
245 error_free_fat_table:
246         fat_table_destroy (fs_info->fat);
247 error_free_fs:
248         fat_free (fs);
249 error:
250         return NULL;
251 }
252
253 static int
254 fat_root_dir_clear (PedFileSystem* fs)
255 {
256         FatSpecific*            fs_info = FAT_SPECIFIC (fs);
257         memset (fs_info->buffer, 0, 512 * fs_info->root_dir_sector_count);
258         return ped_geometry_write (fs->geom, fs_info->buffer,
259                                    fs_info->root_dir_offset,
260                                    fs_info->root_dir_sector_count);
261 }
262
263 /* hack: use the ext2 uuid library to generate a reasonably random (hopefully
264  * with /dev/random) number.  Unfortunately, we can only use 4 bytes of it
265  */
266 static uint32_t
267 _gen_new_serial_number (void)
268 {
269         union {
270                 uuid_t uuid;
271                 uint32_t i;
272         } uu32;
273
274         uuid_generate (uu32.uuid);
275         return uu32.i;
276 }
277
278 PedFileSystem*
279 fat_create (PedGeometry* geom, FatType fat_type, PedTimer* timer)
280 {
281         PedFileSystem*          fs;
282         FatSpecific*            fs_info;
283         FatCluster              table_size;
284
285         fs = fat_alloc (geom);
286         if (!fs)
287                 goto error;
288         fs_info = (FatSpecific*) fs->type_specific;
289
290         fs_info->logical_sector_size = 1;
291         fs_info->sectors_per_track = geom->dev->bios_geom.sectors;
292         fs_info->heads = geom->dev->bios_geom.heads;
293         fs_info->sector_count = fs->geom->length;
294         fs_info->fat_table_count = 2;
295 /* some initial values, to be changed later */
296         fs_info->root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
297                                           / (512 / sizeof (FatDirEntry));
298         fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
299
300         fs_info->fat_type = fat_type;
301         if (!fat_calc_sizes (fs->geom->length, 0,
302                         fs_info->fat_type,
303                         fs_info->root_dir_sector_count,
304                         &fs_info->cluster_sectors,
305                         &fs_info->cluster_count,
306                         &fs_info->fat_sectors)) {
307                 ped_exception_throw (PED_EXCEPTION_ERROR,
308                         PED_EXCEPTION_CANCEL,
309                         _("Partition too big/small for a %s file system."),
310                         (fat_type == FAT_TYPE_FAT16)
311                                 ? fat16_type.name
312                                 : fat32_type.name);
313                 goto error_free_fs;
314         }
315
316         fs_info->cluster_size = fs_info->cluster_sectors * 512;
317
318         fs_info->fat_offset = fat_min_reserved_sector_count (fs_info->fat_type);
319         fs_info->dir_entries_per_cluster
320                 = fs_info->cluster_size / sizeof (FatDirEntry);
321
322         if (fs_info->fat_type == FAT_TYPE_FAT16) {
323                 /* FAT16 */
324                 fs->type = &fat16_type;
325
326                 if (fs_info->cluster_count
327                         > fat_max_cluster_count (fs_info->fat_type)) {
328                         fs_info->cluster_count
329                                 = fat_max_cluster_count (fs_info->fat_type);
330                 }
331
332                 fs_info->root_dir_sector_count
333                         = FAT_ROOT_DIR_ENTRY_COUNT
334                                 / (512 / sizeof (FatDirEntry));
335                 fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
336                 fs_info->root_dir_offset
337                         = fs_info->fat_offset
338                         + fs_info->fat_sectors * fs_info->fat_table_count;
339                 fs_info->cluster_offset
340                         = fs_info->root_dir_offset
341                           + fs_info->root_dir_sector_count;
342         } else {
343                 /* FAT32 */
344                 fs->type = &fat32_type;
345
346                 fs_info->info_sector_offset = 1;
347                 fs_info->boot_sector_backup_offset = 6;
348
349                 fs_info->root_dir_sector_count = 0;
350                 fs_info->root_dir_entry_count = 0;
351                 fs_info->root_dir_offset = 0;
352
353                 fs_info->cluster_offset
354                         = fs_info->fat_offset
355                           + fs_info->fat_sectors * fs_info->fat_table_count;
356         }
357
358         table_size = fs_info->fat_sectors * 512
359                      / fat_table_entry_size (fs_info->fat_type);
360         fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
361         if (!fs_info->fat)
362                 goto error_free_fs;
363         fat_table_set_cluster_count (fs_info->fat, fs_info->cluster_count);
364         if (!fat_alloc_buffers (fs))
365                 goto error_free_fat_table;
366
367         if (fs_info->fat_type == FAT_TYPE_FAT32) {
368                 fs_info->root_cluster
369                         = fat_table_alloc_cluster (fs_info->fat);
370                 fat_table_set_eof (fs_info->fat, fs_info->root_cluster);
371                 memset (fs_info->buffer, 0, fs_info->cluster_size);
372                 if (!fat_write_cluster (fs, fs_info->buffer,
373                                         fs_info->root_cluster))
374                         return 0;
375         }
376
377         fs_info->serial_number = _gen_new_serial_number ();
378
379         if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector))
380                 goto error_free_buffers;
381         if (!fat_boot_sector_generate (&fs_info->boot_sector, fs))
382                 goto error_free_buffers;
383         if (!fat_boot_sector_write (&fs_info->boot_sector, fs))
384                 goto error_free_buffers;
385         if (fs_info->fat_type == FAT_TYPE_FAT32) {
386                 if (!fat_info_sector_generate (&fs_info->info_sector, fs))
387                         goto error_free_buffers;
388                 if (!fat_info_sector_write (&fs_info->info_sector, fs))
389                         goto error_free_buffers;
390         }
391
392         if (!fat_table_write_all (fs_info->fat, fs))
393                 goto error_free_buffers;
394
395         if (fs_info->fat_type == FAT_TYPE_FAT16) {
396                 if (!fat_root_dir_clear (fs))
397                         goto error_free_buffers;
398         }
399
400         return fs;
401
402 error_free_buffers:
403         fat_free_buffers (fs);
404 error_free_fat_table:
405         fat_table_destroy (fs_info->fat);
406 error_free_fs:
407         fat_free (fs);
408 error:
409         return NULL;
410 }
411
412 PedFileSystem*
413 fat_create_fat16 (PedGeometry* geom, PedTimer* timer)
414 {
415         return fat_create (geom, FAT_TYPE_FAT16, timer);
416 }
417
418 PedFileSystem*
419 fat_create_fat32 (PedGeometry* geom, PedTimer* timer)
420 {
421         return fat_create (geom, FAT_TYPE_FAT32, timer);
422 }
423
424 int
425 fat_close (PedFileSystem* fs)
426 {
427         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
428
429         fat_free_buffers (fs);
430         fat_table_destroy (fs_info->fat);
431         fat_free (fs);
432         return 1;
433 }
434
435 /* Hack: just resize the file system outside of its boundaries! */
436 PedFileSystem*
437 fat_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
438 {
439         PedFileSystem*          new_fs;
440
441         new_fs = ped_file_system_open (fs->geom);
442         if (!new_fs)
443                 goto error;
444         if (!ped_file_system_resize (new_fs, geom, timer))
445                 goto error_close_new_fs;
446         return new_fs;
447
448 error_close_new_fs:
449         ped_file_system_close (new_fs);
450 error:
451         return 0;
452 }
453
454 static int
455 _compare_fats (PedFileSystem* fs)
456 {
457         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
458         FatTable*       table_copy;
459         FatCluster      table_size;
460         int             i;
461
462         table_size = fs_info->fat_sectors * 512
463                      / fat_table_entry_size (fs_info->fat_type);
464
465         table_copy = fat_table_new (fs_info->fat_type, table_size);
466         if (!table_copy)
467                 goto error;
468
469         for (i = 1; i < fs_info->fat_table_count; i++) {
470                 if (!fat_table_read (table_copy, fs, i))
471                         goto error_free_table_copy;
472                 if (!fat_table_compare (fs_info->fat, table_copy)) {
473                         if (ped_exception_throw (PED_EXCEPTION_ERROR,
474                                 PED_EXCEPTION_IGNORE_CANCEL,
475                                 _("The FATs don't match.  If you don't know "
476                                   "what this means, then select cancel, run "
477                                   "scandisk on the file system, and then come "
478                                   "back."))
479                             != PED_EXCEPTION_IGNORE)
480                                 goto error_free_table_copy;
481                 }
482         }
483
484         fat_table_destroy (table_copy);
485         return 1;
486
487 error_free_table_copy:
488         fat_table_destroy (table_copy);
489 error:
490         return 0;
491 }
492
493 int
494 fat_check (PedFileSystem* fs, PedTimer* timer)
495 {
496         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
497         PedSector       cluster_sectors;
498         FatCluster      cluster_count;
499         PedSector       fat_sectors;
500         PedSector       align_sectors;
501         FatCluster      info_free_clusters;
502
503         align_sectors = fs_info->fat_offset
504                         - fat_min_reserved_sector_count (fs_info->fat_type);
505
506         if (!fat_calc_sizes (fs->geom->length,
507                              align_sectors,
508                              fs_info->fat_type,
509                              fs_info->root_dir_sector_count,
510                              &cluster_sectors,
511                              &cluster_count,
512                              &fat_sectors)) {
513                 if (ped_exception_throw (PED_EXCEPTION_BUG,
514                         PED_EXCEPTION_IGNORE_CANCEL,
515                         _("There are no possible configurations for this FAT "
516                           "type."))
517                                 != PED_EXCEPTION_IGNORE)
518                         goto error;
519         }
520
521         if (fs_info->fat_type == FAT_TYPE_FAT16) {
522                 if (cluster_sectors != fs_info->cluster_sectors
523                     || cluster_count != fs_info->cluster_count
524                     || fat_sectors != fs_info->fat_sectors) {
525                         if (ped_exception_throw (PED_EXCEPTION_WARNING,
526                                 PED_EXCEPTION_IGNORE_CANCEL,
527                                 _("File system doesn't have expected sizes for "
528                                   "Windows to like it.  "
529                                   "Cluster size is %dk (%dk expected); "
530                                   "number of clusters is %d (%d expected); "
531                                   "size of FATs is %d sectors (%d expected)."),
532                                 (int) fs_info->cluster_sectors / 2,
533                                         (int) cluster_sectors / 2,
534                                 (int) fs_info->cluster_count,
535                                         (int) cluster_count,
536                                 (int) fs_info->fat_sectors,
537                                         (int) fat_sectors)
538                                         != PED_EXCEPTION_IGNORE)
539                                 goto error;
540                 }
541         }
542
543         if (fs_info->fat_type == FAT_TYPE_FAT32) {
544                 info_free_clusters
545                         = PED_LE32_TO_CPU (fs_info->info_sector.free_clusters);
546                 if (info_free_clusters != (FatCluster) -1
547                     && info_free_clusters != fs_info->fat->free_cluster_count) {
548                         if (ped_exception_throw (PED_EXCEPTION_WARNING,
549                                 PED_EXCEPTION_IGNORE_CANCEL,
550                                 _("File system is reporting the free space as "
551                                   "%d clusters, not %d clusters."),
552                                 info_free_clusters,
553                                 fs_info->fat->free_cluster_count)
554                                         != PED_EXCEPTION_IGNORE)
555                                 goto error;
556                 }
557         }
558
559         if (!_compare_fats (fs))
560                 goto error;
561
562         fs->checked = 1;
563         return 1;       /* existence of fs implies consistency ;-) */
564
565 error:
566         return 0;
567 }
568
569 /* Calculates how much space there will be in clusters in:
570  *      old_fs intersect the-new-fs
571  */
572 static PedSector
573 _calc_resize_data_size (
574         const PedFileSystem* old_fs,
575         PedSector new_cluster_sectors,
576         FatCluster new_cluster_count,
577         PedSector new_fat_size)
578 {
579         FatSpecific*    old_fs_info = FAT_SPECIFIC (old_fs);
580         PedSector       fat_size_delta;
581
582         fat_size_delta = old_fs_info->fat_sectors - new_fat_size;
583         return new_cluster_sectors * new_cluster_count - fat_size_delta * 2;
584 }
585
586 static int
587 _test_resize_size (const PedFileSystem* fs,
588                    PedSector length, PedSector min_data_size)
589 {
590         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
591         PedGeometry     geom;
592         PedSector       _cluster_sectors;
593         FatCluster      _cluster_count;
594         PedSector       _fat_size;
595
596         ped_geometry_init (&geom, fs->geom->dev, fs->geom->start, length);
597
598         if (fat_calc_resize_sizes (
599                                 &geom,
600                                 fs_info->cluster_sectors,
601                                 FAT_TYPE_FAT16,
602                                 fs_info->root_dir_sector_count,
603                                 fs_info->cluster_sectors,
604                                 &_cluster_sectors,
605                                 &_cluster_count,
606                                 &_fat_size)
607             && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
608                                        _fat_size)
609                         >= min_data_size)
610                 return 1;
611
612         if (fat_calc_resize_sizes (
613                                 &geom,
614                                 fs_info->cluster_sectors,
615                                 FAT_TYPE_FAT32,
616                                 0,
617                                 fs_info->cluster_sectors,
618                                 &_cluster_sectors,
619                                 &_cluster_count,
620                                 &_fat_size)
621             && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
622                                        _fat_size)
623                         >= min_data_size)
624                 return 1;
625
626         return 0;
627 }
628
629 /* does a binary search (!) for the mininum size.  Too hard to compute directly
630  * (see calc_sizes() for why!)
631  */
632 static PedSector
633 _get_min_resize_size (const PedFileSystem* fs, PedSector min_data_size)
634 {
635         PedSector       min_length = 0;
636         PedSector       max_length = fs->geom->length;
637         PedSector       length;
638
639         while (min_length < max_length - 1) {
640                 length = (min_length + max_length) / 2;
641                 if (_test_resize_size (fs, length, min_data_size))
642                         max_length = length;
643                 else
644                         min_length = length;
645         }
646
647 /* adds a bit of leeway (64 sectors), for resolving extra issues, like root
648  * directory allocation, that aren't covered here.
649  */
650         return max_length + 64;
651 }
652
653 PedConstraint*
654 fat_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
655 {
656         FatSpecific*    fs_info = FAT_SPECIFIC (fs);
657         PedGeometry     full_dev;
658         PedSector       min_cluster_count;
659         FatCluster      used_clusters;
660         PedSector       min_data_size;
661
662         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
663                 return NULL;
664
665         used_clusters = fs_info->fat->cluster_count
666                         - fs_info->fat->free_cluster_count;
667         min_cluster_count = used_clusters + fs_info->total_dir_clusters;
668         min_data_size = min_cluster_count * fs_info->cluster_sectors;
669
670         return ped_constraint_new (ped_alignment_any, ped_alignment_any,
671                                    &full_dev, &full_dev,
672                                    _get_min_resize_size (fs, min_data_size),
673                                    dev->length);
674 }
675
676 PedConstraint*
677 fat_get_resize_constraint (const PedFileSystem* fs)
678 {
679         return fat_get_copy_constraint (fs, fs->geom->dev);
680 }
681
682 /* FIXME: fat_calc_sizes() needs to say "too big" or "too small", or
683  * something.  This is a really difficult (maths) problem to do
684  * nicely...
685  *      So, this algorithm works if dev->length / 2 is a valid fat_type
686  * size.  (Which is how I got the magic numbers below)
687  */
688 #if 0
689 /* returns: -1 too small, 0 ok, 1 too big */
690 static int
691 _test_create_size (PedSector length, FatType fat_type,
692                    PedSector cluster_sectors, PedSector cluster_count)
693 {
694         PedSector       rootdir_sectors;
695         PedSector       _cluster_sectors;
696         FatCluster      _cluster_count;
697         PedSector       _fat_size;
698
699         rootdir_sectors = (fat_type == FAT_TYPE_FAT16) ? 16 : 0;
700
701         if (!fat_calc_sizes (length, 0, fat_type, rootdir_sectors,
702                              &_cluster_sectors, &_cluster_count, &_fat_size))
703                 return -1; // XXX: doesn't work... can't see a better way!
704
705         if (_cluster_sectors < cluster_sectors)
706                 return -1;
707         if (_cluster_sectors > cluster_sectors)
708                 return 1;
709
710         if (_cluster_count < cluster_count)
711                 return -1;
712         if (_cluster_count > cluster_count)
713                 return 1;
714
715         return 0;
716 }
717
718 static PedSector
719 _get_create_size (PedSector upper_bound, FatType fat_type,
720                   PedSector cluster_sectors, FatCluster cluster_count)
721 {
722         PedSector       min_length = 0;
723         PedSector       max_length = upper_bound;
724         PedSector       length;
725
726         while (1) {
727                 length = (min_length + max_length) / 2;
728                 switch (_test_create_size (length, fat_type, cluster_sectors,
729                                            cluster_count)) {
730                         case -1: min_length = length; break;
731                         case 0: return length;
732                         case 1: max_length = length; break;
733                 }
734                 /* hack... won't always be able to get max cluster count
735                  * with max cluster size, etc. */
736                 if (max_length - min_length == 1)
737                         return min_length;
738         }
739
740         return 0;       /* shut gcc up */
741 }
742 #endif
743
744 PedConstraint*
745 fat_get_create_constraint_fat16 (const PedDevice* dev)
746 {
747         PedGeometry     full_dev;
748         PedSector       min_size;
749         PedSector       max_size;
750
751         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
752                 return NULL;
753
754 #if 0
755         min_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
756                                      fat_min_cluster_size (FAT_TYPE_FAT16),
757                                      fat_min_cluster_count (FAT_TYPE_FAT16));
758         max_size = _get_create_size (dev->length, FAT_TYPE_FAT16,
759                                      fat_max_cluster_size (FAT_TYPE_FAT16),
760                                      fat_max_cluster_count (FAT_TYPE_FAT16));
761         if (!min_size)
762                 return NULL;
763 #else
764         min_size = 65794;
765         max_size = 2097153;
766 #endif
767
768         return ped_constraint_new (
769                         ped_alignment_any, ped_alignment_any,
770                         &full_dev, &full_dev,
771                         min_size, max_size);
772 }
773
774 PedConstraint*
775 fat_get_create_constraint_fat32 (const PedDevice* dev)
776 {
777         PedGeometry     full_dev;
778         PedSector       min_size;
779
780         if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
781                 return NULL;
782
783 #if 0
784         min_size = _get_create_size (dev->length, FAT_TYPE_FAT32,
785                                      fat_min_cluster_size (FAT_TYPE_FAT32),
786                                      fat_min_cluster_count (FAT_TYPE_FAT32));
787         if (!min_size)
788                 return NULL;
789 #else
790         min_size = 525224;
791 #endif
792
793         return ped_constraint_new (
794                         ped_alignment_any, ped_alignment_any,
795                         &full_dev, &full_dev,
796                         min_size, dev->length);
797 }
798 #endif /* !DISCOVER_ONLY */
799
800 #if 0
801
802 static PedFileSystemOps fat16_ops = {
803         probe:          fat_probe_fat16,
804 #ifndef DISCOVER_ONLY
805         clobber:        fat_clobber,
806         open:           fat_open,
807         create:         fat_create_fat16,
808         close:          fat_close,
809         check:          fat_check,
810         resize:         fat_resize,
811         copy:           fat_copy,
812         get_create_constraint:  fat_get_create_constraint_fat16,
813         get_resize_constraint:  fat_get_resize_constraint,
814         get_copy_constraint:    fat_get_copy_constraint,
815 #else /* !DISCOVER_ONLY */
816         clobber:        NULL,
817         open:           NULL,
818         create:         NULL,
819         close:          NULL,
820         check:          NULL,
821         resize:         NULL,
822         copy:           NULL,
823         get_create_constraint:  NULL,
824         get_resize_constraint:  NULL,
825         get_copy_constraint:    NULL,
826 #endif /* !DISCOVER_ONLY */
827 };
828
829 static PedFileSystemOps fat32_ops = {
830         probe:          fat_probe_fat32,
831 #ifndef DISCOVER_ONLY
832         clobber:        fat_clobber,
833         open:           fat_open,
834         create:         fat_create_fat32,
835         close:          fat_close,
836         check:          fat_check,
837         resize:         fat_resize,
838         copy:           fat_copy,
839         get_create_constraint:  fat_get_create_constraint_fat32,
840         get_resize_constraint:  fat_get_resize_constraint,
841         get_copy_constraint:    fat_get_copy_constraint,
842 #else /* !DISCOVER_ONLY */
843         clobber:        NULL,
844         open:           NULL,
845         create:         NULL,
846         close:          NULL,
847         check:          NULL,
848         resize:         NULL,
849         copy:           NULL,
850         get_create_constraint:  NULL,
851         get_resize_constraint:  NULL,
852         get_copy_constraint:    NULL,
853 #endif /* !DISCOVER_ONLY */
854 };
855
856 #define FAT_BLOCK_SIZES ((int[2]){512, 0})
857
858 PedFileSystemType fat16_type = {
859         next:           NULL,
860         ops:            &fat16_ops,
861         name:           "fat16",
862         block_sizes:    FAT_BLOCK_SIZES
863 };
864
865 PedFileSystemType fat32_type = {
866         next:           NULL,
867         ops:            &fat32_ops,
868         name:           "fat32",
869         block_sizes:    FAT_BLOCK_SIZES
870 };
871
872 void
873 ped_file_system_fat_init ()
874 {
875         if (sizeof (FatBootSector) != 512) {
876                 ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
877                         _("GNU Parted was miscompiled: the FAT boot sector "
878                         "should be 512 bytes.  FAT support will be disabled."));
879         } else {
880                 ped_file_system_type_register (&fat16_type);
881                 ped_file_system_type_register (&fat32_type);
882         }
883 }
884
885 void
886 ped_file_system_fat_done ()
887 {
888         ped_file_system_type_unregister (&fat16_type);
889         ped_file_system_type_unregister (&fat32_type);
890 }
891
892 #endif