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