}
/* Recurse on directory contents */
+ ret = 0;
for (;;) {
errno = 0;
entry = readdir(dir);
return ret;
}
-static char *
-fixup_symlink(char *dest, ino_t capture_root_ino, dev_t capture_root_dev)
-{
- char *p = dest;
- struct stat stbuf;
-
- for (;;) {
- char save;
- int ret;
-
- while (*p == '/')
- p++;
-
- save = *p;
- *p = '\0';
- if (stat(dest, &stbuf)) {
- WARNING_WITH_ERRNO("Failed to stat \"%s\": %m", dest);
- *p = save;
- /* Treat as a link pointing outside the capture root (it
- * most likely is). */
- return NULL;
- }
- *p = save;
-
- if (stbuf.st_ino == capture_root_ino &&
- stbuf.st_dev == capture_root_dev)
- {
- /* Link points inside capture root. Return abbreviated
- * path. */
- if (*p == '\0')
- *(p - 1) = '/';
- while (p - 1 >= dest && *(p - 1) == '/')
- p--;
- return p;
- }
-
- if (*p == '\0') {
- /* Link points outside capture root. */
- return NULL;
- }
-
- do {
- p++;
- } while (*p != '/' && *p != '\0');
- }
-}
-
static int
unix_capture_symlink(struct wim_dentry **root_p,
const char *path,
if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX) &&
dest[0] == '/')
{
- dest = fixup_symlink(dest,
- params->capture_root_ino,
- params->capture_root_dev);
+ dest = capture_fixup_absolute_symlink(dest,
+ params->capture_root_ino,
+ params->capture_root_dev);
if (!dest) {
WARNING("Ignoring out of tree absolute symlink "
"\"%s\" -> \"%s\"\n"
*root_p = NULL;
return 0;
}
+ inode->i_not_rpfixed = 0;
}
- ret = inode_set_symlink(inode, dest,
- params->lookup_table, NULL);
+ ret = wim_inode_set_symlink(inode, dest, params->lookup_table);
if (ret == 0) {
/* Unfortunately, Windows seems to have the concept of
* "file" symbolic links as being different from
struct wim_inode *inode;
if (exclude_path(path, path_len, params->config, true)) {
- if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
- ERROR("Cannot exclude the root directory from capture");
- ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
- goto out;
- }
if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
&& params->progress_func)
{
ret = inode_table_new_dentry(params->inode_table,
path_basename_with_len(path, path_len),
- stbuf.st_ino,
- stbuf.st_dev,
- &root);
+ stbuf.st_ino, stbuf.st_dev, false, &root);
if (ret)
goto out;
return WIMLIB_ERR_STAT;
}
- if (!S_ISDIR(root_stbuf.st_mode)) {
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
+ !S_ISDIR(root_stbuf.st_mode))
+ {
ERROR("Root of capture \"%s\" is not a directory",
root_disk_path);
return WIMLIB_ERR_NOTDIR;
}
-/* Strip leading and trailing forward slashes from a string. Modifies it in
- * place and returns the stripped string. */
-static const tchar *
-canonicalize_target_path(tchar *target_path)
-{
- tchar *p;
- if (target_path == NULL)
- return T("");
- for (;;) {
- if (*target_path == T('\0'))
- return target_path;
- else if (*target_path == T('/'))
- target_path++;
- else
- break;
- }
-
- p = tstrchr(target_path, T('\0')) - 1;
- while (*p == T('/'))
- *p-- = T('\0');
- return target_path;
-}
-
/* Strip leading and trailing slashes from the target paths, and translate all
* backslashes in the source and target paths into forward slashes. */
static void
/* The Windows API can handle forward slashes. Just get rid of
* backslashes to avoid confusing other parts of the library
* code. */
- zap_backslashes(sources->fs_source_path);
- if (sources->wim_target_path)
- zap_backslashes(sources->wim_target_path);
-
- sources->wim_target_path =
- (tchar*)canonicalize_target_path(sources->wim_target_path);
+ sources->fs_source_path = canonicalize_fs_path(sources->fs_source_path);
+ sources->wim_target_path = canonicalize_wim_path(sources->wim_target_path);
DEBUG("Canonical target: \"%"TS"\"", sources->wim_target_path);
sources++;
}
return ret;
}
-/* Transfers the children of @branch to @target. It is an error if @target is
- * not a directory or if both @branch and @target contain a child dentry with
- * the same name. */
+/* Overlays @branch onto @target, both of which must be directories. */
static int
do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
{
DEBUG("Doing overlay \"%"WS"\" => \"%"WS"\"",
branch->file_name, target->file_name);
- if (!dentry_is_directory(target)) {
- ERROR("Cannot overlay directory \"%"WS"\" "
- "over non-directory", branch->file_name);
+ if (!dentry_is_directory(branch) || !dentry_is_directory(target)) {
+ ERROR("Cannot overlay \"%"WS"\" onto existing dentry: "
+ "is not directory-on-directory!", branch->file_name);
return WIMLIB_ERR_INVALID_OVERLAY;
}
rb_root = &branch->d_inode->i_children;
while (rb_root->rb_node) { /* While @branch has children... */
struct wim_dentry *child = rbnode_dentry(rb_root->rb_node);
+ struct wim_dentry *existing;
+
/* Move @child to the directory @target */
unlink_dentry(child);
- if (!dentry_add_child(target, child)) {
- /* Revert the change to avoid leaking the directory tree
- * rooted at @child */
- dentry_add_child(branch, child);
- ERROR("Overlay error: file \"%"WS"\" already exists "
- "as a child of \"%"WS"\"",
- child->file_name, target->file_name);
- return WIMLIB_ERR_INVALID_OVERLAY;
+ existing = dentry_add_child(target, child);
+
+ /* File or directory with same name already exists */
+ if (existing) {
+ int ret;
+ ret = do_overlay(existing, child);
+ if (ret) {
+ /* Overlay failed. Revert the change to avoid
+ * leaking the directory tree rooted at @child.
+ * */
+ dentry_add_child(branch, child);
+ return ret;
+ }
}
}
free_dentry(branch);
return 0;
-
}
/* Attach or overlay a branch onto the WIM image.
if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == 0)
- if (w->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+ {
+ /* Do reparse-point fixups by default if the header flag is set
+ * from previous images, or if this is the first image being
+ * added. */
+ if ((w->hdr.flags & WIM_HDR_FLAG_RP_FIX) || w->hdr.image_count == 0)
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+ }
if (!name || !*name) {
ERROR("Must specify a non-empty string for the image name");