X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmodify.c;h=dcd0b6d353eaf0ce34e4b591dd68b9861e1dcbae;hb=f7d48eea9e1a6a9620ee7d8e883a6505939c7777;hp=4a28e0a47621ca1c1197528873689e7bb672c20c;hpb=6f7956a06fcf92a304fae93e393e8eaee34e92d5;p=wimlib diff --git a/src/modify.c b/src/modify.c index 4a28e0a4..dcd0b6d3 100644 --- a/src/modify.c +++ b/src/modify.c @@ -36,18 +36,22 @@ #include #include #include +#include -static void destroy_image_metadata(struct image_metadata *imd, - struct lookup_table *lt) +/** Private flag: Used to mark that we currently adding the root directory of + * the WIM. */ +#define WIMLIB_ADD_IMAGE_FLAG_ROOT 0x80000000 + +void destroy_image_metadata(struct image_metadata *imd,struct lookup_table *lt) { - free_dentry_tree(imd->root_dentry, lt, true); -#ifdef ENABLE_SECURITY_DATA + free_dentry_tree(imd->root_dentry, lt); free_security_data(imd->security_data); -#endif + free_link_group_table(imd->lgt); /* Get rid of the lookup table entry for this image's metadata resource * */ - lookup_table_remove(lt, imd->metadata_lte); + if (lt) + lookup_table_remove(lt, imd->metadata_lte); } /* @@ -56,9 +60,7 @@ static void destroy_image_metadata(struct image_metadata *imd, * * @root: A dentry that has already been created for the root of the dentry * tree. - * @source_path: The path to the root of the tree on disk. - * @root_stat: A pointer to a `struct stat' that contains the metadata for the - * root of the tree on disk. + * @root_disk_path: The path to the root of the tree on disk. * @lookup_table: The lookup table for the WIM file. For each file added to the * dentry tree being built, an entry is added to the lookup table, * unless an identical file is already in the lookup table. These @@ -70,31 +72,61 @@ static void destroy_image_metadata(struct image_metadata *imd, * to the WIM may still occur later when trying to actually read * the regular files in the tree into the WIM as file resources. */ -static int build_dentry_tree(struct dentry *root, const char *source_path, - struct stat *root_stat, - struct lookup_table* lookup_table) +static int build_dentry_tree(struct dentry *root, const char *root_disk_path, + struct lookup_table* lookup_table, + int add_flags) { + DEBUG("%s", root_disk_path); + struct stat root_stbuf; int ret = 0; + int (*stat_fn)(const char *restrict, struct stat *restrict); + + if (add_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) + stat_fn = stat; + else + stat_fn = lstat; + + if (add_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) + printf("Scanning `%s'\n", root_disk_path); + + + ret = (*stat_fn)(root_disk_path, &root_stbuf); + if (ret != 0) { + ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path); + return WIMLIB_ERR_STAT; + } + + if ((add_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) && + !S_ISDIR(root_stbuf.st_mode)) { + ERROR("`%s' is not a directory", root_disk_path); + return WIMLIB_ERR_NOTDIR; + } + if (!S_ISREG(root_stbuf.st_mode) && !S_ISDIR(root_stbuf.st_mode) + && !S_ISLNK(root_stbuf.st_mode)) { + ERROR("`%s' is not a regular file, directory, or symbolic link."); + return WIMLIB_ERR_SPECIAL_FILE; + } + stbuf_to_dentry(&root_stbuf, root); + add_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT; + root->resolved = true; - stbuf_to_dentry(root_stat, root); if (dentry_is_directory(root)) { /* Open the directory on disk */ DIR *dir; struct dirent *p; - struct stat child_stat; struct dentry *child; - dir = opendir(source_path); + dir = opendir(root_disk_path); if (!dir) { ERROR_WITH_ERRNO("Failed to open the directory `%s'", - source_path); + root_disk_path); return WIMLIB_ERR_OPEN; } /* Buffer for names of files in directory. */ - size_t len = strlen(source_path); + size_t len = strlen(root_disk_path); char name[len + 1 + FILENAME_MAX + 1]; - memcpy(name, source_path, len); + memcpy(name, root_disk_path, len); name[len] = '/'; /* Create a dentry for each entry in the directory on disk, and recurse @@ -104,39 +136,53 @@ static int build_dentry_tree(struct dentry *root, const char *source_path, || (p->d_name[1] == '.' && p->d_name[2] == '\0'))) continue; strcpy(name + len + 1, p->d_name); - if (stat(name, &child_stat) != 0) { - ERROR_WITH_ERRNO("Cannot stat `%s'", name); - ret = WIMLIB_ERR_STAT; - break; - } child = new_dentry(p->d_name); - if (!child) { - ERROR("No memory to allocate new dentry"); + if (!child) return WIMLIB_ERR_NOMEM; - } - ret = build_dentry_tree(child, name, &child_stat, - lookup_table); + ret = build_dentry_tree(child, name, lookup_table, + add_flags); link_dentry(child, root); if (ret != 0) break; } closedir(dir); + } else if (dentry_is_symlink(root)) { + /* Archiving a symbolic link */ + size_t symlink_buf_len; + char deref_name_buf[4096]; + ssize_t deref_name_len; + + deref_name_len = readlink(root_disk_path, deref_name_buf, + sizeof(deref_name_buf) - 1); + if (deref_name_len == -1) { + ERROR_WITH_ERRNO("Failed to read target of " + "symbolic link `%s'", root_disk_path); + return WIMLIB_ERR_READLINK; + } + deref_name_buf[deref_name_len] = '\0'; + DEBUG("Read symlink `%s'", deref_name_buf); + ret = dentry_set_symlink(root, deref_name_buf, + lookup_table, NULL); } else { + /* Regular file */ struct lookup_table_entry *lte; + u8 hash[SHA1_HASH_SIZE]; - /* For each non-directory, we must check to see if the file is - * in the lookup table already; if it is, we increment its - * refcnt; otherwise, we create a new lookup table entry and - * insert it. */ - ret = sha1sum(source_path, root->hash); + /* For each regular file, we must check to see if the file is in + * the lookup table already; if it is, we increment its refcnt; + * otherwise, we create a new lookup table entry and insert it. + * */ + ret = sha1sum(root_disk_path, hash); if (ret != 0) return ret; - lte = lookup_resource(lookup_table, root->hash); + lte = __lookup_resource(lookup_table, hash); if (lte) { lte->refcnt++; + DEBUG("Add lte reference %u for `%s'", lte->refcnt, + root_disk_path); } else { - char *file_on_disk = STRDUP(source_path); + char *file_on_disk = STRDUP(root_disk_path); if (!file_on_disk) { ERROR("Failed to allocate memory for file path"); return WIMLIB_ERR_NOMEM; @@ -147,14 +193,13 @@ static int build_dentry_tree(struct dentry *root, const char *source_path, return WIMLIB_ERR_NOMEM; } lte->file_on_disk = file_on_disk; - lte->resource_entry.flags = 0; - lte->refcnt = 1; - lte->part_number = 1; - lte->resource_entry.original_size = root_stat->st_size; - lte->resource_entry.size = root_stat->st_size; - memcpy(lte->hash, root->hash, WIM_HASH_SIZE); + lte->resource_location = RESOURCE_IN_FILE_ON_DISK; + lte->resource_entry.original_size = root_stbuf.st_size; + lte->resource_entry.size = root_stbuf.st_size; + copy_hash(lte->hash, hash); lookup_table_insert(lookup_table, lte); } + root->lte = lte; } return ret; } @@ -172,38 +217,38 @@ struct wim_pair { * entry is created that references the location of the file resource in the * source WIM file through the other_wim_fp field of the lookup table entry. */ -static int add_lookup_table_entry_to_dest_wim(struct dentry *dentry, void *arg) +static int add_lte_to_dest_wim(struct dentry *dentry, void *arg) { WIMStruct *src_wim, *dest_wim; - struct lookup_table_entry *src_table_entry; - struct lookup_table_entry *dest_table_entry; src_wim = ((struct wim_pair*)arg)->src_wim; dest_wim = ((struct wim_pair*)arg)->dest_wim; - if (dentry_is_directory(dentry)) - return 0; - - src_table_entry = wim_lookup_resource(src_wim, dentry); - if (!src_table_entry) - return 0; - - dest_table_entry = wim_lookup_resource(dest_wim, dentry); - if (dest_table_entry) { - dest_table_entry->refcnt++; - } else { - dest_table_entry = new_lookup_table_entry(); - if (!dest_table_entry) - return WIMLIB_ERR_NOMEM; - dest_table_entry->other_wim_fp = src_wim->fp; - dest_table_entry->other_wim_ctype = - wimlib_get_compression_type(src_wim); - dest_table_entry->refcnt = 1; - memcpy(&dest_table_entry->resource_entry, - &src_table_entry->resource_entry, - sizeof(struct resource_entry)); - memcpy(dest_table_entry->hash, dentry->hash, WIM_HASH_SIZE); - lookup_table_insert(dest_wim->lookup_table, dest_table_entry); + wimlib_assert(!dentry->resolved); + + for (unsigned i = 0; i < (unsigned)dentry->num_ads + 1; i++) { + struct lookup_table_entry *src_lte, *dest_lte; + src_lte = dentry_stream_lte_unresolved(dentry, i, + src_wim->lookup_table); + if (!src_lte) + continue; + dest_lte = dentry_stream_lte_unresolved(dentry, i, + dest_wim->lookup_table); + if (dest_lte) { + dest_lte->refcnt++; + } else { + dest_lte = new_lookup_table_entry(); + if (!dest_lte) + return WIMLIB_ERR_NOMEM; + dest_lte->resource_location = RESOURCE_IN_WIM; + dest_lte->wim = src_wim; + memcpy(&dest_lte->resource_entry, + &src_lte->resource_entry, + sizeof(struct resource_entry)); + copy_hash(dest_lte->hash, + dentry_stream_hash_unresolved(dentry, i)); + lookup_table_insert(dest_wim->lookup_table, dest_lte); + } } return 0; } @@ -223,9 +268,8 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) struct lookup_table_entry *metadata_lte; struct image_metadata *imd; struct image_metadata *new_imd; -#ifdef ENABLE_SECURITY_DATA struct wim_security_data *sd; -#endif + struct link_group_table *lgt; DEBUG("Reallocating image metadata array for image_count = %u", w->hdr.image_count + 1); @@ -242,32 +286,36 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) metadata_lte = new_lookup_table_entry(); if (!metadata_lte) goto out_free_imd; -#ifdef ENABLE_SECURITY_DATA sd = CALLOC(1, sizeof(struct wim_security_data)); if (!sd) goto out_free_metadata_lte; sd->refcnt = 1; sd->total_length = 8; -#endif + + lgt = new_link_group_table(9001); + if (!lgt) + goto out_free_security_data; metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA; - randomize_byte_array(metadata_lte->hash, WIM_HASH_SIZE); + random_hash(metadata_lte->hash); lookup_table_insert(w->lookup_table, metadata_lte); - w->hdr.image_count++; + new_imd = &imd[w->hdr.image_count]; - new_imd = &imd[w->hdr.image_count - 1]; - new_imd->metadata_lte = metadata_lte; - new_imd->modified = true; new_imd->root_dentry = root_dentry; -#ifdef ENABLE_SECURITY_DATA + new_imd->metadata_lte = metadata_lte; new_imd->security_data = sd; -#endif + new_imd->lgt = lgt; + new_imd->modified = true; + FREE(w->image_metadata); w->image_metadata = imd; + w->hdr.image_count++; /* Change the current image to the new one. */ return wimlib_select_image(w, w->hdr.image_count); +out_free_security_data: + FREE(sd); out_free_metadata_lte: FREE(metadata_lte); out_free_imd: @@ -357,7 +405,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, /* Cleaning up here on failure would be hard. For example, we could - * fail to allocate memory in add_lookup_table_entry_to_dest_wim(), + * fail to allocate memory in add_lte_to_dest_wim(), * leaving the lookup table entries in the destination WIM in an * inconsistent state. Until these issues can be resolved, * wimlib_export_image() is documented as leaving dest_wim is an @@ -366,13 +414,12 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, for_dentry_in_tree(root, increment_dentry_refcnt, NULL); wims.src_wim = src_wim; wims.dest_wim = dest_wim; - ret = for_dentry_in_tree(root, add_lookup_table_entry_to_dest_wim, &wims); + ret = for_dentry_in_tree(root, add_lte_to_dest_wim, &wims); if (ret != 0) return ret; ret = add_new_dentry_tree(dest_wim, root); if (ret != 0) return ret; -#ifdef ENABLE_SECURITY_DATA /* Bring over old security data */ struct wim_security_data *sd = wim_security_data(src_wim); struct image_metadata *new_imd = wim_get_current_image_metadata(dest_wim); @@ -380,7 +427,6 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, free_security_data(new_imd->security_data); new_imd->security_data = sd; sd->refcnt++; -#endif if (flags & WIMLIB_EXPORT_FLAG_BOOT) { DEBUG("Setting boot_idx to %d", dest_wim->hdr.image_count); @@ -399,7 +445,6 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image) int num_images; int i; int ret; - struct image_metadata *imd; if (image == WIM_ALL_IMAGES) { num_images = w->hdr.image_count; @@ -458,7 +503,6 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, const char *flags_element, int flags) { struct dentry *root_dentry; - struct stat root_stat; struct image_metadata *imd; int ret; @@ -484,33 +528,17 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, root_dentry = new_dentry(""); if (!root_dentry) return WIMLIB_ERR_NOMEM; - ret = calculate_dentry_full_path(root_dentry, NULL); - if (ret != 0) - goto out_free_dentry_tree; - - root_dentry->attributes |= WIM_FILE_ATTRIBUTE_DIRECTORY; - - /* Construct the dentry tree from the outside filesystem. */ - if (stat(dir, &root_stat) != 0) { - ERROR_WITH_ERRNO("Failed to stat `%s'", dir); - ret = WIMLIB_ERR_STAT; - goto out_free_dentry_tree; - } - if (!S_ISDIR(root_stat.st_mode)) { - ERROR("`%s' is not a directory", dir); - ret = WIMLIB_ERR_NOTDIR; - goto out_free_dentry_tree; - } DEBUG("Building dentry tree."); - ret = build_dentry_tree(root_dentry, dir, &root_stat, w->lookup_table); + ret = build_dentry_tree(root_dentry, dir, w->lookup_table, + flags | WIMLIB_ADD_IMAGE_FLAG_ROOT); if (ret != 0) { ERROR("Failed to build dentry tree for `%s'", dir); goto out_free_dentry_tree; } - DEBUG("Recalculating full paths of dentries."); + DEBUG("Calculating full paths of dentries."); ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL); if (ret != 0) goto out_free_dentry_tree; @@ -519,6 +547,14 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, if (ret != 0) goto out_free_dentry_tree; + DEBUG("Inserting dentries into hard link group table"); + ret = for_dentry_in_tree(root_dentry, link_group_table_insert, + w->image_metadata[w->hdr.image_count - 1].lgt); + if (ret != 0) + goto out_destroy_imd; + DEBUG("Assigning hard link groups"); + assign_link_groups(w->image_metadata[w->hdr.image_count - 1].lgt); + if (flags & WIMLIB_ADD_IMAGE_FLAG_BOOT) wimlib_set_boot_idx(w, w->hdr.image_count); @@ -530,8 +566,9 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, out_destroy_imd: destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1], w->lookup_table); + w->hdr.image_count--; return ret; out_free_dentry_tree: - free_dentry_tree(root_dentry, w->lookup_table, true); + free_dentry_tree(root_dentry, w->lookup_table); return ret; }