Handle streams with uncompressed size 4 GiB consistently
[wimlib] / include / wimlib / resource.h
1 #ifndef _WIMLIB_RESOURCE_H
2 #define _WIMLIB_RESOURCE_H
3
4 #include "wimlib/callback.h"
5 #include "wimlib/file_io.h"
6 #include "wimlib/list.h"
7 #include "wimlib/sha1.h"
8 #include "wimlib/types.h"
9
10 struct wim_lookup_table_entry;
11 struct wim_image_metadata;
12
13 /* Specification of a resource in a WIM file.
14  *
15  * If a `struct wim_lookup_table_entry' lte has
16  * (lte->resource_location == RESOURCE_IN_WIM), then lte->wim_res_spec points to
17  * an instance of this structure.
18  *
19  * Normally, there is a one-to-one correspondence between WIM lookup table
20  * entries ("streams", each of which may be the contents of a file, for example)
21  * and WIM resources.  However, WIM resources with the
22  * WIM_RESHDR_FLAG_PACKED_STREAMS flag set may actually contain multiple streams
23  * compressed together.  */
24 struct wim_resource_spec {
25         /* The WIM containing this resource.  @wim->in_fd is expected to be a
26          * file descriptor to the underlying WIM file, opened for reading.  */
27         WIMStruct *wim;
28
29         /* The offset, in bytes, from the start of WIM file at which this
30          * resource starts.  */
31         u64 offset_in_wim;
32
33         /* The size of this resource in the WIM file.  For compressed resources
34          * this is the compressed size, including overhead such as the chunk
35          * table.  */
36         u64 size_in_wim;
37
38         /* The number of bytes of uncompressed data this resource decompresses
39          * to.  */
40         u64 uncompressed_size;
41
42         /* The list of streams this resource contains.  */
43         struct list_head stream_list;
44
45         /* Flags for this resource (WIM_RESHDR_FLAG_*).  */
46         u32 flags : 8;
47
48         /* [wimlib extension] This flag will be set if the WIM is pipable.  In
49          * such cases, the resource will be in a slightly different format if it
50          * is compressed.  */
51         u32 is_pipable : 1;
52
53         /* Temporary flag.  */
54         u32 raw_copy_ok : 1;
55 };
56
57 /* On-disk version of a WIM resource header.  */
58 struct wim_reshdr_disk {
59         /* Size of the resource as it appears in the WIM file (possibly
60          * compressed).  */
61         u8 size_in_wim[7];
62
63         /* Zero or more of the WIM_RESHDR_FLAG_* flags.  These indicate, for
64          * example, whether the resource is compressed or not.  */
65         u8 flags;
66
67         /* Offset of the resource from the start of the WIM file, in bytes.  */
68         le64 offset_in_wim;
69
70         /* Uncompressed size of the resource, in bytes.  */
71         le64 uncompressed_size;
72 } _packed_attribute;
73
74 /* In-memory version of a WIM resource header (`struct wim_reshdr_disk').  */
75 struct wim_reshdr {
76         u64 size_in_wim : 56;
77         u64 flags : 8;
78         u64 offset_in_wim;
79         u64 uncompressed_size;
80 };
81
82 /* Flags for the `flags' field of WIM resource headers (`struct wim_reshdr').
83  */
84
85 /* Unknown meaning; may be intended to indicate spaces in the WIM that are free
86  * to overwrite.  Currently ignored by wimlib.  */
87 #define WIM_RESHDR_FLAG_FREE            0x01
88
89 /* The resource is a metadata resource for a WIM image, or is the lookup table
90  * or XML data for the WIM.  */
91 #define WIM_RESHDR_FLAG_METADATA        0x02
92
93 /* The resource is compressed using the WIM's default compression type and uses
94  * the regular chunk table format.  */
95 #define WIM_RESHDR_FLAG_COMPRESSED      0x04
96
97 /* Unknown meaning; may be intended to indicate a partial stream.  Currently
98  * ignored by wimlib.  */
99 #define WIM_RESHDR_FLAG_SPANNED         0x08
100
101 /* The resource is packed in a special format that may contain multiple
102  * underlying streams, or this resource entry represents a stream packed into
103  * one such resource.  When resources have this flag set, the WIM version number
104  * should be WIM_VERSION_PACKED_STREAMS.  */
105 #define WIM_RESHDR_FLAG_PACKED_STREAMS  0x10
106
107 /* Magic number in the 'uncompressed_size' field of the resource header that
108  * identifies the main entry for a pack.  */
109 #define WIM_PACK_MAGIC_NUMBER           0x100000000ULL
110
111 /* Returns true if the specified WIM resource is compressed, using either the
112  * original chunk table layout or the alternate layout for resources that may
113  * contain multiple packed streams.  */
114 static inline bool
115 resource_is_compressed(const struct wim_resource_spec *rspec)
116 {
117         return (rspec->flags & (WIM_RESHDR_FLAG_COMPRESSED |
118                                 WIM_RESHDR_FLAG_PACKED_STREAMS));
119 }
120
121 static inline void
122 copy_reshdr(struct wim_reshdr *dest, const struct wim_reshdr *src)
123 {
124         memcpy(dest, src, sizeof(struct wim_reshdr));
125 }
126
127 static inline void
128 zero_reshdr(struct wim_reshdr *reshdr)
129 {
130         memset(reshdr, 0, sizeof(struct wim_reshdr));
131 }
132
133 extern void
134 wim_res_hdr_to_spec(const struct wim_reshdr *reshdr, WIMStruct *wim,
135                     struct wim_resource_spec *rspec);
136
137 extern void
138 wim_res_spec_to_hdr(const struct wim_resource_spec *rspec,
139                     struct wim_reshdr *reshdr);
140
141 extern void
142 get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
143                struct wim_reshdr *reshdr);
144
145 void
146 put_wim_reshdr(const struct wim_reshdr *reshdr,
147                struct wim_reshdr_disk *disk_reshdr);
148
149 /* Alternate chunk table format for resources with
150  * WIM_RESHDR_FLAG_PACKED_STREAMS set.  */
151 struct alt_chunk_table_header_disk {
152         /* Uncompressed size of the resource in bytes.  */
153         le64 res_usize;
154
155         /* Number of bytes each compressed chunk decompresses into, except
156          * possibly the last which decompresses into the remainder.  This
157          * overrides the chunk size specified by the WIM header.  */
158         le32 chunk_size;
159
160         /* Compression format used for compressed chunks:
161          * 0 = None
162          * 1 = LZX
163          * 2 = XPRESS
164          * 3 = LZMS
165          *
166          * This overrides the compression type specified by the WIM header.  */
167         le32 compression_format;
168
169         /* This header is directly followed by a table of compressed sizes of
170          * the chunks (4 bytes per entry).  */
171 } _packed_attribute;
172
173 static inline unsigned int
174 get_chunk_entry_size(u64 res_size, bool is_alt)
175 {
176         if (res_size <= UINT32_MAX || is_alt)
177                 return 4;
178         else
179                 return 8;
180 }
181
182 /* Functions to read streams  */
183
184 extern int
185 read_partial_wim_stream_into_buf(const struct wim_lookup_table_entry *lte,
186                                  size_t size, u64 offset, void *buf);
187
188 extern int
189 read_full_stream_into_buf(const struct wim_lookup_table_entry *lte, void *buf);
190
191 extern int
192 read_full_stream_into_alloc_buf(const struct wim_lookup_table_entry *lte,
193                                 void **buf_ret);
194
195 extern int
196 wim_reshdr_to_data(const struct wim_reshdr *reshdr,
197                    WIMStruct *wim, void **buf_ret);
198
199 extern int
200 skip_wim_stream(struct wim_lookup_table_entry *lte);
201
202 /*
203  * Type of callback function for beginning to read a stream.
204  *
205  * @lte:
206  *      Stream that is about to be read.
207  *
208  * @is_partial_res:
209  *      Set to true if the stream is just one of several being read from a
210  *      single pack and therefore would be extra expensive to read
211  *      independently.
212  *
213  * @ctx:
214  *      User-provided context.
215  *
216  * Must return 0 on success, a positive error code on failure, or the special
217  * value BEGIN_STREAM_STATUS_SKIP_STREAM to indicate that the stream should not
218  * be read, and read_stream_list() should continue on to the next stream
219  * (without calling @consume_chunk or @end_stream).
220  */
221 typedef int (*read_stream_list_begin_stream_t)(struct wim_lookup_table_entry *lte,
222                                                bool is_partial_res,
223                                                void *ctx);
224
225 #define BEGIN_STREAM_STATUS_SKIP_STREAM -1
226
227 /*
228  * Type of callback function for finishing reading a stream.
229  *
230  * @lte:
231  *      Stream that has been fully read, or stream that started being read but
232  *      could not be fully read due to a read error.
233  *
234  * @status:
235  *      0 if reading the stream was successful; otherwise a nonzero error code
236  *      that specifies the return status.
237  *
238  * @ctx:
239  *      User-provided context.
240  */
241 typedef int (*read_stream_list_end_stream_t)(struct wim_lookup_table_entry *lte,
242                                              int status,
243                                              void *ctx);
244
245
246 /* Callback functions and contexts for read_stream_list().  */
247 struct read_stream_list_callbacks {
248
249         /* Called when a stream is about to be read.  */
250         read_stream_list_begin_stream_t begin_stream;
251
252         /* Called when a chunk of data has been read.  */
253         consume_data_callback_t consume_chunk;
254
255         /* Called when a stream has been fully read.  A successful call to
256          * @begin_stream will always be matched by a call to @end_stream.  */
257         read_stream_list_end_stream_t end_stream;
258
259         /* Parameter passed to @begin_stream.  */
260         void *begin_stream_ctx;
261
262         /* Parameter passed to @consume_chunk.  */
263         void *consume_chunk_ctx;
264
265         /* Parameter passed to @end_stream.  */
266         void *end_stream_ctx;
267 };
268
269 /* Flags for read_stream_list()  */
270 #define VERIFY_STREAM_HASHES            0x1
271 #define COMPUTE_MISSING_STREAM_HASHES   0x2
272 #define STREAM_LIST_ALREADY_SORTED      0x4
273
274 extern int
275 read_stream_list(struct list_head *stream_list,
276                  size_t list_head_offset,
277                  const struct read_stream_list_callbacks *cbs,
278                  int flags);
279
280 /* Functions to extract streams.  */
281
282 extern int
283 extract_stream(struct wim_lookup_table_entry *lte,
284                u64 size,
285                consume_data_callback_t extract_chunk,
286                void *extract_chunk_arg);
287
288 extern int
289 extract_stream_to_fd(struct wim_lookup_table_entry *lte,
290                      struct filedes *fd, u64 size);
291
292 extern int
293 extract_full_stream_to_fd(struct wim_lookup_table_entry *lte,
294                           struct filedes *fd);
295
296 extern int
297 extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p);
298
299 /* Miscellaneous stream functions.  */
300
301 extern int
302 sha1_stream(struct wim_lookup_table_entry *lte);
303
304 /* Functions to read/write metadata resources.  */
305
306 extern int
307 read_metadata_resource(WIMStruct *wim,
308                        struct wim_image_metadata *image_metadata);
309
310 extern int
311 write_metadata_resource(WIMStruct *wim, int image, int write_resource_flags);
312
313 /* Definitions specific to pipable WIM resources.  */
314
315 /* Arbitrary number to begin each stream in the pipable WIM, used for sanity
316  * checking.  */
317 #define PWM_STREAM_MAGIC 0x2b9b9ba2443db9d8ULL
318
319 /* Header that precedes each resource in a pipable WIM.  */
320 struct pwm_stream_hdr {
321         le64 magic;                     /* +0   */
322         le64 uncompressed_size;         /* +8   */
323         u8 hash[SHA1_HASH_SIZE];        /* +16  */
324         le32 flags;                     /* +36  */
325                                         /* +40  */
326 } _packed_attribute;
327
328 /* Extra flag for the @flags field in `struct pipable_wim_stream_hdr': Indicates
329  * that the SHA1 message digest of the stream has not been calculated.
330  * Currently only used for the XML data.  */
331 #define PWM_RESHDR_FLAG_UNHASHED         0x100
332
333 /* Header that precedes each chunk of a compressed resource in a pipable WIM.
334  */
335 struct pwm_chunk_hdr {
336         le32 compressed_size;
337 } _packed_attribute;
338
339 #endif /* _WIMLIB_RESOURCE_H */