Example #1
0
// make buffer with 32/64 bit Data Descriptor chunk, this follows files with incomplete headers
ngx_chain_t*
ngx_http_zip_data_descriptor_chain_link(ngx_http_request_t *r, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *range)
{
    ngx_chain_t *link;
    ngx_buf_t   *b;
    ngx_http_zip_file_t *file = piece->file;
    size_t struct_size = file->need_zip64? sizeof(ngx_zip_data_descriptor_zip64_t) : sizeof(ngx_zip_data_descriptor_t);
    union {
        ngx_zip_data_descriptor_t  descriptor;
        ngx_zip_data_descriptor_zip64_t  descriptor64;
    } data;

    if ((link = ngx_alloc_chain_link(r->pool)) == NULL || (b = ngx_calloc_buf(r->pool)) == NULL
            || (b->pos = ngx_palloc(r->pool, struct_size)) == NULL)
        return NULL;
    b->memory = 1;
    b->last = b->pos + struct_size;

    if (!file->need_zip64) {
        data.descriptor = ngx_zip_data_descriptor_template;
        data.descriptor.signature = htole32(data.descriptor.signature);
        data.descriptor.crc32 = htole32(file->crc32);
        data.descriptor.compressed_size = data.descriptor.uncompressed_size = htole32(file->size);
    } else {
        data.descriptor64 = ngx_zip_data_descriptor_zip64_template;
        data.descriptor64.signature = htole32(data.descriptor64.signature);
        data.descriptor64.crc32 = htole32(file->crc32);
        data.descriptor64.compressed_size = data.descriptor64.uncompressed_size = htole64(file->size);
    }

    ngx_memcpy(b->pos, &data, struct_size);
    ngx_http_zip_truncate_buffer(b, &piece->range, range);

    link->buf = b;
    link->next = NULL;

    return link;
}
Example #2
0
//make archive footer: Central Directory, Zip64 Central Directory End, Zip64 locator and Central Directory end chunks
ngx_chain_t *
ngx_http_zip_central_directory_chain_link(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx, ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *range)
{
    //nb: this is to be called only after 'generate pieces'
    ngx_chain_t           *trailer;
    ngx_buf_t             *trailer_buf;
    u_char                *p;
    off_t                  cd_size;
    ngx_uint_t             i;
    ngx_array_t           *files;
    ngx_zip_end_of_central_directory_record_t  eocdr;
    ngx_zip_zip64_end_of_central_directory_record_t eocdr64;
    ngx_zip_zip64_end_of_central_directory_locator_t locator64;

    if (!ctx || !ctx->cd_size || (trailer = ngx_alloc_chain_link(r->pool)) == NULL
            || (trailer_buf = ngx_calloc_buf(r->pool)) == NULL
            || (p = ngx_palloc(r->pool, ctx->cd_size)) == NULL)
        return NULL;

    files = &ctx->files;
    trailer->buf = trailer_buf;
    trailer->next = NULL;

    trailer_buf->pos = p;
    trailer_buf->last = p + ctx->cd_size;
    trailer_buf->last_buf = 1;
    trailer_buf->sync = 1;
    trailer_buf->memory = 1;

    for (i = 0; i < files->nelts; i++)
        p = ngx_http_zip_write_central_directory_entry(p, &((ngx_http_zip_file_t *)files->elts)[i], ctx);

    eocdr = ngx_zip_end_of_central_directory_record_template;
    eocdr.signature = htole32(eocdr.signature);
    if (files->nelts < NGX_MAX_UINT16_VALUE) {
        eocdr.disk_entries_n = htole16(files->nelts);
        eocdr.entries_n = htole16(files->nelts);
    }

    cd_size = ctx->cd_size - sizeof(ngx_zip_end_of_central_directory_record_t)
        - (!!ctx->zip64_used)*(sizeof(ngx_zip_zip64_end_of_central_directory_record_t)
                + sizeof(ngx_zip_zip64_end_of_central_directory_locator_t));

    if (cd_size < (off_t) NGX_MAX_UINT32_VALUE)
        eocdr.size = htole32(cd_size);
    if (piece->range.start < (off_t) NGX_MAX_UINT32_VALUE)
        eocdr.offset = htole32(piece->range.start);

    if (ctx->zip64_used) {
        eocdr64 = ngx_zip_zip64_end_of_central_directory_record_template;
        eocdr64.signature = htole32(eocdr64.signature);
        eocdr64.size = htole64(eocdr64.size);
        eocdr64.version_made_by = htole16(eocdr64.version_made_by);
        eocdr64.version_needed = htole16(eocdr64.version_made_by);

        eocdr64.cd_n_entries_on_this_disk = eocdr64.cd_n_entries_total = htole64(files->nelts);
        eocdr64.cd_size = htole64(cd_size);
        eocdr64.cd_offset = htole64(piece->range.start);

        ngx_memcpy(p, &eocdr64, sizeof(ngx_zip_zip64_end_of_central_directory_record_t));
        p += sizeof(ngx_zip_zip64_end_of_central_directory_record_t);

        locator64 = ngx_zip_zip64_end_of_central_directory_locator_template;
        locator64.signature = htole32(locator64.signature);
        locator64.disks_total_n = htole32(locator64.disks_total_n);
        locator64.cd_relative_offset = htole64(piece->range.start + cd_size);
        ngx_memcpy(p, &locator64, sizeof(ngx_zip_zip64_end_of_central_directory_locator_t));
        p += sizeof(ngx_zip_zip64_end_of_central_directory_locator_t);
    }

    ngx_memcpy(p, &eocdr, sizeof(ngx_zip_end_of_central_directory_record_t));

    ngx_http_zip_truncate_buffer(trailer->buf, &piece->range, range);
    return trailer;
}
Example #3
0
// make Local File Header chunk with extra fields
ngx_chain_t*
ngx_http_zip_file_header_chain_link(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx,
        ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *range)
{
    ngx_chain_t *link;
    ngx_buf_t   *b;

    ngx_http_zip_file_t *file = piece->file;
    ngx_zip_extra_field_local_t   extra_field_local;
    ngx_zip_extra_field_zip64_sizes_only_t extra_field_zip64;
    ngx_zip_local_file_header_t   local_file_header;
    ngx_zip_extra_field_unicode_path_t extra_field_unicode_path;

    size_t len = sizeof(ngx_zip_local_file_header_t) + file->filename.len
        + sizeof(ngx_zip_extra_field_local_t) + (file->need_zip64? sizeof(ngx_zip_extra_field_zip64_sizes_only_t):0
        + (ctx->unicode_path && file->filename_utf8.len ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0));

    if ((link = ngx_alloc_chain_link(r->pool)) == NULL || (b = ngx_calloc_buf(r->pool)) == NULL
            || (b->pos = ngx_pcalloc(r->pool, len)) == NULL)
        return NULL;

    b->memory = 1;
    b->last = b->pos + len;

    /* A note about the ZIP format: in order to appease all ZIP software I
     * could find, the local file header contains the file sizes but not the
     * CRC-32, even though setting the third bit of the general purpose bit
     * flag would indicate that all three fields should be zeroed out.
     */

    local_file_header = ngx_zip_local_file_header_template;
    local_file_header.signature = htole32(local_file_header.signature);
    local_file_header.version = htole16(local_file_header.version);
    local_file_header.flags = htole16(local_file_header.flags);
    local_file_header.mtime = htole32(file->dos_time);
    local_file_header.filename_len = htole16(file->filename.len);
    if (ctx->native_charset) {
        local_file_header.flags &= htole16(~zip_utf8_flag);
    }
    extra_field_zip64 = ngx_zip_extra_field_zip64_sizes_only_template;
    extra_field_zip64.tag = htole16(extra_field_zip64.tag);
    extra_field_zip64.size = htole16(extra_field_zip64.size);

    if (file->need_zip64) {
        local_file_header.version = htole16(zip_version_zip64);
        local_file_header.extra_field_len = sizeof(ngx_zip_extra_field_zip64_sizes_only_t) + sizeof(ngx_zip_extra_field_local_t);
        extra_field_zip64.uncompressed_size = extra_field_zip64.compressed_size = htole64(file->size);
    } else {
        local_file_header.compressed_size = htole32(file->size);
        local_file_header.uncompressed_size = htole32(file->size);
    }

    extra_field_unicode_path = ngx_zip_extra_field_unicode_path_template;
    extra_field_unicode_path.tag = htole16(extra_field_unicode_path.tag);

    if (ctx->unicode_path && file->filename_utf8.len) {
        extra_field_unicode_path.crc32 = htole32(file->filename_utf8_crc32);
        extra_field_unicode_path.size = htole16(sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len);

        local_file_header.extra_field_len += sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len;
    }
    local_file_header.extra_field_len = htole16(local_file_header.extra_field_len);

    if (!file->missing_crc32) {
        local_file_header.flags &= htole16(~zip_missing_crc32_flag);
        local_file_header.crc32 = htole32(file->crc32);
    }

    extra_field_local = ngx_zip_extra_field_local_template;
    extra_field_local.tag = htole16(extra_field_local.tag);
    extra_field_local.size = htole16(extra_field_local.size);
    extra_field_local.mtime = htole32(file->unix_time);
    extra_field_local.atime = htole32(file->unix_time);

    ngx_memcpy(b->pos, &local_file_header, sizeof(ngx_zip_local_file_header_t));
    ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t), file->filename.data, file->filename.len);
    ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len,
            &extra_field_local, sizeof(ngx_zip_extra_field_local_t));
    if (file->need_zip64) {
        ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t),
                &extra_field_zip64, sizeof(ngx_zip_extra_field_zip64_sizes_only_t));

        if (ctx->unicode_path && file->filename_utf8.len) {
            ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + sizeof(ngx_zip_extra_field_zip64_sizes_only_t), &extra_field_unicode_path, sizeof(ngx_zip_extra_field_unicode_path_t));
            ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + sizeof(ngx_zip_extra_field_zip64_sizes_only_t) + sizeof(ngx_zip_extra_field_unicode_path_t), file->filename_utf8.data, file->filename_utf8.len);
        }
    } else if (ctx->unicode_path && file->filename_utf8.len) {
        ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t), &extra_field_unicode_path, sizeof(ngx_zip_extra_field_unicode_path_t));
        ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + sizeof(ngx_zip_extra_field_unicode_path_t), file->filename_utf8.data, file->filename_utf8.len);
    }

    ngx_http_zip_truncate_buffer(b, &piece->range, range);

    link->buf = b;
    link->next = NULL;

    return link;
}
Example #4
0
// make Local File Header chunk with extra fields
ngx_chain_t*
ngx_http_zip_file_header_chain_link(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx,
        ngx_http_zip_piece_t *piece, ngx_http_zip_range_t *range)
{
    ngx_chain_t *link;
    ngx_buf_t   *b;
   
    ngx_http_zip_file_t *file = piece->file;
    ngx_zip_extra_field_local_t   extra_field_local;
    ngx_zip_extra_field_zip64_sizes_only_t extra_field_zip64;
    ngx_zip_local_file_header_t   local_file_header;

    size_t len = sizeof(ngx_zip_local_file_header_t) + file->filename.len 
        + sizeof(ngx_zip_extra_field_local_t) + (file->need_zip64? sizeof(ngx_zip_extra_field_zip64_sizes_only_t):0);

    if ((link = ngx_alloc_chain_link(r->pool)) == NULL || (b = ngx_calloc_buf(r->pool)) == NULL 
            || (b->pos = ngx_pcalloc(r->pool, len)) == NULL)
        return NULL;
    
    b->memory = 1;
    b->last = b->pos + len;

    file->unix_time = time(NULL);
    file->dos_time = ngx_dos_time(file->unix_time);

    /* A note about the ZIP format: in order to appease all ZIP software I
     * could find, the local file header contains the file sizes but not the
     * CRC-32, even though setting the third bit of the general purpose bit
     * flag would indicate that all three fields should be zeroed out.
     */

    local_file_header = ngx_zip_local_file_header_template;
    local_file_header.mtime = file->dos_time;
    local_file_header.filename_len = file->filename.len;
    if (file->need_zip64) {
        local_file_header.version = zip_version_zip64;
        local_file_header.extra_field_len = sizeof(ngx_zip_extra_field_zip64_sizes_only_t) + sizeof(ngx_zip_extra_field_local_t);
        extra_field_zip64 = ngx_zip_extra_field_zip64_sizes_only_template;
        extra_field_zip64.uncompressed_size = extra_field_zip64.compressed_size = file->size;
    } else {
        local_file_header.compressed_size = file->size;
        local_file_header.uncompressed_size = file->size;
    }

    if (!file->missing_crc32) {
        local_file_header.flags &= ~zip_missing_crc32_flag;
        local_file_header.crc32 = file->crc32;
    }

    extra_field_local = ngx_zip_extra_field_local_template;
    extra_field_local.mtime = file->unix_time;
    extra_field_local.atime = file->unix_time;

    ngx_memcpy(b->pos, &local_file_header, sizeof(ngx_zip_local_file_header_t));
    ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t), file->filename.data, file->filename.len);
    ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len, 
            &extra_field_local, sizeof(ngx_zip_extra_field_local_t));
    if (file->need_zip64)
        ngx_memcpy(b->pos + sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t), 
                &extra_field_zip64, sizeof(ngx_zip_extra_field_zip64_sizes_only_t));

    ngx_http_zip_truncate_buffer(b, &piece->range, range);

    link->buf = b;
    link->next = NULL;

    return link;
}