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