1 #ifndef _WIMLIB_RESOURCE_H
2 #define _WIMLIB_RESOURCE_H
3
4 #include "wimlib/list.h"
5 #include "wimlib/sha1.h"
6 #include "wimlib/types.h"
7
8 struct blob_descriptor;
9 struct filedes;
10 struct wim_image_metadata;
11
12 /*
13 * Description of a "resource" in a WIM file. A "resource" is a standalone,
14 * possibly compressed region of data. Normally, there is a one-to-one
15 * correspondence between "blobs" (each of which may be the contents of a file,
16 * for example) and resources. However, a resource with the
17 * WIM_RESHDR_FLAG_SOLID flag set is a "solid" resource that contains multiple
18 * blobs compressed together.
19 */
20 struct wim_resource_descriptor {
21 /* The WIM containing this resource. @wim->in_fd is expected to be a
22 * file descriptor to the underlying WIM file, opened for reading. */
23 WIMStruct *wim;
24
25 /* The offset, in bytes, from the start of WIM file at which this
26 * resource starts. */
27 u64 offset_in_wim;
28
29 /* The size of this resource in the WIM file. For compressed resources
30 * this is the compressed size, including overhead such as the chunk
31 * table. */
32 u64 size_in_wim;
33
34 /* The number of bytes of uncompressed data this resource decompresses
35 * to. */
36 u64 uncompressed_size;
37
38 /* The list of blobs this resource contains. */
39 struct list_head blob_list;
40
41 /* Flags for this resource (WIM_RESHDR_FLAG_*). */
42 u32 flags : 8;
43
44 /* [wimlib extension] This flag will be set if the WIM is pipable. In
45 * such cases, the resource will be in a slightly different format if it
46 * is compressed. */
47 u32 is_pipable : 1;
48
49 /* Temporary flag. */
50 u32 raw_copy_ok : 1;
51
52 /* Compression type of this resource. */
53 u32 compression_type : 22;
54
55 /* Compression chunk size of this resource. Irrelevant if the resource
56 * is uncompressed. */
57 u32 chunk_size;
58 };
59
60 /* On-disk version of a WIM resource header. */
61 struct wim_reshdr_disk {
62 /* Size of the resource as it appears in the WIM file (possibly
63 * compressed). */
64 u8 size_in_wim[7];
65
66 /* Zero or more of the WIM_RESHDR_FLAG_* flags. These indicate, for
67 * example, whether the resource is compressed or not. */
68 u8 flags;
69
70 /* Offset of the resource from the start of the WIM file, in bytes. */
71 le64 offset_in_wim;
72
73 /* Uncompressed size of the resource, in bytes. */
74 le64 uncompressed_size;
75 } _packed_attribute;
76
77 /* In-memory version of a WIM resource header (`struct wim_reshdr_disk'). */
78 struct wim_reshdr {
79 u64 size_in_wim : 56;
80 u64 flags : 8;
81 u64 offset_in_wim;
82 u64 uncompressed_size;
83 };
84
85 /* Flags for the `flags' field of WIM resource headers (`struct wim_reshdr').
86 */
87
88 /* Unknown meaning; currently ignored by wimlib. */
89 #define WIM_RESHDR_FLAG_FREE 0x01
90
91 /* The resource is a metadata resource for a WIM image, or is the blob table or
92 * XML data for the WIM. */
93 #define WIM_RESHDR_FLAG_METADATA 0x02
94
95 /* The resource is a non-solid resource compressed using the WIM's default
96 * compression type. */
97 #define WIM_RESHDR_FLAG_COMPRESSED 0x04
98
99 /* Unknown meaning; currently ignored by wimlib. */
100 #define WIM_RESHDR_FLAG_SPANNED 0x08
101
102 /* The resource is a solid compressed resource which may contain multiple blobs.
103 * This flag is only allowed if the WIM version number is WIM_VERSION_SOLID. */
104 #define WIM_RESHDR_FLAG_SOLID 0x10
105
106 /* Magic number in the 'uncompressed_size' field of the resource header that
107 * identifies the main entry for a solid resource. */
108 #define SOLID_RESOURCE_MAGIC_NUMBER 0x100000000ULL
109
110 static inline void
copy_reshdr(struct wim_reshdr * dest,const struct wim_reshdr * src)111 copy_reshdr(struct wim_reshdr *dest, const struct wim_reshdr *src)
112 {
113 memcpy(dest, src, sizeof(struct wim_reshdr));
114 }
115
116 static inline void
zero_reshdr(struct wim_reshdr * reshdr)117 zero_reshdr(struct wim_reshdr *reshdr)
118 {
119 memset(reshdr, 0, sizeof(struct wim_reshdr));
120 }
121
122 extern void
123 wim_reshdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
124 struct wim_resource_descriptor *rdesc);
125
126 extern void
127 wim_reshdr_to_desc_and_blob(const struct wim_reshdr *reshdr, WIMStruct *wim,
128 struct wim_resource_descriptor *rdesc,
129 struct blob_descriptor *blob);
130
131 extern void
132 get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
133 struct wim_reshdr *reshdr);
134
135 extern void
136 put_wim_reshdr(const struct wim_reshdr *reshdr,
137 struct wim_reshdr_disk *disk_reshdr);
138
139 /* Alternate chunk table format for resources with WIM_RESHDR_FLAG_SOLID set.
140 */
141 struct alt_chunk_table_header_disk {
142 /* Uncompressed size of the resource in bytes. */
143 le64 res_usize;
144
145 /* Number of bytes each compressed chunk decompresses into, except
146 * possibly the last which decompresses into the remainder. This
147 * overrides the chunk size specified by the WIM header. */
148 le32 chunk_size;
149
150 /* Compression format used for compressed chunks:
151 * 0 = None
152 * 1 = XPRESS
153 * 2 = LZX
154 * 3 = LZMS
155 *
156 * This overrides the compression type specified by the WIM header. */
157 le32 compression_format;
158
159 /* This header is directly followed by a table of compressed sizes of
160 * the chunks (4 bytes per entry). */
161 } _packed_attribute;
162
163 static inline unsigned int
get_chunk_entry_size(u64 res_size,bool is_alt)164 get_chunk_entry_size(u64 res_size, bool is_alt)
165 {
166 if (res_size <= UINT32_MAX || is_alt)
167 return 4;
168 else
169 return 8;
170 }
171
172 /* Functions to read blobs */
173
174 extern int
175 read_partial_wim_blob_into_buf(const struct blob_descriptor *blob,
176 u64 offset, size_t size, void *buf);
177
178 extern int
179 read_blob_into_buf(const struct blob_descriptor *blob, void *buf);
180
181 extern int
182 read_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret);
183
184 extern int
185 wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim,
186 void **buf_ret);
187
188 extern int
189 wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
190 u8 hash[SHA1_HASH_SIZE]);
191
192 extern int
193 skip_wim_resource(const struct wim_resource_descriptor *rdesc);
194
195 /*
196 * Callback function for reading chunks. Called whenever the next chunk of
197 * uncompressed data is available, passing 'ctx' as the last argument. 'size' is
198 * guaranteed to be nonzero. Must return 0 on success, or a positive wimlib
199 * error code on failure.
200 */
201 struct consume_chunk_callback {
202 int (*func)(const void *chunk, size_t size, void *ctx);
203 void *ctx;
204 };
205
206 /* Pass a chunk of data to the specified consume_chunk callback */
207 static inline int
consume_chunk(const struct consume_chunk_callback * cb,const void * chunk,size_t size)208 consume_chunk(const struct consume_chunk_callback *cb,
209 const void *chunk, size_t size)
210 {
211 return (*cb->func)(chunk, size, cb->ctx);
212 }
213
214 /* Callback functions for reading blobs */
215 struct read_blob_callbacks {
216
217 /* Called when starting to read a blob. Must return 0 on success, or a
218 * positive wimlib error code on failure, or in the case of
219 * read_blob_list(), the special value BEGIN_BLOB_STATUS_SKIP_BLOB which
220 * indicates that the data for this blob should not be read. */
221 int (*begin_blob)(struct blob_descriptor *blob, void *ctx);
222 #define BEGIN_BLOB_STATUS_SKIP_BLOB (-1)
223
224 /* Called when the next chunk of uncompressed data is available. 'size'
225 * is guaranteed to be nonzero. Must return 0 on success, or a positive
226 * wimlib error code on failure. */
227 int (*continue_blob)(const struct blob_descriptor *blob, u64 offset,
228 const void *chunk, size_t size, void *ctx);
229
230 /* Called when a blob has been successfully read (status=0), or when
231 * begin_blob() was successfully called but an error occurred before the
232 * blob was fully read (status != 0; in this case the implementation
233 * should do cleanup and then pass on the status). Must return 0 on
234 * success, or a positive wimlib error code on failure. */
235 int (*end_blob)(struct blob_descriptor *blob, int status, void *ctx);
236
237 /* Parameter passed to each of the callback functions. */
238 void *ctx;
239 };
240
241 /* Call cbs->begin_blob() if present. */
242 static inline int
call_begin_blob(struct blob_descriptor * blob,const struct read_blob_callbacks * cbs)243 call_begin_blob(struct blob_descriptor *blob,
244 const struct read_blob_callbacks *cbs)
245 {
246 if (!cbs->begin_blob)
247 return 0;
248 return (*cbs->begin_blob)(blob, cbs->ctx);
249 }
250
251 /* Call cbs->continue_blob() if present. */
252 static inline int
call_continue_blob(const struct blob_descriptor * blob,u64 offset,const void * chunk,size_t size,const struct read_blob_callbacks * cbs)253 call_continue_blob(const struct blob_descriptor *blob, u64 offset,
254 const void *chunk, size_t size,
255 const struct read_blob_callbacks *cbs)
256 {
257 if (!cbs->continue_blob)
258 return 0;
259 return (*cbs->continue_blob)(blob, offset, chunk, size, cbs->ctx);
260 }
261
262 /* Call cbs->end_blob() if present. */
263 static inline int
call_end_blob(struct blob_descriptor * blob,int status,const struct read_blob_callbacks * cbs)264 call_end_blob(struct blob_descriptor *blob, int status,
265 const struct read_blob_callbacks *cbs)
266 {
267 if (!cbs->end_blob)
268 return status;
269 return (*cbs->end_blob)(blob, status, cbs->ctx);
270 }
271
272 /* Flags for read_blob_list() */
273 #define VERIFY_BLOB_HASHES 0x1
274 #define COMPUTE_MISSING_BLOB_HASHES 0x2
275 #define BLOB_LIST_ALREADY_SORTED 0x4
276
277 extern int
278 read_blob_list(struct list_head *blob_list, size_t list_head_offset,
279 const struct read_blob_callbacks *cbs, int flags);
280
281 extern int
282 read_blob_with_cbs(struct blob_descriptor *blob,
283 const struct read_blob_callbacks *cbs);
284
285 extern int
286 read_blob_with_sha1(struct blob_descriptor *blob,
287 const struct read_blob_callbacks *cbs);
288
289 extern int
290 extract_blob_prefix_to_fd(struct blob_descriptor *blob, u64 size,
291 struct filedes *fd);
292
293 extern int
294 extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd);
295
296 /* Miscellaneous blob functions. */
297
298 extern int
299 sha1_blob(struct blob_descriptor *blob);
300
301 /* Functions to read/write metadata resources. */
302
303 extern int
304 read_metadata_resource(struct wim_image_metadata *imd);
305
306 extern int
307 write_metadata_resource(WIMStruct *wim, int image, int write_resource_flags);
308
309 /* Definitions specific to pipable WIM resources. */
310
311 /* Arbitrary number to begin each blob in the pipable WIM, used for sanity
312 * checking. */
313 #define PWM_BLOB_MAGIC 0x2b9b9ba2443db9d8ULL
314
315 /* Header that precedes each blob in a pipable WIM. */
316 struct pwm_blob_hdr {
317 le64 magic; /* +0 */
318 le64 uncompressed_size; /* +8 */
319 u8 hash[SHA1_HASH_SIZE]; /* +16 */
320 le32 flags; /* +36 */
321 /* +40 */
322 } _packed_attribute;
323
324 /* Header that precedes each chunk of a compressed resource in a pipable WIM.
325 */
326 struct pwm_chunk_hdr {
327 le32 compressed_size;
328 } _packed_attribute;
329
330 #endif /* _WIMLIB_RESOURCE_H */
331