1228753Smm/*- 2228753Smm * Copyright (c) 2003-2009 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm#include "archive_platform.h" 26229592Smm__FBSDID("$FreeBSD$"); 27228753Smm 28228753Smm#ifdef HAVE_ERRNO_H 29228753Smm#include <errno.h> 30228753Smm#endif 31228753Smm#include <stdio.h> 32228753Smm#ifdef HAVE_STDLIB_H 33228753Smm#include <stdlib.h> 34228753Smm#endif 35228753Smm 36228753Smm#include "archive.h" 37228753Smm#include "archive_entry.h" 38228753Smm#include "archive_private.h" 39228753Smm#include "archive_read_private.h" 40228753Smm 41228753Smmstruct raw_info { 42228753Smm int64_t offset; /* Current position in the file. */ 43228753Smm int end_of_file; 44228753Smm}; 45228753Smm 46228753Smmstatic int archive_read_format_raw_bid(struct archive_read *); 47228753Smmstatic int archive_read_format_raw_cleanup(struct archive_read *); 48228753Smmstatic int archive_read_format_raw_read_data(struct archive_read *, 49228753Smm const void **, size_t *, off_t *); 50228753Smmstatic int archive_read_format_raw_read_data_skip(struct archive_read *); 51228753Smmstatic int archive_read_format_raw_read_header(struct archive_read *, 52228753Smm struct archive_entry *); 53228753Smm 54228753Smmint 55228753Smmarchive_read_support_format_raw(struct archive *_a) 56228753Smm{ 57228753Smm struct raw_info *info; 58228753Smm struct archive_read *a = (struct archive_read *)_a; 59228753Smm int r; 60228753Smm 61228753Smm info = (struct raw_info *)calloc(1, sizeof(*info)); 62228753Smm if (info == NULL) { 63228753Smm archive_set_error(&a->archive, ENOMEM, 64228753Smm "Can't allocate raw_info data"); 65228753Smm return (ARCHIVE_FATAL); 66228753Smm } 67228753Smm 68228753Smm r = __archive_read_register_format(a, 69228753Smm info, 70228753Smm "raw", 71228753Smm archive_read_format_raw_bid, 72228753Smm NULL, 73228753Smm archive_read_format_raw_read_header, 74228753Smm archive_read_format_raw_read_data, 75228753Smm archive_read_format_raw_read_data_skip, 76228753Smm archive_read_format_raw_cleanup); 77228753Smm if (r != ARCHIVE_OK) 78228753Smm free(info); 79228753Smm return (r); 80228753Smm} 81228753Smm 82228753Smm/* 83228753Smm * Bid 1 if this is a non-empty file. Anyone who can really support 84228753Smm * this should outbid us, so it should generally be safe to use "raw" 85228753Smm * in conjunction with other formats. But, this could really confuse 86228753Smm * folks if there are bid errors or minor file damage, so we don't 87228753Smm * include "raw" as part of support_format_all(). 88228753Smm */ 89228753Smmstatic int 90228753Smmarchive_read_format_raw_bid(struct archive_read *a) 91228753Smm{ 92228753Smm 93228753Smm if (__archive_read_ahead(a, 1, NULL) == NULL) 94228753Smm return (-1); 95228753Smm return (1); 96228753Smm} 97228753Smm 98228753Smm/* 99228753Smm * Mock up a fake header. 100228753Smm */ 101228753Smmstatic int 102228753Smmarchive_read_format_raw_read_header(struct archive_read *a, 103228753Smm struct archive_entry *entry) 104228753Smm{ 105228753Smm struct raw_info *info; 106228753Smm 107228753Smm info = (struct raw_info *)(a->format->data); 108228753Smm if (info->end_of_file) 109228753Smm return (ARCHIVE_EOF); 110228753Smm 111228753Smm a->archive.archive_format = ARCHIVE_FORMAT_RAW; 112228753Smm a->archive.archive_format_name = "Raw data"; 113228753Smm archive_entry_set_pathname(entry, "data"); 114228753Smm /* XXX should we set mode to mimic a regular file? XXX */ 115228753Smm /* I'm deliberately leaving most fields unset here. */ 116228753Smm return (ARCHIVE_OK); 117228753Smm} 118228753Smm 119228753Smmstatic int 120228753Smmarchive_read_format_raw_read_data(struct archive_read *a, 121228753Smm const void **buff, size_t *size, off_t *offset) 122228753Smm{ 123228753Smm struct raw_info *info; 124228753Smm ssize_t avail; 125228753Smm 126228753Smm info = (struct raw_info *)(a->format->data); 127228753Smm if (info->end_of_file) 128228753Smm return (ARCHIVE_EOF); 129228753Smm 130228753Smm /* Get whatever bytes are immediately available. */ 131228753Smm *buff = __archive_read_ahead(a, 1, &avail); 132228753Smm if (avail > 0) { 133228753Smm /* Consume and return the bytes we just read */ 134228753Smm __archive_read_consume(a, avail); 135228753Smm *size = avail; 136228753Smm *offset = info->offset; 137228753Smm info->offset += *size; 138228753Smm return (ARCHIVE_OK); 139228753Smm } else if (0 == avail) { 140228753Smm /* Record and return end-of-file. */ 141228753Smm info->end_of_file = 1; 142228753Smm *size = 0; 143228753Smm *offset = info->offset; 144228753Smm return (ARCHIVE_EOF); 145228753Smm } else { 146228753Smm /* Record and return an error. */ 147228753Smm *size = 0; 148228753Smm *offset = info->offset; 149228753Smm return (avail); 150228753Smm } 151228753Smm} 152228753Smm 153228753Smmstatic int 154228753Smmarchive_read_format_raw_read_data_skip(struct archive_read *a) 155228753Smm{ 156228753Smm struct raw_info *info; 157228753Smm off_t bytes_skipped; 158228753Smm int64_t request = 1024 * 1024 * 1024UL; /* Skip 1 GB at a time. */ 159228753Smm 160228753Smm info = (struct raw_info *)(a->format->data); 161228753Smm if (info->end_of_file) 162228753Smm return (ARCHIVE_EOF); 163228753Smm info->end_of_file = 1; 164228753Smm 165228753Smm for (;;) { 166228753Smm bytes_skipped = __archive_read_skip_lenient(a, request); 167228753Smm if (bytes_skipped < 0) 168228753Smm return (ARCHIVE_FATAL); 169228753Smm if (bytes_skipped < request) 170228753Smm return (ARCHIVE_OK); 171228753Smm /* We skipped all the bytes we asked for. There might 172228753Smm * be more, so try again. */ 173228753Smm } 174228753Smm} 175228753Smm 176228753Smmstatic int 177228753Smmarchive_read_format_raw_cleanup(struct archive_read *a) 178228753Smm{ 179228753Smm struct raw_info *info; 180228753Smm 181228753Smm info = (struct raw_info *)(a->format->data); 182228753Smm free(info); 183228753Smm a->format->data = NULL; 184228753Smm return (ARCHIVE_OK); 185228753Smm} 186