1 /*
   2     reiserfs.c -- libparted / libreiserfs glue
   3     Copyright (C) 2001, 2002, 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     This is all rather complicated.  There are a few combinations:
  19         * shared libraries full support
  20         * dynamic libraries present full support (via dlopen)
  21         * dynamic libraries absent (full support disabled) (via dlopen)
  22         * discover only
  23 
  24     We'd love to hear comments...
  25 
  26     So far, we've opted for maximum flexibility for the user.  Is it
  27     all worth it?
  28 */
  29 
  30 #include <config.h>
  31 
  32 #if (HAVE_LIBREISERFS || DYNAMIC_LOADING) && !DISCOVER_ONLY
  33 #       define REISER_FULL_SUPPORT
  34 #endif
  35 
  36 #include <uuid/uuid.h>
  37 #include <fcntl.h>
  38 #include <errno.h>
  39 
  40 #ifdef DYNAMIC_LOADING
  41 #       include <dlfcn.h>
  42 #endif
  43 
  44 #include <parted/parted.h>
  45 #include <parted/debug.h>
  46 #include <parted/endian.h>
  47 
  48 #if ENABLE_NLS
  49 #       include <libintl.h>
  50 #       define _(String) dgettext (PACKAGE, String)
  51 #else
  52 #       define _(String) (String)
  53 #endif
  54 
  55 #include "reiserfs.h"
  56 #include "geom_dal.h"
  57 
  58 #define REISERFS_BLOCK_SIZES       ((int[2]){512, 0})
  59 
  60 static PedSector reiserfs_super_offset[] = { 128, 16, -1 };
  61 static PedFileSystemType* reiserfs_type;
  62 
  63 #ifdef DYNAMIC_LOADING
  64 #       define FPTR *
  65 #       define FCLASS static
  66 #else
  67 #       define FPTR
  68 #       define FCLASS extern
  69 #endif
  70 
  71 #ifdef DYNAMIC_LOADING
  72 
  73 static int libreiserfs_present;
  74 
  75 static void *libdal_handle;
  76 static void *libreiserfs_handle;
  77 
  78 #endif /* DYNAMIC_LOADING */
  79 
  80 #ifdef REISER_FULL_SUPPORT
  81 
  82 FCLASS blk_t (FPTR reiserfs_fs_probe) (dal_t *);
  83 
  84 FCLASS int (FPTR libreiserfs_exception_type) (reiserfs_exception_t *);
  85 FCLASS int (FPTR libreiserfs_exception_option) (reiserfs_exception_t *);
  86 FCLASS char *(FPTR libreiserfs_exception_message) (reiserfs_exception_t *);
  87 FCLASS void (FPTR libreiserfs_exception_set_handler)
  88                 (int(FPTR)(reiserfs_exception_t *));
  89 
  90 FCLASS void (FPTR dal_realize) (dal_t *);
  91 FCLASS size_t (FPTR dal_block_size) (dal_t *);
  92 FCLASS blk_t (FPTR dal_len) (dal_t *);
  93 FCLASS int (FPTR dal_flags) (dal_t *);
  94 
  95 FCLASS reiserfs_fs_t* (FPTR reiserfs_fs_open) (dal_t *, dal_t *);
  96 FCLASS reiserfs_fs_t* (FPTR reiserfs_fs_create) (dal_t *, dal_t *,
  97                                           blk_t, blk_t, blk_t, size_t,
  98                                           int, int, const char *,
  99                                           const char *, blk_t,
 100                                           reiserfs_gauge_t *);
 101 
 102 FCLASS int (FPTR reiserfs_fs_resize) (reiserfs_fs_t *, blk_t, reiserfs_gauge_t *);
 103 #ifdef HAVE_REISERFS_FS_CHECK
 104 FCLASS int (FPTR reiserfs_fs_check) (reiserfs_fs_t *, reiserfs_gauge_t *);
 105 #endif
 106 
 107 FCLASS reiserfs_fs_t *(FPTR reiserfs_fs_copy) (reiserfs_fs_t *, dal_t *,
 108                                         reiserfs_gauge_t *);
 109 
 110 FCLASS int (FPTR reiserfs_fs_clobber) (dal_t *);
 111 FCLASS void (FPTR reiserfs_fs_close) (reiserfs_fs_t *);
 112 
 113 FCLASS int (FPTR reiserfs_fs_is_resizeable) (reiserfs_fs_t *);
 114 FCLASS int (FPTR reiserfs_fs_is_consistent) (reiserfs_fs_t *);
 115 
 116 FCLASS blk_t (FPTR reiserfs_fs_min_size) (reiserfs_fs_t *);
 117 FCLASS blk_t (FPTR reiserfs_fs_block_size) (reiserfs_fs_t *);
 118 FCLASS dal_t* (FPTR reiserfs_fs_host_dal) (reiserfs_fs_t *);
 119 
 120 FCLASS blk_t (FPTR reiserfs_fs_bitmap_used) (reiserfs_fs_t *);
 121 FCLASS int (FPTR reiserfs_fs_bitmap_check) (reiserfs_fs_t *);
 122 
 123 FCLASS reiserfs_gauge_t *(FPTR libreiserfs_gauge_create) (
 124         char *, reiserfs_gauge_handler_t, void *);
 125 
 126 FCLASS void (FPTR libreiserfs_gauge_free) (reiserfs_gauge_t *);
 127 
 128 static void gauge_handler(const char *name, unsigned int value, void *data,
 129                           int determined, int update_header,
 130                           int update_footer)
 131 {
 132         PedTimer *timer = (PedTimer *) data;
 133         ped_timer_set_state_name(timer, name);
 134         ped_timer_update(timer, 1.0 * value / 100);
 135 }
 136 
 137 static PedExceptionOption
 138 exopt_libreiserfs_to_parted(reiserfs_exception_option_t option)
 139 {
 140         switch (option) {
 141         case EXCEPTION_UNHANDLED:
 142                 return PED_EXCEPTION_UNHANDLED;
 143         case EXCEPTION_FIX:
 144                 return PED_EXCEPTION_FIX;
 145         case EXCEPTION_YES:
 146                 return PED_EXCEPTION_YES;
 147         case EXCEPTION_NO:
 148                 return PED_EXCEPTION_NO;
 149         case EXCEPTION_OK:
 150                 return PED_EXCEPTION_OK;
 151         case EXCEPTION_RETRY:
 152                 return PED_EXCEPTION_RETRY;
 153         case EXCEPTION_IGNORE:
 154                 return PED_EXCEPTION_IGNORE;
 155         case EXCEPTION_CANCEL:
 156                 return PED_EXCEPTION_CANCEL;
 157 
 158         default:
 159                 return PED_EXCEPTION_UNHANDLED;
 160         }
 161 }
 162 
 163 static PedExceptionType
 164 extype_libreiserfs_to_parted(reiserfs_exception_type_t type)
 165 {
 166         switch (type) {
 167         case EXCEPTION_INFORMATION:
 168                 return PED_EXCEPTION_INFORMATION;
 169         case EXCEPTION_WARNING:
 170                 return PED_EXCEPTION_WARNING;
 171         case EXCEPTION_ERROR:
 172                 return PED_EXCEPTION_ERROR;
 173         case EXCEPTION_FATAL:
 174                 return PED_EXCEPTION_FATAL;
 175         case EXCEPTION_BUG:
 176                 return PED_EXCEPTION_BUG;
 177         case EXCEPTION_NO_FEATURE:
 178                 return PED_EXCEPTION_NO_FEATURE;
 179 
 180         default:
 181                 return PED_EXCEPTION_NO_FEATURE;
 182         }
 183 }
 184 
 185 static int exception_handler(reiserfs_exception_t *exception)
 186 {
 187         int ex_type = libreiserfs_exception_type(exception);
 188         int ex_option = libreiserfs_exception_option(exception);
 189         char *ex_message = libreiserfs_exception_message(exception);
 190 
 191         return ped_exception_throw (extype_libreiserfs_to_parted (ex_type),
 192                                     exopt_libreiserfs_to_parted (ex_option),
 193                                     ex_message);
 194 }
 195 #endif /* REISER_FULL_SUPPORT */
 196 
 197 static PedGeometry *reiserfs_probe(PedGeometry *geom)
 198 {
 199         int i;
 200         reiserfs_super_block_t sb;
 201 
 202         PED_ASSERT(geom != NULL, return NULL);
 203 
 204         for (i = 0; reiserfs_super_offset[i] != -1; i++) {
 205                 if (reiserfs_super_offset[i] >= geom->length)
 206                         continue;
 207                 if (!ped_geometry_read (geom, &sb, reiserfs_super_offset[i], 1))
 208                         continue;
 209 
 210                 if (strncmp(REISERFS_SIGNATURE, sb.s_magic,
 211                             strlen(REISERFS_SIGNATURE)) == 0
 212                     || strncmp(REISER2FS_SIGNATURE, sb.s_magic,
 213                                strlen(REISER2FS_SIGNATURE)) == 0
 214                     || strncmp(REISER3FS_SIGNATURE, sb.s_magic,
 215                                strlen(REISER3FS_SIGNATURE)) == 0) {
 216                         PedSector block_size;
 217                         PedSector block_count;
 218 
 219                         block_size = PED_LE16_TO_CPU(sb.s_blocksize)
 220                                         / PED_SECTOR_SIZE_DEFAULT;
 221                         block_count = PED_LE32_TO_CPU(sb.s_block_count);
 222 
 223                         return ped_geometry_new(geom->dev, geom->start,
 224                                                 block_size * block_count);
 225                 }
 226         }
 227         return NULL;
 228 }
 229 
 230 #ifndef DISCOVER_ONLY
 231 static int reiserfs_clobber(PedGeometry *geom)
 232 {
 233         int i;
 234         char buf[512];
 235 
 236         PED_ASSERT(geom != NULL, return 0);
 237 
 238         memset(buf, 0, 512);
 239         for (i = 0; reiserfs_super_offset[i] != -1; i++) {
 240                 if (reiserfs_super_offset[i] >= geom->length)
 241                         continue;
 242                 if (!ped_geometry_write
 243                     (geom, buf, reiserfs_super_offset[i], 1))
 244                         return 0;
 245         }
 246         return 1;
 247 }
 248 #endif /* !DISCOVER_ONLY */
 249 
 250 #ifdef REISER_FULL_SUPPORT
 251 
 252 static PedFileSystem *reiserfs_open(PedGeometry *geom)
 253 {
 254         PedFileSystem *fs;
 255         PedGeometry *fs_geom;
 256         dal_t *dal;
 257         reiserfs_fs_t *fs_info;
 258 
 259         PED_ASSERT(geom != NULL, return NULL);
 260 
 261         if (!(fs_geom = ped_geometry_duplicate(geom)))
 262                 goto error;
 263 
 264         if (! (dal = geom_dal_create(fs_geom, DEFAULT_BLOCK_SIZE, O_RDONLY)))
 265                 goto error_fs_geom_free;
 266 
 267         /*
 268            We are passing NULL as DAL for journal. Therefore we let libreiserfs know, 
 269            that journal not available and parted will be working fine for reiserfs 
 270            with relocated journal too.
 271          */
 272         if (!(fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem))))
 273                 goto error_free_dal;
 274 
 275         if (!(fs_info = reiserfs_fs_open(dal, NULL)))
 276                 goto error_free_fs;
 277 
 278         fs->type = reiserfs_type;
 279         fs->geom = fs_geom;
 280         fs->type_specific = (void *) fs_info;
 281 
 282         return fs;
 283 
 284 error_free_fs:
 285         ped_free(fs);
 286 error_free_dal:
 287         geom_dal_free(dal);
 288 error_fs_geom_free:
 289         ped_geometry_destroy(fs_geom);
 290 error:
 291         return NULL;
 292 }
 293 
 294 static PedFileSystem *reiserfs_create(PedGeometry *geom, PedTimer *timer)
 295 {
 296         dal_t *dal;
 297         uuid_t uuid;
 298         PedFileSystem *fs;
 299         PedGeometry *fs_geom;
 300         reiserfs_fs_t *fs_info;
 301         reiserfs_gauge_t *gauge = NULL;
 302 
 303         PED_ASSERT(geom != NULL, return NULL);
 304 
 305         fs_geom = ped_geometry_duplicate(geom);
 306 
 307         if (!(dal = geom_dal_create(fs_geom, DEFAULT_BLOCK_SIZE, O_RDWR)))
 308                 goto error_fs_geom_free;
 309 
 310         memset(uuid, 0, sizeof(uuid));
 311         uuid_generate(uuid);
 312 
 313         ped_timer_reset(timer);
 314         ped_timer_set_state_name(timer, _("creating"));
 315 
 316         if (libreiserfs_gauge_create && libreiserfs_gauge_free) {
 317                 if (! (gauge =
 318                      libreiserfs_gauge_create(NULL, gauge_handler, timer)))
 319                         goto error_free_dal;
 320         }
 321 
 322         if (!(fs_info = reiserfs_fs_create(dal, dal, 0, JOURNAL_MAX_TRANS,
 323                                            DEFAULT_JOURNAL_SIZE,
 324                                            DEFAULT_BLOCK_SIZE,
 325                                            FS_FORMAT_3_6, R5_HASH, NULL,
 326                                            (char *) uuid, dal_len(dal),
 327                                            gauge)))
 328                 goto error_free_gauge;
 329 
 330         ped_timer_update(timer, 1.0);
 331 
 332         if (gauge)
 333                 libreiserfs_gauge_free(gauge);
 334 
 335         if (!(fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem))))
 336                 goto error_free_fs_info;
 337 
 338         fs->type = reiserfs_type;
 339         fs->geom = fs_geom;
 340         fs->type_specific = (void *) fs_info;
 341 
 342         return fs;
 343 
 344 error_free_fs_info:
 345         ped_free(fs_info);
 346 error_free_gauge:
 347         if (gauge)
 348                 libreiserfs_gauge_free(gauge);
 349 error_free_dal:
 350         geom_dal_free(dal);
 351 error_fs_geom_free:
 352         ped_geometry_destroy(fs_geom);
 353         return NULL;
 354 }
 355 
 356 static int reiserfs_close(PedFileSystem *fs)
 357 {
 358         dal_t *dal;
 359 
 360         PED_ASSERT(fs != NULL, return 0);
 361 
 362         dal = reiserfs_fs_host_dal(fs->type_specific);
 363         reiserfs_fs_close(fs->type_specific);
 364 
 365         geom_dal_free(dal);
 366         ped_geometry_sync(fs->geom);
 367 
 368         ped_free(fs);
 369         return 1;
 370 }
 371 
 372 static PedConstraint *reiserfs_get_create_constraint(const PedDevice *dev)
 373 {
 374         PedGeometry full_dev;
 375         PedSector min_blks = (SUPER_OFFSET_IN_BYTES / DEFAULT_BLOCK_SIZE)
 376                              + 2 + DEFAULT_JOURNAL_SIZE + 1 + 100 + 1;
 377 
 378         if (!ped_geometry_init(&full_dev, dev, 0, dev->length - 1))
 379                 return NULL;
 380 
 381         return ped_constraint_new(ped_alignment_any, ped_alignment_any,
 382                                   &full_dev, &full_dev,
 383                                   min_blks * (DEFAULT_BLOCK_SIZE / 512),
 384                                   dev->length);
 385 }
 386 
 387 static int reiserfs_check(PedFileSystem *fs, PedTimer *timer)
 388 {
 389         reiserfs_fs_t *fs_info;
 390 #ifdef HAVE_REISERFS_FS_CHECK
 391         reiserfs_gauge_t *gauge = NULL;
 392 #endif
 393 
 394         PED_ASSERT(fs != NULL, return 0);
 395 
 396         fs_info = fs->type_specific;
 397 
 398         if (!reiserfs_fs_is_consistent(fs_info)) {
 399                 ped_exception_throw(PED_EXCEPTION_ERROR,
 400                                     PED_EXCEPTION_CANCEL,
 401                                     _("The file system is in an invalid "
 402                                       "state.  Perhaps it is mounted?"));
 403                 return 0;
 404         }
 405 
 406         if (!reiserfs_fs_is_resizeable(fs_info))
 407                 ped_exception_throw(PED_EXCEPTION_WARNING,
 408                                     PED_EXCEPTION_IGNORE,
 409                                     _("The file system is in old "
 410                                       "(unresizeable) format."));
 411 
 412         if (!reiserfs_fs_bitmap_check(fs_info)) {
 413                 ped_exception_throw(PED_EXCEPTION_ERROR,
 414                                     PED_EXCEPTION_CANCEL,
 415                                     _("Invalid free blocks count.  Run "
 416                                       "reiserfsck --check first."));
 417                 return 0;
 418         }
 419 
 420 #ifdef HAVE_REISERFS_FS_CHECK
 421         ped_timer_reset(timer);
 422         
 423         if (libreiserfs_gauge_create && libreiserfs_gauge_free) {
 424                 if (!
 425                     (gauge =
 426                      libreiserfs_gauge_create(NULL, gauge_handler, timer)))
 427                         return 0;
 428         }
 429                 
 430         ped_timer_set_state_name(timer, _("checking"));
 431         ped_timer_update(timer, 0.0);
 432 
 433         if (!reiserfs_fs_check(fs_info, gauge)) {
 434                 ped_exception_throw(PED_EXCEPTION_ERROR,
 435                                     PED_EXCEPTION_CANCEL,
 436                                     _("Reiserfs tree seems to be corrupted.  "
 437                                       "Run reiserfsck --check first."));
 438                 return 0;
 439         }
 440         
 441         ped_timer_update(timer, 1.0);
 442 
 443         if (gauge)
 444                 libreiserfs_gauge_free(gauge);
 445 #endif
 446         
 447         ped_exception_throw(PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK,
 448                             _("The reiserfs file system passed a basic check.  "
 449                               "For a more comprehensive check, run "
 450                               "reiserfsck --check."));
 451 
 452         return 1;
 453 }
 454 
 455 static int reiserfs_resize(PedFileSystem *fs, PedGeometry *geom,
 456                            PedTimer *timer)
 457 {
 458         dal_t *dal;
 459         blk_t fs_len;
 460         PedSector old_length;
 461         reiserfs_fs_t *fs_info;
 462         reiserfs_gauge_t *gauge = NULL;
 463 
 464         PED_ASSERT(fs != NULL, return 0);
 465 
 466         old_length = fs->geom->length;
 467 
 468         PED_ASSERT (fs->geom->dev == geom->dev, return 0);
 469 
 470         if (fs->geom->start != geom->start) {
 471                 ped_exception_throw(PED_EXCEPTION_ERROR,
 472                                     PED_EXCEPTION_CANCEL,
 473                                     _("Sorry, can't move the start of "
 474                                       "reiserfs partitions yet."));
 475                 return 0;
 476         }
 477 
 478         fs_info = fs->type_specific;
 479 
 480         fs_len = (blk_t) (geom->length / (reiserfs_fs_block_size(fs_info) /
 481                                           PED_SECTOR_SIZE_DEFAULT));
 482 
 483         dal = reiserfs_fs_host_dal(fs_info);
 484 
 485         if (dal_flags(dal) && O_RDONLY) {
 486                 if (!geom_dal_reopen(dal, O_RDWR)) {
 487                         ped_exception_throw(PED_EXCEPTION_ERROR,
 488                                             PED_EXCEPTION_CANCEL,
 489                                             _("Couldn't reopen device "
 490                                               "abstraction layer for "
 491                                               "read/write."));
 492                         return 0;
 493                 }
 494         }
 495 
 496         ped_timer_reset(timer);
 497 
 498         if (libreiserfs_gauge_create && libreiserfs_gauge_free) {
 499                 if (!
 500                     (gauge =
 501                      libreiserfs_gauge_create(NULL, gauge_handler, timer)))
 502                         return 0;
 503         }
 504 
 505         if (old_length > geom->length) {
 506 
 507                 ped_timer_set_state_name(timer, _("shrinking"));
 508                 ped_timer_update(timer, 0.0);
 509 
 510                 if (!reiserfs_fs_resize(fs_info, fs_len, gauge))
 511                         goto error_free_gauge;
 512 
 513                 ped_geometry_set_end (fs->geom, geom->end);
 514                 dal_realize(dal);
 515         } else {
 516                 ped_geometry_set_end (fs->geom, geom->end);
 517                 dal_realize(dal);
 518 
 519                 ped_timer_set_state_name(timer, _("expanding"));
 520                 ped_timer_update(timer, 0.0);
 521 
 522                 if (!reiserfs_fs_resize(fs_info, fs_len, gauge))
 523                         goto error_free_gauge;
 524         }
 525 
 526         ped_timer_update(timer, 1.0);
 527 
 528         if (gauge)
 529                 libreiserfs_gauge_free(gauge);
 530 
 531         return 1;
 532 
 533 error_free_gauge:
 534         if (gauge)
 535                 libreiserfs_gauge_free(gauge);
 536         ped_geometry_set_end (fs->geom, fs->geom->start + old_length - 1);
 537         return 0;
 538 }
 539 
 540 static PedConstraint *reiserfs_get_resize_constraint(const PedFileSystem *
 541                                                      fs)
 542 {
 543         PedDevice *dev;
 544         PedSector min_size;
 545         PedGeometry full_disk;
 546         reiserfs_fs_t *fs_info;
 547         PedAlignment start_align;
 548         PedGeometry start_sector;
 549 
 550         PED_ASSERT(fs != NULL, return NULL);
 551 
 552         fs_info = fs->type_specific;
 553         dev = fs->geom->dev;
 554 
 555         if (!ped_alignment_init(&start_align, fs->geom->start, 0))
 556                 return NULL;
 557         if (!ped_geometry_init(&full_disk, dev, 0, dev->length - 1))
 558                 return NULL;
 559         if (!ped_geometry_init(&start_sector, dev, fs->geom->start, 1))
 560                 return NULL;
 561 
 562         /* 
 563            Minsize for reiserfs is area occupied by data blocks and 
 564            metadata blocks minus free space blocks and minus bitmap 
 565            blocks which describes free space blocks.
 566          */
 567         min_size = reiserfs_fs_min_size(fs_info) *
 568             (reiserfs_fs_block_size(fs_info) / PED_SECTOR_SIZE_DEFAULT);
 569 
 570         return ped_constraint_new(&start_align, ped_alignment_any,
 571                                   &start_sector, &full_disk, min_size,
 572                                   dev->length);
 573 }
 574 
 575 static PedFileSystem *reiserfs_copy(const PedFileSystem *fs,
 576                                     PedGeometry *geom, PedTimer *timer)
 577 {
 578         dal_t *dal;
 579         PedGeometry *fs_geom;
 580         PedFileSystem *new_fs;
 581         blk_t fs_len, min_needed_blk;
 582 
 583         reiserfs_fs_t *dest_fs, *src_fs;
 584         reiserfs_gauge_t *gauge = NULL;
 585 
 586         fs_geom = ped_geometry_duplicate(geom);
 587 
 588         if (!(dal = geom_dal_create(fs_geom, DEFAULT_BLOCK_SIZE, O_RDWR))) {
 589                 ped_exception_throw(PED_EXCEPTION_ERROR,
 590                                     PED_EXCEPTION_CANCEL,
 591                                     _("Couldn't create reiserfs device "
 592                                       "abstraction handler."));
 593                 goto error_free_fs_geom;
 594         }
 595 
 596         src_fs = fs->type_specific;
 597 
 598         fs_len =
 599             (geom->length / (reiserfs_fs_block_size(src_fs) / PED_SECTOR_SIZE_DEFAULT));
 600         min_needed_blk = reiserfs_fs_bitmap_used(src_fs);
 601 
 602         if (fs_len <= min_needed_blk) {
 603                 ped_exception_throw(PED_EXCEPTION_ERROR,
 604                                     PED_EXCEPTION_CANCEL,
 605                                     _("Device is too small for %lu blocks."),
 606                                     min_needed_blk);
 607                 goto error_free_dal;
 608         }
 609 
 610         if (! (new_fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem))))
 611                 goto error_free_dal;
 612 
 613         ped_timer_reset(timer);
 614         ped_timer_set_state_name(timer, _("copying"));
 615         ped_timer_update(timer, 0.0);
 616 
 617         if (libreiserfs_gauge_create && libreiserfs_gauge_free) {
 618                 if (! (gauge =
 619                      libreiserfs_gauge_create(NULL, gauge_handler, timer)))
 620                         goto error_free_new_fs;
 621         }
 622 
 623         if (!(dest_fs = reiserfs_fs_copy(src_fs, dal, gauge)))
 624                 goto error_free_gauge;
 625 
 626         ped_timer_update(timer, 1.0);
 627 
 628         if (gauge)
 629                 libreiserfs_gauge_free(gauge);
 630 
 631         new_fs->type = reiserfs_type;
 632         new_fs->geom = fs_geom;
 633         new_fs->type_specific = (void *) dest_fs;
 634 
 635         return new_fs;
 636 
 637 error_free_gauge:
 638         if (gauge)
 639                 libreiserfs_gauge_free(gauge);
 640 error_free_new_fs:
 641         ped_free(new_fs);
 642 error_free_dal:
 643         geom_dal_free(dal);
 644 error_free_fs_geom:
 645         ped_geometry_destroy(fs_geom);
 646         return NULL;
 647 }
 648 
 649 static PedConstraint *reiserfs_get_copy_constraint(const PedFileSystem *fs,
 650                                                    const PedDevice *dev)
 651 {
 652         PedGeometry full_dev;
 653 
 654         PED_ASSERT(fs != NULL, return NULL);
 655         PED_ASSERT(dev != NULL, return NULL);
 656 
 657         if (!ped_geometry_init(&full_dev, dev, 0, dev->length - 1))
 658                 return NULL;
 659 
 660         return ped_constraint_new(ped_alignment_any, ped_alignment_any,
 661                                   &full_dev, &full_dev,
 662                                   reiserfs_fs_bitmap_used(fs->type_specific),
 663                                   dev->length);
 664 }
 665 
 666 #endif /* !REISER_FULL_SUPPORT */
 667 
 668 #ifdef DYNAMIC_LOADING
 669 
 670 #define INIT_SYM(SYM)   SYM = getsym (libreiserfs_handle, #SYM)
 671 
 672 static void *getsym(void *handle, const char *symbol)
 673 {
 674         void *entry;
 675         char *error;
 676 
 677         entry = dlsym(handle, symbol);
 678         if ((error = dlerror()) != NULL) {
 679                 ped_exception_throw(PED_EXCEPTION_WARNING,
 680                                     PED_EXCEPTION_IGNORE,
 681                                     _("Couldn't resolve symbol %s.  "
 682                                       "Error: %s."),
 683                                     symbol, error);
 684                 return NULL;
 685         }
 686 
 687         return entry;
 688 }
 689 
 690 static int reiserfs_ops_interface_version_check(void)
 691 {
 692         int min_interface_version, max_interface_version;
 693         int (*libreiserfs_get_max_interface_version) (void);
 694         int (*libreiserfs_get_min_interface_version) (void);
 695 
 696         INIT_SYM(libreiserfs_get_max_interface_version);
 697         INIT_SYM(libreiserfs_get_min_interface_version);
 698 
 699         if (!libreiserfs_get_min_interface_version ||
 700             !libreiserfs_get_max_interface_version) {
 701                 ped_exception_throw(
 702                         PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL,
 703                         _("GNU Parted found an invalid libreiserfs library."));
 704                 return 0;
 705         }
 706 
 707         min_interface_version = libreiserfs_get_min_interface_version();
 708         max_interface_version = libreiserfs_get_max_interface_version();
 709 
 710         if (REISERFS_API_VERSION < min_interface_version ||
 711             REISERFS_API_VERSION > max_interface_version) {
 712                 ped_exception_throw(
 713                         PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL,
 714                         _("GNU Parted has detected libreiserfs interface "
 715                           "version mismatch.  Found %d-%d, required %d. "
 716                           "ReiserFS support will be disabled."),
 717                         min_interface_version,
 718                         max_interface_version,
 719                         REISERFS_API_VERSION);
 720                 return 0;
 721         }
 722 
 723         return 1;
 724 }
 725 
 726 static int reiserfs_ops_init(void)
 727 {
 728         if (!(libreiserfs_handle = dlopen("libreiserfs.so", RTLD_NOW)))
 729                 goto error;
 730 
 731         if (!reiserfs_ops_interface_version_check())
 732                 goto error_free_libreiserfs_handle;
 733 
 734         if (!(libdal_handle = dlopen("libdal.so", RTLD_NOW)))
 735                 goto error_free_libreiserfs_handle;
 736 
 737         INIT_SYM(reiserfs_fs_probe);
 738         INIT_SYM(libreiserfs_exception_type);
 739 
 740         INIT_SYM(libreiserfs_exception_option);
 741         INIT_SYM(libreiserfs_exception_message);
 742         INIT_SYM(libreiserfs_exception_set_handler);
 743 
 744         INIT_SYM(reiserfs_fs_clobber);
 745         INIT_SYM(reiserfs_fs_open);
 746         INIT_SYM(reiserfs_fs_create);
 747         INIT_SYM(reiserfs_fs_resize);
 748         INIT_SYM(reiserfs_fs_copy);
 749 
 750         INIT_SYM(reiserfs_fs_is_resizeable);
 751         INIT_SYM(reiserfs_fs_is_consistent);
 752 
 753         INIT_SYM(reiserfs_fs_bitmap_check);
 754         INIT_SYM(reiserfs_fs_bitmap_used);
 755 
 756         INIT_SYM(reiserfs_fs_min_size);
 757         INIT_SYM(reiserfs_fs_block_size);
 758 
 759         INIT_SYM(reiserfs_fs_host_dal);
 760         INIT_SYM(reiserfs_fs_close);
 761 
 762         INIT_SYM(libreiserfs_gauge_create);
 763         INIT_SYM(libreiserfs_gauge_free);
 764 
 765         INIT_SYM(dal_realize);
 766         INIT_SYM(dal_flags);
 767 
 768         INIT_SYM(dal_block_size);
 769         INIT_SYM(dal_len);
 770 
 771         return 1;
 772 
 773 error_free_libreiserfs_handle:
 774         dlclose(libreiserfs_handle);
 775         libreiserfs_handle = NULL;
 776 error:
 777         return 0;
 778 }
 779 
 780 static void reiserfs_ops_done()
 781 {
 782         if (libdal_handle)
 783                 dlclose(libdal_handle);
 784         if (libreiserfs_handle)
 785                 dlclose(libreiserfs_handle);
 786 }
 787 #endif /* DYNAMIC_LOADING */
 788 
 789 #define REISER_BLOCK_SIZES ((int[]){512, 1024, 2048, 4096, 8192, 0})
 790 
 791 #ifdef REISER_FULL_SUPPORT
 792 static PedFileSystemOps reiserfs_full_ops = {
 793         .probe =                reiserfs_probe,
 794         .clobber =      reiserfs_clobber,
 795         .open =         reiserfs_open,
 796         .create =               reiserfs_create,
 797         .close =                reiserfs_close,
 798         .check =                reiserfs_check,
 799         .copy =         reiserfs_copy,
 800         .resize =               reiserfs_resize,
 801         .get_create_constraint =        reiserfs_get_create_constraint,
 802         .get_resize_constraint =        reiserfs_get_resize_constraint,
 803         .get_copy_constraint =  reiserfs_get_copy_constraint
 804 };
 805 
 806 static PedFileSystemType reiserfs_full_type = {
 807         .next = NULL,
 808         .ops =  &reiserfs_full_ops,
 809         .name = "reiserfs",
 810         .block_sizes =    REISER_BLOCK_SIZES
 811 };
 812 #endif /* REISER_FULL_SUPPORT */
 813 
 814 static PedFileSystemOps reiserfs_simple_ops = {
 815         .probe =                reiserfs_probe,
 816 #ifdef DISCOVER_ONLY
 817         .clobber =      NULL,
 818 #else
 819         .clobber =      reiserfs_clobber,
 820 #endif
 821         .open =         NULL,
 822         .create =               NULL,
 823         .close =                NULL,
 824         .check =                NULL,
 825         .copy =         NULL,
 826         .resize =               NULL,
 827         .get_create_constraint =        NULL,
 828         .get_resize_constraint =        NULL,
 829         .get_copy_constraint =  NULL
 830 };
 831 
 832 static PedFileSystemType reiserfs_simple_type = {
 833         .next =         NULL,
 834         .ops =          &reiserfs_simple_ops,
 835         .name =         "reiserfs",
 836         .block_sizes =    REISER_BLOCK_SIZES
 837 };
 838 
 839 void ped_file_system_reiserfs_init()
 840 {
 841 #ifdef DYNAMIC_LOADING
 842         libreiserfs_present = reiserfs_ops_init();
 843         if (libreiserfs_present) {
 844                 reiserfs_type = &reiserfs_full_type;
 845                 libreiserfs_exception_set_handler(exception_handler);
 846         } else {
 847                 reiserfs_type = &reiserfs_simple_type;
 848         }
 849 #else   /* !DYNAMIC_LOADING */
 850 #ifdef REISER_FULL_SUPPORT
 851         libreiserfs_exception_set_handler(exception_handler);
 852         reiserfs_type = &reiserfs_full_type;
 853 #else
 854         reiserfs_type = &reiserfs_simple_type;
 855 #endif
 856 #endif  /* !DYNAMIC_LOADING */
 857         ped_file_system_type_register(reiserfs_type);
 858 }
 859 
 860 void ped_file_system_reiserfs_done()
 861 {
 862         ped_file_system_type_unregister(reiserfs_type);
 863 #ifdef DYNAMIC_LOADING
 864         reiserfs_ops_done();
 865 #endif /* DYNAMIC_LOADING */
 866 }