/*
- * Copyright (C) 2013 Eric Biggers
+ * unix_capture.c: Capture a directory tree on UNIX.
+ */
+
+/*
+ * Copyright (C) 2012, 2013 Eric Biggers
*
* This file is part of wimlib, a library for working with WIM files.
*
#ifndef __WIN32__
-#include "wimlib_internal.h"
-#include "dentry.h"
-#include "lookup_table.h"
-#include "timestamp.h"
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include <dirent.h>
#include <errno.h>
-#include <unistd.h>
+#include <limits.h>
#include <sys/stat.h>
+#include <unistd.h>
+
+#include "wimlib/capture.h"
+#include "wimlib/dentry.h"
+#include "wimlib/error.h"
+#include "wimlib/lookup_table.h"
+#include "wimlib/paths.h"
+#include "wimlib/reparse.h"
+#include "wimlib/timestamp.h"
static int
unix_capture_regular_file(const char *path,
u64 size,
struct wim_inode *inode,
- struct wim_lookup_table *lookup_table)
+ struct list_head *unhashed_streams)
{
inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
}
lte->file_on_disk = file_on_disk;
lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
- lte->resource_entry.original_size = size;
- lookup_table_insert_unhashed(lookup_table, lte, inode, 0);
+ lte->size = size;
+ add_unhashed_stream(lte, inode, 0, unhashed_streams);
inode->i_lte = lte;
}
return 0;
if (!dir) {
ERROR_WITH_ERRNO("Failed to open the directory `%s'",
path);
- return WIMLIB_ERR_OPEN;
+ return WIMLIB_ERR_OPENDIR;
}
/* Recurse on directory contents */
if (child)
dentry_add_child(dir_dentry, child);
}
+ path[path_len] = '\0';
closedir(dir);
return ret;
}
inode->i_attributes = FILE_ATTRIBUTE_REPARSE_POINT;
inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
- /* The idea here is to call readlink() to get the UNIX target of
- * the symbolic link, then turn the target into a reparse point
- * data buffer that contains a relative or absolute symbolic
- * link (NOT a junction point or *full* path symbolic link with
- * drive letter).
- */
+ /* The idea here is to call readlink() to get the UNIX target of the
+ * symbolic link, then turn the target into a reparse point data buffer
+ * that contains a relative or absolute symbolic link. */
deref_name_len = readlink(path, deref_name_buf,
sizeof(deref_name_buf) - 1);
if (deref_name_len >= 0) {
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"
- " (Use --norpfix to capture "
- "absolute symlinks as-is)",
- path, deref_name_buf);
+ if (dest == NULL) {
+ /* RPFIX (reparse point fixup) mode: Ignore
+ * absolute symbolic link that points out of the
+ * tree to be captured. */
free_dentry(*root_p);
*root_p = NULL;
+ params->progress.scan.cur_path = path;
+ params->progress.scan.symlink_target = deref_name_buf;
+ do_capture_progress(params,
+ WIMLIB_SCAN_DENTRY_EXCLUDED_SYMLINK,
+ NULL);
return 0;
}
inode->i_not_rpfixed = 0;
struct add_image_params *params)
{
struct wim_dentry *root = NULL;
- int ret = 0;
- struct wim_inode *inode;
+ int ret;
+ struct wim_inode *inode = NULL;
+ struct stat stbuf;
if (exclude_path(path, path_len, params->config, true)) {
- if ((params->add_flags & WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE)
- && params->progress_func)
- {
- union wimlib_progress_info info;
- info.scan.cur_path = path;
- info.scan.excluded = true;
- params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
- }
- goto out;
- }
-
- if ((params->add_flags & WIMLIB_ADD_FLAG_VERBOSE)
- && params->progress_func)
- {
- union wimlib_progress_info info;
- info.scan.cur_path = path;
- info.scan.excluded = false;
- params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
+ ret = 0;
+ goto out_progress;
}
- struct stat stbuf;
- int (*stat_fn)(const char *restrict, struct stat *restrict);
if ((params->add_flags & WIMLIB_ADD_FLAG_DEREFERENCE) ||
(params->add_flags & WIMLIB_ADD_FLAG_ROOT))
- stat_fn = stat;
+ ret = stat(path, &stbuf);
else
- stat_fn = lstat;
+ ret = lstat(path, &stbuf);
- ret = (*stat_fn)(path, &stbuf);
- if (ret != 0) {
- ERROR_WITH_ERRNO("Failed to stat `%s'", path);
+ if (ret) {
+ ERROR_WITH_ERRNO("Failed to stat \"%s\"", path);
+ ret = WIMLIB_ERR_STAT;
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.",
- path);
- ret = WIMLIB_ERR_SPECIAL_FILE;
+
+ if (!S_ISREG(stbuf.st_mode) &&
+ !S_ISDIR(stbuf.st_mode) &&
+ !S_ISLNK(stbuf.st_mode))
+ {
+ if (params->add_flags & WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE)
+ {
+ ERROR("Can't archive unsupported file \"%s\"", path);
+ ret = WIMLIB_ERR_UNSUPPORTED_FILE;
+ goto out;
+ }
+ params->progress.scan.cur_path = path;
+ do_capture_progress(params, WIMLIB_SCAN_DENTRY_UNSUPPORTED, NULL);
+ ret = 0;
goto out;
}
ret = inode_table_new_dentry(params->inode_table,
path_basename_with_len(path, path_len),
- stbuf.st_ino, stbuf.st_dev, false, &root);
+ stbuf.st_ino, stbuf.st_dev,
+ S_ISDIR(stbuf.st_mode), &root);
if (ret)
goto out;
inode = root->d_inode;
- if (inode->i_nlink > 1) /* Already captured this inode? */
- goto out;
+ if (inode->i_nlink > 1) {
+ /* Already captured this inode? */
+ ret = 0;
+ goto out_progress;
+ }
#ifdef HAVE_STAT_NANOSECOND_PRECISION
inode->i_creation_time = timespec_to_wim_timestamp(stbuf.st_mtim);
params->add_flags &= ~WIMLIB_ADD_FLAG_ROOT;
if (S_ISREG(stbuf.st_mode))
ret = unix_capture_regular_file(path, stbuf.st_size,
- inode, params->lookup_table);
+ inode, params->unhashed_streams);
else if (S_ISDIR(stbuf.st_mode))
ret = unix_capture_directory(root, path, path_len, params);
- else
+ else {
ret = unix_capture_symlink(&root, path, inode, params);
-out:
- if (ret == 0)
- *root_ret = root;
+ if (root == NULL)
+ goto out;
+ }
+
+ if (ret)
+ goto out;
+
+out_progress:
+ params->progress.scan.cur_path = path;
+ if (root == NULL)
+ do_capture_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
else
+ do_capture_progress(params, WIMLIB_SCAN_DENTRY_OK, inode);
+out:
+ if (ret)
free_dentry_tree(root, params->lookup_table);
+ else
+ *root_ret = root;
return ret;
}
/*
* unix_build_dentry_tree():
- * Builds a tree of WIM dentries from an on-disk directory tree (UNIX
- * version; no NTFS-specific data is captured).
+ * Builds a tree of WIM dentries from an on-disk directory tree (UNIX
+ * version; no NTFS-specific data is captured).
*
* @root_ret: Place to return a pointer to the root of the dentry tree. Only
* modified if successful. Set to NULL if the file or directory was
return WIMLIB_ERR_STAT;
}
- if ((params->add_flags & WIMLIB_ADD_FLAG_ROOT) &&
- !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;
}
if (path_len >= path_bufsz)
return WIMLIB_ERR_INVALID_PARAM;
- path_buf = MALLOC(path_bufsz);
+ path_buf = MALLOC(path_bufsz);
if (!path_buf)
return WIMLIB_ERR_NOMEM;
memcpy(path_buf, root_disk_path, path_len + 1);