return NULL;
}
-static void
+/* Release a blob descriptor from its location, if any, and set its new location
+ * to BLOB_NONEXISTENT. */
+void
blob_release_location(struct blob_descriptor *blob)
{
switch (blob->blob_location) {
- case BLOB_IN_WIM:
+ case BLOB_IN_WIM: {
+ struct wim_resource_descriptor *rdesc = blob->rdesc;
+
list_del(&blob->rdesc_node);
- if (list_empty(&blob->rdesc->blob_list))
- FREE(blob->rdesc);
+ if (list_empty(&rdesc->blob_list)) {
+ wim_decrement_refcnt(rdesc->wim);
+ FREE(rdesc);
+ }
break;
+ }
case BLOB_IN_FILE_ON_DISK:
#ifdef __WIN32__
case BLOB_IN_WINNT_FILE_ON_DISK:
break;
#endif
}
+ blob->blob_location = BLOB_NONEXISTENT;
}
void
v = (int)blob1->blob_location - (int)blob2->blob_location;
- /* Different locations? */
+ /* Different locations? Note: "unsafe compaction mode" requires that
+ * blobs in WIMs sort before all others. For the logic here to ensure
+ * this, BLOB_IN_WIM must have the lowest value among all defined
+ * blob_locations. Statically verify that the enum values haven't
+ * changed. */
+ STATIC_ASSERT(BLOB_NONEXISTENT == 0 && BLOB_IN_WIM == 1);
if (v)
return v;
/* Different WIM files? */
if (wim1 != wim2) {
+ /* Resources from the WIM file currently being compacted
+ * (if any) must always sort first. */
+ v = (int)wim2->being_compacted - (int)wim1->being_compacted;
+ if (v)
+ return v;
+
/* Different split WIMs? */
v = cmp_guids(wim1->hdr.guid, wim2->hdr.guid);
if (v)
if (ret)
goto out_free_rdescs;
+ wim->refcnt += num_rdescs;
+
*rdescs_ret = rdescs;
*num_rdescs_ret = num_rdescs;
return 0;
free_solid_rdescs(struct wim_resource_descriptor **rdescs, size_t num_rdescs)
{
if (rdescs) {
- for (size_t i = 0; i < num_rdescs; i++)
- if (list_empty(&rdescs[i]->blob_list))
+ for (size_t i = 0; i < num_rdescs; i++) {
+ if (list_empty(&rdescs[i]->blob_list)) {
+ rdescs[i]->wim->refcnt--;
FREE(rdescs[i]);
+ }
+ }
FREE(rdescs);
}
}
goto oom;
wim_reshdr_to_desc_and_blob(&reshdr, wim, rdesc, cur_blob);
+ wim->refcnt++;
}
/* cur_blob is now a blob bound to a resource. */