OSDN Git Service

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