]> wimlib.net Git - wimlib/blobdiff - src/reference.c
WIMBoot / system compression: try WOFADK in addition to WOF
[wimlib] / src / reference.c
index d1e34e19733e9bfcd706abcd99786850ff2060c1..ab0bab2bf6a804b1990a8e43bc3dc3ee892bcd17 100644 (file)
@@ -1,26 +1,24 @@
 /*
  * reference.c
  *
- * Reference resources from external WIM file(s).
+ * Reference blobs from external WIM file(s).
  */
 
 /*
- * Copyright (C) 2013 Eric Biggers
+ * Copyright (C) 2013, 2014 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
 #endif
 
 #include "wimlib.h"
+#include "wimlib/blob_table.h"
 #include "wimlib/error.h"
 #include "wimlib/glob.h"
-#include "wimlib/lookup_table.h"
 #include "wimlib/wim.h"
 
 #define WIMLIB_REF_MASK_PUBLIC (WIMLIB_REF_FLAG_GLOB_ENABLE | \
                                WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH)
 
-#define WIMLIB_REF_FLAG_GIFT 0x80000000
-
-struct lookup_tables {
-       struct wim_lookup_table *src_table;
-       struct wim_lookup_table *dest_table;
+struct reference_info {
+       WIMStruct *dest_wim;
+       struct list_head new_blobs;
+       struct list_head new_subwims;
+       int ref_flags;
+       struct blob_table *src_table;
 };
 
-static int
-lte_gift(struct wim_lookup_table_entry *lte, void *_tables)
+static void
+init_reference_info(struct reference_info *info, WIMStruct *dest_wim,
+                   int ref_flags)
 {
-       struct lookup_tables *tables = _tables;
-       struct wim_lookup_table *src_table = tables->src_table;
-       struct wim_lookup_table *dest_table = tables->dest_table;
-
-       lookup_table_unlink(src_table, lte);
-       if (lookup_stream(dest_table, lte->hash)) {
-               free_lookup_table_entry(lte);
-       } else {
-               lte->out_refcnt = 1;
-               lookup_table_insert(dest_table, lte);
-       }
-       return 0;
+       info->dest_wim = dest_wim;
+       INIT_LIST_HEAD(&info->new_blobs);
+       INIT_LIST_HEAD(&info->new_subwims);
+       info->ref_flags = ref_flags;
 }
 
-static int
-lte_clone_if_new(struct wim_lookup_table_entry *lte, void *_lookup_table)
+static void
+commit_reference_info(struct reference_info *info)
 {
-       struct wim_lookup_table *lookup_table = _lookup_table;
-
-       if (lookup_stream(lookup_table, lte->hash))
-               return 0;  /*  Resource already present.  */
-
-       lte = clone_lookup_table_entry(lte);
-       if (lte == NULL)
-               return WIMLIB_ERR_NOMEM;
-       lte->out_refcnt = 1;
-       lookup_table_insert(lookup_table, lte);
-       return 0;
+       list_splice(&info->new_subwims, &info->dest_wim->subwims);
 }
 
