X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmodify.c;h=744ab2d7cdb42b908a80e3a944e095272e5eff8b;hb=36011d478b941ecaffbbbe98ec82f83916908add;hp=fde95d098c9a3fc97186b138d6db1a9aa95e0000;hpb=ef8f45b98b5c4db398321cd36d052ccbb9c3784a;p=wimlib diff --git a/src/modify.c b/src/modify.c index fde95d09..744ab2d7 100644 --- a/src/modify.c +++ b/src/modify.c @@ -36,16 +36,25 @@ #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); + if (lt) + free_dentry_tree(imd->root_dentry, lt, true); + else + free_dentry_tree(imd->root_dentry, NULL, false); free_security_data(imd->security_data); + 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); } /* @@ -54,9 +63,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 @@ -68,31 +75,52 @@ 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) { - int ret = 0; + DEBUG("%s", root_disk_path); + struct stat root_stbuf; + int ret; + int (*stat_fn)(const char *restrict, struct stat *restrict); + + if (add_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) + stat_fn = stat; + else + stat_fn = lstat; + + + 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; + } + stbuf_to_dentry(&root_stbuf, root); + add_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT; - 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 @@ -102,39 +130,47 @@ 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 ret = readlink(root_disk_path, deref_name_buf, + sizeof(deref_name_buf) - 1); + if (ret == -1) { + ERROR_WITH_ERRNO("Failed to read target of " + "symbolic link `%s'", root_disk_path); + return WIMLIB_ERR_STAT; + } + deref_name_buf[ret] = '\0'; + DEBUG("Read symlink `%s'", deref_name_buf); + ret = dentry_set_symlink(root, deref_name_buf, lookup_table); } else { + /* Regular file */ struct lookup_table_entry *lte; - /* 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, root->hash); if (ret != 0) return ret; - lte = lookup_resource(lookup_table, root->hash); + lte = __lookup_resource(lookup_table, root->hash); if (lte) { lte->refcnt++; } 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; @@ -145,11 +181,8 @@ 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; + lte->resource_entry.original_size = root_stbuf.st_size; + lte->resource_entry.size = root_stbuf.st_size; memcpy(lte->hash, root->hash, WIM_HASH_SIZE); lookup_table_insert(lookup_table, lte); } @@ -182,11 +215,13 @@ static int add_lookup_table_entry_to_dest_wim(struct dentry *dentry, void *arg) if (dentry_is_directory(dentry)) return 0; - src_table_entry = wim_lookup_resource(src_wim, dentry); + /* XXX ADS */ + src_table_entry = __lookup_resource(src_wim->lookup_table, dentry->hash); if (!src_table_entry) return 0; - dest_table_entry = wim_lookup_resource(dest_wim, dentry); + /* XXX ADS */ + dest_table_entry = __lookup_resource(dest_wim->lookup_table, dentry->hash); if (dest_table_entry) { dest_table_entry->refcnt++; } else { @@ -222,6 +257,7 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) struct image_metadata *imd; struct image_metadata *new_imd; struct wim_security_data *sd; + struct link_group_table *lgt; DEBUG("Reallocating image metadata array for image_count = %u", w->hdr.image_count + 1); @@ -244,22 +280,30 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) sd->refcnt = 1; sd->total_length = 8; + 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); 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; + new_imd->metadata_lte = metadata_lte; new_imd->security_data = sd; + 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: @@ -447,7 +491,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; @@ -478,21 +521,11 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, if (ret != 0) goto out_free_dentry_tree; - root_dentry->attributes |= WIM_FILE_ATTRIBUTE_DIRECTORY; + root_dentry->attributes |= 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); @@ -508,6 +541,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); @@ -519,6 +560,7 @@ 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);