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

Diff of /hurd/libstore/gunzip.c

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

revision 1.5.2.1 by roland, Sat Feb 9 04:04:50 2002 UTC revision 1.5.2.2 by roland, Tue Mar 12 03:20:44 2002 UTC
# Line 33  Line 33 
33  #undef file_t  #undef file_t
34  #undef head  #undef head
35    
 #define IN_BUFFERING  (256*1024)  
 #define OUT_BUFFERING (512*1024)  
   
 static struct mutex unzip_lock = MUTEX_INITIALIZER;  
   
 /* Uncompress the contents of FROM, which should contain a valid gzip file,  
    into memory, returning the result buffer in BUF & BUF_LEN.  */  
36  static error_t  static error_t
37  gunzip (struct store *from, void **buf, size_t *buf_len)  DO_UNZIP (void)
38  {  {
39    /* Entry points to unzip engine.  */    /* Entry points to unzip engine.  */
40    int get_method (int);    int get_method (int);
41    extern long int bytes_out;    extern long int bytes_out;
   /* Callbacks from unzip for I/O and error interface.  */  
   extern int (*unzip_read) (char *buf, size_t maxread);  
   extern void (*unzip_write) (const char *buf, size_t nwrite);  
   extern void (*unzip_read_error) (void);  
   extern void (*unzip_error) (const char *msg);  
   
   /* How we return errors from our hook functions.  */  
   jmp_buf zerr_jmp_buf;  
   error_t zerr;  
   
   /* vm_alloced buffer for the input store.  */  
   void *in_buf = 0;  
   size_t in_buf_len = 0;  
   size_t in_buf_offs = 0;       /* Offset of read point in IN_BUF.  */  
   off_t in_buf_addr = 0;        /* Address in FROM of *next* IN_BUF.  */  
   
   /* Buffer input in units that are least IN_BUFFERING bytes, but are also a  
      multiple of FROM's block size.  */  
   size_t in_addr_mask = ((1 << from->log2_block_size) - 1);  
   size_t in_buffering = ((IN_BUFFERING + in_addr_mask) & ~in_addr_mask);  
   
   /* Read at most MAXREAD (or 0 if eof) bytes into BUF from our current  
      position in FROM.  */  
   int zread (char *buf, size_t maxread)  
     {  
       size_t did_read = 0;  
   
       while (maxread > 0)  
         {  
           size_t left = in_buf_len - in_buf_offs;  
   
           if (left > 0)  
             /* Fill BUF with what we can from IN_BUF.  */  
             {  
               if (left > maxread)  
                 left = maxread;  
               bcopy (in_buf + in_buf_offs, buf, left);  
               in_buf_offs += left;  
               buf += left;  
               maxread -= left;  
               did_read += left;  
             }  
   
           /* Limit MAXREAD to the number of bytes left in the input.  */  
           if (maxread > (from->size - (in_buf_addr << from->log2_block_size)))  
             maxread = from->size - (in_buf_addr << from->log2_block_size);  
   
           if (maxread > 0)  
             /* Have to fill IN_BUF again.  */  
             {  
               void *new_in_buf = in_buf;  
               size_t new_in_buf_len = in_buf_len;  
   
               zerr = store_read (from, in_buf_addr, in_buffering,  
                                  &new_in_buf, &new_in_buf_len);  
               if (zerr)  
                 longjmp (zerr_jmp_buf, 1);  
   
               in_buf_addr += (new_in_buf_len >> from->log2_block_size);  
   
               if (new_in_buf != in_buf)  
                 {  
                   if (in_buf_len > 0)  
                     munmap (in_buf, in_buf_len);  
                   in_buf = new_in_buf;  
                   in_buf_len = new_in_buf_len;  
                 }  
   
               in_buf_offs = 0;  
             }  
         }  
       return did_read;  
     }  
   
   size_t out_buf_offs = 0;      /* Position in the output buffer.  */  
   
   /* Write compress data to our output buffer.  */  
   void zwrite (const char *wbuf, size_t nwrite)  
     {  
       size_t old_buf_len = *buf_len;  
   
       if (out_buf_offs + nwrite > old_buf_len)  
         /* Have to grow the output buffer.  */  
         {  
           void *old_buf = *buf;  
           void *new_buf = old_buf + old_buf_len; /* First try.  */  
           size_t new_buf_len = round_page (old_buf_len + old_buf_len + nwrite);  
   
           /* Try to grow the buffer.  */  
           zerr =  
             vm_allocate (mach_task_self (),  
                          (vm_address_t *)&new_buf, new_buf_len - old_buf_len,  
                          0);  
           if (zerr)  
             /* Can't do that, try to make a bigger buffer elsewhere.  */  
             {  
               new_buf = mmap (0, new_buf_len, PROT_READ|PROT_WRITE,  
                               MAP_ANON, 0, 0);  
               zerr = (new_buf == (void *) -1) ? errno : 0;  
               if (zerr)  
                 longjmp (zerr_jmp_buf, 1);  
   
               if (out_buf_offs > 0)  
                 /* Copy the old buffer into the start of the new & free it. */  
                 bcopy (old_buf, new_buf, out_buf_offs);  
   
               munmap (old_buf, old_buf_len);  
   
               *buf = new_buf;  
             }  
   
           *buf_len = new_buf_len;  
         }  
   
       bcopy (wbuf, *buf + out_buf_offs, nwrite);  
       out_buf_offs += nwrite;  
     }  
   
   void zreaderr (void)  
     {  
       zerr = EIO;  
       longjmp (zerr_jmp_buf, 1);  
     }  
   void zerror (const char *msg)  
     {  
       zerr = EINVAL;  
       longjmp (zerr_jmp_buf, 2);  
     }  
   
   /* Try to guess a reasonable output buffer size.  */  
   *buf_len = round_page (from->size * 2);  
   *buf = mmap (0, *buf_len, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);  
   zerr = (*buf == (void *) -1) ? errno : 0;  
   if (zerr)  
     return zerr;  
   
   mutex_lock (&unzip_lock);  
   
   unzip_read = zread;  
   unzip_write = zwrite;  
   unzip_read_error = zreaderr;  
   unzip_error = zerror;  
   
   if (! setjmp (zerr_jmp_buf))  
     {  
       if (get_method (0) != 0)  
         /* Not a happy gzip file.  */  
         zerr = EINVAL;  
       else  
         /* Matched gzip magic number.  Ready to unzip.  
            Set up the output stream and let 'er rip.  */  
         {  
           /* Call the gunzip engine.  */  
           bytes_out = 0;  
           unzip (17, 23);       /* Arguments ignored.  */  
           zerr = 0;  
         }  
     }  
   
   mutex_unlock (&unzip_lock);  
   
   if (in_buf_len > 0)  
     munmap (in_buf, in_buf_len);  
   
   if (zerr)  
     {  
       if (*buf_len > 0)  
         munmap (*buf, *buf_len);  
     }  
   else if (out_buf_offs < *buf_len)  
     /* Trim the output buffer to be the right length.  */  
     {  
       size_t end = round_page (out_buf_offs);  
       if (end < *buf_len)  
         munmap (*buf + end, *buf_len - end);  
       *buf_len = out_buf_offs;  
     }  
   
   return zerr;  
 }  
   
 /* Return a new store in STORE which contains a snapshot of the uncompressed  
    contents of the store FROM; FROM is consumed.  */  
 error_t  
 store_gunzip_create (struct store *from, int flags, struct store **store)  
 {  
   void *buf;  
   size_t buf_len;  
   error_t err = gunzip (from, &buf, &buf_len);  
   
   if (! err)  
     {  
       err = store_buffer_create (buf, buf_len, flags, store);  
       if (err)  
         munmap (buf, buf_len);  
       else  
         store_free (from);  
     }  
   
   return err;  
 }  
   
 /* Open the gunzip NAME -- which consists of another store-class name, a ':',  
    and a name for that store class to open -- and return the corresponding  
    store in STORE.  CLASSES is used to select classes specified by the type  
    name; if it is 0, STORE_STD_CLASSES is used.  */  
 error_t  
 store_gunzip_open (const char *name, int flags,  
                    const struct store_class *const *classes,  
                    struct store **store)  
 {  
   struct store *from;  
   error_t err =  
     store_typed_open (name, flags | STORE_HARD_READONLY, classes, &from);  
   
   if (! err)  
     {  
       err = store_gunzip_create (from, flags, store);  
       if (err)  
         store_free (from);  
     }  
42    
43    return err;    if (get_method (0) != 0)
44        /* Not a happy gzip file.  */
45        return EINVAL;
46    
47      /* Matched gzip magic number.  Ready to unzip.
48         Set up the output stream and let 'er rip.  */
49      bytes_out = 0;
50      unzip (17, 23);               /* Arguments ignored.  */
51      return 0;
52  }  }
53    
54  const struct store_class  #define UNZIP           gunzip
55  store_gunzip_class = { -1, "gunzip", open: store_gunzip_open };  #include "unzipstore.c"
 STORE_STD_CLASS (gunzip);  

Legend:
Removed from v.1.5.2.1  
changed lines
  Added in v.1.5.2.2

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