-static int
-lte_delete_if_new(struct wim_lookup_table_entry *lte, void *_lookup_table)
+static void
+rollback_reference_info(struct reference_info *info)
 {
-       struct wim_lookup_table *lookup_table = _lookup_table;
+       WIMStruct *subwim;
+       struct blob_descriptor *blob;
+
+       while (!list_empty(&info->new_subwims)) {
+               subwim = list_first_entry(&info->new_subwims,
+                                         WIMStruct, subwim_node);
+               list_del(&subwim->subwim_node);
+               wimlib_free(subwim);
+       }
 
-       if (lte->out_refcnt) {
-               lookup_table_unlink(lookup_table, lte);
-               free_lookup_table_entry(lte);
+       while (!list_empty(&info->new_blobs)) {
+               blob = list_first_entry(&info->new_blobs,
+                                       struct blob_descriptor, blob_table_list);
+               list_del(&blob->blob_table_list);
+               blob_table_unlink(info->dest_wim->blob_table, blob);
+               free_blob_descriptor(blob);
        }
-       return 0;
 }
 
 static int
-do_wimlib_reference_resources(WIMStruct *wim, WIMStruct **resource_wims,
-                             unsigned num_resource_wims, int ref_flags)
+commit_or_rollback_reference_info(struct reference_info *info, int ret)
 {
-       unsigned i;
-       int ret;
+       if (unlikely(ret))
+               rollback_reference_info(info);
+       else
+               commit_reference_info(info);
+       return ret;
+}
 
-       if (ref_flags & WIMLIB_REF_FLAG_GIFT) {
-               struct lookup_tables tables;
+static bool
+need_blob(const struct reference_info *info, const struct blob_descriptor *blob)
+{
+       return !lookup_blob(info->dest_wim->blob_table, blob->hash);
+}
 
-               tables.dest_table = wim->lookup_table;
+static void
+reference_blob(struct reference_info *info, struct blob_descriptor *blob)
+{
+       blob_table_insert(info->dest_wim->blob_table, blob);
+       list_add(&blob->blob_table_list, &info->new_blobs);
+}
 
-               for (i = 0; i < num_resource_wims; i++) {
+static void
+reference_subwim(struct reference_info *info, WIMStruct *subwim)
+{
+       list_add(&subwim->subwim_node, &info->new_subwims);
+}
 
-                       tables.src_table = resource_wims[i]->lookup_table;
+static int
+blob_clone_if_new(struct blob_descriptor *blob, void *_info)
+{
+       struct reference_info *info = _info;
 
-                       ret = for_lookup_table_entry(resource_wims[i]->lookup_table,
-                                                    lte_gift, &tables);
-                       if (ret)
-                               goto out_rollback;
-               }
-       } else {
-               for (i = 0; i < num_resource_wims; i++) {
-                       ret = for_lookup_table_entry(resource_wims[i]->lookup_table,
-                                                    lte_clone_if_new, wim->lookup_table);
-                       if (ret)
-                               goto out_rollback;
-               }
+       if (need_blob(info, blob)) {
+               blob = clone_blob_descriptor(blob);
+               if (unlikely(!blob))
+                       return WIMLIB_ERR_NOMEM;
+               reference_blob(info, blob);
        }
        return 0;
-
-out_rollback:
-       for_lookup_table_entry(wim->lookup_table, lte_delete_if_new,
-                              wim->lookup_table);
-       return ret;
 }
 
 /* API function documented in wimlib.h  */
 WIMLIBAPI int
-wimlib_reference_resources(WIMStruct *wim,
-                          WIMStruct **resource_wims, unsigned num_resource_wims,
-                          int ref_flags)
+wimlib_reference_resources(WIMStruct *wim, WIMStruct **resource_wims,
+                          unsigned num_resource_wims, int ref_flags)
 {
        unsigned i;
+       struct reference_info info;
+       int ret = 0;
 
        if (wim == NULL)
                return WIMLIB_ERR_INVALID_PARAM;
@@ -146,122 +145,129 @@ wimlib_reference_resources(WIMStruct *wim,
                if (resource_wims[i] == NULL)
                        return WIMLIB_ERR_INVALID_PARAM;
 
-       return do_wimlib_reference_resources(wim, resource_wims,
-                                            num_resource_wims, ref_flags);
+       init_reference_info(&info, wim, ref_flags);
+
+       for (i = 0; i < num_resource_wims; i++) {
+               ret = for_blob_in_table(resource_wims[i]->blob_table,
+                                       blob_clone_if_new, &info);
+               if (ret)
+                       break;
+       }
+
+       return commit_or_rollback_reference_info(&info, ret);
 }
 
 static int
-reference_resource_paths(WIMStruct *wim,
-                        const tchar * const *resource_wimfiles,
-                        unsigned num_resource_wimfiles,
-                        int ref_flags,
-                        int open_flags)
+blob_gift(struct blob_descriptor *blob, void *_info)
 {
-       WIMStruct **resource_wims;
-       unsigned i;
-       int ret;
+       struct reference_info *info = _info;
 
-       resource_wims = CALLOC(num_resource_wimfiles, sizeof(resource_wims[0]));
-       if (!resource_wims)
-               return WIMLIB_ERR_NOMEM;
-
-       for (i = 0; i < num_resource_wimfiles; i++) {
-               DEBUG("Referencing resources from path \"%"TS"\"",
-                     resource_wimfiles[i]);
-               ret = wimlib_open_wim_with_progress(resource_wimfiles[i],
-                                                   open_flags,
-                                                   &resource_wims[i],
-                                                   wim->progfunc,
-                                                   wim->progctx);
-               if (ret)
-                       goto out_free_resource_wims;
-       }
+       blob_table_unlink(info->src_table, blob);
+       if (need_blob(info, blob))
+               reference_blob(info, blob);
+       else
+               free_blob_descriptor(blob);
+       return 0;
+}
 
-       ret = do_wimlib_reference_resources(wim, resource_wims,
-                                           num_resource_wimfiles,
-                                           ref_flags | WIMLIB_REF_FLAG_GIFT);
-       if (ret)
-               goto out_free_resource_wims;
+static int
+reference_resource_path(struct reference_info *info, const tchar *path,
+                       int open_flags)
+{
+       int ret;
+       WIMStruct *src_wim;
 
-       for (i = 0; i < num_resource_wimfiles; i++)
-               list_add_tail(&resource_wims[i]->subwim_node, &wim->subwims);
+       ret = wimlib_open_wim_with_progress(path, open_flags, &src_wim,
+                                           info->dest_wim->progfunc,
+                                           info->dest_wim->progctx);
+       if (ret)
+               return ret;
 
-       ret = 0;
-       goto out_free_array;
+       info->src_table = src_wim->blob_table;
+       for_blob_in_table(src_wim->blob_table, blob_gift, info);
+       reference_subwim(info, src_wim);
+       return 0;
+}
 
-out_free_resource_wims:
-       for (i = 0; i < num_resource_wimfiles; i++)
-               wimlib_free(resource_wims[i]);
-out_free_array:
-       FREE(resource_wims);
-       return ret;
+static int
+reference_resource_paths(struct reference_info *info,
+                        const tchar * const *paths, unsigned num_paths,
+                        int open_flags)
+{
+       for (unsigned i = 0; i < num_paths; i++) {
+               int ret = reference_resource_path(info, paths[i], open_flags);
+               if (ret)
+                       return ret;
+       }
+       return 0;
 }
 
 static int
-reference_resource_glob(WIMStruct *wim, const tchar *refglob,
-                       int ref_flags, int open_flags)
+reference_resource_glob(struct reference_info *info,
+                       const tchar *refglob, int open_flags)
 {
-       glob_t globbuf;
        int ret;
+       glob_t globbuf;
 
        /* Note: glob() is replaced in Windows native builds.  */
        ret = tglob(refglob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
-       if (ret) {
+       if (unlikely(ret)) {
                if (ret == GLOB_NOMATCH) {
-                       if (ref_flags & WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH) {
+                       if (info->ref_flags &
+                           WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH)
+                       {
                                ERROR("Found no files for glob \"%"TS"\"", refglob);
                                return WIMLIB_ERR_GLOB_HAD_NO_MATCHES;
-                       } else {
-                               return reference_resource_paths(wim,
-                                                               &refglob,
-                                                               1,
-                                                               ref_flags,
-                                                               open_flags);
                        }
-               } else {
-                       ERROR_WITH_ERRNO("Failed to process glob \"%"TS"\"", refglob);
-                       if (ret == GLOB_NOSPACE)
-                               return WIMLIB_ERR_NOMEM;
-                       else
-                               return WIMLIB_ERR_READ;
+                       return reference_resource_path(info,
+                                                      refglob,
+                                                      open_flags);
                }
+               ERROR_WITH_ERRNO("Failed to process glob \"%"TS"\"", refglob);
+               if (ret == GLOB_NOSPACE)
+                       return WIMLIB_ERR_NOMEM;
+               return WIMLIB_ERR_READ;
        }
 
-       ret = reference_resource_paths(wim,
+       ret = reference_resource_paths(info,
                                       (const tchar * const *)globbuf.gl_pathv,
                                       globbuf.gl_pathc,
-                                      ref_flags,
                                       open_flags);
        globfree(&globbuf);
        return ret;
 }
 
+static int
+reference_resource_globs(struct reference_info *info,
+                        const tchar * const *globs, unsigned num_globs,
+                        int open_flags)
+{
+       for (unsigned i = 0; i < num_globs; i++) {
+               int ret = reference_resource_glob(info, globs[i], open_flags);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
 /* API function documented in wimlib.h  */
 WIMLIBAPI int
 wimlib_reference_resource_files(WIMStruct *wim,
-                               const tchar * const * resource_wimfiles_or_globs,
-                               unsigned count,
-                               int ref_flags,
-                               int open_flags)
+                               const tchar * const *paths_or_globs,
+                               unsigned count, int ref_flags, int open_flags)
 {
-       unsigned i;
+       struct reference_info info;
        int ret;
 
        if (ref_flags & ~WIMLIB_REF_MASK_PUBLIC)
                return WIMLIB_ERR_INVALID_PARAM;
 
-       if (ref_flags & WIMLIB_REF_FLAG_GLOB_ENABLE) {
-               for (i = 0; i < count; i++) {
-                       ret = reference_resource_glob(wim,
-                                                     resource_wimfiles_or_globs[i],
-                                                     ref_flags,
-                                                     open_flags);
-                       if (ret)
-                               return ret;
-               }
-               return 0;
-       } else {
-               return reference_resource_paths(wim, resource_wimfiles_or_globs,
-                                               count, ref_flags, open_flags);
-       }
+       init_reference_info(&info, wim, ref_flags);
+
+       if (ref_flags & WIMLIB_REF_FLAG_GLOB_ENABLE)
+               ret = reference_resource_globs(&info, paths_or_globs, count, open_flags);
+       else
+               ret = reference_resource_paths(&info, paths_or_globs, count, open_flags);
+
+       return commit_or_rollback_reference_info(&info, ret);
 }