- Use temp streams internally instead of memory to reduce memory usage

# Internally we try to use only one temp stream if possible by stoing
# the temp stream in the manifest entry and transferring ownership upon
# usage/close. If a particular file gets opened twice in parallel we open
# a second temp stream nonetheless.
This commit is contained in:
Marcus Boerger 2006-01-05 22:24:41 +00:00
parent 71af00ec47
commit abd2aeb1cd
2 changed files with 75 additions and 114 deletions

View File

@ -51,7 +51,7 @@ typedef struct _phar_manifest_entry {
php_uint32 offset_within_phar;
php_uint32 compressed_filesize;
zend_bool crc_checked;
char *filedata;
php_stream *fp;
} phar_manifest_entry;
/* information about a phar file */
@ -68,8 +68,8 @@ typedef struct _phar_file_data {
/* stream access data for one file entry in a phar file */
typedef struct _phar_internal_file_data {
phar_file_data *phar;
long pointer; /* relative position within file data */
phar_file_data *phar;
php_stream *fp;
phar_manifest_entry *internal_file;
} phar_internal_file_data;
@ -108,9 +108,6 @@ static void destroy_phar_manifest(void *pDest) /* {{{ */
{
phar_manifest_entry *entry = (phar_manifest_entry *)pDest;
if (entry->filedata) {
efree(entry->filedata);
}
efree(entry->filename);
}
/* }}} */
@ -127,7 +124,13 @@ static phar_internal_file_data *phar_get_filedata(char *alias, char *path TSRMLS
ret = (phar_internal_file_data *) emalloc(sizeof(phar_internal_file_data));
ret->phar = phar;
ret->internal_file = internal_file;
ret->pointer = 0;
if (internal_file->fp) {
/* transfer ownership */
ret->fp = internal_file->fp;
internal_file->fp = 0;
} else {
ret->fp = 0;
}
}
}
return ret;
@ -172,7 +175,7 @@ PHP_METHOD(Phar, canCompress)
buffer += 4
#else
# define PHAR_GET_VAL(buffer, var) \
var = *(unsigned int*)(buffer); \
var = *(php_uint32*)(buffer); \
buffer += 4
#endif
@ -264,11 +267,11 @@ static int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alia
PHAR_GET_VAL(buffer, entry.timestamp);
PHAR_GET_VAL(buffer, entry.offset_within_phar);
PHAR_GET_VAL(buffer, entry.compressed_filesize);
/* if (entry.uncompressed_filesize != entry.compressed_filesize) {
if (entry.uncompressed_filesize + 8 != entry.compressed_filesize) {
compressed = 1;
}*/
}
entry.crc_checked = 0;
entry.filedata = NULL;
entry.fp = NULL;
if (entry.compressed_filesize < 9) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (file size in phar is not large enough)")
}
@ -519,26 +522,24 @@ php_stream_wrapper php_stream_phar_wrapper = {
0 /* is_url */
};
static int phar_postprocess_file(char *buffer, php_uint32 nr, unsigned long crc32, zend_bool read) /* {{{ */
static int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_internal_file_data *idata, unsigned long crc32 TSRMLS_DC) /* {{{ */
{
unsigned int crc = ~0;
php_uint32 actual_length;
int len = 0;
int len = idata->internal_file->uncompressed_filesize;
char c;
if (read) {
PHAR_GET_VAL(buffer, crc32);
PHAR_GET_VAL(buffer, actual_length);
if (actual_length != nr) {
return -2;
}
}
for (len += nr; nr--; ++buffer) {
CRC32(crc, *buffer);
php_stream_seek(idata->fp, 0, SEEK_SET);
while (len--) {
php_stream_read(idata->fp, &c, 1);
CRC32(crc, c);
}
php_stream_seek(idata->fp, 0, SEEK_SET);
if (~crc == crc32) {
return 0;
return SUCCESS;
} else {
return -1;
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->filename, idata->internal_file->filename);
return FAILURE;
}
}
/* }}} */
@ -550,6 +551,7 @@ static php_stream * php_stream_phar_url_wrapper(php_stream_wrapper *wrapper, cha
char *internal_file;
char *buffer;
char *filedata;
char tmpbuf[8];
php_url *resource = NULL;
php_stream *fp;
int status;
@ -597,16 +599,16 @@ static php_stream * php_stream_phar_url_wrapper(php_stream_wrapper *wrapper, cha
}
#if MBO_0
fprintf(stderr, "Pharname: %s\n", idata->phar->filename);
fprintf(stderr, "Filename: %s\n", internal_file);
fprintf(stderr, "Entry: %s\n", idata->internal_file->filename);
fprintf(stderr, "Pharname: %s\n", idata->phar->filename);
fprintf(stderr, "Filename: %s\n", internal_file);
fprintf(stderr, "Entry: %s\n", idata->internal_file->filename);
fprintf(stderr, "Size: %u\n", idata->internal_file->uncompressed_filesize);
fprintf(stderr, "Offset: %u\n", idata->internal_file->offset_within_phar);
fprintf(stderr, "Cached: %s\n", idata->internal_file->filedata ? "yes" : "no");
fprintf(stderr, "Cached: %s\n", idata->internal_file->filedata ? "yes" : "no");
#endif
/* do we have the data already? */
if (idata->internal_file->filedata) {
if (idata->fp) {
stream = php_stream_alloc(&phar_ops, idata, NULL, mode);
efree(internal_file);
return stream;
@ -670,7 +672,6 @@ static php_stream * php_stream_phar_url_wrapper(php_stream_wrapper *wrapper, cha
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (corrupted zlib compression of file \"%s\")", idata->phar->filename, internal_file);
efree(s1);
efree(savebuf);
efree(filedata);
efree(idata);
efree(internal_file);
return NULL;
@ -717,63 +718,52 @@ static php_stream * php_stream_phar_url_wrapper(php_stream_wrapper *wrapper, cha
efree(idata);
return NULL;
}
/* need to copy filedata to stream now */
idata->fp = php_stream_temp_open(0, PHP_STREAM_MAX_MEM, filedata, actual_length);
efree(filedata);
/* check crc32/filesize */
if (!idata->internal_file->crc_checked) {
status = phar_postprocess_file(filedata, idata->internal_file->uncompressed_filesize, crc32, 0);
if (-1 == status) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->filename, internal_file);
efree(filedata);
efree(idata);
efree(internal_file);
return NULL;
}
if (-2 == status) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (filesize mismatch on file \"%s\")", idata->phar->filename, internal_file);
efree(filedata);
efree(idata);
efree(internal_file);
return NULL;
}
idata->internal_file->crc_checked = 1;
if (!idata->internal_file->crc_checked
&& phar_postprocess_file(wrapper, options, idata, crc32 TSRMLS_CC) != SUCCESS) {
efree(idata);
efree(internal_file);
}
idata->internal_file->crc_checked = 1;
#else
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "zlib extension must be enabled for compressed .phar files");
efree(internal_file);
return NULL;
#endif
} else { /* from here is for non-compressed */
filedata = (char *) emalloc(idata->internal_file->compressed_filesize);
if (idata->internal_file->compressed_filesize !=
php_stream_read(fp, filedata, idata->internal_file->compressed_filesize)) {
buffer = &tmpbuf[0];
php_stream_read(fp, buffer, 8);
PHAR_GET_VAL(buffer, crc32);
PHAR_GET_VAL(buffer, actual_length);
if (actual_length != idata->internal_file->uncompressed_filesize) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", idata->phar->filename, internal_file);
efree(filedata);
efree(idata);
efree(internal_file);
return NULL;
}
/* bypass to temp stream */
idata->fp = php_stream_temp_new();
if (php_stream_copy_to_stream(fp, idata->fp, actual_length) != actual_length) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", idata->phar->filename, internal_file);
php_stream_close(idata->fp);
efree(idata);
efree(internal_file);
return NULL;
}
/* check length, crc32 */
if (!idata->internal_file->crc_checked) {
status = phar_postprocess_file(filedata, idata->internal_file->uncompressed_filesize, 0, 1);
if (-1 == status) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->filename, internal_file);
efree(filedata);
efree(idata);
efree(internal_file);
return NULL;
}
if (-2 == status) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (filesize mismatch on file \"%s\")", idata->phar->filename, internal_file);
efree(filedata);
efree(idata);
efree(internal_file);
return NULL;
}
idata->internal_file->crc_checked = 1;
if (!idata->internal_file->crc_checked
&& phar_postprocess_file(wrapper, options, idata, crc32 TSRMLS_CC) != SUCCESS) {
php_stream_close(idata->fp);
efree(idata);
efree(internal_file);
return NULL;
}
memmove(filedata, filedata + 8, idata->internal_file->uncompressed_filesize);
idata->internal_file->crc_checked = 1;
}
idata->internal_file->filedata = filedata;
stream = php_stream_alloc(&phar_ops, idata, NULL, mode);
efree(internal_file);
return stream;
@ -784,6 +774,14 @@ static int phar_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
{
phar_internal_file_data *data = (phar_internal_file_data *)stream->abstract;
if (data->fp) {
if (data->internal_file->fp) {
php_stream_close(data->fp);
} else {
data->internal_file->fp = data->fp;
}
}
efree(data);
return 0;
}
@ -834,20 +832,9 @@ static int phar_seekdir(php_stream *stream, off_t offset, int whence, off_t *new
static size_t phar_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
{
size_t to_read;
phar_internal_file_data *data = (phar_internal_file_data *)stream->abstract;
to_read = MIN(data->internal_file->uncompressed_filesize - data->pointer, count);
if (to_read == 0) {
if (count != 0) {
stream->eof = 1;
}
return 0;
}
memcpy(buf, data->internal_file->filedata + data->pointer, to_read);
data->pointer += to_read;
return to_read;
return php_stream_read(data->fp, buf, count);
}
/* }}} */
@ -881,36 +868,10 @@ static size_t phar_readdir(php_stream *stream, char *buf, size_t count TSRMLS_DC
static int phar_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
{
phar_internal_file_data *data = (phar_internal_file_data *)stream->abstract;
switch (whence) {
case SEEK_SET :
if (offset < 0 || offset > data->internal_file->uncompressed_filesize) {
*newoffset = (off_t) - 1;
return -1;
}
data->pointer = offset;
*newoffset = offset;
return 0;
case SEEK_CUR :
if (data->pointer + offset < 0 || data->pointer + offset
> data->internal_file->uncompressed_filesize) {
*newoffset = (off_t) - 1;
return -1;
}
data->pointer += offset;
*newoffset = data->pointer;
return 0;
case SEEK_END :
if (offset > 0 || -1 * offset > data->internal_file->uncompressed_filesize) {
*newoffset = (off_t) - 1;
return -1;
}
data->pointer = data->internal_file->uncompressed_filesize + offset;
*newoffset = data->pointer;
return 0;
default :
*newoffset = (off_t) - 1;
return -1;
}
int res = php_stream_seek(data->fp, offset, whence);
*newoffset = php_stream_tell(data->fp);
return res;
}
/* }}} */

View File

@ -17,4 +17,4 @@ echo file_get_contents('phar://hio/a');
--CLEAN--
<?php unlink(dirname(__FILE__) . '/' . basename(__FILE__, '.clean.php') . '.phar.php'); ?>
--EXPECTF--
Warning: file_get_contents(phar://hio/a): failed to open stream: phar error: internal corruption of phar "%s" (filesize mismatch on file "a") in %s on line %d
Warning: file_get_contents(phar://hio/a): failed to open stream: phar error: internal corruption of phar "%s" (actual filesize mismatch on file "a") in %s on line %d