]> wimlib.net Git - wimlib/blobdiff - src/blob_table.c
inode_table: make the inode table resizable
[wimlib] / src / blob_table.c
index 43ea4854b949bb7be932ca71ed36df4392f98dff..54eca2c9f9d753514056cd082aeaae2673d47af2 100644 (file)
@@ -44,6 +44,7 @@
 #include "wimlib/resource.h"
 #include "wimlib/unaligned.h"
 #include "wimlib/util.h"
+#include "wimlib/win32.h"
 #include "wimlib/write.h"
 
 /* A hash table mapping SHA-1 message digests to blob descriptors  */
@@ -53,21 +54,13 @@ struct blob_table {
        size_t mask; /* capacity - 1; capacity is a power of 2  */
 };
 
-static size_t
-next_power_of_2(size_t n)
-{
-       if (n <= 1)
-               return 1;
-       return (size_t)1 << (1 + flsw(n - 1));
-}
-
 struct blob_table *
 new_blob_table(size_t capacity)
 {
        struct blob_table *table;
        struct hlist_head *array;
 
-       capacity = next_power_of_2(capacity);
+       capacity = roundup_pow_of_2(capacity);
 
        table = MALLOC(sizeof(struct blob_table));
        if (table == NULL)
@@ -110,7 +103,7 @@ free_blob_table(struct blob_table *table)
 struct blob_descriptor *
 new_blob_descriptor(void)
 {
-       BUILD_BUG_ON(BLOB_NONEXISTENT != 0);
+       STATIC_ASSERT(BLOB_NONEXISTENT == 0);
        return CALLOC(1, sizeof(struct blob_descriptor));
 }
 
@@ -129,19 +122,20 @@ clone_blob_descriptor(const struct blob_descriptor *old)
                break;
 
        case BLOB_IN_FILE_ON_DISK:
-#ifdef __WIN32__
-       case BLOB_IN_WINNT_FILE_ON_DISK:
-       case BLOB_WIN32_ENCRYPTED:
-#endif
 #ifdef WITH_FUSE
        case BLOB_IN_STAGING_FILE:
-               BUILD_BUG_ON((void*)&old->file_on_disk !=
-                            (void*)&old->staging_file_name);
+               STATIC_ASSERT((void*)&old->file_on_disk ==
+                             (void*)&old->staging_file_name);
 #endif
                new->file_on_disk = TSTRDUP(old->file_on_disk);
                if (new->file_on_disk == NULL)
                        goto out_free;
                break;
+#ifdef __WIN32__
+       case BLOB_IN_WINDOWS_FILE:
+               new->windows_file = clone_windows_file(old->windows_file);
+               break;
+#endif
        case BLOB_IN_ATTACHED_BUFFER:
                new->attached_buffer = memdup(old->attached_buffer, old->size);
                if (new->attached_buffer == NULL)
@@ -162,37 +156,45 @@ out_free:
        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:
-       case BLOB_WIN32_ENCRYPTED:
-#endif
 #ifdef WITH_FUSE
        case BLOB_IN_STAGING_FILE:
-               BUILD_BUG_ON((void*)&blob->file_on_disk !=
-                            (void*)&blob->staging_file_name);
+               STATIC_ASSERT((void*)&blob->file_on_disk ==
+                             (void*)&blob->staging_file_name);
 #endif
        case BLOB_IN_ATTACHED_BUFFER:
-               BUILD_BUG_ON((void*)&blob->file_on_disk !=
-                            (void*)&blob->attached_buffer);
+               STATIC_ASSERT((void*)&blob->file_on_disk ==
+                             (void*)&blob->attached_buffer);
                FREE(blob->file_on_disk);
                break;
+#ifdef __WIN32__
+       case BLOB_IN_WINDOWS_FILE:
+               free_windows_file(blob->windows_file);
+               break;
+#endif
 #ifdef WITH_NTFS_3G
        case BLOB_IN_NTFS_VOLUME:
-               if (blob->ntfs_loc)
-                       free_ntfs_location(blob->ntfs_loc);
+               free_ntfs_location(blob->ntfs_loc);
                break;
 #endif
        }
