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