Bootstrap of 'captive-install-acquire' for W32 modules acquiration process.
[captive.git] / src / install / acquire / cabinet.c
1 /* $Id$
2  * cabextract interface for acquiration installation utility
3  * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
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.
13  * 
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
17  */
18
19
20 #include "config.h"
21
22 #include "cabinet.h"    /* self */
23 #include <glib/gmessages.h>
24 #include <libgnomevfs/gnome-vfs-file-size.h>
25 #include <libgnomevfs/gnome-vfs-ops.h>
26 #include "cabextract/cabextract.h"
27 #include "captivemodid.h"
28 #include "moduriload.h"
29 #include <sys/mman.h>
30 #include <unistd.h>
31
32 #include <captive/macros.h>
33
34
35 void acquire_cabinet_seek(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOffset offset)
36 {
37         g_return_if_fail(acquire_cabinet!=NULL);
38
39         acquire_cabinet->offset=offset;
40 }
41
42 void acquire_cabinet_seek_skip(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOffset offset)
43 {
44         g_return_if_fail(acquire_cabinet!=NULL);
45
46         acquire_cabinet->offset+=offset;
47 }
48
49 GnomeVFSFileOffset acquire_cabinet_tell(struct acquire_cabinet *acquire_cabinet)
50 {
51         g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
52
53         return acquire_cabinet->offset;
54 }
55
56 #define ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,pos)     (!(acquire_cabinet)->base_cached \
57                                                            || (acquire_cabinet)->base_cached[(pos)/8] &  1<<((pos)&7))
58 #define ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,pos) ((acquire_cabinet)->base_cached[(pos)/8] |= 1<<((pos)&7))
59
60 GnomeVFSResult acquire_cabinet_read
61                 (struct acquire_cabinet *acquire_cabinet,gpointer buffer,GnomeVFSFileSize bytes,GnomeVFSFileSize *bytes_read)
62 {
63 GnomeVFSFileOffset offset_start,offset_end,read_behind;
64 GnomeVFSResult errvfsresult;
65 GnomeVFSFileSize bytes_read_now;
66
67         g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
68         g_return_val_if_fail(buffer!=NULL || bytes==0,GNOME_VFS_ERROR_BAD_PARAMETERS);
69
70         bytes=MAX(0,MIN(bytes,acquire_cabinet->size-acquire_cabinet->offset));
71         if (!bytes)
72                 return GNOME_VFS_ERROR_EOF;
73
74         *bytes_read=0;
75         while (bytes) {
76                 read_behind =acquire_cabinet->offset+bytes;
77
78                 /* GnomeVFS block transfer: */
79                 offset_start=acquire_cabinet->offset;
80                 offset_end  =acquire_cabinet->offset;
81                 while (offset_end<read_behind && !ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,offset_end))
82                         offset_end++;
83                 if (offset_end>offset_start) {
84                         if (GNOME_VFS_OK!=(errvfsresult=gnome_vfs_seek(acquire_cabinet->handle,GNOME_VFS_SEEK_START,offset_start)))
85                                 return errvfsresult;
86                         errvfsresult=gnome_vfs_read(acquire_cabinet->handle,
87                                         acquire_cabinet->base+offset_start,offset_end-offset_start,&bytes_read_now);
88                         if (errvfsresult!=GNOME_VFS_OK)
89                                 return errvfsresult;
90                         g_assert(bytes_read_now>0);
91                         while (bytes_read_now) {
92                                 ACQUIRE_CABINET_SET_BYTE_CACHED(acquire_cabinet,offset_start);
93                                 offset_start++;
94                                 bytes_read_now--;
95                                 }
96                         }
97
98                 /* Memory block transfer: */
99                 offset_start=acquire_cabinet->offset;
100                 offset_end  =acquire_cabinet->offset;
101                 while (offset_end<read_behind && ACQUIRE_CABINET_BYTE_CACHED(acquire_cabinet,offset_end))
102                         offset_end++;
103                 memcpy(buffer,acquire_cabinet->base+offset_start,offset_end-offset_start);
104                 if (bytes_read)
105                         *bytes_read+=offset_end-offset_start;
106                 buffer+=offset_end-offset_start;
107                 bytes-=offset_end-offset_start;
108                 acquire_cabinet->offset=offset_end;
109                 }
110
111         return GNOME_VFS_OK;
112 }
113
114 static void acquire_cabinet_set_uri(struct acquire_cabinet *acquire_cabinet,GnomeVFSURI *uri)
115 {
116 GnomeVFSURI *uri_cabextract;
117
118         g_return_if_fail(acquire_cabinet!=NULL);
119         g_return_if_fail(uri!=NULL);
120
121         /* FIXME: HACK: Use proper 'cabextract' scheme after it gets implemented.
122          * GnomeVFS will return NULL on gnome_vfs_uri_new() with scheme not available.
123          */
124         uri_cabextract=gnome_vfs_uri_new("file://");
125         g_assert(uri_cabextract->parent==NULL);
126         /* Do not: g_assert(!strcmp(uri_cabextract->method_string,"file"));
127          *         uri_cabextract->method_string=g_strdup("cabextract");
128          * as it will just strip such anchor. FIXME: Why?
129          */
130
131         uri_cabextract->parent=gnome_vfs_uri_dup(uri);
132
133         acquire_cabinet->uri=uri_cabextract;
134         acquire_cabinet->filename=gnome_vfs_uri_to_string(acquire_cabinet->uri,GNOME_VFS_URI_HIDE_PASSWORD);
135 }
136
137 struct acquire_cabinet *acquire_cabinet_new_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
138 {
139 struct acquire_cabinet *r;
140
141         g_return_val_if_fail(file_base!=NULL,NULL);
142         g_return_val_if_fail(uri!=NULL,NULL);
143         
144         captive_new(r);
145         r->base=(/* de-const */ gpointer)file_base;
146         r->base_cached=NULL;
147         r->offset=0;
148         r->handle=NULL;
149         r->size=file_length;
150         acquire_cabinet_set_uri(r,uri);
151
152         return r;
153 }
154
155 struct acquire_cabinet *acquire_cabinet_new_from_handle(GnomeVFSHandle *handle,GnomeVFSFileInfo *file_info,GnomeVFSURI *uri)
156 {
157 struct acquire_cabinet *r;
158
159         g_return_val_if_fail(handle!=NULL,NULL);
160         g_return_val_if_fail(file_info!=NULL,NULL);
161         g_return_val_if_fail(uri!=NULL,NULL);
162         
163         captive_new(r);
164         if (MAP_FAILED==(r->base=mmap(
165                         NULL,CAPTIVE_ROUND_UP64(file_info->size,getpagesize()),PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0))) {
166                 g_free(r);
167                 g_return_val_if_reached(NULL);
168                 }
169         captive_new0n(r->base_cached,CAPTIVE_ROUND_UP64(file_info->size,8)/8);
170         r->offset=0;
171         r->handle=handle;
172         r->size=file_info->size;
173         acquire_cabinet_set_uri(r,uri);
174
175         return r;
176 }
177
178 void acquire_cabinet_free(struct acquire_cabinet *acquire_cabinet)
179 {
180         g_return_if_fail(acquire_cabinet!=NULL);
181
182         if (acquire_cabinet->base_cached) {
183                 munmap(acquire_cabinet->base,CAPTIVE_ROUND_UP64(acquire_cabinet->size,getpagesize()));  /* errors ignored */
184                 g_free(acquire_cabinet->base_cached);
185                 }
186         g_free((/* de-const */ gchar *)acquire_cabinet->filename);
187         gnome_vfs_uri_unref(acquire_cabinet->uri);
188         g_free(acquire_cabinet);
189 }
190
191 static struct file *file_write_fi_assertion;
192 static GByteArray *file_write_bytearray;
193
194 int file_write(struct file *fi, UBYTE *buf, size_t length)
195 {
196         g_return_val_if_fail(fi!=NULL,0);
197         g_return_val_if_fail(buf!=NULL || length==0,0);
198
199         g_return_val_if_fail(fi==file_write_fi_assertion,0);
200         g_return_val_if_fail(file_write_bytearray!=NULL,0);
201
202         g_byte_array_append(file_write_bytearray,buf,length);
203
204         return 1;       /* success */
205 }
206
207 void acquire_cabinet_load(struct acquire_cabinet *acquire_cabinet)
208 {
209 struct cabinet *basecab;
210 struct file *filelist,*fi;
211
212         g_return_if_fail(acquire_cabinet!=NULL);
213
214         basecab=find_cabs_in_file(acquire_cabinet);
215         if (!basecab)
216                 return;
217         if (basecab->next)
218                 return;
219         if (basecab->prevcab || basecab->nextcab)
220                 return;
221
222         filelist=process_files(basecab);
223
224         for (fi=filelist;fi;fi=fi->next) {
225 gpointer file_buffer;
226 GnomeVFSURI *uri_fi;
227
228                 if (!captivemodid_module_length_is_valid(fi->length))
229                         continue;
230
231                 file_write_fi_assertion=fi;
232                 file_write_bytearray=g_byte_array_new();
233                 extract_file(fi,
234                                 0,      /* lower; ignored now */
235                                 FALSE,  /* fix */
236                                 NULL);  /* dir; ignored now */
237                 if (fi->length!=file_write_bytearray->len) {
238                         g_byte_array_free(file_write_bytearray,
239                                         TRUE);  /* free_segment */
240                         continue;
241                         }
242                 file_buffer=g_byte_array_free(file_write_bytearray,
243                                 FALSE); /* free_segment */
244                 uri_fi=gnome_vfs_uri_append_file_name(acquire_cabinet->uri,fi->filename);
245                 mod_uri_load_file_from_memory(file_buffer,fi->length,uri_fi);
246                 gnome_vfs_uri_unref(uri_fi);
247                 g_free(file_buffer);
248     }
249 }