+       blob->blob_location = BLOB_NONEXISTENT;
 }
 
 void
@@ -403,7 +405,12 @@ cmp_blobs_by_sequential_order(const void *p1, const void *p2)
 
        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;
 
@@ -412,39 +419,52 @@ cmp_blobs_by_sequential_order(const void *p1, const void *p2)
                wim1 = blob1->rdesc->wim;
                wim2 = blob2->rdesc->wim;
 
-               /* Different (possibly split) WIMs?  */
+               /* 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)
                                return v;
+
+                       /* Different part numbers in the same split WIM?  */
+                       v = (int)wim1->hdr.part_number - (int)wim2->hdr.part_number;
+                       if (v)
+                               return v;
+
+                       /* Probably two WIMStructs for the same on-disk file.
+                        * Just sort by pointer.  */
+                       return wim1 < wim2 ? -1 : 1;
                }
 
-               /* Different part numbers in the same WIM?  */
-               v = (int)wim1->hdr.part_number - (int)wim2->hdr.part_number;
-               if (v)
-                       return v;
+               /* Same WIM file  */
 
+               /* Sort by increasing resource offset  */
                if (blob1->rdesc->offset_in_wim != blob2->rdesc->offset_in_wim)
                        return cmp_u64(blob1->rdesc->offset_in_wim,
                                       blob2->rdesc->offset_in_wim);
 
+               /* The blobs are in the same solid resource.  Sort by increasing
+                * offset in the resource.  */
                return cmp_u64(blob1->offset_in_res, blob2->offset_in_res);
 
        case BLOB_IN_FILE_ON_DISK:
 #ifdef WITH_FUSE
        case BLOB_IN_STAGING_FILE:
-#endif
-#ifdef __WIN32__
-       case BLOB_IN_WINNT_FILE_ON_DISK:
-       case BLOB_WIN32_ENCRYPTED:
-               /* Windows: compare by starting LCN (logical cluster number)  */
-               v = cmp_u64(blob1->sort_key, blob2->sort_key);
-               if (v)
-                       return v;
 #endif
                /* Compare files by path: just a heuristic that will place files
                 * in the same directory next to each other.  */
                return tstrcmp(blob1->file_on_disk, blob2->file_on_disk);
+#ifdef __WIN32__
+       case BLOB_IN_WINDOWS_FILE:
+               return cmp_windows_files(blob1->windows_file, blob2->windows_file);
+#endif
 #ifdef WITH_NTFS_3G
        case BLOB_IN_NTFS_VOLUME:
                return cmp_ntfs_locations(blob1->ntfs_loc, blob2->ntfs_loc);
@@ -638,10 +658,10 @@ do_load_solid_info(WIMStruct *wim, struct wim_resource_descriptor **rdescs,
 
                /* Compression format numbers must be the same as in
                 * WIMGAPI to be compatible here.  */
-               BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_NONE != 0);
-               BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 1);
-               BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 2);
-               BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3);
+               STATIC_ASSERT(WIMLIB_COMPRESSION_TYPE_NONE == 0);
+               STATIC_ASSERT(WIMLIB_COMPRESSION_TYPE_XPRESS == 1);
+               STATIC_ASSERT(WIMLIB_COMPRESSION_TYPE_LZX == 2);
+               STATIC_ASSERT(WIMLIB_COMPRESSION_TYPE_LZMS == 3);
                rdesc->compression_type = le32_to_cpu(hdr.compression_format);
                rdesc->chunk_size = le32_to_cpu(hdr.chunk_size);
        }
@@ -685,6 +705,8 @@ load_solid_info(WIMStruct *wim,
        if (ret)
                goto out_free_rdescs;
 
+       wim->refcnt += num_rdescs;
+
        *rdescs_ret = rdescs;
        *num_rdescs_ret = num_rdescs;
        return 0;
@@ -725,9 +747,12 @@ static void
 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);
        }
 }
@@ -959,6 +984,7 @@ read_blob_table(WIMStruct *wim)
                                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.  */