0999660026ebde5c297d2a04684ec922f1683657
[wimlib] / include / wimlib / blob_table.h
1 #ifndef _WIMLIB_BLOB_TABLE_H
2 #define _WIMLIB_BLOB_TABLE_H
3
4 #include "wimlib/list.h"
5 #include "wimlib/resource.h"
6 #include "wimlib/sha1.h"
7 #include "wimlib/types.h"
8
9 /* An enumerated type that identifies where a blob's data is located.  */
10 enum blob_location {
11
12         /* The blob's data does not exist.  This is a temporary state only.  */
13         BLOB_NONEXISTENT = 0,
14
15         /* The blob's data is available in the WIM resource identified by the
16          * `struct wim_resource_descriptor' pointed to by @rdesc.
17          * @offset_in_res identifies the offset at which this particular blob
18          * begins in the uncompressed data of the resource.  */
19         BLOB_IN_WIM,
20
21         /* The blob's data is available as the contents of the file named by
22          * @file_on_disk.  */
23         BLOB_IN_FILE_ON_DISK,
24
25         /* The blob's data is available as the contents of the in-memory buffer
26          * pointed to by @attached_buffer.  */
27         BLOB_IN_ATTACHED_BUFFER,
28
29 #ifdef WITH_FUSE
30         /* The blob's data is available as the contents of the file with name
31          * @staging_file_name relative to the open directory file descriptor
32          * @staging_dir_fd.  */
33         BLOB_IN_STAGING_FILE,
34 #endif
35
36 #ifdef WITH_NTFS_3G
37         /* The blob's data is available as the contents of an NTFS attribute
38          * accessible through libntfs-3g.  @ntfs_loc points to a structure which
39          * identifies the attribute.  */
40         BLOB_IN_NTFS_VOLUME,
41 #endif
42
43 #ifdef __WIN32__
44         /* Windows only: the blob's data is available as the contents of the
45          * data stream named by @file_on_disk.  @file_on_disk is an NT namespace
46          * path that may be longer than the Win32-level MAX_PATH.  Furthermore,
47          * the stream may require "backup semantics" to access.  */
48         BLOB_IN_WINNT_FILE_ON_DISK,
49
50         /* Windows only: the blob's data is available as the raw encrypted data
51          * of the external file named by @file_on_disk.  @file_on_disk is a
52          * Win32 namespace path.  */
53         BLOB_WIN32_ENCRYPTED,
54 #endif
55 };
56
57 /* A "blob extraction target" is a stream, and the inode to which that stream
58  * belongs, to which a blob needs to be extracted as part of an extraction
59  * operation.  Since blobs are single-instanced, a blob may have multiple
60  * extraction targets.  */
61 struct blob_extraction_target {
62         struct wim_inode *inode;
63         struct wim_inode_stream *stream;
64 };
65
66 /*
67  * Descriptor for a "blob", which is a known length sequence of binary data.
68  *
69  * Within a WIM file, blobs are single instanced and are identified by SHA-1
70  * message digest.
71  */
72 struct blob_descriptor {
73
74         /* List node for a hash bucket of the blob table  */
75         struct hlist_node hash_list;
76
77         /*
78          * Uncompressed size of this blob.
79          *
80          * In most cases we are now enforcing that this is nonzero; i.e. an
81          * empty stream will have "no blob" rather than "an empty blob".  The
82          * exceptions are:
83          *
84          *      - blob descriptors with 'blob_location == BLOB_NONEXISTENT',
85          *        e.g. placeholder entries for new metadata resources or for
86          *        blobs required for pipable WIM extraction.  In these cases the
87          *        size is not meaningful information anyway.
88          *      - blob descriptors with 'blob_location == BLOB_IN_STAGING_FILE'
89          *        can vary their size over time, including to 0.
90          */
91         u64 size;
92
93         union {
94                 /*
95                  * For unhashed == 0: 'hash' is the SHA-1 message digest of the
96                  * blob's data.  'hash_short' allows accessing just a prefix of
97                  * the SHA-1 message digest, which is useful for getting a "hash
98                  * code" for hash table lookup/insertion.
99                  */
100                 u8 hash[SHA1_HASH_SIZE];
101                 size_t hash_short;
102
103                 /* For unhashed == 1: these variables make it possible to find
104                  * the stream that references this blob.  There can be at most
105                  * one such reference, since duplicate blobs can only be joined
106                  * after they have been hashed.  */
107                 struct {
108                         struct wim_inode *back_inode;
109                         u32 back_stream_id;
110                 };
111         } _packed_attribute; /* union is SHA1_HASH_SIZE bytes */
112
113         /* Number of times this blob is referenced by file streams in WIM
114          * images.  See blob_decrement_refcnt() for information about the
115          * limitations of this field.  */
116         u32 refcnt;
117
118         /*
119          * When a WIM file is written, this is set to the number of references
120          * (from file streams) to this blob in the output WIM file.
121          *
122          * During extraction, this is set to the number of targets to which this
123          * blob is being extracted.
124          *
125          * During image export, this is set to the number of references of this
126          * blob that originated from the source WIM.
127          *
128          * When mounting a WIM image read-write, this is set to the number of
129          * extra references to this blob preemptively taken to allow later
130          * saving the modified image as a new image and leaving the original
131          * image alone.
132          */
133         u32 out_refcnt;
134
135 #ifdef WITH_FUSE
136         /* Number of open file descriptors to this blob during a FUSE mount of
137          * a WIM image.  */
138         u16 num_opened_fds;
139 #endif
140
141         /* One of the `enum blob_location' values documented above.  */
142         u16 blob_location : 4;
143
144         /* 1 iff this blob contains "metadata" as opposed to data.  */
145         u16 is_metadata : 1;
146
147         /* 1 iff the SHA-1 message digest of this blob is unknown.  */
148         u16 unhashed : 1;
149
150         /* Temporary fields used when writing blobs; set as documented for
151          * prepare_blob_list_for_write().  */
152         u16 unique_size : 1;
153         u16 will_be_in_output_wim : 1;
154
155         u16 may_send_done_with_file : 1;
156
157         /* Only used by wimlib_export_image() */
158         u16 was_exported : 1;
159
160         /* Specification of where this blob's data is located.  Which member of
161          * this union is valid is determined by the @blob_location field.  */
162         union {
163                 /* BLOB_IN_WIM  */
164                 struct {
165                         struct wim_resource_descriptor *rdesc;
166                         u64 offset_in_res;
167
168                         /* Links together blobs that share the same underlying
169                          * WIM resource.  The head is rdesc->blob_list.  */
170                         struct list_head rdesc_node;
171                 };
172
173                 struct {
174
175                         union {
176
177                                 /* BLOB_IN_FILE_ON_DISK
178                                  * BLOB_IN_WINNT_FILE_ON_DISK
179                                  * BLOB_WIN32_ENCRYPTED  */
180                                 struct {
181                                         tchar *file_on_disk;
182                                         struct wim_inode *file_inode;
183                                 #ifdef __WIN32__
184                                         u64 sort_key;
185                                 #endif
186                                 };
187
188                                 /* BLOB_IN_ATTACHED_BUFFER */
189                                 void *attached_buffer;
190
191                         #ifdef WITH_FUSE
192                                 /* BLOB_IN_STAGING_FILE  */
193                                 struct {
194                                         char *staging_file_name;
195                                         int staging_dir_fd;
196                                 };
197                         #endif
198
199                         #ifdef WITH_NTFS_3G
200                                 /* BLOB_IN_NTFS_VOLUME  */
201                                 struct ntfs_location *ntfs_loc;
202                         #endif
203                         };
204
205                         /* List link for per-WIM-image list of unhashed blobs */
206                         struct list_head unhashed_list;
207                 };
208         };
209
210         /* Temporary fields  */
211         union {
212                 /* Fields used temporarily during WIM file writing.  */
213                 struct {
214                         union {
215                                 /* List node used for blob size table.  */
216                                 struct hlist_node hash_list_2;
217
218                                 /* Metadata for the underlying solid resource in
219                                  * the WIM being written (only valid if
220                                  * WIM_RESHDR_FLAG_SOLID set in
221                                  * out_reshdr.flags).  */
222                                 struct {
223                                         u64 out_res_offset_in_wim;
224                                         u64 out_res_size_in_wim;
225                                         u64 out_res_uncompressed_size;
226                                 };
227                         };
228
229                         /* Links blobs being written to the WIM.  */
230                         struct list_head write_blobs_list;
231
232                         union {
233                                 /* Metadata for this blob in the WIM being
234                                  * written.  */
235                                 struct wim_reshdr out_reshdr;
236
237                                 struct {
238                                         /* Name under which this blob is being
239                                          * sorted; used only when sorting blobs
240                                          * for solid compression.  */
241                                         utf16lechar *solid_sort_name;
242                                         size_t solid_sort_name_nbytes;
243                                 };
244                         };
245                 };
246
247                 /* Used temporarily during extraction.  This is an array of
248                  * references to the streams being extracted that use this blob.
249                  * out_refcnt tracks the number of slots filled.  */
250                 union {
251                         struct blob_extraction_target inline_blob_extraction_targets[3];
252                         struct {
253                                 struct blob_extraction_target *blob_extraction_targets;
254                                 u32 alloc_blob_extraction_targets;
255                         };
256                 };
257         };
258
259         /* Temporary list fields.  */
260         union {
261                 /* Links blobs for writing blob table.  */
262                 struct list_head blob_table_list;
263
264                 /* Links blobs being extracted.  */
265                 struct list_head extraction_list;
266
267                 /* Links blobs being exported.  */
268                 struct list_head export_blob_list;
269
270                 /* Links original list of blobs in the read-write mounted image.  */
271                 struct list_head orig_blob_list;
272         };
273 };
274
275 extern struct blob_table *
276 new_blob_table(size_t capacity) _malloc_attribute;
277
278 extern void
279 free_blob_table(struct blob_table *table);
280
281 extern int
282 read_blob_table(WIMStruct *wim);
283
284 extern int
285 write_blob_table_from_blob_list(struct list_head *blob_list,
286                                 struct filedes *out_fd,
287                                 u16 part_number,
288                                 struct wim_reshdr *out_reshdr,
289                                 int write_resource_flags);
290
291 extern struct blob_descriptor *
292 new_blob_descriptor(void) _malloc_attribute;
293
294 extern struct blob_descriptor *
295 clone_blob_descriptor(const struct blob_descriptor *blob) _malloc_attribute;
296
297 extern void
298 blob_decrement_refcnt(struct blob_descriptor *blob, struct blob_table *table);
299
300 extern void
301 blob_subtract_refcnt(struct blob_descriptor *blob, struct blob_table *table,
302                      u32 count);
303
304 #ifdef WITH_FUSE
305 extern void
306 blob_decrement_num_opened_fds(struct blob_descriptor *blob);
307 #endif
308
309 extern void
310 blob_release_location(struct blob_descriptor *blob);
311
312 extern void
313 free_blob_descriptor(struct blob_descriptor *blob);
314
315 extern void
316 blob_table_insert(struct blob_table *table, struct blob_descriptor *blob);
317
318 extern void
319 blob_table_unlink(struct blob_table *table, struct blob_descriptor *blob);
320
321 extern struct blob_descriptor *
322 lookup_blob(const struct blob_table *table, const u8 *hash);
323
324 extern int
325 for_blob_in_table(struct blob_table *table,
326                   int (*visitor)(struct blob_descriptor *, void *), void *arg);
327
328 extern int
329 for_blob_in_table_sorted_by_sequential_order(struct blob_table *table,
330                                              int (*visitor)(struct blob_descriptor *, void *),
331                                              void *arg);
332
333 struct wimlib_resource_entry;
334
335 extern void
336 blob_to_wimlib_resource_entry(const struct blob_descriptor *blob,
337                               struct wimlib_resource_entry *wentry);
338
339 extern int
340 sort_blob_list(struct list_head *blob_list, size_t list_head_offset,
341                int (*compar)(const void *, const void*));
342
343 extern int
344 sort_blob_list_by_sequential_order(struct list_head *blob_list,
345                                    size_t list_head_offset);
346
347 extern int
348 cmp_blobs_by_sequential_order(const void *p1, const void *p2);
349
350 static inline const struct blob_extraction_target *
351 blob_extraction_targets(const struct blob_descriptor *blob)
352 {
353         if (blob->out_refcnt <= ARRAY_LEN(blob->inline_blob_extraction_targets))
354                 return blob->inline_blob_extraction_targets;
355         else
356                 return blob->blob_extraction_targets;
357 }
358
359 /*
360  * Declare that the specified blob is located in the specified WIM resource at
361  * the specified offset.  The caller is expected to set blob->size if required.
362  */
363 static inline void
364 blob_set_is_located_in_wim_resource(struct blob_descriptor *blob,
365                                     struct wim_resource_descriptor *rdesc,
366                                     u64 offset_in_res)
367 {
368         blob->blob_location = BLOB_IN_WIM;
369         blob->rdesc = rdesc;
370         list_add_tail(&blob->rdesc_node, &rdesc->blob_list);
371         blob->offset_in_res = offset_in_res;
372 }
373
374 static inline void
375 blob_unset_is_located_in_wim_resource(struct blob_descriptor *blob)
376 {
377         list_del(&blob->rdesc_node);
378         blob->blob_location = BLOB_NONEXISTENT;
379 }
380
381 static inline void
382 blob_set_is_located_in_attached_buffer(struct blob_descriptor *blob,
383                                        void *buffer, size_t size)
384 {
385         blob->blob_location = BLOB_IN_ATTACHED_BUFFER;
386         blob->attached_buffer = buffer;
387         blob->size = size;
388 }
389
390 static inline bool
391 blob_is_in_file(const struct blob_descriptor *blob)
392 {
393         return blob->blob_location == BLOB_IN_FILE_ON_DISK
394 #ifdef __WIN32__
395             || blob->blob_location == BLOB_IN_WINNT_FILE_ON_DISK
396             || blob->blob_location == BLOB_WIN32_ENCRYPTED
397 #endif
398            ;
399 }
400
401 extern struct blob_descriptor *
402 new_blob_from_data_buffer(const void *buffer, size_t size,
403                           struct blob_table *blob_table);
404
405 extern struct blob_descriptor *
406 after_blob_hashed(struct blob_descriptor *blob,
407                   struct blob_descriptor **back_ptr,
408                   struct blob_table *blob_table);
409
410 extern int
411 hash_unhashed_blob(struct blob_descriptor *blob, struct blob_table *blob_table,
412                    struct blob_descriptor **blob_ret);
413
414 extern struct blob_descriptor **
415 retrieve_pointer_to_unhashed_blob(struct blob_descriptor *blob);
416
417 static inline void
418 prepare_unhashed_blob(struct blob_descriptor *blob,
419                       struct wim_inode *back_inode, u32 stream_id,
420                       struct list_head *unhashed_blobs)
421 {
422         if (!blob)
423                 return;
424         blob->unhashed = 1;
425         blob->back_inode = back_inode;
426         blob->back_stream_id = stream_id;
427         list_add_tail(&blob->unhashed_list, unhashed_blobs);
428 }
429
430 #endif /* _WIMLIB_BLOB_TABLE_H */