unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
char *path,
size_t path_len,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- const struct wimlib_capture_config *config,
- int add_image_flags,
- wimlib_progress_func_t progress_func);
+ struct add_image_params *params);
static int
unix_capture_directory(struct wim_dentry *dir_dentry,
char *path,
size_t path_len,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- const struct wimlib_capture_config *config,
- int add_image_flags,
- wimlib_progress_func_t progress_func)
+ struct add_image_params *params)
{
DIR *dir;
ret = unix_build_dentry_tree_recursive(&child,
path,
path_len + 1 + name_len,
- lookup_table,
- inode_table,
- config,
- add_image_flags,
- progress_func);
+ params);
if (ret)
break;
if (child)
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(const char *path,
+unix_capture_symlink(struct wim_dentry **root_p,
+ const char *path,
struct wim_inode *inode,
- struct wim_lookup_table *lookup_table)
+ struct add_image_params *params)
{
char deref_name_buf[4096];
ssize_t deref_name_len;
deref_name_len = readlink(path, deref_name_buf,
sizeof(deref_name_buf) - 1);
if (deref_name_len >= 0) {
- deref_name_buf[deref_name_len] = '\0';
- DEBUG("Read symlink `%s'", deref_name_buf);
- ret = inode_set_symlink(inode, deref_name_buf,
- lookup_table, NULL);
+ char *dest = deref_name_buf;
+
+ dest[deref_name_len] = '\0';
+ DEBUG("Read symlink `%s'", dest);
+
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX) &&
+ dest[0] == '/')
+ {
+ dest = fixup_symlink(dest,
+ params->capture_root_ino,
+ params->capture_root_dev);
+ if (!dest) {
+ WARNING("Ignoring out of tree absolute symlink "
+ "\"%s\" -> \"%s\"\n"
+ " (Use --norpfix to capture "
+ "absolute symlinks as-is)",
+ path, deref_name_buf);
+ free_dentry(*root_p);
+ *root_p = NULL;
+ return 0;
+ }
+ }
+ ret = inode_set_symlink(inode, dest,
+ params->lookup_table, NULL);
if (ret == 0) {
/* Unfortunately, Windows seems to have the concept of
* "file" symbolic links as being different from
unix_build_dentry_tree_recursive(struct wim_dentry **root_ret,
char *path,
size_t path_len,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- const struct wimlib_capture_config *config,
- int add_image_flags,
- wimlib_progress_func_t progress_func)
+ struct add_image_params *params)
{
struct wim_dentry *root = NULL;
int ret = 0;
struct wim_inode *inode;
- if (exclude_path(path, path_len, config, true)) {
- if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
+ 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 ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
- && progress_func)
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
+ && params->progress_func)
{
union wimlib_progress_info info;
info.scan.cur_path = path;
info.scan.excluded = true;
- progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+ params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
}
goto out;
}
- if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
- && progress_func)
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
+ && params->progress_func)
{
union wimlib_progress_info info;
info.scan.cur_path = path;
info.scan.excluded = false;
- progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+ params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
}
- /* UNIX version of capturing a directory tree */
struct stat stbuf;
int (*stat_fn)(const char *restrict, struct stat *restrict);
- if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) ||
+ (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT))
stat_fn = stat;
else
stat_fn = lstat;
ERROR_WITH_ERRNO("Failed to stat `%s'", path);
goto out;
}
-
- if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
- !S_ISDIR(stbuf.st_mode))
- {
- /* Do a dereference-stat in case the root is a symbolic link.
- * This case is allowed, provided that the symbolic link points
- * to a directory. */
- ret = stat(path, &stbuf);
- if (ret != 0) {
- ERROR_WITH_ERRNO("Failed to stat `%s'", path);
- ret = WIMLIB_ERR_STAT;
- goto out;
- }
- if (!S_ISDIR(stbuf.st_mode)) {
- ERROR("`%s' is not a directory", path);
- ret = WIMLIB_ERR_NOTDIR;
- goto out;
- }
- }
if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)
&& !S_ISLNK(stbuf.st_mode)) {
ERROR("`%s' is not a regular file, directory, or symbolic link.",
goto out;
}
- ret = inode_table_new_dentry(inode_table,
+ ret = inode_table_new_dentry(params->inode_table,
path_basename_with_len(path, path_len),
stbuf.st_ino,
stbuf.st_dev,
inode->i_last_access_time = unix_timestamp_to_wim(stbuf.st_atime);
#endif
inode->i_resolved = 1;
- if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
+ if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
ret = inode_set_unix_data(inode, stbuf.st_uid,
stbuf.st_gid,
stbuf.st_mode,
- lookup_table,
+ params->lookup_table,
UNIX_DATA_ALL | UNIX_DATA_CREATE);
if (ret)
goto out;
}
- add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
+ params->add_image_flags &=
+ ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
if (S_ISREG(stbuf.st_mode))
ret = unix_capture_regular_file(path, stbuf.st_size,
- inode, lookup_table);
+ inode, params->lookup_table);
else if (S_ISDIR(stbuf.st_mode))
- ret = unix_capture_directory(root, path, path_len,
- lookup_table, inode_table, config,
- add_image_flags, progress_func);
+ ret = unix_capture_directory(root, path, path_len, params);
else
- ret = unix_capture_symlink(path, inode, lookup_table);
+ ret = unix_capture_symlink(&root, path, inode, params);
out:
if (ret == 0)
*root_ret = root;
else
- free_dentry_tree(root, lookup_table);
+ free_dentry_tree(root, params->lookup_table);
return ret;
}
*
* @root_disk_path: The path to the root of the directory 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 stream is already in the lookup table.
- * These lookup table entries that are added point to the path of
- * the file on disk.
- *
- * @sd_set: Ignored. (Security data only captured in NTFS mode.)
- *
- * @config:
- * Configuration for files to be excluded from capture.
- *
- * @add_flags: Bitwise or of WIMLIB_ADD_IMAGE_FLAG_*
- *
- * @extra_arg: Ignored
+ * @params: See doc for `struct add_image_params'.
*
* @return: 0 on success, nonzero on failure. It is a failure if any of
* the files cannot be `stat'ed, or if any of the needed
static int
unix_build_dentry_tree(struct wim_dentry **root_ret,
const char *root_disk_path,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- struct sd_set *sd_set,
- const struct wimlib_capture_config *config,
- int add_image_flags,
- wimlib_progress_func_t progress_func,
- void *extra_arg)
+ struct add_image_params *params)
{
char *path_buf;
int ret;
size_t path_len;
size_t path_bufsz;
+ {
+ struct stat root_stbuf;
+ if (stat(root_disk_path, &root_stbuf)) {
+ ERROR_WITH_ERRNO("Failed to stat \"%s\"", root_disk_path);
+ return WIMLIB_ERR_STAT;
+ }
+
+ if (!S_ISDIR(root_stbuf.st_mode)) {
+ ERROR("Root of capture \"%s\" is not a directory",
+ root_disk_path);
+ return WIMLIB_ERR_NOTDIR;
+ }
+ params->capture_root_ino = root_stbuf.st_ino;
+ params->capture_root_dev = root_stbuf.st_dev;
+ }
+
path_bufsz = min(32790, PATH_MAX + 1);
path_len = strlen(root_disk_path);
if (!path_buf)
return WIMLIB_ERR_NOMEM;
memcpy(path_buf, root_disk_path, path_len + 1);
- ret = unix_build_dentry_tree_recursive(root_ret,
- path_buf,
- path_len,
- lookup_table,
- inode_table,
- config,
- add_image_flags,
- progress_func);
+
+ ret = unix_build_dentry_tree_recursive(root_ret, path_buf,
+ path_len, params);
FREE(path_buf);
return ret;
}
{
int (*capture_tree)(struct wim_dentry **,
const tchar *,
- struct wim_lookup_table *,
- struct wim_inode_table *,
- struct sd_set *,
- const struct wimlib_capture_config *,
- int,
- wimlib_progress_func_t,
- void *);
+ struct add_image_params *);
void *extra_arg;
struct wim_dentry *root_dentry;
struct wim_dentry *branch;
struct wim_image_metadata *imd;
struct wim_inode_table inode_table;
struct list_head unhashed_streams;
+ struct add_image_params params;
int ret;
struct sd_set sd_set;
#ifdef WITH_NTFS_3G
if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE;
+ if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
+ WIMLIB_ADD_IMAGE_FLAG_RPFIX)) ==
+ (WIMLIB_ADD_IMAGE_FLAG_RPFIX | WIMLIB_ADD_IMAGE_FLAG_NORPFIX))
+ {
+ ERROR("Cannot specify RPFIX and NORPFIX flags at the same time!");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
+
+ if ((add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_RPFIX |
+ WIMLIB_ADD_IMAGE_FLAG_NORPFIX)) == 0)
+ if (w->hdr.flags & WIM_HDR_FLAG_RP_FIX)
+ add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+
if (!name || !*name) {
ERROR("Must specify a non-empty string for the image name");
return WIMLIB_ERR_INVALID_PARAM;
INIT_LIST_HEAD(&unhashed_streams);
w->lookup_table->unhashed_streams = &unhashed_streams;
root_dentry = NULL;
+
+ params.lookup_table = w->lookup_table;
+ params.inode_table = &inode_table;
+ params.sd_set = &sd_set;
+ params.config = config;
+ params.add_image_flags = add_image_flags;
+ params.progress_func = progress_func;
+ params.extra_arg = extra_arg;
for (size_t i = 0; i < num_sources; i++) {
int flags;
union wimlib_progress_info progress;
flags = add_image_flags | WIMLIB_ADD_IMAGE_FLAG_SOURCE;
if (!*sources[i].wim_target_path)
flags |= WIMLIB_ADD_IMAGE_FLAG_ROOT;
- ret = (*capture_tree)(&branch,
- sources[i].fs_source_path,
- w->lookup_table,
- &inode_table,
- &sd_set,
- config,
- flags,
- progress_func, extra_arg);
+ ret = (*capture_tree)(&branch, sources[i].fs_source_path,
+ ¶ms);
if (ret) {
ERROR("Failed to build dentry tree for `%"TS"'",
sources[i].fs_source_path);
if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
wimlib_set_boot_idx(w, w->hdr.image_count);
+ if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX)
+ w->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
+
ret = 0;
goto out_destroy_inode_table;
out_put_imd:
ntfs_inode *dir_ni;
char *path;
size_t path_len;
- struct wim_lookup_table *lookup_table;
- struct wim_inode_table *inode_table;
- struct sd_set *sd_set;
struct dos_name_map *dos_name_map;
- const struct wimlib_capture_config *config;
ntfs_volume *vol;
- int add_image_flags;
- wimlib_progress_func_t progress_func;
+ struct add_image_params *params;
};
static int
char *path,
size_t path_len,
int name_type,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- struct sd_set *sd_set,
- const struct wimlib_capture_config *config,
ntfs_volume *ntfs_vol,
- int add_image_flags,
- wimlib_progress_func_t progress_func);
+ struct add_image_params *params);
static int
wim_ntfs_capture_filldir(void *dirent, const ntfschar *name,
child = NULL;
ret = build_dentry_tree_ntfs_recursive(&child, ctx->dir_ni,
ni, ctx->path, path_len, name_type,
- ctx->lookup_table,
- ctx->inode_table,
- ctx->sd_set,
- ctx->config, ctx->vol,
- ctx->add_image_flags,
- ctx->progress_func);
+ ctx->vol, ctx->params);
if (child)
dentry_add_child(ctx->parent, child);
ntfs_inode_close(ni);
char *path,
size_t path_len,
int name_type,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- struct sd_set *sd_set,
- const struct wimlib_capture_config *config,
ntfs_volume *vol,
- int add_image_flags,
- wimlib_progress_func_t progress_func)
+ struct add_image_params *params)
{
u32 attributes;
int ret;
struct wim_inode *inode;
ATTR_TYPES stream_type;
- if (exclude_path(path, path_len, config, false)) {
+ if (exclude_path(path, path_len, params->config, false)) {
/* Exclude a file or directory tree based on the capture
* configuration file */
- if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
- && progress_func)
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE)
+ && params->progress_func)
{
union wimlib_progress_info info;
info.scan.cur_path = path;
info.scan.excluded = true;
- progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+ params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
}
root = NULL;
ret = 0;
return WIMLIB_ERR_NTFS_3G;
}
- if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
- && progress_func)
+ if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
+ && params->progress_func)
{
union wimlib_progress_info info;
info.scan.cur_path = path;
info.scan.excluded = false;
- progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+ params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
}
/* Create a WIM dentry with an associated inode, which may be shared */
- ret = inode_table_new_dentry(inode_table,
+ ret = inode_table_new_dentry(params->inode_table,
path_basename_with_len(path, path_len),
ni->mft_no,
0,
* - Directories: capture any named data streams
* - Reparse points: capture reparse data only
*/
- ret = capture_ntfs_streams(inode, ni, path, path_len, lookup_table,
- vol, stream_type);
+ ret = capture_ntfs_streams(inode, ni, path, path_len,
+ params->lookup_table, vol, stream_type);
if (ret)
goto out;
.dir_ni = ni,
.path = path,
.path_len = path_len,
- .lookup_table = lookup_table,
- .inode_table = inode_table,
- .sd_set = sd_set,
.dos_name_map = &dos_name_map,
- .config = config,
.vol = vol,
- .add_image_flags = add_image_flags,
- .progress_func = progress_func,
+ .params = params,
};
ret = ntfs_readdir(ni, &pos, &ctx, wim_ntfs_capture_filldir);
if (ret) {
goto out;
}
- if (!(add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)) {
+ if (!(params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS)) {
/* Get security descriptor */
char _sd[1];
char *sd = _sd;
ni, dir_ni, sd, ret);
}
if (ret > 0) {
- inode->i_security_id = sd_set_add_sd(sd_set, sd, ret);
+ inode->i_security_id = sd_set_add_sd(params->sd_set,
+ sd, ret);
if (inode->i_security_id == -1) {
ERROR("Out of memory");
ret = WIMLIB_ERR_NOMEM;
if (ret == 0)
*root_ret = root;
else
- free_dentry_tree(root, lookup_table);
+ free_dentry_tree(root, params->lookup_table);
return ret;
}
int
build_dentry_tree_ntfs(struct wim_dentry **root_p,
const char *device,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- struct sd_set *sd_set,
- const struct wimlib_capture_config *config,
- int add_image_flags,
- wimlib_progress_func_t progress_func,
- void *extra_arg)
+ struct add_image_params *params)
{
ntfs_volume *vol;
ntfs_inode *root_ni;
path[0] = '/';
path[1] = '\0';
ret = build_dentry_tree_ntfs_recursive(root_p, NULL, root_ni, path, 1,
- FILE_NAME_POSIX, lookup_table,
- inode_table,
- sd_set,
- config, vol,
- add_image_flags,
- progress_func);
+ FILE_NAME_POSIX, vol, params);
out_cleanup:
FREE(path);
ntfs_inode_close(root_ni);
} else {
/* We need to leave the NTFS volume mounted so that we can read
* the NTFS files again when we are actually writing the WIM */
- *(ntfs_volume**)extra_arg = vol;
+ *(ntfs_volume**)params->extra_arg = vol;
}
return ret;
}
* file (if supported by the underlying filesystem). */
#define WIM_HDR_FLAG_WRITE_IN_PROGRESS 0x00000040
-/* Reparse point fixup ???
- * This has something to do with absolute targets of reparse points / symbolic
- * links but I don't know what. wimlib ignores this flag. */
+/* Reparse point fixup flag. See docs for --rpfix and --norpfix in imagex, or
+ * WIMLIB_ADD_IMAGE_FLAG_{RPFIX,NORPFIX} in wimlib.h. Note that
+ * WIM_HDR_FLAG_RP_FIX is a header flag and just sets the default behavior for
+ * the WIM; it can still be overridder on a per-image basis. But there is no
+ * flag to set the default behavior for a specific image. */
#define WIM_HDR_FLAG_RP_FIX 0x00000080
/* Unused, reserved flag for another compression type */
/* add_image.c */
-extern bool
-exclude_path(const tchar *path, size_t path_len,
- const struct wimlib_capture_config *config,
- bool exclude_prefix);
-
-/* extract_image.c */
-
-/* Internal use only */
-#define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000
-#define WIMLIB_EXTRACT_FLAG_NO_STREAMS 0x40000000
-#define WIMLIB_EXTRACT_MASK_PUBLIC 0x3fffffff
-
-/* hardlink.c */
-
/* Hash table to find inodes, given an inode number (in the case of reading
* a WIM images), or both an inode number and a device number (in the case of
* capturing a WIM image). */
struct list_head extra_inodes;
};
+/* Common parameters to implementations of building an in-memory dentry tree
+ * from an on-disk directory structure. */
+struct add_image_params {
+ /* Pointer to the lookup table of the WIM. */
+ struct wim_lookup_table *lookup_table;
+
+ /* Pointer to a hash table of inodes that have been captured for this
+ * WIM image so far. */
+ struct wim_inode_table *inode_table;
+
+ /* Pointer to the set of security descriptors that have been captured
+ * for this image so far. */
+ struct sd_set *sd_set;
+
+ /* Pointer to the capture configuration, which indicates whether any
+ * files should be excluded from capture or not. */
+ const struct wimlib_capture_config *config;
+
+ /* Flags that affect the capture operation (WIMLIB_ADD_IMAGE_FLAG_*) */
+ int add_image_flags;
+
+ /* If non-NULL, the user-supplied progress function. */
+ wimlib_progress_func_t progress_func;
+
+ /* Extra argument; set to point to a pointer to the ntfs_volume for
+ * libntfs-3g capture. */
+ void *extra_arg;
+
+ u64 capture_root_ino;
+ u64 capture_root_dev;
+};
+
+extern bool
+exclude_path(const tchar *path, size_t path_len,
+ const struct wimlib_capture_config *config,
+ bool exclude_prefix);
+
+/* extract_image.c */
+
+/* Internal use only */
+#define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000
+#define WIMLIB_EXTRACT_FLAG_NO_STREAMS 0x40000000
+#define WIMLIB_EXTRACT_MASK_PUBLIC 0x3fffffff
+
+/* hardlink.c */
+
extern int
init_inode_table(struct wim_inode_table *table, size_t capacity);
extern int
build_dentry_tree_ntfs(struct wim_dentry **root_p,
const tchar *device,
- struct wim_lookup_table *lookup_table,
- struct wim_inode_table *inode_table,
- struct sd_set *sd_set,
- const struct wimlib_capture_config *config,
- int add_image_flags,
- wimlib_progress_func_t progress_func,
- void *extra_arg);
+ struct add_image_params *ctx);
#ifdef WITH_NTFS_3G
extern int