xref: /onnv-gate/usr/src/lib/libparted/common/libparted/filesys.c (revision 9663:ace9a2ac3683)
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 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 /** \file filesys.c */
20 
21 /**
22  * \addtogroup PedFileSystem
23  *
24  * \note File systems exist on a PedGeometry - NOT a PedPartition.
25  *
26  * @{
27  */
28 
29 #include <config.h>
30 
31 #include <parted/parted.h>
32 #include <parted/debug.h>
33 
34 #if ENABLE_NLS
35 #  include <libintl.h>
36 #  define _(String) dgettext (PACKAGE, String)
37 #else
38 #  define _(String) (String)
39 #endif /* ENABLE_NLS */
40 
41 #define BUFFER_SIZE	4096		/* in sectors */
42 
43 static PedFileSystemType*	fs_types = NULL;
44 
45 void
ped_file_system_type_register(PedFileSystemType * fs_type)46 ped_file_system_type_register (PedFileSystemType* fs_type)
47 {
48 	PED_ASSERT (fs_type != NULL, return);
49 	PED_ASSERT (fs_type->ops != NULL, return);
50 	PED_ASSERT (fs_type->name != NULL, return);
51 
52 	/* pretend that "next" isn't part of the struct :-) */
53 	((struct _PedFileSystemType*) fs_type)->next = fs_types;
54 	fs_types = (struct _PedFileSystemType*) fs_type;
55 }
56 
57 void
ped_file_system_type_unregister(PedFileSystemType * fs_type)58 ped_file_system_type_unregister (PedFileSystemType* fs_type)
59 {
60 	PedFileSystemType*	walk;
61 	PedFileSystemType*	last = NULL;
62 
63 	PED_ASSERT (fs_types != NULL, return);
64 	PED_ASSERT (fs_type != NULL, return);
65 
66 	for (walk = fs_types; walk && walk != fs_type;
67                 last = walk, walk = walk->next);
68 
69 	PED_ASSERT (walk != NULL, return);
70 	if (last)
71 		((struct _PedFileSystemType*) last)->next = fs_type->next;
72 	else
73 		fs_types = fs_type->next;
74 }
75 
76 /**
77  * Get a PedFileSystemType by its @p name.
78  *
79  * @return @c NULL if none found.
80  */
81 PedFileSystemType*
ped_file_system_type_get(const char * name)82 ped_file_system_type_get (const char* name)
83 {
84 	PedFileSystemType*	walk;
85 
86 	PED_ASSERT (name != NULL, return NULL);
87 
88 	for (walk = fs_types; walk != NULL; walk = walk->next) {
89 		if (!strcasecmp (walk->name, name))
90 			break;
91 	}
92 	return walk;
93 }
94 
95 /**
96  * Get the next PedFileSystemType after @p fs_type.
97  *
98  * @return @c NULL if @p fs_type is the last item in the list.
99  */
100 PedFileSystemType*
ped_file_system_type_get_next(const PedFileSystemType * fs_type)101 ped_file_system_type_get_next (const PedFileSystemType* fs_type)
102 {
103 	if (fs_type)
104 		return fs_type->next;
105 	else
106 		return fs_types;
107 }
108 
109 /**
110  * Attempt to find a file system and return the region it occupies.
111  *
112  * @param fs_type The file system type to probe for.
113  * @param geom The region to be searched.
114  *
115  * @return @p NULL if @p fs_type file system wasn't detected
116  */
117 PedGeometry*
ped_file_system_probe_specific(const PedFileSystemType * fs_type,PedGeometry * geom)118 ped_file_system_probe_specific (
119 		const PedFileSystemType* fs_type, PedGeometry* geom)
120 {
121 	PedGeometry*	result;
122 
123 	PED_ASSERT (fs_type != NULL, return NULL);
124 	PED_ASSERT (fs_type->ops->probe != NULL, return NULL);
125 	PED_ASSERT (geom != NULL, return NULL);
126 
127 	if (!ped_device_open (geom->dev))
128 		return 0;
129 	result = fs_type->ops->probe (geom);
130 	ped_device_close (geom->dev);
131 	return result;
132 }
133 
134 static int
_test_open(PedFileSystemType * fs_type,PedGeometry * geom)135 _test_open (PedFileSystemType* fs_type, PedGeometry* geom)
136 {
137 	PedFileSystem*		fs;
138 
139 	ped_exception_fetch_all ();
140 	fs = fs_type->ops->open (geom);
141 	if (fs)
142 		fs_type->ops->close (fs);
143 	else
144 		ped_exception_catch ();
145 	ped_exception_leave_all ();
146 	return fs != NULL;
147 }
148 
149 static PedFileSystemType*
_probe_with_open(PedGeometry * geom,int detected_count,PedFileSystemType * detected[])150 _probe_with_open (PedGeometry* geom, int detected_count,
151 		  PedFileSystemType* detected[])
152 {
153 	int			i;
154 	PedFileSystemType*	open_detected = NULL;
155 
156 	ped_device_open (geom->dev);
157 
158 	/* If one and only one file system that Parted is able to open
159 	 * can be successfully opened on this geometry, return it.
160 	 * If more than one can be, return NULL.
161 	 */
162 	for (i=0; i<detected_count; i++) {
163 		if (!detected[i]->ops->open || !_test_open (detected [i], geom))
164 			continue;
165 
166 		if (open_detected) {
167 			ped_device_close (geom->dev);
168 			return NULL;
169 		} else {
170 			open_detected = detected [i];
171 		}
172 	}
173 
174 	/* If no file system has been successfully opened, and
175 	 * if Parted has detected at most one unopenable file system,
176 	 * return it.
177 	 */
178 	if (!open_detected)
179 	for (i=0; i<detected_count; i++) {
180 		if (detected[i]->ops->open)
181 			continue;
182 		if (open_detected) {
183 			ped_device_close (geom->dev);
184 			return NULL;
185 		} else {
186 			open_detected = detected [i];
187 		}
188 	}
189 
190 	ped_device_close (geom->dev);
191 	return open_detected;
192 }
193 
194 static int
_geometry_error(const PedGeometry * a,const PedGeometry * b)195 _geometry_error (const PedGeometry* a, const PedGeometry* b)
196 {
197 	PedSector	start_delta = a->start - b->start;
198 	PedSector	end_delta = a->end - b->end;
199 
200 	return abs (start_delta) + abs (end_delta);
201 }
202 
203 static PedFileSystemType*
_best_match(const PedGeometry * geom,PedFileSystemType * detected[],const int detected_error[],int detected_count)204 _best_match (const PedGeometry* geom, PedFileSystemType* detected [],
205 	     const int detected_error [], int detected_count)
206 {
207 	int		best_match = 0;
208 	int		i;
209 	PedSector	min_error;
210 
211 	min_error = PED_MAX (4096, geom->length / 100);
212 
213 	for (i = 1; i < detected_count; i++) {
214 		if (detected_error [i] < detected_error [best_match])
215 			best_match = i;
216 	}
217 
218 	/* make sure the best match is significantly better than all the
219 	 * other matches
220 	 */
221 	for (i = 0; i < detected_count; i++) {
222 		if (i == best_match)
223 			continue;
224 
225 		if (abs (detected_error [best_match] - detected_error [i])
226 				< min_error)
227 			return NULL;
228 	}
229 
230 	return detected [best_match];
231 }
232 
233 
234 /**
235  * Attempt to detect a file system in region \p geom.
236  * This function tries to be clever at dealing with ambiguous
237  * situations, such as when one file system was not completely erased before a
238  * new file system was created on top of it.
239  *
240  * \return a new PedFileSystem on success, \c NULL on failure
241  */
242 PedFileSystemType*
ped_file_system_probe(PedGeometry * geom)243 ped_file_system_probe (PedGeometry* geom)
244 {
245 	PedFileSystemType*	detected[32];
246 	int			detected_error[32];
247 	int			detected_count = 0;
248 	PedFileSystemType*	walk = NULL;
249 
250 	PED_ASSERT (geom != NULL, return NULL);
251 
252 	if (!ped_device_open (geom->dev))
253 		return NULL;
254 
255 	ped_exception_fetch_all ();
256 	while ( (walk = ped_file_system_type_get_next (walk)) ) {
257 		PedGeometry*	probed;
258 
259 		probed = ped_file_system_probe_specific (walk, geom);
260 		if (probed) {
261 			detected [detected_count] = walk;
262 			detected_error [detected_count]
263 				= _geometry_error (geom, probed);
264 			detected_count++;
265 			ped_geometry_destroy (probed);
266 		} else {
267 			ped_exception_catch ();
268 		}
269 	}
270 	ped_exception_leave_all ();
271 
272 	ped_device_close (geom->dev);
273 
274 	if (!detected_count)
275 		return NULL;
276 	walk = _best_match (geom, detected, detected_error, detected_count);
277 	if (walk)
278 		return walk;
279 	return _probe_with_open (geom, detected_count, detected);
280 }
281 
282 /**
283  * This function erases all file system signatures that indicate that a
284  * file system occupies a given region described by \p geom.
285  * After this operation ped_file_system_probe() won't detect any file system.
286  *
287  * \note ped_file_system_create() calls this before creating a new file system.
288  *
289  * \return \c 1 on success, \c 0 on failure
290  */
291 int
ped_file_system_clobber(PedGeometry * geom)292 ped_file_system_clobber (PedGeometry* geom)
293 {
294 	PedFileSystemType*	fs_type = NULL;
295 
296 	PED_ASSERT (geom != NULL, return 0);
297 
298 	if (!ped_device_open (geom->dev))
299 		goto error;
300 
301 	ped_exception_fetch_all ();
302 	while ((fs_type = ped_file_system_type_get_next (fs_type))) {
303 		PedGeometry*	probed;
304 
305 		if (!fs_type->ops->clobber)
306 			continue;
307 
308 		probed = ped_file_system_probe_specific (fs_type, geom);
309 		if (!probed) {
310 			ped_exception_catch ();
311 			continue;
312 		}
313 		ped_geometry_destroy (probed);
314 
315 		if (fs_type->ops->clobber && !fs_type->ops->clobber (geom)) {
316 			ped_exception_leave_all ();
317 			goto error_close_dev;
318 		}
319 	}
320 	ped_device_close (geom->dev);
321 	ped_exception_leave_all ();
322 	return 1;
323 
324 error_close_dev:
325 	ped_device_close (geom->dev);
326 error:
327 	return 0;
328 }
329 
330 /* This function erases all signatures that indicate the presence of
331  * a file system in a particular region, without erasing any data
332  * contained inside the "exclude" region.
333  */
334 static int
ped_file_system_clobber_exclude(PedGeometry * geom,const PedGeometry * exclude)335 ped_file_system_clobber_exclude (PedGeometry* geom,
336 				 const PedGeometry* exclude)
337 {
338 	PedGeometry*    clobber_geom;
339 	int             status;
340 
341 	if (ped_geometry_test_sector_inside (exclude, geom->start))
342 		return 1;
343 
344 	clobber_geom = ped_geometry_duplicate (geom);
345 	if (ped_geometry_test_overlap (clobber_geom, exclude))
346 		ped_geometry_set_end (clobber_geom, exclude->start - 1);
347 
348 	status = ped_file_system_clobber (clobber_geom);
349 	ped_geometry_destroy (clobber_geom);
350 	return status;
351 }
352 
353 /**
354  * This function opens the file system stored on \p geom, if it
355  * can find one.
356  * It is often called in the following manner:
357  * \code
358  * 	fs = ped_file_system_open (&part.geom)
359  * \endcode
360  *
361  * \throws PED_EXCEPTION_ERROR if file system could not be detected
362  * \throws PED_EXCEPTION_ERROR if the file system is bigger than its volume
363  * \throws PED_EXCEPTION_NO_FEATURE if opening of a file system stored on
364  * 	\p geom is not implemented
365  *
366  * \return a PedFileSystem on success, \c NULL on failure.
367  */
368 PedFileSystem*
ped_file_system_open(PedGeometry * geom)369 ped_file_system_open (PedGeometry* geom)
370 {
371 	PedFileSystemType*	type;
372 	PedFileSystem*		fs;
373 	PedGeometry*		probed_geom;
374 
375 	PED_ASSERT (geom != NULL, return NULL);
376 
377 	if (!ped_device_open (geom->dev))
378 		goto error;
379 
380 	type = ped_file_system_probe (geom);
381 	if (!type) {
382 		ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
383 				     _("Could not detect file system."));
384 		goto error_close_dev;
385 	}
386 
387 	probed_geom = ped_file_system_probe_specific (type, geom);
388 	if (!probed_geom)
389 		goto error_close_dev;
390 	if (!ped_geometry_test_inside (geom, probed_geom)) {
391 		if (ped_exception_throw (
392 			PED_EXCEPTION_ERROR,
393 			PED_EXCEPTION_IGNORE_CANCEL,
394 			_("The file system is bigger than its volume!"))
395 				!= PED_EXCEPTION_IGNORE)
396 			goto error_destroy_probed_geom;
397 	}
398 
399 	if (!type->ops->open) {
400 		ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
401 				     PED_EXCEPTION_CANCEL,
402 				     _("Support for opening %s file systems "
403 				       "is not implemented yet."),
404 				     type->name);
405 		goto error_destroy_probed_geom;
406 	}
407 
408 	fs = type->ops->open (probed_geom);
409 	if (!fs)
410 		goto error_destroy_probed_geom;
411 	ped_geometry_destroy (probed_geom);
412 	return fs;
413 
414 error_destroy_probed_geom:
415 	ped_geometry_destroy (probed_geom);
416 error_close_dev:
417 	ped_device_close (geom->dev);
418 error:
419 	return 0;
420 }
421 
422 /**
423  * This function initializes a new file system of type \p type on
424  * a region described by \p geom, writing out appropriate metadata and
425  * signatures.  If \p timer is non-NULL, it is used as the progress meter.
426  *
427  * \throws PED_EXCEPTION_NO_FEATURE if creating file system type \p type
428  * 	is not implemented yet
429  *
430  * \return a PedFileSystem on success, \c NULL on failure
431  */
432 PedFileSystem*
ped_file_system_create(PedGeometry * geom,const PedFileSystemType * type,PedTimer * timer)433 ped_file_system_create (PedGeometry* geom, const PedFileSystemType* type,
434 			PedTimer* timer)
435 {
436 	PedFileSystem*	fs;
437 
438 	PED_ASSERT (geom != NULL, return NULL);
439 	PED_ASSERT (type != NULL, return NULL);
440 
441 	if (!type->ops->create) {
442 		ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
443 				     PED_EXCEPTION_CANCEL,
444 				     _("Support for creating %s file systems "
445 				       "is not implemented yet."),
446 				     type->name);
447 		goto error;
448 	}
449 
450 	if (!ped_device_open (geom->dev))
451 		goto error;
452 
453 	if (!ped_file_system_clobber (geom))
454 		goto error_close_dev;
455 	fs = type->ops->create (geom, timer);
456 	if (!fs)
457 		goto error_close_dev;
458 	return fs;
459 
460 error_close_dev:
461 	ped_device_close (geom->dev);
462 error:
463 	return 0;
464 }
465 
466 /**
467  * Close file system \p fs.
468  *
469  * \return \c 1 on success, \c 0 on failure
470  */
471 int
ped_file_system_close(PedFileSystem * fs)472 ped_file_system_close (PedFileSystem* fs)
473 {
474 	PedDevice*	dev = fs->geom->dev;
475 
476 	PED_ASSERT (fs != NULL, goto error_close_dev);
477 
478 	if (!fs->type->ops->close (fs))
479 		goto error_close_dev;
480 	ped_device_close (dev);
481 	return 1;
482 
483 error_close_dev:
484 	ped_device_close (dev);
485 	return 0;
486 }
487 
488 /**
489  * Check \p fs file system for errors.
490  *
491  * \throws PED_EXCEPTION_NO_FEATURE if checking file system \p fs is
492  * 	not implemented yet
493  *
494  * \return \c 0 on failure (i.e. unfixed errors)
495  */
496 int
ped_file_system_check(PedFileSystem * fs,PedTimer * timer)497 ped_file_system_check (PedFileSystem* fs, PedTimer* timer)
498 {
499 	PED_ASSERT (fs != NULL, return 0);
500 
501 	if (!fs->type->ops->check) {
502 		ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
503 				     PED_EXCEPTION_CANCEL,
504 				     _("Support for checking %s file systems "
505 				       "is not implemented yet."),
506 				     fs->type->name);
507 		return 0;
508 	}
509 	return fs->type->ops->check (fs, timer);
510 }
511 
512 static int
_raw_copy(const PedGeometry * src,PedGeometry * dest,PedTimer * timer)513 _raw_copy (const PedGeometry* src, PedGeometry* dest, PedTimer* timer)
514 {
515 	char*		buf;
516 	PedSector	pos;
517 
518 	PED_ASSERT (src != NULL, goto error);
519 	PED_ASSERT (dest != NULL, goto error);
520 	PED_ASSERT (src->length <= dest->length, goto error);
521 
522 	buf = ped_malloc (BUFFER_SIZE * 512);		/* FIXME */
523 	if (!buf)
524 		goto error;
525 
526 	if (!ped_device_open (src->dev))
527 		goto error_free_buf;
528 	if (!ped_device_open (dest->dev))
529 		goto error_close_src;
530 
531 	for (pos = 0; pos + BUFFER_SIZE < src->length; pos += BUFFER_SIZE) {
532 		ped_timer_update (timer, 1.0 * pos / src->length);
533 		if (!ped_geometry_read (src, buf, pos, BUFFER_SIZE))
534 			goto error_close_dest;
535 		if (!ped_geometry_write (dest, buf, pos, BUFFER_SIZE))
536 			goto error_close_dest;
537 	}
538 	if (pos < src->length) {
539 		ped_timer_update (timer, 1.0 * pos / src->length);
540 		if (!ped_geometry_read (src, buf, pos, src->length - pos))
541 			goto error_close_dest;
542 		if (!ped_geometry_write (dest, buf, pos, src->length - pos))
543 			goto error_close_dest;
544 	}
545 	ped_timer_update (timer, 1.0);
546 
547 	ped_device_close (src->dev);
548 	ped_device_close (dest->dev);
549 	ped_free (buf);
550 	return 1;
551 
552 error_close_dest:
553 	ped_device_close (dest->dev);
554 error_close_src:
555 	ped_device_close (src->dev);
556 error_free_buf:
557 	ped_free (buf);
558 error:
559 	return 0;
560 }
561 
562 static PedFileSystem*
_raw_copy_and_resize(const PedFileSystem * fs,PedGeometry * geom,PedTimer * timer)563 _raw_copy_and_resize (const PedFileSystem* fs, PedGeometry* geom,
564 		      PedTimer* timer)
565 {
566 	PedFileSystem*	new_fs;
567 	PedTimer*	sub_timer = NULL;
568 
569 	ped_timer_reset (timer);
570 	ped_timer_set_state_name (timer, _("raw block copying"));
571 
572 	sub_timer = ped_timer_new_nested (timer, 0.95);
573 	if (!_raw_copy (fs->geom, geom, sub_timer))
574 		goto error;
575 	ped_timer_destroy_nested (sub_timer);
576 
577 	new_fs = ped_file_system_open (geom);
578 	if (!new_fs)
579 		goto error;
580 
581 	ped_timer_set_state_name (timer, _("growing file system"));
582 
583 	sub_timer = ped_timer_new_nested (timer, 0.05);
584 	if (!ped_file_system_resize (new_fs, geom, sub_timer))
585 		goto error_close_new_fs;
586 	ped_timer_destroy_nested (sub_timer);
587 	return new_fs;
588 
589 error_close_new_fs:
590 	ped_file_system_close (new_fs);
591 error:
592 	ped_timer_destroy_nested (sub_timer);
593 	return NULL;
594 }
595 
596 /**
597  * Create a new file system (of the same type) on \p geom, and
598  * copy the contents of \p fs into the new filesystem.
599  * If \p timer is non-NULL, it is used as the progress meter.
600  *
601  * \throws PED_EXCEPTION_ERROR when trying to copy onto an overlapping partition
602  * \throws PED_EXCEPTION_NO_FEATURE if copying of file system \p fs
603  * 	is not implemented yet
604  *
605  * \return a new PedFileSystem on success, \c NULL on failure
606  */
607 PedFileSystem*
ped_file_system_copy(PedFileSystem * fs,PedGeometry * geom,PedTimer * timer)608 ped_file_system_copy (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
609 {
610 	PedFileSystem* new_fs;
611 
612 	PED_ASSERT (fs != NULL, return 0);
613 	PED_ASSERT (geom != NULL, return 0);
614 
615 	if (!ped_device_open (geom->dev))
616 		goto error;
617 
618 	if (ped_geometry_test_overlap (fs->geom, geom)) {
619 		ped_exception_throw (
620 			PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
621 			_("Can't copy onto an overlapping partition."));
622 		goto error_close_dev;
623 	}
624 
625 	if (!fs->checked && fs->type->ops->check) {
626 		if (!ped_file_system_check (fs, timer))
627 			goto error_close_dev;
628 	}
629 
630 	if (!ped_file_system_clobber_exclude (geom, fs->geom))
631 		goto error_close_dev;
632 
633 	if (!fs->type->ops->copy) {
634 		if (fs->type->ops->resize) {
635 			if (fs->geom->length <= geom->length)
636 				return _raw_copy_and_resize (
637 						fs, (PedGeometry*) geom,
638 						timer);
639 
640 			ped_exception_throw (
641 				PED_EXCEPTION_NO_FEATURE,
642 				PED_EXCEPTION_CANCEL,
643 				_("Direct support for copying file systems is "
644 				  "not yet implemented for %s.  However, "
645 				  "support for resizing is implemented.  "
646 				  "Therefore, the file system can be copied if "
647 				  "the new partition is at least as big as the "
648 				  "old one.  So, either shrink the partition "
649 				  "you are trying to copy, or copy to a bigger "
650 				  "partition."),
651 				fs->type->name);
652 			goto error_close_dev;
653 		} else {
654 			ped_exception_throw (
655 				PED_EXCEPTION_NO_FEATURE,
656 				PED_EXCEPTION_CANCEL,
657 				_("Support for copying %s file systems is not "
658 				  "implemented yet."),
659 				fs->type->name);
660 			goto error_close_dev;
661 		}
662 	}
663 	new_fs = fs->type->ops->copy (fs, geom, timer);
664 	if (!new_fs)
665 		goto error_close_dev;
666 	return new_fs;
667 
668 error_close_dev:
669 	ped_device_close (geom->dev);
670 error:
671 	return NULL;;
672 }
673 
674 /**
675  * Resize \p fs to new geometry \p geom.
676  *
677  * \p geom should satisfy the ped_file_system_get_resize_constraint().
678  * (This isn't asserted, so it's not a bug not to... just it's likely
679  * to fail ;)  If \p timer is non-NULL, it is used as the progress meter.
680  *
681  * \throws PED_EXCEPTION_NO_FEATURE if resizing of file system \p fs
682  * 	is not implemented yet
683  *
684  * \return \c 0 on failure
685  */
686 int
ped_file_system_resize(PedFileSystem * fs,PedGeometry * geom,PedTimer * timer)687 ped_file_system_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
688 {
689 	PED_ASSERT (fs != NULL, return 0);
690 	PED_ASSERT (geom != NULL, return 0);
691 
692 	if (!fs->type->ops->resize) {
693 		ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
694 				     PED_EXCEPTION_CANCEL,
695 				     _("Support for resizing %s file systems "
696 				       "is not implemented yet."),
697 				     fs->type->name);
698 		return 0;
699 	}
700 	if (!fs->checked && fs->type->ops->check) {
701 		if (!ped_file_system_check (fs, timer))
702 			return 0;
703 	}
704 	if (!ped_file_system_clobber_exclude (geom, fs->geom))
705 		return 0;
706 
707 	return fs->type->ops->resize (fs, geom, timer);
708 }
709 
710 /**
711  * This function returns a constraint on the region that all file systems
712  * of a particular type \p fs_type created on device \p dev with
713  * ped_file_system_create() must satisfy. For example, FAT16 file systems must
714  * be at least 32 megabytes.
715  *
716  * \return \c NULL on failure
717  */
718 PedConstraint*
ped_file_system_get_create_constraint(const PedFileSystemType * fs_type,const PedDevice * dev)719 ped_file_system_get_create_constraint (const PedFileSystemType* fs_type,
720 				       const PedDevice* dev)
721 {
722 	PED_ASSERT (fs_type != NULL, return NULL);
723 	PED_ASSERT (dev != NULL, return NULL);
724 
725 	if (!fs_type->ops->get_create_constraint)
726 		return NULL;
727 	return fs_type->ops->get_create_constraint (dev);
728 }
729 /**
730  * Return a constraint, that represents all of the possible ways the
731  * file system \p fs can be resized with ped_file_system_resize().
732  * This takes into account the amount of used space on
733  * the filesystem \p fs and the capabilities of the resize algorithm.
734  * Hints:
735  * -# if constraint->start_align->grain_size == 0, or
736  *    constraint->start_geom->length == 1, then the start can not be moved
737  * -# constraint->min_size is the minimum size you can resize the partition
738  *    to.  You might want to tell the user this ;-).
739  *
740  * \return a PedConstraint on success, \c NULL on failure
741  */
742 PedConstraint*
ped_file_system_get_resize_constraint(const PedFileSystem * fs)743 ped_file_system_get_resize_constraint (const PedFileSystem* fs)
744 {
745 	PED_ASSERT (fs != NULL, return 0);
746 
747 	if (!fs->type->ops->get_resize_constraint)
748 		return NULL;
749 	return fs->type->ops->get_resize_constraint (fs);
750 }
751 
752 /**
753  * Get the constraint on copying \p fs with ped_file_system_copy()
754  * to somewhere on \p dev.
755  *
756  * \return a PedConstraint on success, \c NULL on failure
757  */
758 PedConstraint*
ped_file_system_get_copy_constraint(const PedFileSystem * fs,const PedDevice * dev)759 ped_file_system_get_copy_constraint (const PedFileSystem* fs,
760 				     const PedDevice* dev)
761 {
762 	PedGeometry	full_dev;
763 
764 	PED_ASSERT (fs != NULL, return NULL);
765 	PED_ASSERT (dev != NULL, return NULL);
766 
767 	if (fs->type->ops->get_copy_constraint)
768 		return fs->type->ops->get_copy_constraint (fs, dev);
769 
770 	if (fs->type->ops->resize) {
771 		if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
772 			return NULL;
773 		return ped_constraint_new (
774 				ped_alignment_any, ped_alignment_any,
775 				&full_dev, &full_dev,
776 				fs->geom->length, dev->length);
777 	}
778 
779 	return NULL;
780 }
781 
782 /** @} */
783