* extract_image.c
*
* Support for extracting WIM files.
- *
- * This code does NOT contain any filesystem-specific features. In particular,
- * security information (i.e. file permissions) and alternate data streams are
- * ignored, except possibly to read an alternate data stream that contains
- * symbolic link data.
*/
/*
#include "config.h"
#if defined(__CYGWIN__) || defined(__WIN32__)
-#include <windows.h>
-#ifdef ERROR
-#undef ERROR
-#endif
-#include <wchar.h>
+# include <windows.h>
+# ifdef ERROR
+# undef ERROR
+# endif
+# include <wchar.h>
+#else
+# include <dirent.h>
+# ifdef HAVE_UTIME_H
+# include <utime.h>
+# endif
+# include "timestamp.h"
+# include <sys/time.h>
#endif
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#ifdef HAVE_UTIME_H
-#include <utime.h>
-#endif
#include <unistd.h>
#include "dentry.h"
#include "lookup_table.h"
-#include "timestamp.h"
#include "wimlib_internal.h"
#include "xml.h"
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
-#else
-#include <stdlib.h>
+#endif
+
+#if defined(__WIN32__)
+# define swprintf _snwprintf
+# define mkdir(path, mode) (!CreateDirectoryA(path, NULL))
#endif
#if defined(__CYGWIN__) || defined(__WIN32__)
/* Named stream. Create a buffer that contains the UTF-16LE
* string [./]@path:@stream_name_utf16. This is needed to
* create and open the stream using CreateFileW(). I'm not
- * aware of any other APIs to do this. Note: note that the
- * '$DATA' suffix seems to be unneeded; Additional note: a "./"
- * prefix needs to be added when the path is not absolute to
- * avoid ambiguity with drive letters. */
+ * aware of any other APIs to do this. Note: the '$DATA' suffix
+ * seems to be unneeded. Additional note: a "./" prefix needs
+ * to be added when the path is not absolute to avoid ambiguity
+ * with drive letters. */
size_t stream_path_nchars;
size_t path_nchars;
size_t stream_name_nchars;
const wchar_t *prefix;
- path_nchars = wcslen(path);
+ path_nchars = wcslen(path);
stream_name_nchars = wcslen(stream_name_utf16);
stream_path_nchars = path_nchars + 1 + stream_name_nchars;
- if (path[0] != L'/' && path[1] != L'\\') {
+ if (path[0] != L'/' && path[0] != L'\\') {
prefix = L"./";
stream_path_nchars += 2;
} else {
swprintf(stream_path, stream_path_nchars + 1, L"%ls%ls:%ls",
prefix, path, stream_name_utf16);
} else {
- /* Unnamed stream; it's path is just the path to the file
- * itself. */
+ /* Unnamed stream; its path is just the path to the file itself.
+ * */
stream_path = (wchar_t*)path;
/* Directories must be created with CreateDirectoryW(). Then
err = GetLastError();
if (err != ERROR_ALREADY_EXISTS) {
ERROR("Failed to create directory \"%ls\"",
- path);
+ stream_path);
win32_error(err);
ret = WIMLIB_ERR_MKDIR;
goto fail;
DEBUG("Opening \"%ls\"", stream_path);
h = CreateFileW(stream_path,
- GENERIC_WRITE | WRITE_OWNER | WRITE_DAC,
+ GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
0,
NULL,
creationDisposition,
goto fail_close_handle;
} else {
if (lte) {
- DEBUG("Extracting \"%ls\" (len = %zu)",
+ DEBUG("Extracting \"%ls\" (len = %"PRIu64")",
stream_path, wim_resource_size(lte));
ret = do_win32_extract_stream(h, lte);
if (ret)
* Returns 0 on success; nonzero on failure.
*/
static int win32_extract_streams(struct wim_inode *inode,
- const wchar_t *path)
+ const wchar_t *path, u64 *completed_bytes_p)
{
struct wim_lookup_table_entry *unnamed_lte;
int ret;
ret = win32_extract_stream(inode, path, NULL, unnamed_lte);
if (ret)
goto out;
+ if (unnamed_lte)
+ *completed_bytes_p += wim_resource_size(unnamed_lte);
for (u16 i = 0; i < inode->i_num_ads; i++) {
const struct wim_ads_entry *ads_entry = &inode->i_ads_entries[i];
if (ads_entry->stream_name_len != 0) {
ads_entry->lte);
if (ret)
break;
+ if (ads_entry->lte)
+ *completed_bytes_p += wim_resource_size(ads_entry->lte);
}
}
out:
* @inode: The WIM inode that was extracted and has a security descriptor.
* @path: UTF-16LE external path that the inode was extracted to.
* @sd: Security data for the WIM image.
- * @path_utf8: @path in UTF-8 for error messages only.
*
* Returns 0 on success; nonzero on failure.
*/
return 0;
}
-#else
+#else /* __CYGWIN__ || __WIN32__ */
static int extract_regular_file_linked(struct wim_dentry *dentry,
const char *output_path,
struct apply_args *args,
return 0;
}
-#endif /* !__CYGWIN__ && !__WIN32__ */
+#endif /* !(__CYGWIN__ || __WIN32__) */
static int extract_directory(struct wim_dentry *dentry,
const char *output_path, bool is_root)
} else {
/* Create the file, directory, or reparse point, and extract the
* data streams. */
- ret = win32_extract_streams(inode, (const wchar_t*)utf16_path);
+ ret = win32_extract_streams(inode, (const wchar_t*)utf16_path,
+ &args->progress.extract.completed_bytes);
if (ret)
goto out_free_utf16_path;
size_t utf16_path_len;
DWORD err;
HANDLE h;
- BOOL bret1, bret2;
ret = utf8_to_utf16(output_path, len, &utf16_path, &utf16_path_len);
if (ret)
return ret;
- DEBUG("Opening \"%ls\" to set timestamps", utf16_path);
- h = CreateFileW(utf16_path, GENERIC_WRITE, FILE_SHARE_READ,
- NULL, OPEN_EXISTING,
+ DEBUG("Opening \"%s\" to set timestamps", output_path);
+ h = CreateFileW((const wchar_t*)utf16_path,
+ GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
NULL);
if (h == INVALID_HANDLE_VALUE)
goto fail;
- FILETIME creationTime = {.dwLowDateTime = dentry->d_inode->i_creation_time & 0xffffffff,
- .dwHighDateTime = dentry->d_inode->i_creation_time >> 32};
- FILETIME lastAccessTime = {.dwLowDateTime = dentry->d_inode->i_last_access_time & 0xffffffff,
- .dwHighDateTime = dentry->d_inode->i_last_access_time >> 32};
- FILETIME lastWriteTime = {.dwLowDateTime = dentry->d_inode->i_last_write_time & 0xffffffff,
- .dwHighDateTime = dentry->d_inode->i_last_write_time >> 32};
+ FILETIME creationTime = {.dwLowDateTime = inode->i_creation_time & 0xffffffff,
+ .dwHighDateTime = inode->i_creation_time >> 32};
+ FILETIME lastAccessTime = {.dwLowDateTime = inode->i_last_access_time & 0xffffffff,
+ .dwHighDateTime = inode->i_last_access_time >> 32};
+ FILETIME lastWriteTime = {.dwLowDateTime = inode->i_last_write_time & 0xffffffff,
+ .dwHighDateTime = inode->i_last_write_time >> 32};
DEBUG("Calling SetFileTime() on \"%s\"", output_path);
if (!SetFileTime(h, &creationTime, &lastAccessTime, &lastWriteTime)) {
err = GetLastError();
goto fail;
}
- return 0;
+ goto out;
fail:
- ERROR("Can't set timestamps on \"%s\"", output_path);
+ /* Only warn if setting timestamps failed. */
+ WARNING("Can't set timestamps on \"%s\"", output_path);
win32_error(err);
- return WIMLIB_ERR_WRITE;
+out:
+ return 0;
#else
/* UNIX */
w->lookup_table = joined_tab;
}
+#if defined(__CYGWIN__) || defined(__WIN32__)
+ win32_acquire_privilege(SE_RESTORE_NAME);
+ win32_acquire_privilege(SE_SECURITY_NAME);
+ win32_acquire_privilege(SE_TAKE_OWNERSHIP_NAME);
+#endif
if (image == WIMLIB_ALL_IMAGES) {
extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
ret = extract_all_images(w, target, extract_flags,
ret = extract_single_image(w, image, target, extract_flags,
progress_func);
}
+#if defined(__CYGWIN__) || defined(__WIN32__)
+ win32_release_privilege(SE_RESTORE_NAME);
+ win32_release_privilege(SE_SECURITY_NAME);
+ win32_release_privilege(SE_TAKE_OWNERSHIP_NAME);
+#endif
if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
WIMLIB_EXTRACT_FLAG_HARDLINK))