| /* |
| reiserfs.c -- libparted / libreiserfs glue |
| Copyright (C) 2001, 2002, 2007 Free Software Foundation, Inc. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| |
| This is all rather complicated. There are a few combinations: |
| * shared libraries full support |
| * dynamic libraries present full support (via dlopen) |
| * dynamic libraries absent (full support disabled) (via dlopen) |
| * discover only |
| |
| We'd love to hear comments... |
| |
| So far, we've opted for maximum flexibility for the user. Is it |
| all worth it? |
| */ |
| |
| #include <config.h> |
| |
| #if (HAVE_LIBREISERFS || DYNAMIC_LOADING) && !DISCOVER_ONLY |
| # define REISER_FULL_SUPPORT |
| #endif |
| |
| #include <uuid/uuid.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| |
| #ifdef DYNAMIC_LOADING |
| # include <dlfcn.h> |
| #endif |
| |
| #include <parted/parted.h> |
| #include <parted/debug.h> |
| #include <parted/endian.h> |
| |
| #if ENABLE_NLS |
| # include <libintl.h> |
| # define _(String) dgettext (PACKAGE, String) |
| #else |
| # define _(String) (String) |
| #endif |
| |
| #include "reiserfs.h" |
| #include "geom_dal.h" |
| |
| #define REISERFS_BLOCK_SIZES ((int[2]){512, 0}) |
| |
| static PedSector reiserfs_super_offset[] = { 128, 16, -1 }; |
| static PedFileSystemType* reiserfs_type; |
| |
| #ifdef DYNAMIC_LOADING |
| # define FPTR * |
| # define FCLASS static |
| #else |
| # define FPTR |
| # define FCLASS extern |
| #endif |
| |
| #ifdef DYNAMIC_LOADING |
| |
| static int libreiserfs_present; |
| |
| static void *libdal_handle; |
| static void *libreiserfs_handle; |
| |
| #endif /* DYNAMIC_LOADING */ |
| |
| #ifdef REISER_FULL_SUPPORT |
| |
| FCLASS blk_t (FPTR reiserfs_fs_probe) (dal_t *); |
| |
| FCLASS int (FPTR libreiserfs_exception_type) (reiserfs_exception_t *); |
| FCLASS int (FPTR libreiserfs_exception_option) (reiserfs_exception_t *); |
| FCLASS char *(FPTR libreiserfs_exception_message) (reiserfs_exception_t *); |
| FCLASS void (FPTR libreiserfs_exception_set_handler) |
| (int(FPTR)(reiserfs_exception_t *)); |
| |
| FCLASS void (FPTR dal_realize) (dal_t *); |
| FCLASS size_t (FPTR dal_block_size) (dal_t *); |
| FCLASS blk_t (FPTR dal_len) (dal_t *); |
| FCLASS int (FPTR dal_flags) (dal_t *); |
| |
| FCLASS reiserfs_fs_t* (FPTR reiserfs_fs_open) (dal_t *, dal_t *); |
| FCLASS reiserfs_fs_t* (FPTR reiserfs_fs_create) (dal_t *, dal_t *, |
| blk_t, blk_t, blk_t, size_t, |
| int, int, const char *, |
| const char *, blk_t, |
| reiserfs_gauge_t *); |
| |
| FCLASS int (FPTR reiserfs_fs_resize) (reiserfs_fs_t *, blk_t, reiserfs_gauge_t *); |
| #ifdef HAVE_REISERFS_FS_CHECK |
| FCLASS int (FPTR reiserfs_fs_check) (reiserfs_fs_t *, reiserfs_gauge_t *); |
| #endif |
| |
| FCLASS reiserfs_fs_t *(FPTR reiserfs_fs_copy) (reiserfs_fs_t *, dal_t *, |
| reiserfs_gauge_t *); |
| |
| FCLASS int (FPTR reiserfs_fs_clobber) (dal_t *); |
| FCLASS void (FPTR reiserfs_fs_close) (reiserfs_fs_t *); |
| |
| FCLASS int (FPTR reiserfs_fs_is_resizeable) (reiserfs_fs_t *); |
| FCLASS int (FPTR reiserfs_fs_is_consistent) (reiserfs_fs_t *); |
| |
| FCLASS blk_t (FPTR reiserfs_fs_min_size) (reiserfs_fs_t *); |
| FCLASS blk_t (FPTR reiserfs_fs_block_size) (reiserfs_fs_t *); |
| FCLASS dal_t* (FPTR reiserfs_fs_host_dal) (reiserfs_fs_t *); |
| |
| FCLASS blk_t (FPTR reiserfs_fs_bitmap_used) (reiserfs_fs_t *); |
| FCLASS int (FPTR reiserfs_fs_bitmap_check) (reiserfs_fs_t *); |
| |
| FCLASS reiserfs_gauge_t *(FPTR libreiserfs_gauge_create) ( |
| char *, reiserfs_gauge_handler_t, void *); |
| |
| FCLASS void (FPTR libreiserfs_gauge_free) (reiserfs_gauge_t *); |
| |
| static void gauge_handler(const char *name, unsigned int value, void *data, |
| int determined, int update_header, |
| int update_footer) |
| { |
| PedTimer *timer = (PedTimer *) data; |
| ped_timer_set_state_name(timer, name); |
| ped_timer_update(timer, 1.0 * value / 100); |
| } |
| |
| static PedExceptionOption |
| exopt_libreiserfs_to_parted(reiserfs_exception_option_t option) |
| { |
| switch (option) { |
| case EXCEPTION_UNHANDLED: |
| return PED_EXCEPTION_UNHANDLED; |
| case EXCEPTION_FIX: |
| return PED_EXCEPTION_FIX; |
| case EXCEPTION_YES: |
| return PED_EXCEPTION_YES; |
| case EXCEPTION_NO: |
| return PED_EXCEPTION_NO; |
| case EXCEPTION_OK: |
| return PED_EXCEPTION_OK; |
| case EXCEPTION_RETRY: |
| return PED_EXCEPTION_RETRY; |
| case EXCEPTION_IGNORE: |
| return PED_EXCEPTION_IGNORE; |
| case EXCEPTION_CANCEL: |
| return PED_EXCEPTION_CANCEL; |
| |
| default: |
| return PED_EXCEPTION_UNHANDLED; |
| } |
| } |
| |
| static PedExceptionType |
| extype_libreiserfs_to_parted(reiserfs_exception_type_t type) |
| { |
| switch (type) { |
| case EXCEPTION_INFORMATION: |
| return PED_EXCEPTION_INFORMATION; |
| case EXCEPTION_WARNING: |
| return PED_EXCEPTION_WARNING; |
| case EXCEPTION_ERROR: |
| return PED_EXCEPTION_ERROR; |
| case EXCEPTION_FATAL: |
| return PED_EXCEPTION_FATAL; |
| case EXCEPTION_BUG: |
| return PED_EXCEPTION_BUG; |
| case EXCEPTION_NO_FEATURE: |
| return PED_EXCEPTION_NO_FEATURE; |
| |
| default: |
| return PED_EXCEPTION_NO_FEATURE; |
| } |
| } |
| |
| static int exception_handler(reiserfs_exception_t *exception) |
| { |
| int ex_type = libreiserfs_exception_type(exception); |
| int ex_option = libreiserfs_exception_option(exception); |
| char *ex_message = libreiserfs_exception_message(exception); |
| |
| return ped_exception_throw (extype_libreiserfs_to_parted (ex_type), |
| exopt_libreiserfs_to_parted (ex_option), |
| ex_message); |
| } |
| #endif /* REISER_FULL_SUPPORT */ |
| |
| static PedGeometry *reiserfs_probe(PedGeometry *geom) |
| { |
| int i; |
| reiserfs_super_block_t sb; |
| |
| PED_ASSERT(geom != NULL, return NULL); |
| |
| for (i = 0; reiserfs_super_offset[i] != -1; i++) { |
| if (reiserfs_super_offset[i] >= geom->length) |
| continue; |
| if (!ped_geometry_read (geom, &sb, reiserfs_super_offset[i], 1)) |
| continue; |
| |
| if (strncmp(REISERFS_SIGNATURE, sb.s_magic, |
| strlen(REISERFS_SIGNATURE)) == 0 |
| || strncmp(REISER2FS_SIGNATURE, sb.s_magic, |
| strlen(REISER2FS_SIGNATURE)) == 0 |
| || strncmp(REISER3FS_SIGNATURE, sb.s_magic, |
| strlen(REISER3FS_SIGNATURE)) == 0) { |
| PedSector block_size; |
| PedSector block_count; |
| |
| block_size = PED_LE16_TO_CPU(sb.s_blocksize) |
| / PED_SECTOR_SIZE_DEFAULT; |
| block_count = PED_LE32_TO_CPU(sb.s_block_count); |
| |
| return ped_geometry_new(geom->dev, geom->start, |
| block_size * block_count); |
| } |
| } |
| return NULL; |
| } |
| |
| #ifndef DISCOVER_ONLY |
| static int reiserfs_clobber(PedGeometry *geom) |
| { |
| int i; |
| char buf[512]; |
| |
| PED_ASSERT(geom != NULL, return 0); |
| |
| memset(buf, 0, 512); |
| for (i = 0; reiserfs_super_offset[i] != -1; i++) { |
| if (reiserfs_super_offset[i] >= geom->length) |
| continue; |
| if (!ped_geometry_write |
| (geom, buf, reiserfs_super_offset[i], 1)) |
| return 0; |
| } |
| return 1; |
| } |
| #endif /* !DISCOVER_ONLY */ |
| |
| #ifdef REISER_FULL_SUPPORT |
| |
| static PedFileSystem *reiserfs_open(PedGeometry *geom) |
| { |
| PedFileSystem *fs; |
| PedGeometry *fs_geom; |
| dal_t *dal; |
| reiserfs_fs_t *fs_info; |
| |
| PED_ASSERT(geom != NULL, return NULL); |
| |
| if (!(fs_geom = ped_geometry_duplicate(geom))) |
| goto error; |
| |
| if (! (dal = geom_dal_create(fs_geom, DEFAULT_BLOCK_SIZE, O_RDONLY))) |
| goto error_fs_geom_free; |
| |
| /* |
| We are passing NULL as DAL for journal. Therefore we let libreiserfs know, |
| that journal not available and parted will be working fine for reiserfs |
| with relocated journal too. |
| */ |
| if (!(fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem)))) |
| goto error_free_dal; |
| |
| if (!(fs_info = reiserfs_fs_open(dal, NULL))) |
| goto error_free_fs; |
| |
| fs->type = reiserfs_type; |
| fs->geom = fs_geom; |
| fs->type_specific = (void *) fs_info; |
| |
| return fs; |
| |
| error_free_fs: |
| ped_free(fs); |
| error_free_dal: |
| geom_dal_free(dal); |
| error_fs_geom_free: |
| ped_geometry_destroy(fs_geom); |
| error: |
| return NULL; |
| } |
| |
| static PedFileSystem *reiserfs_create(PedGeometry *geom, PedTimer *timer) |
| { |
| dal_t *dal; |
| uuid_t uuid; |
| PedFileSystem *fs; |
| PedGeometry *fs_geom; |
| reiserfs_fs_t *fs_info; |
| reiserfs_gauge_t *gauge = NULL; |
| |
| PED_ASSERT(geom != NULL, return NULL); |
| |
| fs_geom = ped_geometry_duplicate(geom); |
| |
| if (!(dal = geom_dal_create(fs_geom, DEFAULT_BLOCK_SIZE, O_RDWR))) |
| goto error_fs_geom_free; |
| |
| memset(uuid, 0, sizeof(uuid)); |
| uuid_generate(uuid); |
| |
| ped_timer_reset(timer); |
| ped_timer_set_state_name(timer, _("creating")); |
| |
| if (libreiserfs_gauge_create && libreiserfs_gauge_free) { |
| if (! (gauge = |
| libreiserfs_gauge_create(NULL, gauge_handler, timer))) |
| goto error_free_dal; |
| } |
| |
| if (!(fs_info = reiserfs_fs_create(dal, dal, 0, JOURNAL_MAX_TRANS, |
| DEFAULT_JOURNAL_SIZE, |
| DEFAULT_BLOCK_SIZE, |
| FS_FORMAT_3_6, R5_HASH, NULL, |
| (char *) uuid, dal_len(dal), |
| gauge))) |
| goto error_free_gauge; |
| |
| ped_timer_update(timer, 1.0); |
| |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| |
| if (!(fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem)))) |
| goto error_free_fs_info; |
| |
| fs->type = reiserfs_type; |
| fs->geom = fs_geom; |
| fs->type_specific = (void *) fs_info; |
| |
| return fs; |
| |
| error_free_fs_info: |
| ped_free(fs_info); |
| error_free_gauge: |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| error_free_dal: |
| geom_dal_free(dal); |
| error_fs_geom_free: |
| ped_geometry_destroy(fs_geom); |
| return NULL; |
| } |
| |
| static int reiserfs_close(PedFileSystem *fs) |
| { |
| dal_t *dal; |
| |
| PED_ASSERT(fs != NULL, return 0); |
| |
| dal = reiserfs_fs_host_dal(fs->type_specific); |
| reiserfs_fs_close(fs->type_specific); |
| |
| geom_dal_free(dal); |
| ped_geometry_sync(fs->geom); |
| |
| ped_free(fs); |
| return 1; |
| } |
| |
| static PedConstraint *reiserfs_get_create_constraint(const PedDevice *dev) |
| { |
| PedGeometry full_dev; |
| PedSector min_blks = (SUPER_OFFSET_IN_BYTES / DEFAULT_BLOCK_SIZE) |
| + 2 + DEFAULT_JOURNAL_SIZE + 1 + 100 + 1; |
| |
| if (!ped_geometry_init(&full_dev, dev, 0, dev->length - 1)) |
| return NULL; |
| |
| return ped_constraint_new(ped_alignment_any, ped_alignment_any, |
| &full_dev, &full_dev, |
| min_blks * (DEFAULT_BLOCK_SIZE / 512), |
| dev->length); |
| } |
| |
| static int reiserfs_check(PedFileSystem *fs, PedTimer *timer) |
| { |
| reiserfs_fs_t *fs_info; |
| #ifdef HAVE_REISERFS_FS_CHECK |
| reiserfs_gauge_t *gauge = NULL; |
| #endif |
| |
| PED_ASSERT(fs != NULL, return 0); |
| |
| fs_info = fs->type_specific; |
| |
| if (!reiserfs_fs_is_consistent(fs_info)) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("The file system is in an invalid " |
| "state. Perhaps it is mounted?")); |
| return 0; |
| } |
| |
| if (!reiserfs_fs_is_resizeable(fs_info)) |
| ped_exception_throw(PED_EXCEPTION_WARNING, |
| PED_EXCEPTION_IGNORE, |
| _("The file system is in old " |
| "(unresizeable) format.")); |
| |
| if (!reiserfs_fs_bitmap_check(fs_info)) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Invalid free blocks count. Run " |
| "reiserfsck --check first.")); |
| return 0; |
| } |
| |
| #ifdef HAVE_REISERFS_FS_CHECK |
| ped_timer_reset(timer); |
| |
| if (libreiserfs_gauge_create && libreiserfs_gauge_free) { |
| if (! |
| (gauge = |
| libreiserfs_gauge_create(NULL, gauge_handler, timer))) |
| return 0; |
| } |
| |
| ped_timer_set_state_name(timer, _("checking")); |
| ped_timer_update(timer, 0.0); |
| |
| if (!reiserfs_fs_check(fs_info, gauge)) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Reiserfs tree seems to be corrupted. " |
| "Run reiserfsck --check first.")); |
| return 0; |
| } |
| |
| ped_timer_update(timer, 1.0); |
| |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| #endif |
| |
| ped_exception_throw(PED_EXCEPTION_INFORMATION, PED_EXCEPTION_OK, |
| _("The reiserfs file system passed a basic check. " |
| "For a more comprehensive check, run " |
| "reiserfsck --check.")); |
| |
| return 1; |
| } |
| |
| static int reiserfs_resize(PedFileSystem *fs, PedGeometry *geom, |
| PedTimer *timer) |
| { |
| dal_t *dal; |
| blk_t fs_len; |
| PedSector old_length; |
| reiserfs_fs_t *fs_info; |
| reiserfs_gauge_t *gauge = NULL; |
| |
| PED_ASSERT(fs != NULL, return 0); |
| |
| old_length = fs->geom->length; |
| |
| PED_ASSERT (fs->geom->dev == geom->dev, return 0); |
| |
| if (fs->geom->start != geom->start) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Sorry, can't move the start of " |
| "reiserfs partitions yet.")); |
| return 0; |
| } |
| |
| fs_info = fs->type_specific; |
| |
| fs_len = (blk_t) (geom->length / (reiserfs_fs_block_size(fs_info) / |
| PED_SECTOR_SIZE_DEFAULT)); |
| |
| dal = reiserfs_fs_host_dal(fs_info); |
| |
| if (dal_flags(dal) && O_RDONLY) { |
| if (!geom_dal_reopen(dal, O_RDWR)) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Couldn't reopen device " |
| "abstraction layer for " |
| "read/write.")); |
| return 0; |
| } |
| } |
| |
| ped_timer_reset(timer); |
| |
| if (libreiserfs_gauge_create && libreiserfs_gauge_free) { |
| if (! |
| (gauge = |
| libreiserfs_gauge_create(NULL, gauge_handler, timer))) |
| return 0; |
| } |
| |
| if (old_length > geom->length) { |
| |
| ped_timer_set_state_name(timer, _("shrinking")); |
| ped_timer_update(timer, 0.0); |
| |
| if (!reiserfs_fs_resize(fs_info, fs_len, gauge)) |
| goto error_free_gauge; |
| |
| ped_geometry_set_end (fs->geom, geom->end); |
| dal_realize(dal); |
| } else { |
| ped_geometry_set_end (fs->geom, geom->end); |
| dal_realize(dal); |
| |
| ped_timer_set_state_name(timer, _("expanding")); |
| ped_timer_update(timer, 0.0); |
| |
| if (!reiserfs_fs_resize(fs_info, fs_len, gauge)) |
| goto error_free_gauge; |
| } |
| |
| ped_timer_update(timer, 1.0); |
| |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| |
| return 1; |
| |
| error_free_gauge: |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| ped_geometry_set_end (fs->geom, fs->geom->start + old_length - 1); |
| return 0; |
| } |
| |
| static PedConstraint *reiserfs_get_resize_constraint(const PedFileSystem * |
| fs) |
| { |
| PedDevice *dev; |
| PedSector min_size; |
| PedGeometry full_disk; |
| reiserfs_fs_t *fs_info; |
| PedAlignment start_align; |
| PedGeometry start_sector; |
| |
| PED_ASSERT(fs != NULL, return NULL); |
| |
| fs_info = fs->type_specific; |
| dev = fs->geom->dev; |
| |
| if (!ped_alignment_init(&start_align, fs->geom->start, 0)) |
| return NULL; |
| if (!ped_geometry_init(&full_disk, dev, 0, dev->length - 1)) |
| return NULL; |
| if (!ped_geometry_init(&start_sector, dev, fs->geom->start, 1)) |
| return NULL; |
| |
| /* |
| Minsize for reiserfs is area occupied by data blocks and |
| metadata blocks minus free space blocks and minus bitmap |
| blocks which describes free space blocks. |
| */ |
| min_size = reiserfs_fs_min_size(fs_info) * |
| (reiserfs_fs_block_size(fs_info) / PED_SECTOR_SIZE_DEFAULT); |
| |
| return ped_constraint_new(&start_align, ped_alignment_any, |
| &start_sector, &full_disk, min_size, |
| dev->length); |
| } |
| |
| static PedFileSystem *reiserfs_copy(const PedFileSystem *fs, |
| PedGeometry *geom, PedTimer *timer) |
| { |
| dal_t *dal; |
| PedGeometry *fs_geom; |
| PedFileSystem *new_fs; |
| blk_t fs_len, min_needed_blk; |
| |
| reiserfs_fs_t *dest_fs, *src_fs; |
| reiserfs_gauge_t *gauge = NULL; |
| |
| fs_geom = ped_geometry_duplicate(geom); |
| |
| if (!(dal = geom_dal_create(fs_geom, DEFAULT_BLOCK_SIZE, O_RDWR))) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Couldn't create reiserfs device " |
| "abstraction handler.")); |
| goto error_free_fs_geom; |
| } |
| |
| src_fs = fs->type_specific; |
| |
| fs_len = |
| (geom->length / (reiserfs_fs_block_size(src_fs) / PED_SECTOR_SIZE_DEFAULT)); |
| min_needed_blk = reiserfs_fs_bitmap_used(src_fs); |
| |
| if (fs_len <= min_needed_blk) { |
| ped_exception_throw(PED_EXCEPTION_ERROR, |
| PED_EXCEPTION_CANCEL, |
| _("Device is too small for %lu blocks."), |
| min_needed_blk); |
| goto error_free_dal; |
| } |
| |
| if (! (new_fs = (PedFileSystem *) ped_malloc(sizeof(PedFileSystem)))) |
| goto error_free_dal; |
| |
| ped_timer_reset(timer); |
| ped_timer_set_state_name(timer, _("copying")); |
| ped_timer_update(timer, 0.0); |
| |
| if (libreiserfs_gauge_create && libreiserfs_gauge_free) { |
| if (! (gauge = |
| libreiserfs_gauge_create(NULL, gauge_handler, timer))) |
| goto error_free_new_fs; |
| } |
| |
| if (!(dest_fs = reiserfs_fs_copy(src_fs, dal, gauge))) |
| goto error_free_gauge; |
| |
| ped_timer_update(timer, 1.0); |
| |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| |
| new_fs->type = reiserfs_type; |
| new_fs->geom = fs_geom; |
| new_fs->type_specific = (void *) dest_fs; |
| |
| return new_fs; |
| |
| error_free_gauge: |
| if (gauge) |
| libreiserfs_gauge_free(gauge); |
| error_free_new_fs: |
| ped_free(new_fs); |
| error_free_dal: |
| geom_dal_free(dal); |
| error_free_fs_geom: |
| ped_geometry_destroy(fs_geom); |
| return NULL; |
| } |
| |
| static PedConstraint *reiserfs_get_copy_constraint(const PedFileSystem *fs, |
| const PedDevice *dev) |
| { |
| PedGeometry full_dev; |
| |
| PED_ASSERT(fs != NULL, return NULL); |
| PED_ASSERT(dev != NULL, return NULL); |
| |
| if (!ped_geometry_init(&full_dev, dev, 0, dev->length - 1)) |
| return NULL; |
| |
| return ped_constraint_new(ped_alignment_any, ped_alignment_any, |
| &full_dev, &full_dev, |
| reiserfs_fs_bitmap_used(fs->type_specific), |
| dev->length); |
| } |
| |
| #endif /* !REISER_FULL_SUPPORT */ |
| |
| #ifdef DYNAMIC_LOADING |
| |
| #define INIT_SYM(SYM) SYM = getsym (libreiserfs_handle, #SYM) |
| |
| static void *getsym(void *handle, const char *symbol) |
| { |
| void *entry; |
| char *error; |
| |
| entry = dlsym(handle, symbol); |
| if ((error = dlerror()) != NULL) { |
| ped_exception_throw(PED_EXCEPTION_WARNING, |
| PED_EXCEPTION_IGNORE, |
| _("Couldn't resolve symbol %s. " |
| "Error: %s."), |
| symbol, error); |
| return NULL; |
| } |
| |
| return entry; |
| } |
| |
| static int reiserfs_ops_interface_version_check(void) |
| { |
| int min_interface_version, max_interface_version; |
| int (*libreiserfs_get_max_interface_version) (void); |
| int (*libreiserfs_get_min_interface_version) (void); |
| |
| INIT_SYM(libreiserfs_get_max_interface_version); |
| INIT_SYM(libreiserfs_get_min_interface_version); |
| |
| if (!libreiserfs_get_min_interface_version || |
| !libreiserfs_get_max_interface_version) { |
| ped_exception_throw( |
| PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL, |
| _("GNU Parted found an invalid libreiserfs library.")); |
| return 0; |
| } |
| |
| min_interface_version = libreiserfs_get_min_interface_version(); |
| max_interface_version = libreiserfs_get_max_interface_version(); |
| |
| if (REISERFS_API_VERSION < min_interface_version || |
| REISERFS_API_VERSION > max_interface_version) { |
| ped_exception_throw( |
| PED_EXCEPTION_WARNING, PED_EXCEPTION_CANCEL, |
| _("GNU Parted has detected libreiserfs interface " |
| "version mismatch. Found %d-%d, required %d. " |
| "ReiserFS support will be disabled."), |
| min_interface_version, |
| max_interface_version, |
| REISERFS_API_VERSION); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int reiserfs_ops_init(void) |
| { |
| if (!(libreiserfs_handle = dlopen("libreiserfs.so", RTLD_NOW))) |
| goto error; |
| |
| if (!reiserfs_ops_interface_version_check()) |
| goto error_free_libreiserfs_handle; |
| |
| if (!(libdal_handle = dlopen("libdal.so", RTLD_NOW))) |
| goto error_free_libreiserfs_handle; |
| |
| INIT_SYM(reiserfs_fs_probe); |
| INIT_SYM(libreiserfs_exception_type); |
| |
| INIT_SYM(libreiserfs_exception_option); |
| INIT_SYM(libreiserfs_exception_message); |
| INIT_SYM(libreiserfs_exception_set_handler); |
| |
| INIT_SYM(reiserfs_fs_clobber); |
| INIT_SYM(reiserfs_fs_open); |
| INIT_SYM(reiserfs_fs_create); |
| INIT_SYM(reiserfs_fs_resize); |
| INIT_SYM(reiserfs_fs_copy); |
| |
| INIT_SYM(reiserfs_fs_is_resizeable); |
| INIT_SYM(reiserfs_fs_is_consistent); |
| |
| INIT_SYM(reiserfs_fs_bitmap_check); |
| INIT_SYM(reiserfs_fs_bitmap_used); |
| |
| INIT_SYM(reiserfs_fs_min_size); |
| INIT_SYM(reiserfs_fs_block_size); |
| |
| INIT_SYM(reiserfs_fs_host_dal); |
| INIT_SYM(reiserfs_fs_close); |
| |
| INIT_SYM(libreiserfs_gauge_create); |
| INIT_SYM(libreiserfs_gauge_free); |
| |
| INIT_SYM(dal_realize); |
| INIT_SYM(dal_flags); |
| |
| INIT_SYM(dal_block_size); |
| INIT_SYM(dal_len); |
| |
| return 1; |
| |
| error_free_libreiserfs_handle: |
| dlclose(libreiserfs_handle); |
| libreiserfs_handle = NULL; |
| error: |
| return 0; |
| } |
| |
| static void reiserfs_ops_done() |
| { |
| if (libdal_handle) |
| dlclose(libdal_handle); |
| if (libreiserfs_handle) |
| dlclose(libreiserfs_handle); |
| } |
| #endif /* DYNAMIC_LOADING */ |
| |
| #define REISER_BLOCK_SIZES ((int[]){512, 1024, 2048, 4096, 8192, 0}) |
| |
| #ifdef REISER_FULL_SUPPORT |
| static PedFileSystemOps reiserfs_full_ops = { |
| probe: reiserfs_probe, |
| clobber: reiserfs_clobber, |
| open: reiserfs_open, |
| create: reiserfs_create, |
| close: reiserfs_close, |
| check: reiserfs_check, |
| copy: reiserfs_copy, |
| resize: reiserfs_resize, |
| get_create_constraint: reiserfs_get_create_constraint, |
| get_resize_constraint: reiserfs_get_resize_constraint, |
| get_copy_constraint: reiserfs_get_copy_constraint |
| }; |
| |
| static PedFileSystemType reiserfs_full_type = { |
| next: NULL, |
| ops: &reiserfs_full_ops, |
| name: "reiserfs", |
| block_sizes: REISER_BLOCK_SIZES |
| }; |
| #endif /* REISER_FULL_SUPPORT */ |
| |
| static PedFileSystemOps reiserfs_simple_ops = { |
| probe: reiserfs_probe, |
| #ifdef DISCOVER_ONLY |
| clobber: NULL, |
| #else |
| clobber: reiserfs_clobber, |
| #endif |
| open: NULL, |
| create: NULL, |
| close: NULL, |
| check: NULL, |
| copy: NULL, |
| resize: NULL, |
| get_create_constraint: NULL, |
| get_resize_constraint: NULL, |
| get_copy_constraint: NULL |
| }; |
| |
| static PedFileSystemType reiserfs_simple_type = { |
| next: NULL, |
| ops: &reiserfs_simple_ops, |
| name: "reiserfs", |
| block_sizes: REISER_BLOCK_SIZES |
| }; |
| |
| void ped_file_system_reiserfs_init() |
| { |
| #ifdef DYNAMIC_LOADING |
| libreiserfs_present = reiserfs_ops_init(); |
| if (libreiserfs_present) { |
| reiserfs_type = &reiserfs_full_type; |
| libreiserfs_exception_set_handler(exception_handler); |
| } else { |
| reiserfs_type = &reiserfs_simple_type; |
| } |
| #else /* !DYNAMIC_LOADING */ |
| #ifdef REISER_FULL_SUPPORT |
| libreiserfs_exception_set_handler(exception_handler); |
| reiserfs_type = &reiserfs_full_type; |
| #else |
| reiserfs_type = &reiserfs_simple_type; |
| #endif |
| #endif /* !DYNAMIC_LOADING */ |
| ped_file_system_type_register(reiserfs_type); |
| } |
| |
| void ped_file_system_reiserfs_done() |
| { |
| ped_file_system_type_unregister(reiserfs_type); |
| #ifdef DYNAMIC_LOADING |
| reiserfs_ops_done(); |
| #endif /* DYNAMIC_LOADING */ |
| } |