2 * W32 disk modules finder for acquiration installation utility
3 * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
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; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "moduriload.h" /* self */
23 #include <glib/gmessages.h>
25 #include <glib/ghash.h>
26 #include <glib/glist.h>
27 #include <libgnomevfs/gnome-vfs-uri.h>
28 #include "../libcaptive-install/proc_partitions.h"
31 #include "captivemodid.h"
33 #include <libgnomevfs/gnome-vfs-ops.h>
34 #include <libgnomevfs/gnome-vfs-directory.h>
38 #include <captive/macros.h>
42 #define MAX_FILE_LOAD_LENGTH 5000000 /* Otherwise use cabextract-over-http. */
45 /* map: (const xmlChar *)type -> (struct module_available *) */
46 GHashTable *module_available_hash;
48 static void module_available_hash_value_destroy_func(struct module_available *module_available)
50 g_return_if_fail(module_available!=NULL);
52 g_free(module_available->file_base);
53 g_free(module_available->uri_text);
54 g_free(module_available);
57 static void module_available_hash_init(void)
59 if (module_available_hash)
61 module_available_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
63 (GDestroyNotify)module_available_hash_value_destroy_func);
67 void (*acquire_module_available_notify)(struct module_available *module_available);
68 void (*acquire_module_all_modules_found_notify)(void);
70 static void mod_uri_load_module_from_memory
71 (struct captivemodid_module *module,gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
73 struct module_available *module_available;
75 gboolean all_modules_found;
77 g_return_if_fail(module!=NULL);
78 g_return_if_fail(file_base!=NULL);
79 g_return_if_fail(uri!=NULL);
80 g_return_if_fail((size_t)module->length==file_length);
82 module_available_hash_init();
83 if ((module_available=g_hash_table_lookup(module_available_hash,module->type))) {
84 if (module_available->module->priority>=module->priority)
88 captive_new(module_available);
89 module_available->module=module;
90 module_available->file_base=g_memdup(file_base,file_length);
91 module_available->uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
92 /* It may possibly destroy the old 'module_available': */
93 g_hash_table_insert(module_available_hash,(/* de-const */ xmlChar *)module->type,module_available);
96 const gchar *dest_pathname;
99 dest_pathname=captive_printf_alloca("%s/%s",G_STRINGIFY(VARLIBCAPTIVEDIR),module->type);
100 if (-1==(dest_fd=open(dest_pathname,O_CREAT|O_TRUNC|O_WRONLY,0644)))
101 g_warning(_("Cannot open target file \"%s\": %m"),dest_pathname);
103 if ((ssize_t)file_length!=write(dest_fd,file_base,file_length))
104 g_warning(_("Error writing target file \"%s\": %m"),dest_pathname);
106 g_warning(_("Error closing target file \"%s\": %m"),dest_pathname);
110 all_modules_found=FALSE;
112 best_priority=captivemodid_module_type_best_priority_lookup(module->type);
113 if (best_priority==G_MININT /* no longer seeking for such module */
114 || module_available->module->priority==best_priority) {
115 if (captivemodid_module_type_best_priority_found(module->type)) {
116 /* Postpone (*acquire_module_all_modules_found_notify)()
117 * after (*acquire_module_available_notify)().
119 all_modules_found=TRUE;
123 if (acquire_module_available_notify)
124 (*acquire_module_available_notify)(module_available);
125 if (all_modules_found)
126 if (acquire_module_all_modules_found_notify)
127 (*acquire_module_all_modules_found_notify)();
130 void mod_uri_load_file_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
133 struct captivemodid_module *module;
135 g_return_if_fail(file_base!=NULL);
136 g_return_if_fail(uri!=NULL);
138 if ((*ui_progress)(uri))
141 file_md5=calc_md5(file_base,file_length);
142 if (!(module=captivemodid_module_md5_lookup(file_md5)))
143 goto fail_free_file_md5;
145 if (strcmp("cabinet",module->type))
146 mod_uri_load_module_from_memory(module,file_base,file_length,uri);
148 struct acquire_cabinet *acquire_cabinet;
149 /* acquire_cabinet_load() will call mod_uri_load_module_from_memory(): */
150 acquire_cabinet=acquire_cabinet_new_from_memory(file_base,file_length,uri,module->cabinet_used);
151 acquire_cabinet_load(acquire_cabinet);
152 acquire_cabinet_free(acquire_cabinet);
159 static void mod_uri_load_file_handle_to_memory(GnomeVFSHandle *handle,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri)
161 guint8 *file_buffer,file_tail_check;
162 GnomeVFSFileSize bytes_read;
163 GnomeVFSResult errvfsresult;
165 g_return_if_fail(handle!=NULL);
166 g_return_if_fail(file_info!=NULL);
167 g_return_if_fail(uri!=NULL);
169 /* gnome_vfs_read_entire_file() reads the file by chunks although
170 * it does not need to know the file size.
172 file_buffer=g_malloc(file_info->size);
174 errvfsresult=gnome_vfs_read(handle,file_buffer,file_info->size,&bytes_read);
175 if (errvfsresult!=GNOME_VFS_OK || bytes_read!=file_info->size)
176 goto fail_free_file_buffer;
177 /* 'bytes_read' must be !=NULL for GnomeVFS-2.0.x! */
178 errvfsresult=gnome_vfs_read(handle,&file_tail_check,1,&bytes_read);
179 if (!(errvfsresult==GNOME_VFS_ERROR_EOF
180 /* At least RedHat gnome-vfs2-2.0.2-5
181 * and ntfsprogs-200309071734-1captive1 and ntfsprogs-gnomevfs-1.0.1-0
182 * do not report GNOME_VFS_ERROR_EOF.
183 * FIXME: Check if it is a bug in ntfsprogs-gnomevfs-1.0.1-0.
185 || (errvfsresult==GNOME_VFS_OK && bytes_read==0)))
186 goto fail_free_file_buffer;
187 mod_uri_load_file_from_memory(file_buffer,file_info->size,uri);
189 fail_free_file_buffer:
193 static void mod_uri_load_file_handle_remote_cabinet
194 (GnomeVFSHandle *handle,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri,gint cabinet_used)
196 struct acquire_cabinet *acquire_cabinet;
198 g_return_if_fail(handle!=NULL);
199 g_return_if_fail(file_info!=NULL);
200 g_return_if_fail(uri!=NULL);
202 acquire_cabinet=acquire_cabinet_new_from_handle(handle,file_info,uri,cabinet_used);
203 /* acquire_cabinet_load() will call mod_uri_load_module_from_memory(): */
204 acquire_cabinet_load(acquire_cabinet);
205 acquire_cabinet_free(acquire_cabinet);
208 static void mod_uri_load_file(GnomeVFSURI *uri)
210 GnomeVFSResult errvfsresult;
211 GnomeVFSFileInfo file_info_local;
212 GnomeVFSHandle *handle;
214 g_return_if_fail(uri!=NULL);
216 if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_open_uri(&handle,uri,GNOME_VFS_OPEN_READ)))
218 if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_get_file_info_from_handle(handle,&file_info_local,GNOME_VFS_FILE_INFO_DEFAULT)))
219 goto fail_close_handle;
220 if (file_info_local.type!=GNOME_VFS_FILE_TYPE_REGULAR) {
221 errvfsresult=GNOME_VFS_ERROR_WRONG_FORMAT;
222 goto fail_close_handle;
224 if (!(file_info_local.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
225 errvfsresult=GNOME_VFS_ERROR_WRONG_FORMAT;
226 goto fail_close_handle;
228 if (!captivemodid_module_length_is_valid(file_info_local.size)) {
229 errvfsresult=GNOME_VFS_ERROR_WRONG_FORMAT;
230 goto fail_close_handle;
232 if (file_info_local.size<=MAX_FILE_LOAD_LENGTH)
233 mod_uri_load_file_handle_to_memory(handle,&file_info_local,uri);
235 gint cabinet_used=captivemodid_cabinet_length_to_used(file_info_local.size);
237 mod_uri_load_file_handle_remote_cabinet(handle,&file_info_local,uri,cabinet_used);
239 errvfsresult=GNOME_VFS_OK;
242 gnome_vfs_close(handle);
246 static gboolean mod_uri_load_directory_visit_func
247 (const gchar *rel_path,GnomeVFSFileInfo *info,gboolean recursing_will_loop,GnomeVFSURI *root_uri /* data */,
250 g_return_val_if_fail(rel_path!=NULL,FALSE);
251 g_return_val_if_fail(info!=NULL,FALSE);
252 g_return_val_if_fail(root_uri!=NULL,FALSE);
253 g_return_val_if_fail(recurse!=NULL,FALSE);
257 /* Do not: (*ui_progress)(root_uri);
258 * here as we are called with the same 'root_uri' for all of our 'rel_path's.
260 (*ui_progress)(NULL);
262 switch (info->type) {
263 case GNOME_VFS_FILE_TYPE_REGULAR: {
264 GnomeVFSURI *file_uri;
266 file_uri=gnome_vfs_uri_append_path(root_uri,rel_path);
267 if ((*ui_progress)(file_uri)) {
268 gnome_vfs_uri_unref(file_uri);
269 return FALSE; /* abort traversal */
271 mod_uri_load_file(file_uri);
272 gnome_vfs_uri_unref(file_uri);
274 case GNOME_VFS_FILE_TYPE_DIRECTORY: {
275 GnomeVFSURI *directory_uri;
276 GnomeVFSDirectoryHandle *directory_handle;
278 /* Never set '*recurse' if it would cause 'Access denied' error
279 * as it would completely abort the upper gnome_vfs_directory_visit_uri().
280 * Check the directory accessibility manually:
282 directory_uri=gnome_vfs_uri_append_path(root_uri,rel_path);
283 if ((*ui_progress)(directory_uri)) {
284 gnome_vfs_uri_unref(directory_uri);
285 return FALSE; /* abort traversal */
287 if (GNOME_VFS_OK==gnome_vfs_directory_open_from_uri(&directory_handle,directory_uri,GNOME_VFS_FILE_INFO_DEFAULT)) {
289 gnome_vfs_directory_close(directory_handle); /* errors ignored */
291 gnome_vfs_uri_unref(directory_uri);
296 return TRUE; /* continue traversal */
299 static void mod_uri_load_directory(GnomeVFSURI *uri)
301 GnomeVFSResult errvfsresult;
303 g_return_if_fail(uri!=NULL);
305 errvfsresult=gnome_vfs_directory_visit_uri(uri,
306 GNOME_VFS_FILE_INFO_DEFAULT, /* info_options */
307 GNOME_VFS_DIRECTORY_VISIT_SAMEFS, /* visit_options; 'GNOME_VFS_DIRECTORY_VISIT_LOOPCHECK'? */
308 (GnomeVFSDirectoryVisitFunc)mod_uri_load_directory_visit_func,
310 if (errvfsresult!=GNOME_VFS_OK) {
313 uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
314 g_warning(_("Error scanning sub-tree of \"%s\": %s"),uri_text,gnome_vfs_result_to_string(errvfsresult));
319 void mod_uri_load(GnomeVFSURI *uri)
321 GnomeVFSFileInfo file_info_local;
322 GnomeVFSResult errvfsresult;
324 g_return_if_fail(uri!=NULL);
326 if (optarg_verbose) {
329 uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
330 g_message(_("Scanning...: %s"),uri_text);
334 file_info_local.type=GNOME_VFS_FILE_TYPE_UNKNOWN;
335 if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_get_file_info_uri(uri,&file_info_local,GNOME_VFS_FILE_INFO_DEFAULT)))
336 return /* errvfsresult */;
337 switch (file_info_local.type) {
338 case GNOME_VFS_FILE_TYPE_REGULAR: return mod_uri_load_file(uri);
339 case GNOME_VFS_FILE_TYPE_DIRECTORY: return mod_uri_load_directory(uri);
340 default: return /* GNOME_VFS_ERROR_WRONG_FORMAT */;