--- evms-2.5.0.orig/aclocal.m4 2004-10-20 23:50:31 +0400 +++ evms-2.5.0/aclocal.m4 2004-11-19 15:00:21 +0300 @@ -116,6 +116,11 @@ [Disable the ReiserFS FSIM]), [build_reiser="$enableval"], [build_reiser="yes"]) +AC_ARG_ENABLE([fat], + AC_HELP_STRING([--disable-fat], + [Disable the FAT FSIM]), + [build_fat="$enableval"], + [build_fat="yes"]) AC_ARG_ENABLE([xfs], AC_HELP_STRING([--disable-xfs], [Disable the XFS FSIM]), @@ -145,7 +150,7 @@ # Create the list of plugin directories to build. This is where each plugin # can specify its dependencies. plugin_dirs="" -plugin_distdirs="bbr bbr_seg bsd csm disk dos drivelink error ext2 gpt ha jfs lvm lvm2 mac md multipath ntfs ogfs reiser replace rsct s390 snapshot swap xfs" +plugin_distdirs="bbr bbr_seg bsd csm disk dos drivelink error ext2 gpt ha jfs lvm lvm2 mac md multipath ntfs ogfs reiser fat replace rsct s390 snapshot swap xfs" # BBR if test "$build_bbr" = "no"; then @@ -323,6 +328,14 @@ AC_MSG_NOTICE([ building reiser]) fi +# FAT +if test "$build_fat" = "no"; then + AC_MSG_NOTICE([ not building fat ... disabled by user]) +else + plugin_dirs="$plugin_dirs fat" + AC_MSG_NOTICE([ building fat]) +fi + # Replace if test "$build_replace" = "no"; then AC_MSG_NOTICE([ not building replace ... disabled by user]) --- evms-2.5.0.orig/configure.ac 2004-10-20 23:46:50 +0400 +++ evms-2.5.0/configure.ac 2004-11-19 15:00:36 +0300 @@ -177,6 +177,7 @@ [plugins/ntfs/Makefile] \ [plugins/ogfs/Makefile] \ [plugins/reiser/Makefile] \ + [plugins/fat/Makefile] \ [plugins/replace/Makefile] \ [plugins/rsct/Makefile] \ [plugins/s390/Makefile] \ --- evms-2.5.0/plugins/dos/segoptions.c.orig 2004-09-13 19:15:46 +0400 +++ evms-2.5.0/plugins/dos/segoptions.c 2005-01-18 21:23:29 +0300 @@ -49,6 +49,7 @@ static const struct seg_partition_type_info_s partition_types[] = { + {"FAT32", 0x0b}, {"FAT16", 6}, {"HPFS", 7}, {"NTFS", 7}, diff -Naur evms-2.5.2/plugins/fat.orig/fatfsim.c evms-2.5.2/plugins/fat/fatfsim.c --- evms-2.5.2/plugins/fat.orig/fatfsim.c 1970-01-01 03:00:00 +0300 +++ evms-2.5.2/plugins/fat/fatfsim.c 2005-09-12 17:24:51 +0400 @@ -0,0 +1,1323 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: fatfsim.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "fatfsim.h" +#include "utils.h" + +/* FIXME: correct min FAT size */ +#define MIN_FAT_SIZE (8 * 1024) + +static plugin_record_t fat_plugrec; +static plugin_record_t fat16_plugrec; +plugin_record_t * my_plugin_record; +engine_functions_t * EngFncs; +boolean have_mkdosfs = FALSE; +boolean have_dosfsck = FALSE; +boolean have_fatresize = FALSE; + +static int fat_setup(engine_functions_t *engine_function_table) { + + int rc = 0; + + EngFncs = engine_function_table; + + LOG_ENTRY(); + + if (try_run("mkdosfs") == 0) { + have_mkdosfs = TRUE; + } + + if (try_run("dosfsck") == 0) { + have_dosfsck = TRUE; + } + + if (try_run("fatresize") == 0) { + have_fatresize = TRUE; + } + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Free all of the private data we have left on volumes. + */ +static void _fat_cleanup(int isfat16) { + int rc = 0; + list_anchor_t global_volumes; + list_element_t iter; + logical_volume_t * vol; + LOG_ENTRY(); + + rc = EngFncs->get_volume_list(my_plugin_record, NULL, 0, &global_volumes); + if (!rc) { + LIST_FOR_EACH(global_volumes, iter, vol) { + free_private_data(vol); + } + + EngFncs->destroy_list(global_volumes); + global_volumes = NULL; + } + + have_mkdosfs = FALSE; + have_dosfsck = FALSE; + have_fatresize = FALSE; + + LOG_EXIT_VOID(); +} + +static void fat_cleanup() { + my_plugin_record = &fat_plugrec; + _fat_cleanup(0); +} + +static void fat16_cleanup() { + my_plugin_record = &fat16_plugrec; + _fat_cleanup(1); +} + +/* + * Does this FSIM manage the file system on this volume? + * Return 0 for "yes", else a reason code. + */ +static int _fat_probe(int isfat16, logical_volume_t * volume) { + + int rc = 0; + fat_boot *boot; + + LOG_ENTRY(); + + boot = EngFncs->engine_alloc(sizeof(fat_boot)); + if (boot == NULL) { + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + rc = get_fat_boot(isfat16, volume, boot); + + if (rc == 0) { + volume->private_data = EngFncs->engine_alloc(sizeof(private_data_t)); + + if (volume->private_data != NULL) { + rc = fill_private_data(isfat16, volume, boot); + + } else { + rc = ENOMEM; + } + } + EngFncs->engine_free(boot); + + LOG_EXIT_INT(rc); + return rc; +} + +static int fat_probe(logical_volume_t * volume) { + my_plugin_record = &fat_plugrec; + return _fat_probe(0, volume); +} + +static int fat16_probe(logical_volume_t * volume) { + my_plugin_record = &fat16_plugrec; + return _fat_probe(1, volume); +} + + +/* + * Get the size limits for this volume. + */ +static int fat_get_fs_limits(logical_volume_t * volume, + sector_count_t * min_size, + sector_count_t * max_volume_size, + sector_count_t * max_object_size) { + + int rc = 0; + private_data_t * pd = volume->private_data; + + LOG_ENTRY(); + + rc = get_fs_limits(volume, min_size, max_volume_size, max_object_size); + *max_object_size = pd->max_vol_size; + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Can mkfs this volume? + */ +static int fat_can_mkfs(logical_volume_t * volume) { + + LOG_ENTRY(); + + if (!have_mkdosfs) { + LOG_DEBUG("The mkdosfs utility is not installed.\n"); + LOG_EXIT_INT(ENOSYS); + return ENOSYS; + } + + if (volume->vol_size < MIN_FAT_SIZE) { + LOG_DETAILS("Volume %s is too small. FAT volumes must be at least 128k in size.\n", + volume->name); + LOG_EXIT_INT(EINVAL); + return EBUSY; + } + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * Can unmkfs this volume? + */ +static int _fat_can_unmkfs(logical_volume_t * volume) { + + LOG_ENTRY(); + + if (volume->file_system_manager != my_plugin_record) { + /* It's not my volume. */ + LOG_DEBUG("Volume %s does not have FAT on it.\n", volume->name); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + /* If mounted, can't unmkfs. */ + if (EngFncs->is_mounted(volume->dev_node, NULL)) { + LOG_DEBUG("Volume %s is mounted.\n", volume->name); + LOG_EXIT_INT(EBUSY); + return EBUSY; + } + + LOG_EXIT_INT(0); + return 0; +} + +static int fat_can_unmkfs(logical_volume_t * volume) { + my_plugin_record = &fat_plugrec; + return _fat_can_unmkfs(volume); +} + +static int fat16_can_unmkfs(logical_volume_t * volume) { + my_plugin_record = &fat16_plugrec; + return _fat_can_unmkfs(volume); +} + + +/* + * Can fsck this volume? + */ +static int fat_can_fsck(logical_volume_t * volume) { + + LOG_ENTRY(); + + if (!have_dosfsck) { + LOG_DEBUG("The dosfsck utility is not installed.\n"); + LOG_EXIT_INT(ENOSYS); + return ENOSYS; + } + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * Can this volume be expanded? + */ +static int fat_can_expand_by(logical_volume_t * volume, + sector_count_t * delta_size) { + + int rc = 0; + + LOG_ENTRY(); + if (EngFncs->is_mounted(volume->dev_node, NULL)) { + rc = EBUSY; /* If mounted, can't expand */ + goto errout; + } + rc = fat_get_fs_limits(volume, /* reset limits */ + &volume->min_fs_size, + &volume->max_fs_size, + &volume->max_vol_size); + + if (*delta_size > volume->max_fs_size - volume->fs_size) { + *delta_size = volume->max_fs_size - volume->fs_size; + } +errout: + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Can this volume be shrunk? + */ +static int fat_can_shrink_by(logical_volume_t * volume, + sector_count_t * delta_size) { + + int rc = 0; + + LOG_ENTRY(); + if (EngFncs->is_mounted(volume->dev_node, NULL)) { + rc = EBUSY; /* If mounted, can't shrink */ + goto errout; + } + rc = fat_get_fs_limits(volume, /* reset limits */ + &volume->min_fs_size, + &volume->max_fs_size, + &volume->max_vol_size); + if (*delta_size > volume->fs_size - volume->min_fs_size) { + *delta_size = volume->fs_size - volume->min_fs_size; + } + if (volume->min_fs_size >= volume->fs_size) { + rc = ENOSPC; + } +errout: + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Get the current size of this volume + */ +static int fat_get_fs_size(logical_volume_t * volume, + sector_count_t * size) { + + private_data_t * pd = volume->private_data; + + LOG_ENTRY(); + + *size = pd->fs_size; + LOG_DEBUG("Size of file system on volume %s is %"PRIu64"\n", volume->name, pd->fs_size); + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * mkfs has been scheduled. Do any setup work such as claiming another + * volume for an external log. + */ +static int fat_mkfs_setup(logical_volume_t * volume, + option_array_t * options) { + + int rc = 0; + + LOG_ENTRY(); + + volume->private_data = EngFncs->engine_alloc(sizeof(private_data_t)); + + if (volume->private_data == NULL) { + LOG_CRITICAL("Unable to get memory for private data.\n"); + rc = ENOMEM; + } + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * NAME: set_fat_mkfs_options + * + * FUNCTION: Build options array (argv) for mkdosfs + * + * PARAMETERS: + * options - options array passed from EVMS engine + * argv - mkfs options array + * vol_name - volume on which program will be executed + * + */ +static void set_fat_mkfs_options(int isfat16, + option_array_t * options, + char * * argv, + logical_volume_t * volume) { + + int i; + int bufsize; + int opt_count = 0; + char *buf; + + LOG_ENTRY(); + + argv[opt_count++] = "mkdosfs"; + argv[opt_count++] = isfat16 ? "-F16" : "-F32"; + + for (i = 0; i < options->count; i++) { + + if (!options->option[i].is_number_based) { + + if (!strcmp(options->option[i].name, MKFS_LABEL_NAME)) { + options->option[i].number = MKFS_LABEL_INDEX; + } else { + /* Unknown. Ignore. */ + continue; + } + } + + switch (options->option[i].number) { + + case MKFS_LABEL_INDEX: + if (options->option[i].value.s != NULL) { + argv[opt_count++] = "-n"; + argv[opt_count++] = options->option[i].value.s; + } + break; + + default: + break; + } + } + + argv[opt_count++] = volume->dev_node; + argv[opt_count] = NULL; + + bufsize = 0; + for (i = 0; argv[i]; i++) { + bufsize += strlen(argv[i]) + 1; + } + buf = EngFncs->engine_alloc(bufsize + 1); + if (buf != NULL) { + buf[0] = 0; + for (i=0; argv[i]; i++) { + strcat(buf, argv[i]); + strcat(buf, " "); + } + + LOG_DEBUG("mkdosfs command: %s\n", buf); + EngFncs->engine_free(buf); + } + + LOG_EXIT_VOID(); + return; +} + + +/* + * Put the file system on the volume. + */ +static int _fat_mkfs(int isfat16, + logical_volume_t * volume, + option_array_t * options) { + + int rc = 0; + char * argv[MKFS_OPTIONS_COUNT + 10]; + pid_t pidm; + int status; + int fds[2]; + + LOG_ENTRY(); + + if (!have_mkdosfs) { + MESSAGE(_("The mkdosfs utility is not installed on this machine.\n")); + LOG_EXIT_INT(ENOSYS); + return ENOSYS; + } + + set_fat_mkfs_options(isfat16, options, argv, volume); + + fds[0] = 0; + fds[1] = open("/dev/null", O_WRONLY); + + pidm = EngFncs->fork_and_execvp(volume, argv, NULL, fds, fds); + if (pidm != -1) { + waitpid( pidm, &status, 0 ); + if (WIFEXITED(status)) { + /* get mkdosfs exit code */ + rc = WEXITSTATUS(status); + } else { + rc = EINTR; + } + } else { + rc = errno; + } + + close(fds[1]); + + LOG_EXIT_INT(rc); + return rc; +} + +static int fat_mkfs(logical_volume_t * volume, option_array_t * options) { + my_plugin_record = &fat_plugrec; + return _fat_mkfs(0, volume, options); +} + +static int fat16_mkfs(logical_volume_t * volume, option_array_t * options) { + my_plugin_record = &fat16_plugrec; + return _fat_mkfs(1, volume, options); +} + + +/* + * Expand the volume to new_size. If the volume is not expanded exactly to + * new_size, set new_size to the new_size of the volume. + */ +static int _fat_expand(int isfat16, + logical_volume_t * volume, + sector_count_t * new_size) { + + int rc; + + LOG_ENTRY(); + + /* Expand must be done offline. */ + if (EngFncs->is_mounted(volume->dev_node, NULL)) { + LOG_DETAILS("Volume %s is mounted.\n", volume->name); + LOG_EXIT_INT(EBUSY); + return EBUSY; + } + + rc = resize_fat(isfat16, volume, new_size); + + LOG_EXIT_INT(rc); + return rc; +} + +static int fat_expand(logical_volume_t * volume, + sector_count_t * new_size) { + return _fat_expand(0, volume, new_size); +} + +static int fat16_expand(logical_volume_t * volume, + sector_count_t * new_size) { + return _fat_expand(1, volume, new_size); +} + +/* + * Shrink the volume to new_size. If the volume is not shrunk exactly to + * new_size, set new_size to the new_size of the volume. + */ +static int _fat_shrink(int isfat16, + logical_volume_t * volume, + sector_count_t requested_size, + sector_count_t * new_size) { + + int rc; + + LOG_ENTRY(); + + /* Shrink must be done offline. */ + if (EngFncs->is_mounted(volume->dev_node, NULL)) { + LOG_DETAILS("Volume %s is mounted.\n", volume->name); + LOG_EXIT_INT(EBUSY); + return EBUSY; + } + + *new_size = requested_size; + rc = resize_fat(isfat16, volume, new_size); + + LOG_EXIT_INT(rc); + return rc; +} + +static int fat_shrink(logical_volume_t * volume, + sector_count_t requested_size, + sector_count_t * new_size) { + return _fat_shrink(0, volume, requested_size, new_size); +} + +static int fat16_shrink(logical_volume_t * volume, + sector_count_t requested_size, + sector_count_t * new_size) { + return _fat_shrink(1, volume, requested_size, new_size); +} + +/* + * Forget about this volume. Don't remove the file system. Just clean up any + * data structures you may have associated with it. + */ +static int fat_discard(logical_volume_t * volume) { + + LOG_ENTRY(); + + if (volume->private_data) { + free_private_data(volume); + } + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * unmkfs has been scheduled. Do any setup work such as releasing another + * volume that was used for an external log. + */ +static int fat_unmkfs_setup(logical_volume_t * volume) { + + LOG_ENTRY(); + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * Remove the file system from the volume. + */ +static int fat_unmkfs(logical_volume_t * volume) { + + int rc = 0; + + LOG_ENTRY(); + + if (EngFncs->is_mounted(volume->dev_node, NULL)) { + rc = EBUSY; + } else { + rc = clear_fat_boot_sectors(volume); + if (rc == 0) { + free_private_data(volume); + } + } + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Do any operations you wanted to do at commit time, based on the phase of the + * commit. + */ +int fat_commit_changes(logical_volume_t * volume, commit_phase_t phase) { + + LOG_ENTRY(); + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * Return the total number of supported options for the specified task. + */ +static int fat_get_option_count(task_context_t * context) { + + int count = 0; + + LOG_ENTRY(); + + switch (context->action) { + case EVMS_Task_mkfs: + count = MKFS_OPTIONS_COUNT; + break; + default: + count = -1; + break; + } + + LOG_EXIT_INT(count); + return count; +} + +/* + * Initialize mkfs task acceptable objects by enumerating volumes, finding + * those that have no FSIM claiming them and are of the proper size and + * adding them to the acceptable objects list. + */ +static int init_mkfs_acceptable_objects(task_context_t * context) { + + int rc; + list_anchor_t global_volumes; + list_element_t vol_list_iter; + logical_volume_t * volume; + + LOG_ENTRY(); + + rc = EngFncs->get_volume_list(NULL, NULL, 0, &global_volumes); + if (!rc) { + LIST_FOR_EACH(global_volumes, vol_list_iter, volume) { + if ((volume->file_system_manager == NULL) && + (!EngFncs->is_mounted(volume->name, NULL)) && + (volume->vol_size >= MIN_FAT_SIZE)) { + EngFncs->insert_thing(context->acceptable_objects, + volume, + INSERT_BEFORE, + NULL); + } + } + EngFncs->destroy_list(global_volumes); + } + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Fill in the initial list of acceptable objects. Fill in the minimum and + * maximum number of objects that must/can be selected. Set up all initial + * values in the option_descriptors in the context record for the given + * task. Some fields in the option_descriptor may be dependent on a + * selected object. Leave such fields blank for now, and fill in during the + * set_objects call. + */ +static int fat_init_task(task_context_t * context) { + + int rc = 0; + option_descriptor_t * opt; + + LOG_ENTRY(); + + /* Parameter check */ + if (!context) { + LOG_EXIT_INT(EFAULT); + return EFAULT; + } + + switch (context->action) { + + case EVMS_Task_mkfs: + rc = init_mkfs_acceptable_objects(context); + if (rc) { + LOG_EXIT_INT(rc); + return rc; + } + context->option_descriptors->count = MKFS_OPTIONS_COUNT; + + /* Volume label option */ + opt = &context->option_descriptors->option[MKFS_LABEL_INDEX]; + opt->name = EngFncs->engine_strdup(MKFS_LABEL_NAME); + opt->title = EngFncs->engine_strdup(_("Volume label")); + opt->tip = EngFncs->engine_strdup(_("Set the label for the volume.")); + opt->help = NULL; + opt->type = EVMS_Type_String; + opt->unit = EVMS_Unit_None; + opt->min_len = 1; + opt->max_len = MAX_LABEL_LEN; + opt->flags = EVMS_OPTION_FLAGS_NOT_REQUIRED; + opt->constraint_type = EVMS_Collection_None; + opt->value.s = EngFncs->engine_alloc(MAX_LABEL_LEN + 1); + + context->min_selected_objects = 0; + context->max_selected_objects = 0; + break; + + default: + rc = EINVAL; + break; + } + + LOG_EXIT_INT(rc); + return rc; + +} + + +/* + * Examine the specified value, and determine if it is valid for the task + * and option_descriptor index. If it is acceptable, set that value in the + * appropriate entry in the option_descriptor. The value may be adjusted + * if necessary/allowed. If so, set the effect return value accordingly. + */ +static int fat_set_option(task_context_t * context, + u_int32_t index, + value_t * value, + task_effect_t * effect) { + int rc= 0; + + LOG_ENTRY(); + + /* Parameter check */ + if (!context || !value || !effect) { + LOG_EXIT_INT(EFAULT); + return EFAULT; + } + + switch (context->action) { + + case EVMS_Task_mkfs: + switch (index) { + case MKFS_LABEL_INDEX: + strncpy(context->option_descriptors->option[index].value.s, value->s, MAX_LABEL_LEN); + if (strlen(value->s) > MAX_LABEL_LEN) { + MESSAGE(_("Volume label is truncated to \"%s\".\n"), + context->option_descriptors->option[index].value.s); + } + break; + + default: + break; + } + break; + + default: + LOG_ERROR("I don't know how to set an option for action code %d (%#x).\n", + context->action, context->action); + rc = EINVAL; + break; + } + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Validate the volumes in the selected_objects list in the task context. + * Remove from the selected objects lists any volumes which are not + * acceptable. For unacceptable volumes, create a declined_handle_t + * structure with the reason why it is not acceptable, and add it to the + * declined_volumes list. Modify the acceptable_objects list in the task + * context as necessary based on the selected objects and the current + * settings of the options. Modify any option settings as necessary based + * on the selected objects. Return the appropriate task_effect_t settings + * if the object list(s), minimum or maximum objects selected, or option + * settings have changed. + */ +static int fat_set_volumes(task_context_t * context, + list_anchor_t declined_volumes, /* of type declined_handle_t */ + task_effect_t * effect) { + int rc; + list_element_t iter1; + list_element_t iter2; + logical_volume_t * vol; + + LOG_ENTRY(); + + switch (context->action) { + case EVMS_Task_mkfs: + + /* get the selected volume */ + LIST_FOR_EACH_SAFE(context->selected_objects, iter1, iter2, vol){ + if (EngFncs->is_mounted(vol->dev_node, NULL)) { + /* If mounted, can't mkdosfs. */ + LOG_ERROR("Volume %s is mounted on %s.\n", + vol->name, vol->mount_point); + rc = EBUSY; + } else { + if (vol->vol_size < MIN_FAT_SIZE) { + LOG_ERROR("Volume %s is too small. " + "FAT volumes must be at least 1MB in size.\n", + vol->name); + rc = EINVAL; + + } else { + /* This one looks fine. */ + rc = 0; + } + } + + if (rc != 0) { + declined_object_t * dec_vol; + + EngFncs->delete_element(iter1); + + dec_vol = EngFncs->engine_alloc(sizeof(declined_object_t)); + if (dec_vol != NULL) { + dec_vol->object = vol; + dec_vol->reason = rc; + + EngFncs->insert_thing(declined_volumes, + dec_vol, + INSERT_AFTER, + NULL); + } else { + LOG_CRITICAL("Unable to get memory for a declined_object_t.\n"); + + /* + * Put any already declined objects + * back on the selected_objects list. + */ + + /* + * Yeah, I know I'm using the iterators + * from the loop we're in. We're bailing + * out here, so it doesn't matter. + */ + LIST_FOR_EACH_SAFE(declined_volumes, iter1, iter2, dec_vol) { + EngFncs->delete_element(iter1); + EngFncs->insert_thing(context->selected_objects, + dec_vol->object, + INSERT_AFTER,NULL); + EngFncs->engine_free(dec_vol); + } + + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + } + } + break; + + default: + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + LOG_EXIT_INT(0); + return 0; +} + + +/* + * Return any additional information that you wish to provide about the + * volume. The Engine provides an external API to get the information + * stored in the logical_volume_t. This call is to get any other + * information about the volume that is not specified in the + * logical_volume_t. Any piece of information you wish to provide must be + * in an extended_info_t structure. Use the Engine's engine_alloc() to + * allocate the memory for the extended_info_t. Also use engine_alloc() to + * allocate any strings that may go into the extended_info_t. Then use + * engine_alloc() to allocate an extended_info_array_t with enough entries + * for the number of extended_info_t structures you are returning. Fill + * in the array and return it in *info. + * If you have extended_info_t descriptors that themselves may have more + * extended information, set the EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag + * in the extended_info_t flags field. If the caller wants more information + * about a particular extended_info_t item, this API will be called with a + * pointer to the storage_object_t and with a pointer to the name of the + * extended_info_t item. In that case, return an extended_info_array_t with + * further information about the item. Each of those items may have the + * EVMS_EINFO_FLAGS_MORE_INFO_AVAILABLE flag set if you desire. It is your + * responsibility to give the items unique names so that you know which item + * the caller is asking additional information for. If info_name is NULL, + * the caller just wants top level information about the object. + */ +static int fat_get_volume_info(logical_volume_t * volume, + char * info_name, + extended_info_array_t * * info) { + int rc = 0; + private_data_t * pd = volume->private_data; + extended_info_array_t * Info; + int i; + + LOG_ENTRY(); + + if (pd == NULL) { + LOG_SERIOUS("Oops! Volume %s does not have private data.\n", volume->name); + LOG_EXIT_INT(ENOENT); + return ENOENT; + } + + if (info_name != NULL) { + LOG_ERROR("Volume %s has no extra information named \"%s\".\n", + volume->name, info_name); + rc = EINVAL; + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + Info = EngFncs->engine_alloc(sizeof(extended_info_array_t) + (3 * sizeof(extended_info_t))); + + if (Info == NULL) { + LOG_CRITICAL("Unable to allocate memory for the extended_info_array_t buffer.\n"); + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + i = 0; + + if (pd->vol_name != NULL) { + Info->info[i].name = EngFncs->engine_strdup("FAT Volume Name"); + Info->info[i].title = EngFncs->engine_strdup(_("FAT Volume Name")); + Info->info[i].desc = EngFncs->engine_strdup(_("The FAT name of the volume")); + Info->info[i].type = EVMS_Type_String; + Info->info[i].unit = EVMS_Unit_None; + Info->info[i].value.s = EngFncs->engine_strdup(pd->vol_name); + Info->info[i].collection_type = EVMS_Collection_None; + i++; + } + + if (pd->vol_id != 0) { + Info->info[i].name = EngFncs->engine_strdup("FAT Volume ID"); + Info->info[i].title = EngFncs->engine_strdup(_("FAT Volume ID")); + Info->info[i].desc = EngFncs->engine_strdup(_("The FAT ID of the volume")); + Info->info[i].type = EVMS_Type_Int32; + Info->info[i].unit = EVMS_Unit_None; + Info->info[i].format = EVMS_Format_Hex; + Info->info[i].value.i32 = pd->vol_id; + Info->info[i].collection_type = EVMS_Collection_None; + i++; + } + + if (pd->cluster_size != 0) { + Info->info[i].name = EngFncs->engine_strdup("Cluster Size"); + Info->info[i].title = EngFncs->engine_strdup(_("Cluster Size")); + Info->info[i].desc = EngFncs->engine_strdup(_("Size of a cluster.")); + Info->info[i].type = EVMS_Type_Unsigned_Int32; + Info->info[i].unit = EVMS_Unit_None; + Info->info[i].value.ui32 = pd->cluster_size; + Info->info[i].collection_type = EVMS_Collection_None; + i++; + } + + Info->count = i; + *info = Info; + + rc = 0; + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + * Return Plug-in specific information. + */ +static int _fat_get_plugin_info(int isfat16, + char * descriptor_name, + extended_info_array_t * * info) { + + int rc = EINVAL; + extended_info_array_t * Info; + char version_string[64]; + char required_engine_api_version_string[64]; + char required_fsim_api_version_string[64]; + + LOG_ENTRY(); + + if (info) { + + if (descriptor_name == NULL) { + *info = NULL; // init to no info returned + + Info = EngFncs->engine_alloc(sizeof(extended_info_array_t) + (6 * sizeof(extended_info_t))); + if (Info) { + + Info->count = 6; + + sprintf(version_string, "%d.%d.%d", + MAJOR_VERSION, + MINOR_VERSION, + PATCH_LEVEL); + + sprintf(required_engine_api_version_string, "%d.%d.%d", + my_plugin_record->required_engine_api_version.major, + my_plugin_record->required_engine_api_version.minor, + my_plugin_record->required_engine_api_version.patchlevel); + + sprintf(required_fsim_api_version_string, "%d.%d.%d", + my_plugin_record->required_plugin_api_version.fsim.major, + my_plugin_record->required_plugin_api_version.fsim.minor, + my_plugin_record->required_plugin_api_version.fsim.patchlevel); + + Info->info[0].name = EngFncs->engine_strdup("Short Name"); + Info->info[0].title = EngFncs->engine_strdup(_("Short Name")); + Info->info[0].desc = EngFncs->engine_strdup(_("A short name given to this plug-in")); + Info->info[0].type = EVMS_Type_String; + Info->info[0].unit = EVMS_Unit_None; + Info->info[0].value.s = EngFncs->engine_strdup(my_plugin_record->short_name); + Info->info[0].collection_type = EVMS_Collection_None; + memset(&Info->info[0].group, 0, sizeof(group_info_t)); + + Info->info[1].name = EngFncs->engine_strdup("Long Name"); + Info->info[1].title = EngFncs->engine_strdup(_("Long Name")); + Info->info[1].desc = EngFncs->engine_strdup(_("A longer, more descriptive name for this plug-in")); + Info->info[1].type = EVMS_Type_String; + Info->info[1].unit = EVMS_Unit_None; + Info->info[1].value.s = EngFncs->engine_strdup(my_plugin_record->long_name); + Info->info[1].collection_type = EVMS_Collection_None; + memset(&Info->info[1].group, 0, sizeof(group_info_t)); + + Info->info[2].name = EngFncs->engine_strdup("Type"); + Info->info[2].title = EngFncs->engine_strdup(_("Plug-in Type")); + Info->info[2].desc = EngFncs->engine_strdup(_("There are various types of plug-ins, each responsible for some kind of storage object or logical volume.")); + Info->info[2].type = EVMS_Type_String; + Info->info[2].unit = EVMS_Unit_None; + Info->info[2].value.s = EngFncs->engine_strdup(_("File System Interface Module")); + Info->info[2].collection_type = EVMS_Collection_None; + memset(&Info->info[2].group, 0, sizeof(group_info_t)); + + Info->info[3].name = EngFncs->engine_strdup("Version"); + Info->info[3].title = EngFncs->engine_strdup(_("Plug-in Version")); + Info->info[3].desc = EngFncs->engine_strdup(_("This is the version number of the plug-in.")); + Info->info[3].type = EVMS_Type_String; + Info->info[3].unit = EVMS_Unit_None; + Info->info[3].value.s = EngFncs->engine_strdup(version_string); + Info->info[3].collection_type = EVMS_Collection_None; + memset(&Info->info[3].group, 0, sizeof(group_info_t)); + + Info->info[4].name = EngFncs->engine_strdup("Required Engine Services Version"); + Info->info[4].title = EngFncs->engine_strdup(_("Required Engine Services Version")); + Info->info[4].desc = EngFncs->engine_strdup(_("This is the version of the Engine services that this plug-in requires. " + "It will not run on older versions of the Engine services.")); + Info->info[4].type = EVMS_Type_String; + Info->info[4].unit = EVMS_Unit_None; + Info->info[4].value.s = EngFncs->engine_strdup(required_engine_api_version_string); + Info->info[4].collection_type = EVMS_Collection_None; + memset(&Info->info[4].group, 0, sizeof(group_info_t)); + + Info->info[5].name = EngFncs->engine_strdup("Required Engine FSIM API Version"); + Info->info[5].title = EngFncs->engine_strdup(_("Required Engine FSIM API Version")); + Info->info[5].desc = EngFncs->engine_strdup(_("This is the version of the Engine FSIM API that this plug-in requires. " + "It will not run on older versions of the Engine FSIM API.")); + Info->info[5].type = EVMS_Type_String; + Info->info[5].unit = EVMS_Unit_None; + Info->info[5].value.s = EngFncs->engine_strdup(required_fsim_api_version_string); + Info->info[5].collection_type = EVMS_Collection_None; + memset(&Info->info[5].group, 0, sizeof(group_info_t)); + + *info = Info; + + rc = 0; + } else { + rc = ENOMEM; + } + + } else { + /* There is no more information on any of the descriptors. */ + rc = EINVAL; + } + } + + LOG_EXIT_INT(rc); + return rc; +} + +static inline int fat_get_plugin_info(char * descriptor_name, extended_info_array_t * * info) { + my_plugin_record = &fat_plugrec; + return _fat_get_plugin_info(0, descriptor_name, info); +} + +static inline int fat16_get_plugin_info(char * descriptor_name, extended_info_array_t * * info) { + my_plugin_record = &fat16_plugrec; + return _fat_get_plugin_info(1, descriptor_name, info); +} + +/* + * Return an array of plug-in functions that you support for this volume. + */ +static int _fat_get_plugin_functions(int isfat16, + logical_volume_t * volume, + function_info_array_t * * actions) { + + private_data_t * pd; + function_info_array_t * fia; + int i; + + LOG_ENTRY(); + + /* "volume" is NULL when the Engine is asking for functions that + * apply to the plug-in rather than to a particular volume. + */ + if (volume == NULL) { + LOG_DEBUG("There are no functions targeted at this plug-in.\n"); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + if (volume->file_system_manager != my_plugin_record) { + /* It's not my volume. */ + LOG_DEBUG("Volume %s does not have FAT16/FAT32 on it.\n", volume->name); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + if (!(volume->flags & (VOLFLAG_ACTIVE | VOLFLAG_NEEDS_ACTIVATE))) { + LOG_DEBUG("Volume %s is not active.\n", + volume->name); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + if (volume->flags & VOLFLAG_NEEDS_DEACTIVATE) { + LOG_DEBUG("Volume %s will be deactivated.\n", volume->name); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + if (volume->flags & (VOLFLAG_NEW | VOLFLAG_MKFS)) { + /* mkdosfs has yet to be run on this volume. */ + LOG_DEBUG("Volume %s does not yet have FAT16/FAT32 on it. mkfs is scheduled to be run.\n", + volume->name); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + pd = (private_data_t *) volume->private_data; + + fia = EngFncs->engine_alloc(sizeof(function_info_array_t) + sizeof(function_info_t)); + if (fia == NULL) { + LOG_CRITICAL("Unable to get memory for a function_info_array_t.\n"); + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + i = 0; + + fia->count = i; + *actions = fia; + + LOG_EXIT_INT(0); + return 0; +} + +int fat_get_plugin_functions(logical_volume_t * volume, + function_info_array_t * * actions) { + my_plugin_record = &fat_plugrec; + return _fat_get_plugin_functions(0, volume, actions); +} + +static int fat16_get_plugin_functions(logical_volume_t * volume, + function_info_array_t * * actions) { + my_plugin_record = &fat16_plugrec; + return _fat_get_plugin_functions(1, volume, actions); +} + +/* + * Execute the plug-in function on the volume. + */ +static int fat_plugin_function(logical_volume_t * volume, + task_action_t action, + list_anchor_t objects, + option_array_t * options) { + + int rc = 0; + + LOG_ENTRY(); + + if (volume == NULL) { + LOG_ERROR("No volume specified.\n"); + LOG_EXIT_INT(EINVAL); + return EINVAL; + } + + switch (action) { + default: + LOG_ERROR("Plug-in function %d (%#x) is not supported.\n", + action, action); + rc = EINVAL; + break; + } + + LOG_EXIT_INT(rc); + return rc; +} + +/*-------------------------------------------------------------------------------------+ ++ + ++ PLUG-IN FUNCTION TABLE + ++ + ++--------------------------------------------------------------------------------------*/ +static fsim_functions_t fsim_ops = { + + setup_evms_plugin: fat_setup, + cleanup_evms_plugin: fat_cleanup, + probe: fat_probe, + get_fs_size: fat_get_fs_size, + get_fs_limits: fat_get_fs_limits, + mkfs_setup: fat_mkfs_setup, + mkfs: fat_mkfs, + can_mkfs: fat_can_mkfs, + can_unmkfs: fat_can_unmkfs, + can_fsck: fat_can_fsck, + can_expand_by: fat_can_expand_by, + can_shrink_by: fat_can_shrink_by, + discard: fat_discard, + unmkfs_setup: fat_unmkfs_setup, + unmkfs: fat_unmkfs, + expand: fat_expand, + shrink: fat_shrink, + commit_changes: fat_commit_changes, + get_option_count: fat_get_option_count, + init_task: fat_init_task, + set_option: fat_set_option, + set_volumes: fat_set_volumes, + get_volume_info: fat_get_volume_info, + get_plugin_info: fat_get_plugin_info, + get_plugin_functions: fat_get_plugin_functions, + plugin_function: fat_plugin_function +}; + +static fsim_functions_t fsim16_ops = { + + setup_evms_plugin: fat_setup, + cleanup_evms_plugin: fat16_cleanup, + probe: fat16_probe, + get_fs_size: fat_get_fs_size, + get_fs_limits: fat_get_fs_limits, + mkfs_setup: fat_mkfs_setup, + mkfs: fat16_mkfs, + can_mkfs: fat_can_mkfs, + can_unmkfs: fat16_can_unmkfs, + can_fsck: fat_can_fsck, + can_expand_by: fat_can_expand_by, + can_shrink_by: fat_can_shrink_by, + discard: fat_discard, + unmkfs_setup: fat_unmkfs_setup, + unmkfs: fat_unmkfs, + expand: fat16_expand, + shrink: fat16_shrink, + commit_changes: fat_commit_changes, + get_option_count: fat_get_option_count, + init_task: fat_init_task, + set_option: fat_set_option, + set_volumes: fat_set_volumes, + get_volume_info: fat_get_volume_info, + get_plugin_info: fat16_get_plugin_info, + get_plugin_functions: fat16_get_plugin_functions, + plugin_function: fat_plugin_function +}; + + +/*-------------------------------------------------------------------------------------+ ++ + ++ PLUG-IN RECORD + ++ + ++-------------------------------------------------------------------------------------*/ + +static plugin_record_t fat_plugrec = { + id: SetPluginID(795, EVMS_FILESYSTEM_INTERFACE_MODULE, FS_TYPE_FAT), + version: {MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL}, + required_engine_api_version: {15, 0, 0}, + required_plugin_api_version: {fsim: {11, 0, 0}}, + short_name: "FAT32", + long_name: "FAT32 File System Interface Module", + oem_name: "ALT Linux", + functions: {fsim: &fsim_ops}, + container_functions: NULL + +}; + +static plugin_record_t fat16_plugrec = { + id: SetPluginID(795, EVMS_FILESYSTEM_INTERFACE_MODULE, FS_TYPE_FAT16), + version: {MAJOR_VERSION, MINOR_VERSION, PATCH_LEVEL}, + required_engine_api_version: {15, 0, 0}, + required_plugin_api_version: {fsim: {11, 0, 0}}, + short_name: "FAT16", + long_name: "FAT16 File System Interface Module", + oem_name: "ALT Linux", + functions: {fsim: &fsim16_ops}, + container_functions: NULL + +}; + +// Vector of plug-in record pointers that we export for the EVMS Engine. +plugin_record_t *evms_plugin_records[] = { + &fat_plugrec, + &fat16_plugrec, + NULL +}; + diff -Naur evms-2.5.2/plugins/fat.orig/fatfsim.h evms-2.5.2/plugins/fat/fatfsim.h --- evms-2.5.2/plugins/fat.orig/fatfsim.h 1970-01-01 03:00:00 +0300 +++ evms-2.5.2/plugins/fat/fatfsim.h 2005-09-12 17:14:34 +0400 @@ -0,0 +1,47 @@ +/* + * + * (C) Copyright ALT Linux Ltd. 2005 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: fatfsim.h + */ + +extern plugin_record_t * my_plugin_record; +extern engine_functions_t * EngFncs; +extern boolean have_fatresize; + +#define FS_TYPE_FAT 19 +#define FS_TYPE_FAT16 20 + +typedef struct private_data_s { + sector_count_t fs_size; + sector_count_t max_fs_size; + sector_count_t max_vol_size; + u_int32_t cluster_size; + u_int16_t logical_sector_size; + char * vol_name; + u_int32_t vol_id; + logical_volume_t * clone_source; + logical_volume_t * clone_target; + u_int32_t flags; +} private_data_t; + +/* mkntfs option array indices */ +#define MKFS_LABEL_INDEX 0 +#define MKFS_LABEL_NAME "label" +#define MKFS_OPTIONS_COUNT 1 + +#define MAX_LABEL_LEN 11 diff -Naur evms-2.5.2/plugins/fat.orig/Makefile.in evms-2.5.2/plugins/fat/Makefile.in --- evms-2.5.2/plugins/fat.orig/Makefile.in 1970-01-01 03:00:00 +0300 +++ evms-2.5.2/plugins/fat/Makefile.in 2005-09-12 17:14:34 +0400 @@ -0,0 +1,50 @@ +# Enterprise Volume Management System +# +# (C) Copyright ALT Linux Ltd. 2005 +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +include @top_srcdir@/make.rules + +NAME = fat +TARGET = $(PLUGIN_TARGET) + +MAJOR_VERSION = 1 +MINOR_VERSION = 1 +PATCH_LEVEL = 12 + +all: $(TARGET) + +$(TARGET): .depend .export $(OBJECTS) + $(BUILD_PLUGIN) + +install: all + $(MKINSTALLDIRS) $(DESTDIR)$(evmspluginsdir) + $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(evmspluginsdir) + +uninstall: + rm -f $(DESTDIR)$(evmspluginsdir)/$(TARGET) + +clean: + rm -f .depend .export $(OBJECTS) $(TARGET) + +distclean: clean + rm -f Makefile + +ifeq (.depend, $(wildcard .depend)) +include .depend +endif diff -Naur evms-2.5.2/plugins/fat.orig/utils.c evms-2.5.2/plugins/fat/utils.c --- evms-2.5.2/plugins/fat.orig/utils.c 1970-01-01 03:00:00 +0300 +++ evms-2.5.2/plugins/fat/utils.c 2005-09-12 17:29:32 +0400 @@ -0,0 +1,500 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: utils.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "fatfsim.h" + +#define LLONG_MAX 0x8fffffffffffffffLL +#define FAT_BLOCK_SIZE 512 + +/* + * FIXME: correct values + */ +#define MAXVOL_FAT16 1024*1024*4 +#define MAXVOL_FAT32 INT32_MAX + +/* + * is_boot_sector_fat() checks whether the buffer at boot_sector is a valid + * FAT boot sector. Returns TRUE if it is valid and FALSE if not. + */ +static boolean is_boot_sector_fat(const fat_boot * boot) { + + LOG_ENTRY(); + + if (!strncmp(boot->b.system_id, "MSDOS", 5) || + !strncmp(boot->b.system_id, "MSWIN", 5) || + !strncmp(boot->b.system_id, "MTOOL", 5) || + !strncmp(boot->b.system_id, "mkdosfs", 7) || + !strncmp(boot->b.system_id, "kmkdosfs", 8) || + /* Michal Svec: created by fdformat, old msdos utility for + * formatting large (1.7) floppy disks. + */ + !strncmp(boot->b.system_id, "CH-FOR18", 8) + || !strncmp(boot->b.fat.vi.fs, "FAT12 ", 8) || + !strncmp(boot->b.fat.vi.fs, "FAT16 ", 8) || + !strncmp(boot->b.fat32.vi.fs, "FAT32 ", 8)) { + + LOG_EXIT_BOOL(TRUE); + return TRUE; + } + + LOG_EXIT_BOOL(FALSE); + return FALSE; +} + +int fill_private_data(int isfat16, + logical_volume_t * vol, + const fat_boot * boot) { + + int rc = 0; + private_data_t * pd = (private_data_t *) vol->private_data; + u_int16_t sectors; + + LOG_ENTRY(); + + pd->logical_sector_size = DISK_TO_CPU16(boot->b.sector_size); + if (!pd->logical_sector_size) { + LOG_DETAILS("Logical sector size is zero."); + //LOG_EXIT_BOOL(FALSE); + //return FALSE; + } + pd->cluster_size = boot->b.cluster_size*pd->logical_sector_size; + if (!pd->cluster_size) { + LOG_DETAILS("Cluster size is zero."); + //LOG_EXIT_BOOL(FALSE); + //return FALSE; + } + if (boot->b.fats != 2 && boot->b.fats != 1) { + LOG_DETAILS("Currently, only 1 or 2 FATs are supported, not %d.\n", boot->b.fats); + //LOG_EXIT_BOOL(FALSE); + //return FALSE; + } + sectors = DISK_TO_CPU16(boot->b.sectors); + pd->fs_size = sectors ? sectors : DISK_TO_CPU32(boot->b.total_sect); + + /* + * FIXME: make correct MAX VOLUME size + */ + pd->max_vol_size = isfat16 ? MAXVOL_FAT16 : MAXVOL_FAT32; + pd->max_fs_size = pd->fs_size; + + pd->vol_id = isfat16 ? DISK_TO_CPU32(boot->b.fat.vi.volume_id) + : DISK_TO_CPU32(boot->b.fat32.vi.volume_id); + + pd->vol_name = isfat16 ? EngFncs->engine_strdup(boot->b.fat.vi.volume_label) + : EngFncs->engine_strdup(boot->b.fat32.vi.volume_label); + + LOG_EXIT_INT(rc); + return rc; +} + +/* + * Read the boot sector from the volume and validate it. + */ +int get_fat_boot(int isfat16, logical_volume_t * ev, fat_boot *boot) +{ + int rc = 0; + int fd; + + if (boot == NULL) { + LOG_CRITICAL("Failed to allocate memory for a boot info.\n"); + + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + fd = EngFncs->open_volume(ev, O_RDONLY); + if (fd < 0) { + LOG_SERIOUS("Failed to open volume %s. Error code is %d: %s\n", + ev->name, -fd, EngFncs->strerror(-fd)); + LOG_EXIT_INT(-fd); + return -fd; + } + + /* Try to read primary boot sector. */ + if (EngFncs->read_volume(ev, fd, &boot->b, FAT_BLOCK_SIZE, 0) == FAT_BLOCK_SIZE) { + if (is_boot_sector_fat(boot)) { + if (isfat16 || (!boot->b.fat_length && boot->b.fat32.length)) { + goto finished; + } + } else { + LOG_DETAILS("Primary boot sector is not valid."); + } + } else + LOG_WARNING("Unable to read primary boot sector."); + + rc = EINVAL; +finished: + EngFncs->close_volume(ev, fd); + // FIXME: trim space chars + if (isfat16) { + boot->b.fat.vi.volume_label[11] = '\0'; + } else { + boot->b.fat32.vi.volume_label[11] = '\0'; + } + + LOG_EXIT_INT(rc); + return rc; +} + + +int clear_fat_boot_sectors(logical_volume_t * ev) +{ + int rc = 0; + int fd; + void * block; + int32_t bytes_written; + + LOG_ENTRY(); + + block = EngFncs->engine_alloc(FAT_BLOCK_SIZE); + if (block == NULL) { + LOG_CRITICAL("Can't get a buffer for writing.\n"); + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + fd = EngFncs->open_volume(ev, O_WRONLY); + if (fd < 0) { + LOG_SERIOUS("Failed to open volume %s. Error code is %d: %s\n", + ev->name, -fd, EngFncs->strerror(-fd)); + EngFncs->engine_free(block); + LOG_EXIT_INT(-fd); + return -fd; + } + + /* Wipe out the primary boot sector. */ + bytes_written = EngFncs->write_volume(ev, fd, block, FAT_BLOCK_SIZE, 0); + if (bytes_written != FAT_BLOCK_SIZE) { + LOG_WARNING("Failed to clear the primary boot sector on volume %s. " + "Only %d bytes were written.\n", + ev->name, bytes_written); + rc = -bytes_written; + } + + EngFncs->close_volume(ev, fd); + + EngFncs->engine_free(block); + + LOG_EXIT_INT(rc); + return rc; +} + + +int try_run(char * prog_name) { + + int rc = 0; + char * argv[3]; + pid_t pidm; + int status; + int fds[2]; + + /* Open a pipe to catch the program output that we don't care about. */ + rc = pipe(fds); + if (rc) { + LOG_SERIOUS("Could not opening a pipe. Error code is %d: %s\n", + errno, strerror(errno)); + + LOG_EXIT_INT(errno); + return(errno); + } + + argv[0] = prog_name; + argv[1] = NULL; + + pidm = EngFncs->fork_and_execvp(NULL, argv, NULL, NULL, NULL); + + if (pidm != -1) { + + waitpid(pidm, &status, 0); + + if (WIFEXITED(status)) { + + LOG_DEFAULT("%s completed with exit code %d.\n", + prog_name, WEXITSTATUS(status)); + + } else { + LOG_WARNING("%s did not exit normally.\n", prog_name); + rc = EINTR; + } + + } else { + rc = errno; + LOG_DEFAULT("Unable to run %s. Error code is %d: %s\n", + prog_name, rc, EngFncs->strerror(rc)); + } + + close(fds[0]); + close(fds[1]); + + LOG_EXIT_INT(rc); + return(rc); +} + + +int get_fs_limits(logical_volume_t * vol, sector_count_t * min_fs_size, + sector_count_t * max_fs_size, + sector_count_t * max_vol_size) { + + int rc = 0; + char * argv[5]; + pid_t pidm; + int status; + int fds[2]; + char * buffer = NULL; + char * p = NULL; + u_int64_t min_fs_size_bytes = 0; + u_int64_t max_fs_size_bytes = 0; + + LOG_ENTRY(); + + if (!have_fatresize) { + LOG_DETAILS("The fatresize utility is not installed.\n"); + LOG_EXIT_INT(ENOSYS); + return ENOSYS; + } + + *min_fs_size = vol->fs_size; + *max_fs_size = vol->fs_size; + *max_vol_size = vol->fs_size; + + buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN); + if (buffer == NULL) { + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + status = pipe(fds); + if (status < 0) { + EngFncs->engine_free(buffer); + LOG_EXIT_INT(ENOSYS); + return ENOSYS; + } + + /* Run fatresize -i to get the smallest volume size. */ + argv[0] = "fatresize"; + argv[1] = "-i"; + argv[2] = vol->dev_node; + argv[3] = NULL; + + fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL, 0) | O_NONBLOCK); + fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL, 0) | O_NONBLOCK); + + pidm = EngFncs->fork_and_execvp(vol, argv, NULL, fds, fds); + if (pidm != -1) { + + waitpid( pidm, &status, 0); + + if (WIFEXITED(status)) { + read(fds[0], buffer, MAX_USER_MESSAGE_LEN); + + rc = WEXITSTATUS(status); + LOG_DETAILS("%s completed with exit code %d \n", argv[0], rc); + } else { + /* + * The process didn't exit. It must have been + * interrupted by a signal. + */ + rc = EINTR; + } + + } else { + LOG_SERIOUS("Failed to fork and exec %s. Error code is %d: %s\n", + argv[0], rc, EngFncs->strerror(rc)); + rc = errno; + } + + if (rc == 0) { + + if ((p = strstr(buffer, "Min size:"))) { + p += 10; + min_fs_size_bytes = atoll(p); + } + + if ((p = strstr(buffer, "Max size:"))) { + p += 10; + max_fs_size_bytes = atoll(p); + } + + if (min_fs_size_bytes != 0) { + /* fatresize reports the size in bytes. */ + *min_fs_size = min_fs_size_bytes >> EVMS_VSECTOR_SIZE_SHIFT; + } + + if (max_fs_size_bytes != 0) { + /* fatresize reports the size in bytes. */ + *max_fs_size = max_fs_size_bytes >> EVMS_VSECTOR_SIZE_SHIFT; + *max_vol_size = *max_fs_size; + } + } + + EngFncs->engine_free(buffer); + + close(fds[0]); + close(fds[1]); + + LOG_EXIT_INT(rc); + return rc; +} + + +/* + if (pd->ntfs_cluster_size == EVMS_VSECTOR_SIZE) { + pd->fs_size = pd->ntfs_nr_clusters; + pd->max_fs_size = LLONG_MAX; + + } else if (pd->ntfs_cluster_size > EVMS_VSECTOR_SIZE) { + pd->fs_size = pd->ntfs_nr_clusters * (pd->ntfs_cluster_size / EVMS_VSECTOR_SIZE); + pd->max_fs_size = LLONG_MAX * (pd->ntfs_cluster_size / EVMS_VSECTOR_SIZE); + + } else { + pd->fs_size = pd->ntfs_nr_clusters / (EVMS_VSECTOR_SIZE - pd->ntfs_cluster_size); + pd->max_fs_size = LLONG_MAX / (EVMS_VSECTOR_SIZE - pd->ntfs_cluster_size); + } + +*/ + +void free_private_data(logical_volume_t * vol) { + + LOG_ENTRY(); + + if (vol->private_data != NULL) { + private_data_t * pd = (private_data_t *) vol->private_data; + + if (pd->vol_name != NULL) { + EngFncs->engine_free(pd->vol_name); + } + + EngFncs->engine_free(vol->private_data); + vol->private_data = NULL; + } + + LOG_EXIT_VOID(); +} + +int resize_fat(int isfat16, logical_volume_t * volume, sector_count_t * new_size) { + + int rc = 0; + char * argv[6]; + char ascii_new_size[16]; + pid_t pidm; + int status; + int fds[2]; + char * buffer = NULL; + fat_boot *boot = NULL; + private_data_t * pd = volume->private_data; + + LOG_ENTRY(); + + if (!have_fatresize) { + MESSAGE("The fatresize utility is not installed on this machine. " + "The FAT16/FAT32 FSIM uses fatresize to expand the FAT16/FAT32 file system on the volume. " + "Get the latest version of the FAT utilities from http://sourceforge.net/projects/fatresize/\n"); + LOG_EXIT_INT(ENOSYS); + return ENOSYS; + } + + buffer = EngFncs->engine_alloc(MAX_USER_MESSAGE_LEN); + if (buffer == NULL) { + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + status = pipe(fds); + if (status < 0) { + EngFncs->engine_free(buffer); + LOG_EXIT_INT(errno); + return errno; + } + + argv[0] = "fatresize"; + argv[1] = "-vvv"; + argv[2] = "-s"; + + /* Get the ASCII version of the new size in KB. */ + sprintf(ascii_new_size, "%"PRIu64, (*new_size) >> 1); + strcat(ascii_new_size, "k"); + argv[3] = ascii_new_size; + + argv[4] = volume->dev_node; + argv[5] = NULL; + + fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL, 0) | O_NONBLOCK); + fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL, 0) | O_NONBLOCK); + + pidm = EngFncs->fork_and_execvp(volume, argv, NULL, fds, fds); + if (pidm != -1) { + + waitpid(pidm, &status, 0); + if (WIFEXITED(status)) { + rc = WEXITSTATUS(status); + if (rc == 0) { + LOG_DETAILS("%s completed with exit code %d \n", argv[0], rc); + } else { + LOG_WARNING("%s completed with exit code %d \n", argv[0], rc); + } + } else { + /* + * The process didn't exit. It must have been + * interrupted by a signal. + */ + rc = EINTR; + } + + } else { + LOG_SERIOUS("Failed to fork and exec %s. Error code is %d: %s\n", + argv[0], rc, EngFncs->strerror(rc)); + rc = errno; + } + + close(fds[0]); + close(fds[1]); + + EngFncs->engine_free(buffer); + + if (rc == 0) { + /* Get the new sizes into the private data. */ + memset(pd, 0, sizeof(private_data_t)); + + boot = EngFncs->engine_alloc(sizeof(fat_boot)); + if (boot == NULL) { + LOG_EXIT_INT(ENOMEM); + return ENOMEM; + } + + rc = get_fat_boot(isfat16, volume, boot); + if (rc == 0) { + rc = fill_private_data(isfat16, volume, boot); + } + /* + * FIXME: shall I get new size after resize? + */ + pd->fs_size = *new_size; + } + + LOG_EXIT_INT(rc); + return rc; +} diff -Naur evms-2.5.2/plugins/fat.orig/utils.h evms-2.5.2/plugins/fat/utils.h --- evms-2.5.2/plugins/fat.orig/utils.h 1970-01-01 03:00:00 +0300 +++ evms-2.5.2/plugins/fat/utils.h 2005-09-12 17:14:34 +0400 @@ -0,0 +1,98 @@ +/* + * (C) ALT Linux Ltd. 2005 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Module: utils.h + * + */ + +/* + * FAT boot sector structure. + */ +struct msdos_volume_info { + u_int8_t drive_number; /* BIOS drive number */ + u_int8_t RESERVED; /* Unused */ + u_int8_t ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */ + u_int32_t volume_id; /* Volume ID number */ + u_int8_t volume_label[11];/* Volume label */ + u_int8_t fs[8]; /* Typically FAT12 or FAT16 */ +} __attribute__ ((packed)); + +typedef struct { + u_int8_t ignored[3]; /* Boot strap short or near jump */ + u_int8_t system_id[8]; /* Name - can be used to special case + partition manager volumes */ + u_int16_t sector_size; /* bytes per logical sector */ + u_int8_t cluster_size; /* sectors/cluster */ + u_int16_t reserved; /* reserved sectors */ + u_int8_t fats; /* number of FATs */ + u_int8_t dir_entries[2]; /* root directory entries */ + u_int16_t sectors; /* number of sectors */ + u_int8_t media; /* media code (unused) */ + u_int16_t fat_length; /* sectors/FAT */ + u_int16_t secs_track; /* sectors per track */ + u_int16_t heads; /* number of heads */ + u_int32_t hidden; /* hidden sectors (unused) */ + u_int32_t total_sect; /* number of sectors (if sectors == 0) */ + + union { + struct { + struct msdos_volume_info vi; + //u_int8_t fs[8]; /* FS name */ + u_int16_t reserved2[14]; + } __attribute__ ((packed)) fat; + struct { + /* The following fields are only used by FAT32 */ + u_int32_t length; /* sectors/FAT */ + u_int16_t flags; /* bit 8: fat mirroring, low 4: active fat */ + u_int8_t version[2]; /* major, minor filesystem version */ + u_int32_t root_cluster; /* first cluster in root directory */ + u_int16_t info_sector; /* filesystem info sector */ + u_int16_t backup_boot; /* backup boot sector */ + u_int16_t reserved2[6]; /* Unused */ + struct msdos_volume_info vi; + //u_int8_t fs[8]; /* FS name: FAT 32 */ + } __attribute__ ((packed)) fat32; + }; + + /* fill up to 512 bytes */ + u_int8_t junk[422]; +} __attribute__ ((packed)) fat_boot_sector; + +typedef struct { + fat_boot_sector b; +} fat_boot; + +extern int get_fat_boot(int isfat16, logical_volume_t * ev, fat_boot *boot); + +extern int clear_fat_boot_sectors(logical_volume_t * ev); + +extern int try_run(char * prog_name); + +extern int get_fs_limits(logical_volume_t * vol, + sector_count_t * min_fs_size, + sector_count_t * max_fs_size, + sector_count_t * max_vol_size); + +void free_private_data(logical_volume_t * vol); + +extern int fill_private_data(int isfat16, + logical_volume_t * vol, + const fat_boot * boot); + +extern int resize_fat(int isfat16, + logical_volume_t * volume, + sector_count_t * new_size);