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