]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libarchive/archive_read_support_format_raw.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libarchive / archive_read_support_format_raw.c
1 /*-\r
2  * Copyright (c) 2003-2009 Tim Kientzle\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  * 1. Redistributions of source code must retain the above copyright\r
9  *    notice, this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright\r
11  *    notice, this list of conditions and the following disclaimer in the\r
12  *    documentation and/or other materials provided with the distribution.\r
13  *\r
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR\r
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,\r
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
24  */\r
25 #include "archive_platform.h"\r
26 __FBSDID("$FreeBSD$");\r
27 \r
28 #ifdef HAVE_ERRNO_H\r
29 #include <errno.h>\r
30 #endif\r
31 #include <stdio.h>\r
32 #ifdef HAVE_STDLIB_H\r
33 #include <stdlib.h>\r
34 #endif\r
35 \r
36 #include "archive.h"\r
37 #include "archive_entry.h"\r
38 #include "archive_private.h"\r
39 #include "archive_read_private.h"\r
40 \r
41 struct raw_info {\r
42         int64_t offset; /* Current position in the file. */\r
43         int     end_of_file;\r
44 };\r
45 \r
46 static int      archive_read_format_raw_bid(struct archive_read *);\r
47 static int      archive_read_format_raw_cleanup(struct archive_read *);\r
48 static int      archive_read_format_raw_read_data(struct archive_read *,\r
49                     const void **, size_t *, off_t *);\r
50 static int      archive_read_format_raw_read_data_skip(struct archive_read *);\r
51 static int      archive_read_format_raw_read_header(struct archive_read *,\r
52                     struct archive_entry *);\r
53 \r
54 int\r
55 archive_read_support_format_raw(struct archive *_a)\r
56 {\r
57         struct raw_info *info;\r
58         struct archive_read *a = (struct archive_read *)_a;\r
59         int r;\r
60 \r
61         info = (struct raw_info *)calloc(1, sizeof(*info));\r
62         if (info == NULL) {\r
63                 archive_set_error(&a->archive, ENOMEM,\r
64                     "Can't allocate raw_info data");\r
65                 return (ARCHIVE_FATAL);\r
66         }\r
67 \r
68         r = __archive_read_register_format(a,\r
69             info,\r
70             "raw",\r
71             archive_read_format_raw_bid,\r
72             NULL,\r
73             archive_read_format_raw_read_header,\r
74             archive_read_format_raw_read_data,\r
75             archive_read_format_raw_read_data_skip,\r
76             archive_read_format_raw_cleanup);\r
77         if (r != ARCHIVE_OK)\r
78                 free(info);\r
79         return (r);\r
80 }\r
81 \r
82 /*\r
83  * Bid 1 if this is a non-empty file.  Anyone who can really support\r
84  * this should outbid us, so it should generally be safe to use "raw"\r
85  * in conjunction with other formats.  But, this could really confuse\r
86  * folks if there are bid errors or minor file damage, so we don't\r
87  * include "raw" as part of support_format_all().\r
88  */\r
89 static int\r
90 archive_read_format_raw_bid(struct archive_read *a)\r
91 {\r
92         const char *p;\r
93 \r
94         if ((p = __archive_read_ahead(a, 1, NULL)) == NULL)\r
95                 return (-1);\r
96         return (1);\r
97 }\r
98 \r
99 /*\r
100  * Mock up a fake header.\r
101  */\r
102 static int\r
103 archive_read_format_raw_read_header(struct archive_read *a,\r
104     struct archive_entry *entry)\r
105 {\r
106         struct raw_info *info;\r
107 \r
108         info = (struct raw_info *)(a->format->data);\r
109         if (info->end_of_file)\r
110                 return (ARCHIVE_EOF);\r
111 \r
112         a->archive.archive_format = ARCHIVE_FORMAT_RAW;\r
113         a->archive.archive_format_name = "Raw data";\r
114         archive_entry_set_pathname(entry, "data");\r
115         /* XXX should we set mode to mimic a regular file? XXX */\r
116         /* I'm deliberately leaving most fields unset here. */\r
117         return (ARCHIVE_OK);\r
118 }\r
119 \r
120 static int\r
121 archive_read_format_raw_read_data(struct archive_read *a,\r
122     const void **buff, size_t *size, off_t *offset)\r
123 {\r
124         struct raw_info *info;\r
125         ssize_t avail;\r
126 \r
127         info = (struct raw_info *)(a->format->data);\r
128         if (info->end_of_file)\r
129                 return (ARCHIVE_EOF);\r
130 \r
131         /* Get whatever bytes are immediately available. */\r
132         *buff = __archive_read_ahead(a, 1, &avail);\r
133         if (avail > 0) {\r
134                 /* Consume and return the bytes we just read */\r
135                 __archive_read_consume(a, avail);\r
136                 *size = avail;\r
137                 *offset = info->offset;\r
138                 info->offset += *size;\r
139                 return (ARCHIVE_OK);\r
140         } else if (0 == avail) {\r
141                 /* Record and return end-of-file. */\r
142                 info->end_of_file = 1;\r
143                 *size = 0;\r
144                 *offset = info->offset;\r
145                 return (ARCHIVE_EOF);\r
146         } else {\r
147                 /* Record and return an error. */\r
148                 *size = 0;\r
149                 *offset = info->offset;\r
150                 return (avail);\r
151         }\r
152         return (ARCHIVE_OK);\r
153 }\r
154 \r
155 static int\r
156 archive_read_format_raw_read_data_skip(struct archive_read *a)\r
157 {\r
158         struct raw_info *info;\r
159         off_t bytes_skipped;\r
160         int64_t request = 1024 * 1024 * 1024UL; /* Skip 1 GB at a time. */\r
161 \r
162         info = (struct raw_info *)(a->format->data);\r
163         if (info->end_of_file)\r
164                 return (ARCHIVE_EOF);\r
165         info->end_of_file = 1;\r
166 \r
167         for (;;) {\r
168                 bytes_skipped = __archive_read_skip_lenient(a, request);\r
169                 if (bytes_skipped < 0)\r
170                         return (ARCHIVE_FATAL);\r
171                 if (bytes_skipped < request)\r
172                         return (ARCHIVE_OK);\r
173                 /* We skipped all the bytes we asked for.  There might\r
174                  * be more, so try again. */\r
175         }\r
176 }\r
177 \r
178 static int\r
179 archive_read_format_raw_cleanup(struct archive_read *a)\r
180 {\r
181         struct raw_info *info;\r
182 \r
183         info = (struct raw_info *)(a->format->data);\r
184         free(info);\r
185         a->format->data = NULL;\r
186         return (ARCHIVE_OK);\r
187 }\r