/[hurd]/hurd/libstore/unzipstore.c
ViewVC logotype

Diff of /hurd/libstore/unzipstore.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by roland, Tue Mar 12 03:20:44 2002 UTC revision 1.2 by roland, Thu Mar 14 21:09:42 2002 UTC
# Line 0  Line 1 
1    /* Decompressing store backend (common code for gunzip and bunzip2)
2    
3       Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
4       Written by okuji@kuicr.kyoto-u.ac.jp <okuji@kuicr.kyoto-u.ac.jp>
5       This file is part of the GNU Hurd.
6    
7       The GNU Hurd is free software; you can redistribute it and/or
8       modify it under the terms of the GNU General Public License as
9       published by the Free Software Foundation; either version 2, or (at
10       your option) any later version.
11    
12       The GNU Hurd is distributed in the hope that it will be useful, but
13       WITHOUT ANY WARRANTY; without even the implied warranty of
14       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15       General Public License for more details.
16    
17       You should have received a copy of the GNU General Public License
18       along with this program; if not, write to the Free Software
19       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
20    
21    #include <stdio.h>
22    #include <string.h>
23    #include <setjmp.h>
24    #include <cthreads.h>
25    #include <sys/mman.h>
26    
27    #include "store.h"
28    
29    #define IN_BUFFERING  (256*1024)
30    #define OUT_BUFFERING (512*1024)
31    
32    static struct mutex unzip_lock = MUTEX_INITIALIZER;
33    
34    #define STORE_UNZIP(name)               STORE_UNZIP_1 (UNZIP, name)
35    #define STORE_UNZIP_1(unzip,name)       STORE_UNZIP_2 (unzip, name)
36    #define STORE_UNZIP_2(unzip,name)       store_##unzip##_##name
37    #define STORE_STD_CLASS_1(name) STORE_STD_CLASS(name)
38    #define STRINGIFY(name) STRINGIFY_1(name)
39    #define STRINGIFY_1(name) #name
40    
41    
42    /* Uncompress the contents of FROM, which should contain a valid bzip2 file,
43       into memory, returning the result buffer in BUF & BUF_LEN.  */
44    static error_t
45    unzip_store (struct store *from, void **buf, size_t *buf_len)
46    {
47      /* Callbacks from decompression engine for I/O and error interface.  */
48      extern int (*unzip_read) (char *buf, size_t maxread);
49      extern void (*unzip_write) (const char *buf, size_t nwrite);
50      extern void (*unzip_read_error) (void);
51      extern void (*unzip_error) (const char *msg);
52    
53      /* How we return errors from our hook functions.  */
54      jmp_buf zerr_jmp_buf;
55      error_t zerr;
56    
57      /* vm_alloced buffer for the input store.  */
58      void *in_buf = 0;
59      size_t in_buf_len = 0;        /* Amount of valid data in IN_BUF.  */
60      size_t in_buf_size = 0;       /* Allocated space for IN_BUF.  */
61      size_t in_buf_offs = 0;       /* Offset of read point in IN_BUF.  */
62      off_t in_buf_addr = 0;        /* Address in FROM of *next* IN_BUF.  */
63    
64      /* Buffer input in units that are least IN_BUFFERING bytes, but are also a
65         multiple of FROM's block size.  */
66      size_t in_addr_mask = ((1 << from->log2_block_size) - 1);
67      size_t in_buffering = ((IN_BUFFERING + in_addr_mask) & ~in_addr_mask);
68    
69      /* Read at most MAXREAD (or 0 if eof) bytes into BUF from our current
70         position in FROM.  */
71      int zread (char *buf, size_t maxread)
72        {
73          size_t did_read = 0;
74    
75          while (maxread > 0)
76            {
77              size_t left = in_buf_len - in_buf_offs;
78    
79              if (left > 0)
80                /* Fill BUF with what we can from IN_BUF.  */
81                {
82                  if (left > maxread)
83                    left = maxread;
84                  bcopy (in_buf + in_buf_offs, buf, left);
85                  in_buf_offs += left;
86                  buf += left;
87                  maxread -= left;
88                  did_read += left;
89                }
90    
91              /* Limit MAXREAD to the number of bytes left in the input.  */
92              if (maxread > (from->size - (in_buf_addr << from->log2_block_size)))
93                maxread = from->size - (in_buf_addr << from->log2_block_size);
94    
95              if (maxread > 0)
96                /* Have to fill IN_BUF again.  */
97                {
98                  void *new_in_buf = in_buf;
99                  size_t new_in_buf_len = in_buf_len;
100    
101                  zerr = store_read (from, in_buf_addr, in_buffering,
102                                     &new_in_buf, &new_in_buf_len);
103                  if (zerr)
104                    longjmp (zerr_jmp_buf, 1);
105    
106                  in_buf_addr += (new_in_buf_len >> from->log2_block_size);
107    
108                  if (new_in_buf != in_buf)
109                    {
110                      if (in_buf_size > 0)
111                        munmap (in_buf, in_buf_size);
112                      in_buf = new_in_buf;
113                      in_buf_size = new_in_buf_len;
114                    }
115    
116                  in_buf_len = new_in_buf_len;
117                  in_buf_offs = 0;
118                }
119            }
120          return did_read;
121        }
122    
123      size_t out_buf_offs = 0;      /* Position in the output buffer.  */
124    
125      /* Write compress data to our output buffer.  */
126      void zwrite (const char *wbuf, size_t nwrite)
127        {
128          size_t old_buf_len = *buf_len;
129    
130          if (out_buf_offs + nwrite > old_buf_len)
131            /* Have to grow the output buffer.  */
132            {
133              void *old_buf = *buf;
134              void *new_buf = old_buf + old_buf_len; /* First try.  */
135              size_t new_buf_len = round_page (old_buf_len + old_buf_len + nwrite);
136    
137              /* Try to grow the buffer.  */
138              zerr =
139                vm_allocate (mach_task_self (),
140                             (vm_address_t *)&new_buf, new_buf_len - old_buf_len,
141                             0);
142              if (zerr)
143                /* Can't do that, try to make a bigger buffer elsewhere.  */
144                {
145                  new_buf = mmap (0, new_buf_len, PROT_READ|PROT_WRITE,
146                                  MAP_ANON, 0, 0);
147                  zerr = (new_buf == (void *) -1) ? errno : 0;
148                  if (zerr)
149                    longjmp (zerr_jmp_buf, 1);
150    
151                  if (out_buf_offs > 0)
152                    /* Copy the old buffer into the start of the new & free it. */
153                    bcopy (old_buf, new_buf, out_buf_offs);
154    
155                  munmap (old_buf, old_buf_len);
156    
157                  *buf = new_buf;
158                }
159    
160              *buf_len = new_buf_len;
161            }
162    
163          bcopy (wbuf, *buf + out_buf_offs, nwrite);
164          out_buf_offs += nwrite;
165        }
166    
167      void zreaderr (void)
168        {
169          zerr = EIO;
170          longjmp (zerr_jmp_buf, 1);
171        }
172      void zerror (const char *msg)
173        {
174          zerr = EINVAL;
175          longjmp (zerr_jmp_buf, 2);
176        }
177    
178      /* Try to guess a reasonable output buffer size.  */
179      *buf_len = round_page (from->size * 2);
180      *buf = mmap (0, *buf_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
181      zerr = (*buf == (void *) -1) ? errno : 0;
182      if (zerr)
183        return zerr;
184    
185      mutex_lock (&unzip_lock);
186    
187      unzip_read = zread;
188      unzip_write = zwrite;
189      unzip_read_error = zreaderr;
190      unzip_error = zerror;
191    
192      if (! setjmp (zerr_jmp_buf))
193        {
194          /* Call the decompression engine.  */
195          zerr = DO_UNZIP ();
196        }
197    
198      mutex_unlock (&unzip_lock);
199    
200      if (in_buf_size > 0)
201        munmap (in_buf, in_buf_size);
202    
203      if (zerr)
204        {
205          if (*buf_len > 0)
206            munmap (*buf, *buf_len);
207        }
208      else if (out_buf_offs < *buf_len)
209        /* Trim the output buffer to be the right length.  */
210        {
211          size_t end = round_page (out_buf_offs);
212          if (end < *buf_len)
213            munmap (*buf + end, *buf_len - end);
214          *buf_len = out_buf_offs;
215        }
216    
217      return zerr;
218    }
219    
220    
221    /* Return a new store in STORE which contains a snapshot of the uncompressed
222       contents of the store FROM; FROM is consumed.  */
223    error_t
224    STORE_UNZIP(create) (struct store *from, int flags, struct store **store)
225    {
226      void *buf;
227      size_t buf_len;
228      error_t err = unzip_store (from, &buf, &buf_len);
229    
230      if (! err)
231        {
232          err = store_buffer_create (buf, buf_len, flags, store);
233          if (err)
234            munmap (buf, buf_len);
235          else
236            store_free (from);
237        }
238    
239      return err;
240    }
241    
242    /* Open the compressed store NAME -- which consists of another store-class
243       name, a ':', and a name for that store class to open -- and return the
244       corresponding store in STORE.  CLASSES is used to select classes
245       specified by the type name; if it is 0, STORE_STD_CLASSES is used.  */
246    error_t
247    STORE_UNZIP(open) (const char *name, int flags,
248                        const struct store_class *const *classes,
249                        struct store **store)
250    {
251      struct store *from;
252      error_t err =
253        store_typed_open (name, flags | STORE_HARD_READONLY, classes, &from);
254    
255      if (! err)
256        {
257          err = STORE_UNZIP(create) (from, flags, store);
258          if (err)
259            store_free (from);
260        }
261    
262      return err;
263    }
264    
265    const struct store_class STORE_UNZIP(class) =
266    { -1, STRINGIFY(UNZIP), open: STORE_UNZIP(open) };
267    STORE_STD_CLASS_1 (UNZIP);

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26