if (ret)
return ret;
- ctx->supported_features.archive_files = 1;
- ctx->supported_features.hidden_files = 1;
- ctx->supported_features.system_files = 1;
- ctx->supported_features.compressed_files = !!(vol_flags & FILE_FILE_COMPRESSION);
- ctx->supported_features.encrypted_files = !!(vol_flags & FILE_SUPPORTS_ENCRYPTION);
+ ctx->supported_features.archive_files = 1;
+ ctx->supported_features.hidden_files = 1;
+ ctx->supported_features.system_files = 1;
+
+ if (vol_flags & FILE_FILE_COMPRESSION)
+ ctx->supported_features.compressed_files = 1;
+
+ if (vol_flags & FILE_SUPPORTS_ENCRYPTION) {
+ ctx->supported_features.encrypted_files = 1;
+ ctx->supported_features.encrypted_directories = 1;
+ }
+
ctx->supported_features.not_context_indexed_files = 1;
- ctx->supported_features.sparse_files = !!(vol_flags & FILE_SUPPORTS_SPARSE_FILES);
- ctx->supported_features.named_data_streams = !!(vol_flags & FILE_NAMED_STREAMS);
- ctx->supported_features.hard_links = !!(vol_flags & FILE_SUPPORTS_HARD_LINKS);
- ctx->supported_features.reparse_points = !!(vol_flags & FILE_SUPPORTS_REPARSE_POINTS);
- ctx->supported_features.security_descriptors = !!(vol_flags & FILE_PERSISTENT_ACLS);
- ctx->supported_features.short_names = !!supports_SetFileShortName;
+
+ if (vol_flags & FILE_SUPPORTS_SPARSE_FILES)
+ ctx->supported_features.sparse_files = 1;
+
+ if (vol_flags & FILE_NAMED_STREAMS)
+ ctx->supported_features.named_data_streams = 1;
+
+ if (vol_flags & FILE_SUPPORTS_HARD_LINKS)
+ ctx->supported_features.hard_links = 1;
+
+ if (vol_flags & FILE_SUPPORTS_REPARSE_POINTS) {
+ ctx->supported_features.reparse_points = 1;
+ if (win32func_CreateSymbolicLinkW)
+ ctx->supported_features.symlink_reparse_points = 1;
+ }
+
+ if (vol_flags & FILE_PERSISTENT_ACLS)
+ ctx->supported_features.security_descriptors = 1;
+
+ if (supports_SetFileShortName)
+ ctx->supported_features.short_names = 1;
return 0;
}
static int
-win32_create_file(const wchar_t *path, struct apply_ctx *ctx)
+win32_create_file(const wchar_t *path, struct apply_ctx *ctx, u64 *cookie_ret)
{
HANDLE h;
}
static int
-win32_create_directory(const wchar_t *path, struct apply_ctx *ctx)
+win32_create_directory(const wchar_t *path, struct apply_ctx *ctx,
+ u64 *cookie_ret)
{
if (!CreateDirectory(path, NULL))
if (GetLastError() != ERROR_ALREADY_EXISTS)
win32_create_hardlink(const wchar_t *oldpath, const wchar_t *newpath,
struct apply_ctx *ctx)
{
- if (!CreateHardLink(newpath, oldpath, NULL))
- goto error;
+ if (!CreateHardLink(newpath, oldpath, NULL)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ goto error;
+ if (!DeleteFile(newpath))
+ goto error;
+ if (!CreateHardLink(newpath, oldpath, NULL))
+ goto error;
+ }
+ return 0;
+
+error:
+ set_errno_from_GetLastError();
+ return WIMLIB_ERR_LINK;
+}
+
+static int
+win32_create_symlink(const wchar_t *oldpath, const wchar_t *newpath,
+ struct apply_ctx *ctx)
+{
+ if (!(*win32func_CreateSymbolicLinkW)(newpath, oldpath, 0)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ goto error;
+ if (!DeleteFile(newpath))
+ goto error;
+ if (!(*win32func_CreateSymbolicLinkW)(newpath, oldpath, 0))
+ goto error;
+ }
return 0;
error:
stream_path = alloca(sizeof(wchar_t) *
(wcslen(path) + 1 +
wcslen(stream_name) + 1));
- swprintf(stream_path, L"%ls:%ls", path, stream_name);
+ tsprintf(stream_path, L"%ls:%ls", path, stream_name);
}
h = CreateFile(stream_path, FILE_WRITE_DATA, 0, NULL,
ret = 0;
if (!lte)
goto out_close_handle;
- ret = extract_wim_resource(lte, wim_resource_size(lte),
- win32_extract_wim_chunk, h);
+ ret = extract_stream(lte, lte->size, win32_extract_wim_chunk, h);
out_close_handle:
if (!CloseHandle(h))
goto error;
}
static int
-win32_extract_unnamed_stream(const wchar_t *path,
+win32_extract_unnamed_stream(file_spec_t file,
struct wim_lookup_table_entry *lte,
struct apply_ctx *ctx)
{
- return win32_extract_stream(path, NULL, 0, lte, ctx);
+ return win32_extract_stream(file.path, NULL, 0, lte, ctx);
}
static int
-win32_extract_named_stream(const wchar_t *path, const wchar_t *stream_name,
+win32_extract_named_stream(file_spec_t file, const wchar_t *stream_name,
size_t stream_name_nchars,
struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
{
- return win32_extract_stream(path, stream_name,
+ return win32_extract_stream(file.path, stream_name,
stream_name_nchars, lte, ctx);
}
unsigned long len = *len_p;
const struct wim_lookup_table_entry *lte = import_ctx->lte;
- len = min(len, wim_resource_size(lte) - import_ctx->offset);
+ len = min(len, lte->size - import_ctx->offset);
- if (read_partial_wim_resource_into_buf(lte, len, import_ctx->offset, data))
+ if (read_partial_wim_stream_into_buf(lte, len, import_ctx->offset, data))
return ERROR_READ_FAULT;
import_ctx->offset += len;
err = OpenEncryptedFileRaw(path, CREATE_FOR_IMPORT, &file_ctx);
if (err != ERROR_SUCCESS) {
- errno = win32_error_to_errno(err);
+ set_errno_from_win32_error(err);
ret = WIMLIB_ERR_OPEN;
goto out;
}
err = WriteEncryptedFileRaw(win32_encrypted_import_cb, &extract_ctx,
file_ctx);
if (err != ERROR_SUCCESS) {
- errno = win32_error_to_errno(err);
+ set_errno_from_win32_error(err);
ret = WIMLIB_ERR_WRITE;
goto out_close;
}
USHORT compression_format = COMPRESSION_FORMAT_DEFAULT;
DWORD bytes_returned;
- h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
+ h = win32_open_existing_file(path, GENERIC_READ | GENERIC_WRITE);
if (h == INVALID_HANDLE_VALUE)
goto error;
static int
win32_set_file_attributes(const wchar_t *path, u32 attributes,
- struct apply_ctx *ctx)
+ struct apply_ctx *ctx, unsigned pass)
{
u32 special_attributes =
FILE_ATTRIBUTE_REPARSE_POINT |
FILE_ATTRIBUTE_ENCRYPTED;
u32 actual_attributes;
+ /* Delay setting FILE_ATTRIBUTE_READONLY on the initial pass (when files
+ * are created, but data not extracted); otherwise the system will
+ * refuse access to the file even if the process has SeRestorePrivilege.
+ */
+ if (pass == 0)
+ attributes &= ~FILE_ATTRIBUTE_READONLY;
+
if (!SetFileAttributes(path, attributes & ~special_attributes))
goto error;
+ if (pass != 0)
+ return 0;
+
if (attributes & (FILE_ATTRIBUTE_SPARSE_FILE |
FILE_ATTRIBUTE_ENCRYPTED |
FILE_ATTRIBUTE_COMPRESSED))
DWORD bytes_returned;
USHORT compression_format = COMPRESSION_FORMAT_NONE;
- h = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
+ h = win32_open_existing_file(path, GENERIC_READ | GENERIC_WRITE);
if (h == INVALID_HANDLE_VALUE)
goto error;
goto error;
}
-success:
return 0;
error:
DWORD err;
DWORD bytes_returned;
- h = CreateFile(path, GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
+ h = win32_open_existing_file(path, GENERIC_WRITE);
if (h == INVALID_HANDLE_VALUE)
goto error;
HANDLE h;
DWORD err;
- h = CreateFile(path, GENERIC_WRITE | DELETE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
+ h = win32_open_existing_file(path, GENERIC_WRITE | DELETE);
if (h == INVALID_HANDLE_VALUE)
goto error;
return WIMLIB_ERR_WRITE; /* XXX: need better error code */
}
+static DWORD
+do_win32_set_security_descriptor(HANDLE h, const wchar_t *path,
+ SECURITY_INFORMATION info,
+ PSECURITY_DESCRIPTOR desc)
+{
+#ifdef WITH_NTDLL
+ if (func_NtSetSecurityObject) {
+ return (*func_RtlNtStatusToDosError)(
+ (*func_NtSetSecurityObject)(h, info, desc));
+ }
+#endif
+ if (SetFileSecurity(path, info, desc))
+ return ERROR_SUCCESS;
+ else
+ return GetLastError();
+}
+
static int
-win32_set_security_descriptor(const wchar_t *path, const u8 *desc, size_t desc_size,
- struct apply_ctx *ctx)
+win32_set_security_descriptor(const wchar_t *path, const u8 *desc,
+ size_t desc_size, struct apply_ctx *ctx)
{
SECURITY_INFORMATION info;
+ HANDLE h;
+ DWORD err;
+ int ret;
+
+ info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+ h = INVALID_HANDLE_VALUE;
+
+#ifdef WITH_NTDLL
+ if (func_NtSetSecurityObject) {
+ h = win32_open_existing_file(path, MAXIMUM_ALLOWED);
+ if (h == INVALID_HANDLE_VALUE) {
+ ERROR_WITH_ERRNO("Can't open %ls (%u)", path, GetLastError());
+ goto error;
+ }
+ }
+#endif
- info = OWNER_SECURITY_INFORMATION |
- GROUP_SECURITY_INFORMATION |
- DACL_SECURITY_INFORMATION |
- SACL_SECURITY_INFORMATION;
-retry:
- if (!SetFileSecurity(path, info, (PSECURITY_DESCRIPTOR)desc)) {
- if (!(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS) &&
- GetLastError() == ERROR_PRIVILEGE_NOT_HELD &&
- (info & SACL_SECURITY_INFORMATION))
+ for (;;) {
+ err = do_win32_set_security_descriptor(h, path, info,
+ (PSECURITY_DESCRIPTOR)desc);
+ if (err == ERROR_SUCCESS)
+ break;
+ if ((err == ERROR_PRIVILEGE_NOT_HELD ||
+ err == ERROR_ACCESS_DENIED) &&
+ !(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
{
- info &= ~SACL_SECURITY_INFORMATION;
- goto retry;
+ if (info & SACL_SECURITY_INFORMATION) {
+ info &= ~SACL_SECURITY_INFORMATION;
+ ctx->partial_security_descriptors++;
+ continue;
+ }
+ if (info & DACL_SECURITY_INFORMATION) {
+ info &= ~DACL_SECURITY_INFORMATION;
+ continue;
+ }
+ if (info & OWNER_SECURITY_INFORMATION) {
+ info &= ~OWNER_SECURITY_INFORMATION;
+ continue;
+ }
+ ctx->partial_security_descriptors--;
+ ctx->no_security_descriptors++;
+ break;
}
+ SetLastError(err);
goto error;
}
- return 0;
+ ret = 0;
+out_close:
+#ifdef WITH_NTDLL
+ if (func_NtSetSecurityObject)
+ CloseHandle(h);
+#endif
+ return ret;
error:
set_errno_from_GetLastError();
- return WIMLIB_ERR_SET_SECURITY;
+ ret = WIMLIB_ERR_SET_SECURITY;
+ goto out_close;
}
static int
FILETIME lastWriteTime = {.dwLowDateTime = last_write_time & 0xffffffff,
.dwHighDateTime = last_write_time >> 32};
- h = CreateFile(path, FILE_WRITE_ATTRIBUTES, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
+ h = win32_open_existing_file(path, FILE_WRITE_ATTRIBUTES);
if (h == INVALID_HANDLE_VALUE)
goto error;
.create_file = win32_create_file,
.create_directory = win32_create_directory,
.create_hardlink = win32_create_hardlink,
+ .create_symlink = win32_create_symlink,
.extract_unnamed_stream = win32_extract_unnamed_stream,
.extract_named_stream = win32_extract_named_stream,
.extract_encrypted_stream = win32_extract_encrypted_stream,
.requires_realtarget_in_paths = 1,
.realpath_works_on_nonexisting_files = 1,
.root_directory_is_special = 1,
+ .requires_final_set_attributes_pass = 1,
+ .extract_encrypted_stream_creates_file = 1,
+ .requires_short_name_reordering = 1, /* TODO: check if this is really needed */
};
#endif /* __WIN32__ */