/* $Id$ * W32 disk modules finder for acquiration installation utility * Copyright (C) 2003 Jan Kratochvil * * 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; exactly version 2 of June 1991 is required * * 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 */ #include "config.h" #include "moduriload.h" /* self */ #include #include #include #include #include #include "../libcaptive-install/proc_partitions.h" #include "main.h" #include #include "captivemodid.h" #include "cabinet.h" #include #include #include #include #include /* Config: */ #define MAX_FILE_LOAD_LENGTH 5000000 /* Otherwise use cabextract-over-http. */ /* map: (const xmlChar *)type -> (struct module_available *) */ GHashTable *module_available_hash; static void module_available_hash_value_destroy_func(struct module_available *module_available) { g_return_if_fail(module_available!=NULL); g_free(module_available->file_base); g_free(module_available->uri_text); g_free(module_available); } static void module_available_hash_init(void) { if (module_available_hash) return; module_available_hash=g_hash_table_new_full(g_str_hash,g_str_equal, (GDestroyNotify)NULL, (GDestroyNotify)module_available_hash_value_destroy_func); } void (*acquire_module_available_notify)(struct module_available *module_available); void (*acquire_module_all_modules_found_notify)(void); static void mod_uri_load_module_from_memory (struct captivemodid_module *module,gconstpointer file_base,size_t file_length,GnomeVFSURI *uri) { struct module_available *module_available; gint best_priority; gboolean all_modules_found; g_return_if_fail(module!=NULL); g_return_if_fail(file_base!=NULL); g_return_if_fail(uri!=NULL); g_return_if_fail((size_t)module->length==file_length); module_available_hash_init(); if ((module_available=g_hash_table_lookup(module_available_hash,module->type))) { if (module_available->module->priority>=module->priority) return; } captive_new(module_available); module_available->module=module; module_available->file_base=g_memdup(file_base,file_length); module_available->uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD); /* It may possibly destroy the old 'module_available': */ g_hash_table_insert(module_available_hash,(/* de-const */ xmlChar *)module->type,module_available); if (!optarg_dry) { const gchar *dest_pathname; int dest_fd; dest_pathname=captive_printf_alloca("%s/%s",G_STRINGIFY(VARLIBCAPTIVEDIR),module->type); if (-1==(dest_fd=open(dest_pathname,O_CREAT|O_TRUNC|O_WRONLY,0644))) g_warning(_("Cannot open target file \"%s\": %m"),dest_pathname); else { if ((ssize_t)file_length!=write(dest_fd,file_base,file_length)) g_warning(_("Error writing target file \"%s\": %m"),dest_pathname); if (close(dest_fd)) g_warning(_("Error closing target file \"%s\": %m"),dest_pathname); } } all_modules_found=FALSE; best_priority=captivemodid_module_type_best_priority_lookup(module->type); if (best_priority==G_MININT /* no longer seeking for such module */ || module_available->module->priority==best_priority) { if (captivemodid_module_type_best_priority_found(module->type)) { /* Postpone (*acquire_module_all_modules_found_notify)() * after (*acquire_module_available_notify)(). */ all_modules_found=TRUE; } } if (acquire_module_available_notify) (*acquire_module_available_notify)(module_available); if (all_modules_found) if (acquire_module_all_modules_found_notify) (*acquire_module_all_modules_found_notify)(); } void mod_uri_load_file_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri) { gchar *file_md5; struct captivemodid_module *module; g_return_if_fail(file_base!=NULL); g_return_if_fail(uri!=NULL); if ((*ui_progress)(uri)) return; file_md5=calc_md5(file_base,file_length); if (!(module=captivemodid_module_md5_lookup(file_md5))) goto fail_free_file_md5; if (strcmp("cabinet",module->type)) mod_uri_load_module_from_memory(module,file_base,file_length,uri); else { struct acquire_cabinet *acquire_cabinet; /* acquire_cabinet_load() will call mod_uri_load_module_from_memory(): */ acquire_cabinet=acquire_cabinet_new_from_memory(file_base,file_length,uri,module->cabinet_used); acquire_cabinet_load(acquire_cabinet); acquire_cabinet_free(acquire_cabinet); } fail_free_file_md5: g_free(file_md5); } static void mod_uri_load_file_handle_to_memory(GnomeVFSHandle *handle,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri) { guint8 *file_buffer,file_tail_check; GnomeVFSFileSize bytes_read; GnomeVFSResult errvfsresult; g_return_if_fail(handle!=NULL); g_return_if_fail(file_info!=NULL); g_return_if_fail(uri!=NULL); /* gnome_vfs_read_entire_file() reads the file by chunks although * it does not need to know the file size. */ file_buffer=g_malloc(file_info->size); errvfsresult=gnome_vfs_read(handle,file_buffer,file_info->size,&bytes_read); if (errvfsresult!=GNOME_VFS_OK || bytes_read!=file_info->size) goto fail_free_file_buffer; /* 'bytes_read' must be !=NULL for GnomeVFS-2.0.x! */ errvfsresult=gnome_vfs_read(handle,&file_tail_check,1,&bytes_read); if (!(errvfsresult==GNOME_VFS_ERROR_EOF /* At least RedHat gnome-vfs2-2.0.2-5 * and ntfsprogs-200309071734-1captive1 and ntfsprogs-gnomevfs-1.0.1-0 * do not report GNOME_VFS_ERROR_EOF. * FIXME: Check if it is a bug in ntfsprogs-gnomevfs-1.0.1-0. */ || (errvfsresult==GNOME_VFS_OK && bytes_read==0))) goto fail_free_file_buffer; mod_uri_load_file_from_memory(file_buffer,file_info->size,uri); fail_free_file_buffer: g_free(file_buffer); } static void mod_uri_load_file_handle_remote_cabinet (GnomeVFSHandle **handlep,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri,gint cabinet_used) { struct acquire_cabinet *acquire_cabinet; g_return_if_fail(handlep!=NULL); g_return_if_fail(*handlep!=NULL); g_return_if_fail(file_info!=NULL); g_return_if_fail(uri!=NULL); acquire_cabinet=acquire_cabinet_new_from_handle(handlep,file_info,uri,cabinet_used); /* acquire_cabinet_load() will call mod_uri_load_module_from_memory(): */ acquire_cabinet_load(acquire_cabinet); acquire_cabinet_free(acquire_cabinet); } static void mod_uri_load_file(GnomeVFSURI *uri) { GnomeVFSResult errvfsresult; GnomeVFSFileInfo file_info_local; GnomeVFSHandle *handle; g_return_if_fail(uri!=NULL); if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_open_uri(&handle,uri,GNOME_VFS_OPEN_READ))) goto fail; if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_get_file_info_from_handle(handle,&file_info_local,GNOME_VFS_FILE_INFO_DEFAULT))) goto fail_close_handle; if (file_info_local.type!=GNOME_VFS_FILE_TYPE_REGULAR) { errvfsresult=GNOME_VFS_ERROR_WRONG_FORMAT; goto fail_close_handle; } if (!(file_info_local.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) { errvfsresult=GNOME_VFS_ERROR_WRONG_FORMAT; goto fail_close_handle; } if (!captivemodid_module_length_is_valid(file_info_local.size)) { errvfsresult=GNOME_VFS_ERROR_WRONG_FORMAT; goto fail_close_handle; } if (file_info_local.size<=MAX_FILE_LOAD_LENGTH) mod_uri_load_file_handle_to_memory(handle,&file_info_local,uri); else { gint cabinet_used=captivemodid_cabinet_length_to_used(file_info_local.size); mod_uri_load_file_handle_remote_cabinet(&handle,&file_info_local,uri,cabinet_used); } errvfsresult=GNOME_VFS_OK; /* PASSTHRU */ fail_close_handle: gnome_vfs_close(handle); fail:; } static gboolean mod_uri_load_directory_visit_func (const gchar *rel_path,GnomeVFSFileInfo *info,gboolean recursing_will_loop,GnomeVFSURI *root_uri /* data */, gboolean *recurse) { g_return_val_if_fail(rel_path!=NULL,FALSE); g_return_val_if_fail(info!=NULL,FALSE); g_return_val_if_fail(root_uri!=NULL,FALSE); g_return_val_if_fail(recurse!=NULL,FALSE); *recurse=FALSE; /* Do not: (*ui_progress)(root_uri); * here as we are called with the same 'root_uri' for all of our 'rel_path's. */ (*ui_progress)(NULL); switch (info->type) { case GNOME_VFS_FILE_TYPE_REGULAR: { GnomeVFSURI *file_uri; file_uri=gnome_vfs_uri_append_path(root_uri,rel_path); if ((*ui_progress)(file_uri)) { gnome_vfs_uri_unref(file_uri); return FALSE; /* abort traversal */ } mod_uri_load_file(file_uri); gnome_vfs_uri_unref(file_uri); } break; case GNOME_VFS_FILE_TYPE_DIRECTORY: { GnomeVFSURI *directory_uri; GnomeVFSDirectoryHandle *directory_handle; /* Never set '*recurse' if it would cause 'Access denied' error * as it would completely abort the upper gnome_vfs_directory_visit_uri(). * Check the directory accessibility manually: */ directory_uri=gnome_vfs_uri_append_path(root_uri,rel_path); if ((*ui_progress)(directory_uri)) { gnome_vfs_uri_unref(directory_uri); return FALSE; /* abort traversal */ } if (GNOME_VFS_OK==gnome_vfs_directory_open_from_uri(&directory_handle,directory_uri,GNOME_VFS_FILE_INFO_DEFAULT)) { *recurse=TRUE; gnome_vfs_directory_close(directory_handle); /* errors ignored */ } gnome_vfs_uri_unref(directory_uri); } break; default:; } return TRUE; /* continue traversal */ } static void mod_uri_load_directory(GnomeVFSURI *uri) { GnomeVFSResult errvfsresult; g_return_if_fail(uri!=NULL); errvfsresult=gnome_vfs_directory_visit_uri(uri, GNOME_VFS_FILE_INFO_DEFAULT, /* info_options */ GNOME_VFS_DIRECTORY_VISIT_SAMEFS, /* visit_options; 'GNOME_VFS_DIRECTORY_VISIT_LOOPCHECK'? */ (GnomeVFSDirectoryVisitFunc)mod_uri_load_directory_visit_func, uri); /* data */ if (errvfsresult!=GNOME_VFS_OK) { gchar *uri_text; uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD); g_warning(_("Error scanning sub-tree of \"%s\": %s"),uri_text,gnome_vfs_result_to_string(errvfsresult)); g_free(uri_text); } } static void mod_uri_load_internal(GnomeVFSURI *uri,gboolean base_reporting) { GnomeVFSFileInfo file_info_local; GnomeVFSResult errvfsresult; g_return_if_fail(uri!=NULL); if (optarg_verbose) { gchar *uri_text; uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD); g_message(_("Scanning...: %s"),uri_text); g_free(uri_text); } file_info_local.type=GNOME_VFS_FILE_TYPE_UNKNOWN; if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_get_file_info_uri(uri,&file_info_local,GNOME_VFS_FILE_INFO_DEFAULT))) { if (base_reporting) { gchar *uri_text; uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD); g_warning(_("Error loading \"%s\": %s"),uri_text,gnome_vfs_result_to_string(errvfsresult)); g_free(uri_text); } return; } switch (file_info_local.type) { case GNOME_VFS_FILE_TYPE_REGULAR: return mod_uri_load_file(uri); case GNOME_VFS_FILE_TYPE_DIRECTORY: return mod_uri_load_directory(uri); default: return /* GNOME_VFS_ERROR_WRONG_FORMAT */; } /* NOTREACHED */ } void mod_uri_load(GnomeVFSURI *uri) { g_return_if_fail(uri!=NULL); mod_uri_load_internal(uri, FALSE); /* base_reporting */ } void mod_uri_load_base_reporting(GnomeVFSURI *uri) { g_return_if_fail(uri!=NULL); mod_uri_load_internal(uri, TRUE); /* base_reporting */ }