Home | History | Annotate | Line # | Download | only in hpcboot
file_manager.cpp revision 1.6.6.1
      1  1.6.6.1  simonb /* -*-C++-*-	$NetBSD: file_manager.cpp,v 1.6.6.1 2006/04/22 11:37:28 simonb Exp $	*/
      2      1.1     uch 
      3      1.1     uch /*-
      4      1.4     uch  * Copyright(c) 1996, 2001, 2004 The NetBSD Foundation, Inc.
      5      1.1     uch  * All rights reserved.
      6      1.1     uch  *
      7      1.1     uch  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1     uch  * by Matthias Drochner. and UCHIYAMA Yasushi.
      9      1.1     uch  *
     10      1.1     uch  * Redistribution and use in source and binary forms, with or without
     11      1.1     uch  * modification, are permitted provided that the following conditions
     12      1.1     uch  * are met:
     13      1.1     uch  * 1. Redistributions of source code must retain the above copyright
     14      1.1     uch  *    notice, this list of conditions and the following disclaimer.
     15      1.1     uch  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1     uch  *    notice, this list of conditions and the following disclaimer in the
     17      1.1     uch  *    documentation and/or other materials provided with the distribution.
     18      1.1     uch  * 3. All advertising materials mentioning features or use of this software
     19      1.1     uch  *    must display the following acknowledgement:
     20      1.1     uch  *        This product includes software developed by the NetBSD
     21      1.1     uch  *        Foundation, Inc. and its contributors.
     22      1.1     uch  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23      1.1     uch  *    contributors may be used to endorse or promote products derived
     24      1.1     uch  *    from this software without specific prior written permission.
     25      1.1     uch  *
     26      1.1     uch  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27      1.1     uch  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28      1.1     uch  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29      1.1     uch  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30      1.1     uch  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31      1.1     uch  * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32      1.1     uch  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33      1.1     uch  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34      1.1     uch  * CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE)
     35      1.1     uch  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36      1.1     uch  * POSSIBILITY OF SUCH DAMAGE.
     37      1.1     uch  */
     38      1.1     uch 
     39      1.1     uch #include <console.h>
     40      1.1     uch #include <file.h>
     41      1.4     uch #include <limits.h>
     42      1.1     uch 
     43      1.1     uch __BEGIN_DECLS
     44      1.1     uch #include <string.h>
     45      1.1     uch #include <zlib.h>
     46      1.1     uch __END_DECLS
     47      1.1     uch 
     48      1.1     uch static struct z_stream_s __stream;	// XXX for namespace.
     49      1.1     uch 
     50      1.1     uch void
     51      1.1     uch FileManager::_reset()
     52      1.1     uch {
     53      1.1     uch 	_stream = &__stream;
     54      1.1     uch 	memset(_stream, 0, sizeof(struct z_stream_s));
     55      1.1     uch 	_z_err = 0;
     56      1.1     uch 	_z_eof = 0;
     57      1.1     uch 	_crc = 0;
     58      1.1     uch 	_compressed = 0;
     59      1.1     uch }
     60      1.1     uch 
     61      1.1     uch FileManager::~FileManager()
     62      1.1     uch {
     63      1.1     uch 	delete _file;
     64      1.1     uch }
     65      1.1     uch 
     66      1.1     uch BOOL
     67      1.1     uch FileManager::setRoot(TCHAR *drive)
     68      1.1     uch {
     69      1.1     uch 	return _file->setRoot(drive);
     70      1.1     uch }
     71      1.1     uch 
     72      1.1     uch BOOL
     73  1.6.6.1  simonb FileManager::open(const TCHAR *name, uint32_t flags)
     74      1.1     uch {
     75      1.1     uch 	if (!_file->open(name, flags))
     76      1.1     uch 		return FALSE;
     77      1.1     uch 
     78      1.1     uch 	_reset();
     79      1.4     uch 
     80      1.1     uch 	if (inflateInit2(_stream, -15) != Z_OK)
     81      1.1     uch 		goto errout;
     82      1.1     uch 	_stream->next_in = _inbuf;
     83      1.1     uch 
     84      1.1     uch 	_check_header(); // skip the .gz header
     85      1.1     uch 
     86      1.1     uch 	return TRUE;
     87      1.2     uch  errout:
     88      1.1     uch 	_file->close();
     89      1.1     uch 	return FALSE;
     90      1.1     uch }
     91      1.1     uch 
     92      1.1     uch size_t
     93      1.1     uch FileManager::read(void *buf, size_t len, off_t ofs)
     94      1.1     uch {
     95      1.1     uch 	if (ofs != -1)
     96      1.1     uch 		seek(ofs);
     97      1.1     uch 
     98      1.1     uch 	return _read(buf, len);
     99      1.1     uch }
    100      1.1     uch 
    101      1.1     uch size_t
    102      1.1     uch FileManager::_read(void *buf, size_t len)
    103      1.1     uch {
    104      1.5     uch 	// starting point for crc computation
    105  1.6.6.1  simonb 	uint8_t *start = reinterpret_cast<uint8_t *>(buf);
    106      1.1     uch 
    107      1.1     uch 	if (_z_err == Z_DATA_ERROR || _z_err == Z_ERRNO) {
    108      1.1     uch 		return -1;
    109      1.1     uch 	}
    110      1.1     uch 	if (_z_err == Z_STREAM_END) {
    111      1.1     uch 		return 0;  // EOF
    112      1.1     uch 	}
    113  1.6.6.1  simonb 	_stream->next_out = reinterpret_cast<uint8_t *>(buf);
    114      1.1     uch 	_stream->avail_out = len;
    115      1.1     uch 
    116      1.1     uch 	int got;
    117      1.1     uch 	while (_stream->avail_out != 0) {
    118      1.1     uch 		if (!_compressed) {
    119      1.1     uch 			// Copy first the lookahead bytes
    120  1.6.6.1  simonb 			uint32_t n = _stream->avail_in;
    121      1.1     uch 			if (n > _stream->avail_out)
    122      1.1     uch 				n = _stream->avail_out;
    123      1.1     uch 			if (n > 0) {
    124      1.1     uch 				memcpy(_stream->next_out, _stream->next_in, n);
    125      1.1     uch 				_stream->next_out  += n;
    126      1.1     uch 				_stream->next_in   += n;
    127      1.1     uch 				_stream->avail_out -= n;
    128      1.1     uch 				_stream->avail_in  -= n;
    129      1.1     uch 			}
    130      1.1     uch 			if (_stream->avail_out > 0) {
    131      1.1     uch 				got = _file->read(_stream->next_out,
    132      1.2     uch 				    _stream->avail_out);
    133      1.1     uch 				if (got == -1) {
    134      1.1     uch 					return(got);
    135      1.1     uch 				}
    136      1.1     uch 				_stream->avail_out -= got;
    137      1.1     uch 			}
    138      1.1     uch 			return(int)(len - _stream->avail_out);
    139      1.1     uch 		}
    140      1.1     uch 
    141      1.1     uch 		if (_stream->avail_in == 0 && !_z_eof) {
    142      1.1     uch 			got = _file->read(_inbuf, Z_BUFSIZE);
    143      1.1     uch 			if (got <= 0)
    144      1.1     uch 				_z_eof = 1;
    145      1.1     uch 
    146      1.1     uch 			_stream->avail_in = got;
    147      1.1     uch 			_stream->next_in = _inbuf;
    148      1.1     uch 		}
    149      1.1     uch 
    150      1.1     uch 		_z_err = inflate(_stream, Z_NO_FLUSH);
    151      1.5     uch 
    152      1.1     uch 		if (_z_err == Z_STREAM_END) {
    153      1.1     uch 			/* Check CRC and original size */
    154      1.1     uch 			_crc = crc32(_crc, start,(unsigned int)
    155      1.2     uch 			    (_stream->next_out - start));
    156      1.1     uch 			start = _stream->next_out;
    157      1.1     uch 
    158      1.1     uch 			if (_get_long() != _crc ||
    159      1.1     uch 			    _get_long() != _stream->total_out) {
    160      1.1     uch 				_z_err = Z_DATA_ERROR;
    161      1.1     uch 			} else {
    162      1.1     uch 				/* Check for concatenated .gz files: */
    163      1.1     uch 				_check_header();
    164      1.1     uch 				if (_z_err == Z_OK) {
    165      1.1     uch 					inflateReset(_stream);
    166      1.1     uch 					_crc = crc32(0L, Z_NULL, 0);
    167      1.1     uch 				}
    168      1.1     uch 			}
    169      1.1     uch 		}
    170      1.1     uch 		if (_z_err != Z_OK || _z_eof)
    171      1.1     uch 			break;
    172      1.1     uch 	}
    173      1.1     uch 
    174      1.1     uch 	_crc = crc32(_crc, start,(unsigned int)(_stream->next_out - start));
    175      1.1     uch 
    176      1.1     uch 	return(int)(len - _stream->avail_out);
    177      1.1     uch }
    178      1.1     uch 
    179      1.1     uch size_t
    180      1.1     uch FileManager::write(const void *buf, size_t bytes, off_t ofs)
    181      1.1     uch {
    182      1.1     uch 	return _file->write(buf, bytes, ofs);
    183      1.1     uch }
    184      1.1     uch 
    185      1.1     uch size_t
    186      1.1     uch FileManager::size()
    187      1.1     uch {
    188      1.1     uch 	return _file->size();
    189      1.1     uch }
    190      1.1     uch 
    191      1.1     uch BOOL
    192      1.1     uch FileManager::close()
    193      1.1     uch {
    194      1.1     uch 	inflateEnd(_stream);
    195      1.1     uch 
    196      1.1     uch 	return _file->close();
    197      1.1     uch }
    198      1.1     uch 
    199      1.3     uwe size_t
    200      1.3     uwe FileManager::_skip_compressed(off_t toskip)
    201      1.3     uwe {
    202      1.5     uch #define	DUMMYBUFSIZE 256
    203      1.3     uwe 	char dummybuf[DUMMYBUFSIZE];
    204      1.3     uwe 
    205      1.3     uwe 	size_t skipped = 0;
    206      1.3     uwe 
    207      1.3     uwe 	while (toskip > 0) {
    208      1.3     uwe 		size_t toread = toskip;
    209      1.3     uwe 		if (toread > DUMMYBUFSIZE)
    210      1.3     uwe 			toread = DUMMYBUFSIZE;
    211      1.3     uwe 
    212      1.3     uwe 		size_t nread = _read(dummybuf, toread);
    213      1.3     uwe 		if ((int)nread < 0)
    214      1.3     uwe 			return nread;
    215      1.3     uwe 
    216      1.3     uwe 		toskip  -= nread;
    217      1.3     uwe 		skipped += nread;
    218      1.3     uwe 
    219      1.3     uwe 		if (nread != toread)
    220      1.3     uwe 			break;
    221      1.3     uwe 	}
    222      1.3     uwe 
    223      1.3     uwe 	return skipped;
    224      1.3     uwe }
    225      1.3     uwe 
    226      1.3     uwe size_t
    227      1.3     uwe FileManager::realsize()
    228      1.3     uwe {
    229      1.3     uwe 	if (!_compressed)
    230      1.3     uwe 		return size();
    231      1.3     uwe 
    232      1.3     uwe 	off_t pos = _stream->total_out;
    233      1.3     uwe 	size_t sz = _skip_compressed(INT_MAX);
    234      1.3     uwe 	seek(pos);
    235      1.3     uwe 
    236      1.3     uwe 	return sz;
    237      1.3     uwe }
    238      1.3     uwe 
    239      1.1     uch BOOL
    240      1.1     uch FileManager::seek(off_t offset)
    241      1.1     uch {
    242      1.5     uch 
    243      1.1     uch 	if (!_compressed) {
    244      1.1     uch 		_file->seek(offset);
    245      1.1     uch 		_stream->avail_in = 0;
    246      1.1     uch 
    247      1.1     uch 		return TRUE;
    248      1.1     uch 	}
    249      1.1     uch 	/* if seek backwards, simply start from the beginning */
    250      1.1     uch 	if (offset < _stream->total_out) {
    251      1.1     uch 		_file->seek(0);
    252      1.1     uch 
    253      1.1     uch 		inflateEnd(_stream);
    254      1.1     uch 		_reset(); /* this resets total_out to 0! */
    255      1.1     uch 		inflateInit2(_stream, -15);
    256      1.1     uch 		_stream->next_in = _inbuf;
    257      1.1     uch 
    258      1.1     uch 		_check_header(); /* skip the .gz header */
    259      1.1     uch 	}
    260      1.1     uch 
    261      1.1     uch 	/* to seek forwards, throw away data */
    262      1.1     uch 	if (offset > _stream->total_out) {
    263      1.1     uch 		off_t toskip = offset - _stream->total_out;
    264      1.3     uwe 		size_t skipped = _skip_compressed(toskip);
    265      1.1     uch 
    266      1.3     uwe 		if (skipped != toskip)
    267      1.3     uwe 			return FALSE;
    268      1.1     uch 	}
    269      1.1     uch 
    270      1.1     uch 	return TRUE;
    271      1.1     uch }
    272      1.1     uch 
    273      1.1     uch //
    274      1.1     uch // GZIP util.
    275      1.1     uch //
    276      1.1     uch int
    277      1.1     uch FileManager::_get_byte()
    278      1.1     uch {
    279      1.5     uch 
    280      1.1     uch 	if (_z_eof)
    281      1.1     uch 		return(EOF);
    282      1.1     uch 
    283      1.1     uch 	if (_stream->avail_in == 0) {
    284      1.1     uch 		int got;
    285      1.1     uch 
    286      1.1     uch 		got = _file->read(_inbuf, Z_BUFSIZE);
    287      1.1     uch 		if (got <= 0) {
    288      1.1     uch 			_z_eof = 1;
    289      1.1     uch 			return EOF;
    290      1.1     uch 		}
    291      1.1     uch 		_stream->avail_in = got;
    292      1.1     uch 		_stream->next_in = _inbuf;
    293      1.1     uch 	}
    294      1.1     uch 	_stream->avail_in--;
    295      1.1     uch 	return *(_stream->next_in)++;
    296      1.1     uch }
    297      1.1     uch 
    298  1.6.6.1  simonb uint32_t
    299      1.1     uch FileManager::_get_long()
    300      1.1     uch {
    301  1.6.6.1  simonb 	uint32_t x = static_cast<uint32_t>(_get_byte());
    302      1.1     uch 	int c;
    303      1.1     uch 
    304  1.6.6.1  simonb 	x +=(static_cast<uint32_t>(_get_byte())) << 8;
    305  1.6.6.1  simonb 	x +=(static_cast<uint32_t>(_get_byte())) << 16;
    306      1.1     uch 	c = _get_byte();
    307      1.1     uch 	if (c == EOF)
    308      1.1     uch 		_z_err = Z_DATA_ERROR;
    309  1.6.6.1  simonb 	x +=(static_cast<uint32_t>(c)) << 24;
    310      1.1     uch 
    311      1.1     uch 	return x;
    312      1.1     uch }
    313      1.1     uch 
    314      1.1     uch void
    315      1.1     uch FileManager::_check_header()
    316      1.1     uch {
    317      1.1     uch 	int method; /* method byte */
    318      1.1     uch 	int flags;  /* flags byte */
    319      1.1     uch 	unsigned int len;
    320      1.1     uch 	int c;
    321      1.1     uch 
    322      1.1     uch 	/* Check the gzip magic header */
    323      1.1     uch 	for (len = 0; len < 2; len++) {
    324      1.1     uch 		c = _get_byte();
    325      1.1     uch 		if (c == _gz_magic[len])
    326      1.1     uch 			continue;
    327      1.1     uch 		if ((c == EOF) &&(len == 0))  {
    328      1.1     uch 			/*
    329      1.1     uch 			 * We must not change _compressed if we are at EOF;
    330      1.1     uch 			 * we may have come to the end of a gzipped file and be
    331      1.1     uch 			 * check to see if another gzipped file is concatenated
    332      1.1     uch 			 * to this one. If one isn't, we still need to be able
    333      1.1     uch 			 * to lseek on this file as a compressed file.
    334      1.1     uch 			 */
    335      1.1     uch 			return;
    336      1.1     uch 		}
    337      1.1     uch 		_compressed = 0;
    338      1.1     uch 		if (c != EOF) {
    339      1.1     uch 			_stream->avail_in++;
    340      1.1     uch 			_stream->next_in--;
    341      1.1     uch 		}
    342      1.1     uch 		_z_err = _stream->avail_in != 0 ? Z_OK : Z_STREAM_END;
    343      1.1     uch 		return;
    344      1.1     uch 	}
    345      1.1     uch 	_compressed = 1;
    346      1.1     uch 	method = _get_byte();
    347      1.1     uch 	flags = _get_byte();
    348      1.1     uch 	if (method != Z_DEFLATED ||(flags & RESERVED) != 0) {
    349      1.1     uch 		_z_err = Z_DATA_ERROR;
    350      1.1     uch 		return;
    351      1.1     uch 	}
    352      1.1     uch 
    353      1.1     uch 	/* Discard time, xflags and OS code: */
    354      1.1     uch 	for (len = 0; len < 6; len++)
    355      1.1     uch 		(void)_get_byte();
    356      1.1     uch 
    357      1.1     uch 	if ((flags & EXTRA_FIELD) != 0) {
    358      1.1     uch 		/* skip the extra field */
    359      1.1     uch 		len  = (unsigned int)_get_byte();
    360      1.1     uch 		len +=((unsigned int)_get_byte()) << 8;
    361      1.1     uch 		/* len is garbage if EOF but the loop below will quit anyway */
    362      1.1     uch 		while (len-- != 0 && _get_byte() != EOF) /*void*/;
    363      1.1     uch 	}
    364      1.1     uch 	if ((flags & ORIG_NAME) != 0) {
    365      1.1     uch 		/* skip the original file name */
    366      1.1     uch 		while ((c = _get_byte()) != 0 && c != EOF) /*void*/;
    367      1.1     uch 	}
    368      1.1     uch 	if ((flags & COMMENT) != 0) {
    369      1.1     uch 		/* skip the .gz file comment */
    370      1.1     uch 		while ((c = _get_byte()) != 0 && c != EOF) /*void*/;
    371      1.1     uch 	}
    372      1.1     uch 	if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
    373      1.1     uch 		for (len = 0; len < 2; len++)
    374      1.1     uch 			(void)_get_byte();
    375      1.1     uch 	}
    376      1.1     uch 	_z_err = _z_eof ? Z_DATA_ERROR : Z_OK;
    377      1.1     uch }
    378