X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fupdate_image.c;h=892049cff816e9e2875dfaaee40254a4764e93eb;hb=f32f8032fbced9b9e00771cdf8bcc28d214ba199;hp=70038d42d0e605bbea400ef9a9406bf2779a88b2;hpb=269f10a27c62027d48c0ba58f164d20e3bf3cf85;p=wimlib diff --git a/src/update_image.c b/src/update_image.c index 70038d42..892049cf 100644 --- a/src/update_image.c +++ b/src/update_image.c @@ -328,15 +328,13 @@ static int journaled_link(struct update_command_journal *j, struct wim_dentry *subject, struct wim_dentry *parent) { - struct update_primitive prim = { - .type = LINK_DENTRY, - .link = { - .subject = subject, - .parent = parent, - }, - }; + struct update_primitive prim; int ret; + prim.type = LINK_DENTRY; + prim.link.subject = subject; + prim.link.parent = parent; + ret = record_update_primitive(j, prim); if (ret) return ret; @@ -356,21 +354,18 @@ journaled_link(struct update_command_journal *j, static int journaled_unlink(struct update_command_journal *j, struct wim_dentry *subject) { - int ret; struct wim_dentry *parent; + struct update_primitive prim; + int ret; if (dentry_is_root(subject)) parent = NULL; else parent = subject->parent; - struct update_primitive prim = { - .type = UNLINK_DENTRY, - .link = { - .subject = subject, - .parent = parent, - }, - }; + prim.type = UNLINK_DENTRY; + prim.link.subject = subject; + prim.link.parent = parent; ret = record_update_primitive(j, prim); if (ret) @@ -458,21 +453,33 @@ rollback_update(struct update_command_journal *j) free_update_command_journal(j); } +/* + * Set the name of @branch for placing it at @target in the WIM image. This + * assumes that @target is in "canonical form", as produced by + * canonicalize_wim_path(). + * + * Note: for the root target this produces the empty name. + */ static int set_branch_name(struct wim_dentry *branch, const utf16lechar *target) { const utf16lechar *p; + /* Find end of string. (We can assume it contains at least one + * character, the leading slash.) */ + wimlib_assert(target[0] == cpu_to_le16(WIM_PATH_SEPARATOR)); p = target; - while (*p) + do { p++; + } while (*p); - /* No trailing slashes allowed */ - wimlib_assert(p == target || *(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR)); - - while (p > target && *(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR)) + while (*(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR)) p--; + + /* We're assuming no trailing slashes. */ + wimlib_assert(*p || p == &target[1]); + return dentry_set_name_utf16le(branch, p); } @@ -842,10 +849,7 @@ execute_add_command(struct update_command_journal *j, if (progress_func) progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, ¶ms.progress); - config.prefix = fs_source_path; - config.prefix_num_tchars = tstrlen(fs_source_path); - - if (wim_target_path[0] == T('\0')) + if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path)) params.add_flags |= WIMLIB_ADD_FLAG_ROOT; ret = (*capture_tree)(&branch, fs_source_path, ¶ms); if (ret) @@ -854,7 +858,7 @@ execute_add_command(struct update_command_journal *j, if (progress_func) progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, ¶ms.progress); - if (wim_target_path[0] == T('\0') && + if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path) && branch && !dentry_is_directory(branch)) { ERROR("\"%"TS"\" is not a directory!", fs_source_path); @@ -869,7 +873,7 @@ execute_add_command(struct update_command_journal *j, goto out_cleanup_after_capture; if (config_file && (add_flags & WIMLIB_ADD_FLAG_WIMBOOT) && - wim_target_path[0] == T('\0')) + WIMLIB_IS_WIM_ROOT_PATH(wim_target_path)) { params.add_flags = 0; params.progress_func = NULL; @@ -949,6 +953,19 @@ free_dentry_full_path(struct wim_dentry *dentry, void *_ignore) return 0; } +/* Is @d1 a (possibly nonproper) ancestor of @d2? */ +static bool +is_ancestor(struct wim_dentry *d1, struct wim_dentry *d2) +{ + for (;;) { + if (d2 == d1) + return true; + if (dentry_is_root(d2)) + return false; + d2 = d2->parent; + } +} + /* Rename a file or directory in the WIM. * * This returns a -errno value. @@ -1003,29 +1020,29 @@ rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to, return -ENOTDIR; } + /* @src can't be an ancestor of @dst. Otherwise we're unlinking @src + * from the tree and creating a loop... */ + if (is_ancestor(src, parent_of_dst)) + return -EBUSY; + if (j) { + if (dst) + if (journaled_unlink(j, dst)) + return -ENOMEM; + if (journaled_unlink(j, src)) + return -ENOMEM; if (journaled_change_name(j, src, path_basename(to))) return -ENOMEM; + if (journaled_link(j, src, parent_of_dst)) + return -ENOMEM; } else { ret = dentry_set_name(src, path_basename(to)); if (ret) return -ENOMEM; - } - if (dst) { - if (j) { - if (journaled_unlink(j, dst)) - return -ENOMEM; - } else { + if (dst) { unlink_dentry(dst); free_dentry_tree(dst, wim->lookup_table); } - } - if (j) { - if (journaled_unlink(j, src)) - return -ENOMEM; - if (journaled_link(j, src, parent_of_dst)) - return -ENOMEM; - } else { unlink_dentry(src); dentry_add_child(parent_of_dst, src); } @@ -1059,6 +1076,9 @@ execute_rename_command(struct update_command_journal *j, ret = WIMLIB_ERR_NOTDIR; break; case ENOTEMPTY: + case EBUSY: + /* XXX: EBUSY is returned when the rename would create a + * loop. It maybe should have its own error code. */ ret = WIMLIB_ERR_NOTEMPTY; break; case EISDIR: @@ -1232,12 +1252,7 @@ check_add_command(struct wimlib_update_command *cmd, WIMLIB_ADD_FLAG_NO_REPLACE)) return WIMLIB_ERR_INVALID_PARAM; - /* Are we adding the entire image or not? An empty wim_target_path - * indicates that the tree we're adding is to be placed in the root of - * the image. We consider this to be capturing the entire image, - * although it could potentially be an overlay on an existing root as - * well. */ - bool is_entire_image = cmd->add.wim_target_path[0] == T('\0'); + bool is_entire_image = WIMLIB_IS_WIM_ROOT_PATH(cmd->add.wim_target_path); #ifdef __WIN32__ /* Check for flags not supported on Windows */ @@ -1354,9 +1369,7 @@ free_update_commands(struct wimlib_update_command *cmds, size_t num_cmds) for (size_t i = 0; i < num_cmds; i++) { switch (cmds[i].op) { case WIMLIB_UPDATE_OP_ADD: - FREE(cmds[i].add.fs_source_path); FREE(cmds[i].add.wim_target_path); - FREE(cmds[i].add.config_file); break; case WIMLIB_UPDATE_OP_DELETE: FREE(cmds[i].delete_.wim_path); @@ -1387,18 +1400,12 @@ copy_update_commands(const struct wimlib_update_command *cmds, cmds_copy[i].op = cmds[i].op; switch (cmds[i].op) { case WIMLIB_UPDATE_OP_ADD: - cmds_copy[i].add.fs_source_path = - canonicalize_fs_path(cmds[i].add.fs_source_path); + cmds_copy[i].add.fs_source_path = cmds[i].add.fs_source_path; cmds_copy[i].add.wim_target_path = canonicalize_wim_path(cmds[i].add.wim_target_path); - if (!cmds_copy[i].add.fs_source_path || - !cmds_copy[i].add.wim_target_path) + if (!cmds_copy[i].add.wim_target_path) goto oom; - if (cmds[i].add.config_file) { - cmds_copy[i].add.config_file = TSTRDUP(cmds[i].add.config_file); - if (!cmds_copy[i].add.config_file) - goto oom; - } + cmds_copy[i].add.config_file = cmds[i].add.config_file; cmds_copy[i].add.add_flags = cmds[i].add.add_flags; break; case WIMLIB_UPDATE_OP_DELETE: