OSDN Git Service

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