OSDN Git Service

664f30050e153fcfe0ff04c94be8b83f2fea9d7c
[android-x86/external-parted.git] / libparted / arch / gnu.c
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 1999-2001, 2005, 2007, 2009-2011 Free Software Foundation,
4     Inc.
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <config.h>
21
22 #include <parted/parted.h>
23 #include <parted/debug.h>
24
25 #include <errno.h>
26 #include <hurd.h>
27 #include <hurd/fs.h>
28 #include <hurd/store.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 #if ENABLE_NLS
34 #  include <libintl.h>
35 #  define _(String) dgettext (PACKAGE, String)
36 #else
37 #  define _(String) (String)
38 #endif /* ENABLE_NLS */
39
40 #include "../architecture.h"
41
42 #define GNU_SPECIFIC(dev)       ((GNUSpecific*) (dev)->arch_specific)
43
44 typedef struct _GNUSpecific     GNUSpecific;
45
46 struct _GNUSpecific {
47         struct store*   store;
48         int consume;
49 };
50
51 /* Initialize a PedDevice using SOURCE.  The SOURCE will NOT be destroyed;
52    the caller created it, it is the caller's responsilbility to free it
53    after it calls ped_device_destory.  SOURCE is not registered in Parted's
54    list of devices.  */
55 PedDevice* ped_device_new_from_store (struct store *source);
56
57 static int
58 _device_get_sector_size (PedDevice* dev)
59 {
60         GNUSpecific*    arch_specific = GNU_SPECIFIC (dev);
61         size_t          store_block_size = arch_specific->store->block_size;
62
63         return PED_SECTOR_SIZE_DEFAULT;
64 }
65
66 static PedSector
67 _device_get_length (PedDevice* dev)
68 {
69         GNUSpecific*    arch_specific = GNU_SPECIFIC (dev);
70         size_t          store_blocks = arch_specific->store->blocks;
71         size_t          store_block_size = arch_specific->store->block_size;
72
73         return ((long long) store_blocks * store_block_size) / PED_SECTOR_SIZE_DEFAULT;
74 }
75
76 static int
77 _device_probe_geometry (PedDevice* dev)
78 {
79         PedSector cyl_size;
80
81         dev->length = _device_get_length (dev);
82         if (!dev->length)
83                 return 0;
84
85         dev->sector_size = _device_get_sector_size (dev);
86         if (!dev->sector_size)
87                 return 0;
88
89         /* XXX: We have no way to get this!  */
90         dev->bios_geom.sectors = 63;
91         dev->bios_geom.heads = 255;
92         cyl_size = dev->bios_geom.sectors * dev->bios_geom.heads;
93         dev->bios_geom.cylinders = dev->length / cyl_size
94                                         * (dev->sector_size / PED_SECTOR_SIZE_DEFAULT);
95         dev->hw_geom = dev->bios_geom;
96
97         return 1;
98 }
99
100 static int
101 init_file (PedDevice* dev)
102 {
103         PedExceptionOption      ex_status;
104
105 retry_open:
106         if (!ped_device_open (dev)) {
107                 ex_status = ped_exception_throw (
108                                 PED_EXCEPTION_WARNING,
109                                 PED_EXCEPTION_RETRY_CANCEL,
110                                 _("Unable to open %s."),
111                                 dev->path);
112                 switch (ex_status) {
113                         case PED_EXCEPTION_RETRY:
114                                 goto retry_open;
115
116                         case PED_EXCEPTION_UNHANDLED:
117                                 ped_exception_catch ();
118                         case PED_EXCEPTION_CANCEL:
119                                 goto error;
120                 }
121
122                 return 0;
123         }
124
125 retry_probe:
126         if (!_device_probe_geometry (dev)) {
127                 ex_status = ped_exception_throw (
128                                 PED_EXCEPTION_WARNING,
129                                 PED_EXCEPTION_RETRY_CANCEL,
130                                 _("Unable to probe store."));
131                 switch (ex_status) {
132                         case PED_EXCEPTION_RETRY:
133                                 goto retry_probe;
134
135                         case PED_EXCEPTION_UNHANDLED:
136                                 ped_exception_catch ();
137                         case PED_EXCEPTION_CANCEL:
138                                 goto error_close_dev;
139                 }
140
141                 return 0;
142         }
143
144         dev->model = "";
145
146         ped_device_close (dev);
147         return 1;
148
149 error_close_dev:
150         ped_device_close (dev);
151 error:
152         return 0;
153 }
154
155 static void
156 _flush_cache (PedDevice* dev)
157 {
158         GNUSpecific*    arch_specific = GNU_SPECIFIC (dev);
159
160         if (dev->read_only)
161                 return;
162
163         /* Wait for a complete sync to finish.  */
164         file_sync (arch_specific->store->source, 1, 0);
165 }
166
167 /* Initialize by allocating memory and filling in a few defaults, a
168    PedDevice structure.  */
169 static PedDevice*
170 _init_device (const char *path)
171 {
172         PedDevice *dev;
173         GNUSpecific*    arch_specific;
174
175         dev = (PedDevice*) ped_malloc (sizeof (PedDevice));
176         if (!dev)
177                 goto error;
178
179         dev->path = strdup (path);
180         if (!dev->path)
181                 goto error_free_dev;
182
183         dev->arch_specific
184                 = (GNUSpecific*) ped_malloc (sizeof (GNUSpecific));
185         if (!dev->arch_specific)
186                 goto error_free_path;
187
188         dev->type = PED_DEVICE_FILE;    /* FIXME? */
189         dev->open_count = 0;
190         dev->read_only = 0;
191         dev->external_mode = 0;
192         dev->dirty = 0;
193         dev->boot_dirty = 0;
194
195         return dev;
196
197 error_free_arch_specific:
198         free (dev->arch_specific);
199 error_free_path:
200         free (dev->path);
201 error_free_dev:
202         free (dev);
203 error:
204         return NULL;
205 }
206
207 static int
208 _kernel_reread_part_table (PedDevice* dev)
209 {
210         /* XXX: We must wait for partfs to be finished.  */
211         return 1;
212 }
213
214 /* Free the memory associated with a PedDevice structure.  */
215 static void
216 _done_device (PedDevice *dev)
217 {
218         free (dev->arch_specific);
219         free (dev->path);
220         free (dev);
221 }
222
223 /* Release all resources that libparted owns in DEV.  */
224 static void
225 gnu_destroy (PedDevice* dev)
226 {
227         GNUSpecific*    arch_specific = GNU_SPECIFIC (dev);
228
229         if (arch_specific->consume)
230                 store_free (arch_specific->store);
231
232         _done_device (dev);
233 }
234
235 static PedDevice*
236 gnu_new (const char* path)
237 {
238         PedDevice*      dev;
239         GNUSpecific*    arch_specific;
240         error_t         ro_err, rw_err;
241         int             ispath;
242
243         PED_ASSERT (path != NULL);
244
245         dev = _init_device (path);
246         if (!dev)
247                 return NULL;
248
249         arch_specific = GNU_SPECIFIC (dev);
250         arch_specific->consume = 1;
251
252  retry_open:
253         /* Try read-write. */
254         if (strchr (dev->path, '/') != NULL) {
255                 /* We set this to prevent having to use strchr more then once. */
256                 ispath = 1;
257
258                 rw_err = store_open (dev->path, 0, NULL, &arch_specific->store);
259         } else {
260                 rw_err = store_typed_open (dev->path, 0, NULL, &arch_specific->store);
261         }
262
263         /* Try readonly. */
264         if (rw_err) {
265           if (ispath) {
266                 ro_err = store_open (dev->path, STORE_READONLY, NULL,
267                                  &arch_specific->store);
268           } else {
269                 ro_err = store_typed_open (dev->path, STORE_READONLY, NULL,
270                                        &arch_specific->store);
271           }
272
273         if (ro_err) {
274                 if (ped_exception_throw (
275                                 PED_EXCEPTION_ERROR,
276                                 PED_EXCEPTION_RETRY_CANCEL,
277                                 _("Error opening %s: %s"),
278                                 dev->path, strerror (ro_err))
279                                         != PED_EXCEPTION_RETRY) {
280                                 return NULL;
281                         } else
282                                 goto retry_open;
283                 } else {
284                         ped_exception_throw (
285                                 PED_EXCEPTION_WARNING,
286                                 PED_EXCEPTION_OK,
287                                 _("Unable to open %s read-write (%s).  %s has "
288                                   "been opened read-only."),
289                                 dev->path, strerror (rw_err), dev->path);
290                         dev->read_only = 1;
291                 }
292         } else {
293                 dev->read_only = 0;
294         }
295
296         _flush_cache (dev);
297
298         if (!init_file (dev)) {
299                 gnu_destroy(dev);
300                 return NULL;
301         }
302
303         return dev;
304 }
305
306 PedDevice*
307 ped_device_new_from_store (struct store *source)
308 {
309         PedDevice*      dev;
310         GNUSpecific*    arch_specific;
311
312         PED_ASSERT (source != NULL);
313
314         dev = _init_device (source->name ?: "(unknown)");
315         if (!dev)
316                 return NULL;
317
318         arch_specific = GNU_SPECIFIC (dev);
319         arch_specific->store = source;
320         arch_specific->consume = 0;
321
322         dev->read_only = source->flags & (STORE_READONLY|STORE_HARD_READONLY);
323
324         if (!init_file (dev)) {
325                 _done_device (dev);
326                 return NULL;
327         }
328
329         return dev;
330 }
331
332 static int
333 gnu_is_busy (PedDevice* dev)
334 {
335         return 0;
336 }
337
338 static int
339 gnu_open (PedDevice* dev)
340 {
341         return 1;
342 }
343
344 static int
345 gnu_refresh_open (PedDevice* dev)
346 {
347         return 1;
348 }
349
350 static int
351 gnu_close (PedDevice* dev)
352 {
353         GNUSpecific*    arch_specific = GNU_SPECIFIC (dev);
354
355         _flush_cache (dev);
356
357         if (dev->dirty && dev->type != PED_DEVICE_FILE) {
358                 if (_kernel_reread_part_table (dev))
359                         dev->dirty = 0;
360         }
361
362 #if 0
363         if (dev->dirty && dev->boot_dirty && dev->type != PED_DEVICE_FILE) {
364                 /* ouch! */
365                 ped_exception_throw (
366                         PED_EXCEPTION_WARNING,
367                         PED_EXCEPTION_OK,
368                         _("The partition table cannot be re-read.  This means "
369                           "you need to reboot before mounting any "
370                           "modified partitions.  You also need to reinstall "
371                           "your boot loader before you reboot (which may "
372                           "require mounting modified partitions).  It is "
373                           "impossible do both things!  So you'll need to "
374                           "boot off a rescue disk, and reinstall your boot "
375                           "loader from the rescue disk.  Read section 4 of "
376                           "the Parted User documentation for more "
377                           "information."));
378                 return 1;
379         }
380
381         if (dev->dirty && dev->type != PED_DEVICE_FILE) {
382                 ped_exception_throw (
383                         PED_EXCEPTION_WARNING,
384                         PED_EXCEPTION_IGNORE,
385                         _("The partition table on %s cannot be re-read "
386                           "(%s).  This means the Hurd knows nothing about any "
387                           "modifications you made.  You should reboot your "
388                           "computer before doing anything with %s."),
389                         dev->path, strerror (errno), dev->path);
390         }
391
392         if (dev->boot_dirty && dev->type != PED_DEVICE_FILE) {
393                 ped_exception_throw (
394                         PED_EXCEPTION_WARNING,
395                         PED_EXCEPTION_OK,
396                         _("You should reinstall your boot loader before "
397                           "rebooting.  Read section 4 of the Parted User "
398                           "documentation for more information."));
399         }
400 #endif
401
402         return 1;
403 }
404
405 static int
406 gnu_refresh_close (PedDevice* dev)
407 {
408         _flush_cache (dev);
409         return 1;
410 }
411
412 static int
413 gnu_read (const PedDevice* dev, void* user_buffer, PedSector device_start,
414           PedSector count)
415 {
416         GNUSpecific*            arch_specific = GNU_SPECIFIC (dev);
417         error_t                 err;
418         PedExceptionOption      ex_status;
419         size_t                  start;
420         size_t                  store_start_block;
421         /* In bytes.  This can be larger than COUNT when store pages are
422            larger than PED_SECTOR_SIZE_DEFAULT.  */
423         size_t                  store_read_length;
424         char                    local_buffer[PED_SECTOR_SIZE_DEFAULT];
425         void *                  store_read_buffer;
426         size_t                  have_read;
427         size_t                  read_offset;
428         size_t                  device_read_length = count * PED_SECTOR_SIZE_DEFAULT;
429
430         start = device_start * PED_SECTOR_SIZE_DEFAULT;
431         if (PED_SECTOR_SIZE_DEFAULT != arch_specific->store->block_size) {
432                 store_start_block = start / arch_specific->store->block_size;
433                 store_read_length = (device_read_length
434                                      + arch_specific->store->block_size - 1)
435                                     / arch_specific->store->block_size;
436         } else {
437                 store_start_block = device_start;
438                 store_read_length = device_read_length;
439         }
440
441         read_offset = start
442                       - store_start_block * arch_specific->store->block_size;
443
444         if (store_read_length % arch_specific->store->block_size != 0)
445                 store_read_length = store_read_length
446                                     + arch_specific->store->block_size
447                                     - store_read_length % arch_specific->store->block_size;
448
449 retry:
450         have_read = 0;
451         while (1) {
452                 size_t  did_read;
453                 size_t  offset;
454
455                 store_read_buffer = local_buffer;
456                 did_read = sizeof (local_buffer);
457
458                 err = store_read (arch_specific->store, store_start_block,
459                                   store_read_length - have_read,
460                                   &store_read_buffer, &did_read);
461                 if (err) {
462                         ex_status = ped_exception_throw (
463                                 PED_EXCEPTION_ERROR,
464                                 PED_EXCEPTION_RETRY_IGNORE_CANCEL,
465                                 _("%s during read on %s"),
466                                 strerror (err),
467                                 dev->path);
468
469                         switch (ex_status) {
470                                 case PED_EXCEPTION_IGNORE:
471                                         return 1;
472
473                                 case PED_EXCEPTION_RETRY:
474                                         goto retry;
475
476                                 case PED_EXCEPTION_UNHANDLED:
477                                         ped_exception_catch ();
478                                 case PED_EXCEPTION_CANCEL:
479                                         return 0;
480                         }
481                 }
482
483                 memcpy (user_buffer + have_read - read_offset,
484                         store_read_buffer
485                         + (have_read >= read_offset
486                                 ? 0 : read_offset - have_read),
487                         have_read + did_read > device_read_length + read_offset
488                                 ? device_read_length + read_offset - have_read
489                                 : did_read);
490
491                 if (store_read_buffer != local_buffer)
492                         vm_deallocate (mach_task_self (),
493                                        (long) store_read_buffer, did_read);
494
495                 have_read += did_read;
496                 store_start_block += did_read
497                                         / arch_specific->store->block_size;
498
499                 if (have_read >= device_read_length)
500                         break;
501         }
502
503         return 1;
504 }
505
506 static int
507 gnu_write (PedDevice* dev, const void* buffer, PedSector start, PedSector count)
508 {
509         GNUSpecific*            arch_specific = GNU_SPECIFIC (dev);
510         error_t                 err;
511         PedExceptionOption      ex_status;
512         void *                  temp;
513         char                    local_buffer[PED_SECTOR_SIZE_DEFAULT];
514         size_t                  did_read;
515         size_t                  did_write;
516
517         /* Map a disk sector to a store sector.  */
518         #define PED_TO_STORE(store, sector) (((sector) * PED_SECTOR_SIZE_DEFAULT) \
519                                         / (store)->block_size)
520
521         if (dev->read_only) {
522                 if (ped_exception_throw (
523                         PED_EXCEPTION_ERROR,
524                         PED_EXCEPTION_IGNORE_CANCEL,
525                         _("Can't write to %s, because it is opened read-only."),
526                         dev->path)
527                                 != PED_EXCEPTION_IGNORE)
528                         return 0;
529                 else
530                         return 1;
531         }
532
533 #ifdef READ_ONLY
534         printf ("ped_device_write (\"%s\", %p, %d, %d)\n",
535                 dev->path, buffer, (int) start, (int) count);
536 #else
537         dev->dirty = 1;
538
539         /* If the first ``device'' block (PedSector) is not aligned on a
540            store block, then we need to fetch the old block, copy in the
541            overlaping area and finally, write the modified data out to the
542            store.  */
543         if ((PED_SECTOR_SIZE_DEFAULT * start) % arch_specific->store->block_size
544             != 0) {
545                 size_t          write_offset;
546                 size_t          flushing;
547
548 doggy_first_block_read:
549                 /* We do not bother looping as we are only reading a
550                    single block.  */
551                 temp = local_buffer;
552                 did_read = sizeof (local_buffer);
553                 err = store_read (arch_specific->store,
554                                   PED_TO_STORE (arch_specific->store, start),
555                                   arch_specific->store->block_size, &temp,
556                                   &did_read);
557                 if (! err && did_read != arch_specific->store->block_size)
558                         err = EIO;
559
560                 if (err) {
561                         ex_status = ped_exception_throw (
562                                 PED_EXCEPTION_ERROR,
563                                 PED_EXCEPTION_RETRY_IGNORE_CANCEL,
564                                 _("%s during read on %s"),
565                                 strerror (err), dev->path);
566
567                         switch (ex_status) {
568                                 case PED_EXCEPTION_IGNORE:
569                                         break;
570
571                                 case PED_EXCEPTION_RETRY:
572                                         goto doggy_first_block_read;
573
574                                 case PED_EXCEPTION_UNHANDLED:
575                                         ped_exception_catch ();
576                                 case PED_EXCEPTION_CANCEL:
577                                         return 0;
578                         }
579                 }
580
581                 write_offset = (start * PED_SECTOR_SIZE_DEFAULT)
582                                % arch_specific->store->block_size;
583                 flushing = arch_specific->store->block_size - write_offset;
584                 if (flushing > count * PED_SECTOR_SIZE_DEFAULT)
585                         flushing = count * PED_SECTOR_SIZE_DEFAULT;
586
587                 memcpy (temp + write_offset, buffer, flushing);
588
589 doggy_first_block_write:
590                 err = store_write (arch_specific->store,
591                                    PED_TO_STORE (arch_specific->store, start),
592                                    temp, arch_specific->store->block_size,
593                                    &did_write);
594                 if (! err && did_write != arch_specific->store->block_size)
595                         err = EIO;
596
597                 if (err) {
598                         ex_status = ped_exception_throw (
599                                 PED_EXCEPTION_ERROR,
600                                 PED_EXCEPTION_RETRY_IGNORE_CANCEL,
601                                 _("%s during write on %s"),
602                                 strerror (err), dev->path);
603
604                         switch (ex_status) {
605                                 case PED_EXCEPTION_IGNORE:
606                                         break;
607
608                                 case PED_EXCEPTION_RETRY:
609                                         goto doggy_first_block_write;
610
611                                 case PED_EXCEPTION_UNHANDLED:
612                                         ped_exception_catch ();
613                                 case PED_EXCEPTION_CANCEL:
614                                         if (temp != local_buffer)
615                                                 vm_deallocate (
616                                                         mach_task_self (),
617                                                         (long) temp,
618                                                         did_read);
619                                         return 0;
620                         }
621                 }
622
623                 start += flushing / PED_SECTOR_SIZE_DEFAULT;
624                 count -= flushing / PED_SECTOR_SIZE_DEFAULT;
625                 buffer += write_offset;
626
627                 if (temp != local_buffer)
628                         vm_deallocate (mach_task_self (), (long) temp,
629                                        did_read);
630
631                 if (count == 0)
632                         return 1;
633         }
634
635         while (count > 0
636            && count >= arch_specific->store->block_size / PED_SECTOR_SIZE_DEFAULT) {
637                 err = store_write (arch_specific->store,
638                                    PED_TO_STORE (arch_specific->store, start),
639                                    buffer, count * PED_SECTOR_SIZE_DEFAULT,
640                                    &did_write);
641
642                 if (err) {
643                         ex_status = ped_exception_throw (
644                                 PED_EXCEPTION_ERROR,
645                                 PED_EXCEPTION_RETRY_IGNORE_CANCEL,
646                                 _("%s during write on %s"),
647                                 strerror (err), dev->path);
648
649                         switch (ex_status) {
650                                 case PED_EXCEPTION_IGNORE:
651                                         break;
652
653                                 case PED_EXCEPTION_RETRY:
654                                         continue;
655
656                                 case PED_EXCEPTION_UNHANDLED:
657                                         ped_exception_catch ();
658                                 case PED_EXCEPTION_CANCEL:
659                                         return 0;
660                         }
661                 }
662
663                 start += did_write / PED_SECTOR_SIZE_DEFAULT;
664                 count -= did_write / PED_SECTOR_SIZE_DEFAULT;
665                 buffer += did_write;
666         }
667
668         if (count == 0)
669                 return 1;
670
671         /* We are now left with (strictly) less then a store block to write
672            to disk.  Thus, we read the block, overlay the buffer and flush.  */
673         PED_ASSERT (count * PED_SECTOR_SIZE_DEFAULT
674                     < arch_specific->store->block_size);
675
676 doggy_last_block_read:
677         /* We do not bother looping as we are only reading a
678            single block.  */
679         temp = local_buffer;
680         did_read = sizeof (local_buffer);
681         err = store_read (arch_specific->store,
682                           PED_TO_STORE (arch_specific->store, start),
683                           arch_specific->store->block_size, &temp,
684                           &did_read);
685         if (! err && did_read != arch_specific->store->block_size)
686                 err = EIO;
687
688         if (err) {
689                 ex_status = ped_exception_throw (
690                         PED_EXCEPTION_ERROR,
691                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
692                         _("%s during read on %s"),
693                         strerror (err), dev->path);
694
695                 switch (ex_status) {
696                         case PED_EXCEPTION_IGNORE:
697                                 break;
698
699                         case PED_EXCEPTION_RETRY:
700                                 goto doggy_last_block_read;
701
702                         case PED_EXCEPTION_UNHANDLED:
703                                 ped_exception_catch ();
704                         case PED_EXCEPTION_CANCEL:
705                                 return 0;
706                 }
707         }
708
709         memcpy (temp, buffer, count * PED_SECTOR_SIZE_DEFAULT);
710
711 doggy_last_block_write:
712         err = store_write (arch_specific->store,
713                            PED_TO_STORE (arch_specific->store, start),
714                            temp, arch_specific->store->block_size,
715                            &did_write);
716         if (! err && did_write != arch_specific->store->block_size)
717                 err = EIO;
718
719         if (err) {
720                 ex_status = ped_exception_throw (
721                         PED_EXCEPTION_ERROR,
722                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
723                         _("%s during write on %s"),
724                         strerror (err), dev->path);
725
726                 switch (ex_status) {
727                         case PED_EXCEPTION_IGNORE:
728                                 break;
729
730                         case PED_EXCEPTION_RETRY:
731                                 goto doggy_last_block_write;
732
733                         case PED_EXCEPTION_UNHANDLED:
734                                 ped_exception_catch ();
735                         case PED_EXCEPTION_CANCEL:
736                                 if (temp != local_buffer)
737                                         vm_deallocate (mach_task_self (),
738                                                        (long) temp,
739                                                        did_read);
740                                 return 0;
741                 }
742         }
743
744 #endif /* !READ_ONLY */
745         return 1;
746 }
747
748 /* TODO: returns the number of sectors that are ok.
749  */
750 static PedSector
751 gnu_check (PedDevice* dev, void* buffer, PedSector start, PedSector count)
752 {
753         int                     status;
754         int                     done = 0;
755
756         PED_ASSERT (dev != NULL);
757         PED_ASSERT (!dev->external_mode);
758         PED_ASSERT (buffer != NULL);
759
760         return count;
761 }
762
763 static int
764 gnu_sync (PedDevice* dev)
765 {
766         GNUSpecific*            arch_specific;
767         error_t                 err;
768         PedExceptionOption      ex_status;
769         static char *last_failure = NULL;
770
771         PED_ASSERT (dev != NULL);
772         PED_ASSERT (!dev->external_mode);
773
774         arch_specific = GNU_SPECIFIC (dev);
775
776         if (dev->read_only || ! dev->dirty)
777                 return 1;
778
779         while (1) {
780                 err = file_sync (arch_specific->store->source, 1, 0);
781                 if (! err || err == EOPNOTSUPP || err == EPERM
782                     || (last_failure && strcmp (last_failure, dev->path) == 0))
783                   break;
784
785                 ex_status = ped_exception_throw (
786                         PED_EXCEPTION_ERROR,
787                         PED_EXCEPTION_RETRY_IGNORE_CANCEL,
788                         _("%s trying to sync %s to disk"),
789                         strerror (errno), dev->path);
790
791                 switch (ex_status) {
792                         case PED_EXCEPTION_IGNORE:
793                                 free (last_failure);
794                                 last_failure = strdup (dev->path);
795                                 return 1;
796
797                         case PED_EXCEPTION_RETRY:
798                                 break;
799
800                         case PED_EXCEPTION_UNHANDLED:
801                                 ped_exception_catch ();
802                         case PED_EXCEPTION_CANCEL:
803                                 return 0;
804                 }
805         }
806
807         return 1;
808 }
809
810 static int
811 probe_standard_devices ()
812 {
813         _ped_device_probe ("/dev/sd0");
814         _ped_device_probe ("/dev/sd1");
815         _ped_device_probe ("/dev/sd2");
816         _ped_device_probe ("/dev/sd3");
817         _ped_device_probe ("/dev/sd4");
818         _ped_device_probe ("/dev/sd5");
819
820         _ped_device_probe ("/dev/hd0");
821         _ped_device_probe ("/dev/hd1");
822         _ped_device_probe ("/dev/hd2");
823         _ped_device_probe ("/dev/hd3");
824         _ped_device_probe ("/dev/hd4");
825         _ped_device_probe ("/dev/hd5");
826         _ped_device_probe ("/dev/hd6");
827         _ped_device_probe ("/dev/hd7");
828
829         return 1;
830 }
831
832 static void
833 gnu_probe_all ()
834 {
835         probe_standard_devices ();
836 }
837
838 static char*
839 gnu_partition_get_path (const PedPartition* part)
840 {
841         const char*     dev_path = part->disk->dev->path;
842         int             result_len = strlen (dev_path) + 16;
843         char*           result;
844
845         result = (char*) ped_malloc (result_len);
846         if (!result)
847                 return NULL;
848         snprintf (result, result_len, "%s%d", dev_path, part->num);
849         return result;
850 }
851
852 static int
853 gnu_partition_is_busy (const PedPartition* part)
854 {
855         return 0;
856 }
857
858 static int
859 gnu_disk_commit (PedDisk* disk)
860 {
861         return 1;
862 }
863
864 static PedDeviceArchOps gnu_dev_ops = {
865         _new:           gnu_new,
866         destroy:        gnu_destroy,
867         is_busy:        gnu_is_busy,
868         open:           gnu_open,
869         refresh_open:   gnu_refresh_open,
870         close:          gnu_close,
871         refresh_close:  gnu_refresh_close,
872         read:           gnu_read,
873         write:          gnu_write,
874         check:          gnu_check,
875         sync:           gnu_sync,
876         sync_fast:      gnu_sync,
877         probe_all:      gnu_probe_all
878 };
879
880 static PedDiskArchOps gnu_disk_ops = {
881         partition_get_path:     gnu_partition_get_path,
882         partition_is_busy:      gnu_partition_is_busy,
883         disk_commit:            gnu_disk_commit
884 };
885
886 PedArchitecture ped_gnu_arch = {
887         dev_ops:        &gnu_dev_ops,
888         disk_ops:       &gnu_disk_ops
889 };