+}
+
+static int
+free_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
+{
+ FREE(dentry->_full_path);
+ dentry->_full_path = NULL;
+ return 0;
+}
+
+/* Rename a file or directory in the WIM. */
+int
+rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to,
+ CASE_SENSITIVITY_TYPE case_type)
+{
+ struct wim_dentry *src;
+ struct wim_dentry *dst;
+ struct wim_dentry *parent_of_dst;
+ int ret;
+
+ /* This rename() implementation currently only supports actual files
+ * (not alternate data streams) */
+
+ src = get_dentry(wim, from, case_type);
+ if (!src)
+ return -errno;
+
+ dst = get_dentry(wim, to, case_type);
+
+ if (dst) {
+ /* Destination file exists */
+
+ if (src == dst) /* Same file */
+ return 0;
+
+ if (!dentry_is_directory(src)) {
+ /* Cannot rename non-directory to directory. */
+ if (dentry_is_directory(dst))
+ return -EISDIR;
+ } else {
+ /* Cannot rename directory to a non-directory or a non-empty
+ * directory */
+ if (!dentry_is_directory(dst))
+ return -ENOTDIR;
+ if (dentry_has_children(dst))
+ return -ENOTEMPTY;
+ }
+ parent_of_dst = dst->parent;
+ } else {
+ /* Destination does not exist */
+ parent_of_dst = get_parent_dentry(wim, to, case_type);
+ if (!parent_of_dst)
+ return -errno;
+
+ if (!dentry_is_directory(parent_of_dst))
+ return -ENOTDIR;
+ }
+
+ ret = set_dentry_name(src, path_basename(to));
+ if (ret)
+ return -ENOMEM;
+ if (dst) {
+ unlink_dentry(dst);
+ free_dentry_tree(dst, wim->lookup_table);
+ }
+ unlink_dentry(src);
+ dentry_add_child(parent_of_dst, src);
+ if (src->_full_path)
+ for_dentry_in_tree(src, free_dentry_full_path, NULL);
+ return 0;