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
  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
  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*
  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*
 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*
 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
 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*
 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
 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*
 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*
 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
 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
 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*
 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*
 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
 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
 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
 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*
 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*
 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
 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*
 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*
 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*
 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 /** @} */