1231200Smm/*-
2231200Smm * Copyright (c) 2003-2007 Tim Kientzle
3231200Smm * Copyright (c) 2010-2011 Michihiro NAKAJIMA
4231200Smm * All rights reserved.
5231200Smm *
6231200Smm * Redistribution and use in source and binary forms, with or without
7231200Smm * modification, are permitted provided that the following conditions
8231200Smm * are met:
9231200Smm * 1. Redistributions of source code must retain the above copyright
10231200Smm *    notice, this list of conditions and the following disclaimer.
11231200Smm * 2. Redistributions in binary form must reproduce the above copyright
12231200Smm *    notice, this list of conditions and the following disclaimer in the
13231200Smm *    documentation and/or other materials provided with the distribution.
14231200Smm *
15231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25231200Smm */
26231200Smm
27231200Smm#include "archive_platform.h"
28231200Smm__FBSDID("$FreeBSD$");
29231200Smm
30231200Smm#include "archive.h"
31231200Smm#include "archive_entry.h"
32231200Smm#include "archive_private.h"
33231200Smm#include "archive_entry_private.h"
34231200Smm
35231200Smm/*
36231200Smm * sparse handling
37231200Smm */
38231200Smm
39231200Smmvoid
40231200Smmarchive_entry_sparse_clear(struct archive_entry *entry)
41231200Smm{
42231200Smm	struct ae_sparse *sp;
43231200Smm
44231200Smm	while (entry->sparse_head != NULL) {
45231200Smm		sp = entry->sparse_head->next;
46231200Smm		free(entry->sparse_head);
47231200Smm		entry->sparse_head = sp;
48231200Smm	}
49231200Smm	entry->sparse_tail = NULL;
50231200Smm}
51231200Smm
52231200Smmvoid
53231200Smmarchive_entry_sparse_add_entry(struct archive_entry *entry,
54231200Smm	int64_t offset, int64_t length)
55231200Smm{
56231200Smm	struct ae_sparse *sp;
57231200Smm
58231200Smm	if (offset < 0 || length < 0)
59231200Smm		/* Invalid value */
60231200Smm		return;
61231200Smm	if (offset + length < 0 ||
62231200Smm	    offset + length > archive_entry_size(entry))
63231200Smm		/* A value of "length" parameter is too large. */
64231200Smm		return;
65231200Smm	if ((sp = entry->sparse_tail) != NULL) {
66231200Smm		if (sp->offset + sp->length > offset)
67231200Smm			/* Invalid value. */
68231200Smm			return;
69231200Smm		if (sp->offset + sp->length == offset) {
70231200Smm			if (sp->offset + sp->length + length < 0)
71231200Smm				/* A value of "length" parameter is
72231200Smm				 * too large. */
73231200Smm				return;
74231200Smm			/* Expand existing sparse block size. */
75231200Smm			sp->length += length;
76231200Smm			return;
77231200Smm		}
78231200Smm	}
79231200Smm
80231200Smm	if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL)
81231200Smm		/* XXX Error XXX */
82231200Smm		return;
83231200Smm
84231200Smm	sp->offset = offset;
85231200Smm	sp->length = length;
86231200Smm	sp->next = NULL;
87231200Smm
88231200Smm	if (entry->sparse_head == NULL)
89231200Smm		entry->sparse_head = entry->sparse_tail = sp;
90231200Smm	else {
91231200Smm		/* Add a new sparse block to the tail of list. */
92231200Smm		if (entry->sparse_tail != NULL)
93231200Smm			entry->sparse_tail->next = sp;
94231200Smm		entry->sparse_tail = sp;
95231200Smm	}
96231200Smm}
97231200Smm
98231200Smm
99231200Smm/*
100231200Smm * returns number of the sparse entries
101231200Smm */
102231200Smmint
103231200Smmarchive_entry_sparse_count(struct archive_entry *entry)
104231200Smm{
105231200Smm	struct ae_sparse *sp;
106231200Smm	int count = 0;
107231200Smm
108231200Smm	for (sp = entry->sparse_head; sp != NULL; sp = sp->next)
109231200Smm		count++;
110231200Smm
111231200Smm	/*
112231200Smm	 * Sanity check if this entry is exactly sparse.
113231200Smm	 * If amount of sparse blocks is just one and it indicates the whole
114231200Smm	 * file data, we should remove it and return zero.
115231200Smm	 */
116231200Smm	if (count == 1) {
117231200Smm		sp = entry->sparse_head;
118231200Smm		if (sp->offset == 0 &&
119231200Smm		    sp->length >= archive_entry_size(entry)) {
120231200Smm			count = 0;
121231200Smm			archive_entry_sparse_clear(entry);
122231200Smm		}
123231200Smm	}
124231200Smm
125231200Smm	return (count);
126231200Smm}
127231200Smm
128231200Smmint
129231200Smmarchive_entry_sparse_reset(struct archive_entry * entry)
130231200Smm{
131231200Smm	entry->sparse_p = entry->sparse_head;
132231200Smm
133231200Smm	return archive_entry_sparse_count(entry);
134231200Smm}
135231200Smm
136231200Smmint
137231200Smmarchive_entry_sparse_next(struct archive_entry * entry,
138231200Smm	int64_t *offset, int64_t *length)
139231200Smm{
140231200Smm	if (entry->sparse_p) {
141231200Smm		*offset = entry->sparse_p->offset;
142231200Smm		*length = entry->sparse_p->length;
143231200Smm
144231200Smm		entry->sparse_p = entry->sparse_p->next;
145231200Smm
146231200Smm		return (ARCHIVE_OK);
147231200Smm	} else {
148231200Smm		*offset = 0;
149231200Smm		*length = 0;
150231200Smm		return (ARCHIVE_WARN);
151231200Smm	}
152231200Smm}
153231200Smm
154231200Smm/*
155231200Smm * end of sparse handling
156231200Smm */
157