4 * Capture a WIM image from a NTFS volume. We capture everything we can,
5 * including security data and alternate data streams. There should be no loss
10 * Copyright (C) 2012 Eric Biggers
12 * This file is part of wimlib, a library for working with WIM files.
14 * wimlib is free software; you can redistribute it and/or modify it under the
15 * terms of the GNU Lesser General Public License as published by the Free
16 * Software Foundation; either version 2.1 of the License, or (at your option)
19 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
20 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
21 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with wimlib; if not, see http://www.gnu.org/licenses/.
29 #include "wimlib_internal.h"
34 #include "lookup_table.h"
36 #include <ntfs-3g/layout.h>
37 #include <ntfs-3g/acls.h>
38 #include <ntfs-3g/attrib.h>
39 #include <ntfs-3g/misc.h>
40 #include <ntfs-3g/reparse.h>
41 #include <ntfs-3g/security.h>
42 #include <ntfs-3g/volume.h>
46 extern int ntfs_inode_get_security(ntfs_inode *ni, u32 selection, char *buf,
47 u32 buflen, u32 *psize);
49 extern int ntfs_inode_get_attributes(ntfs_inode *ni);
53 struct wim_security_data *sd;
59 u8 hash[SHA1_HASH_SIZE];
61 struct sd_node *right;
64 static void free_sd_tree(struct sd_node *root)
67 free_sd_tree(root->left);
68 free_sd_tree(root->right);
73 static void insert_sd_node(struct sd_node *new, struct sd_node *root)
75 int cmp = hashes_cmp(root->hash, new->hash);
78 insert_sd_node(new, root->left);
83 insert_sd_node(new, root->right);
91 static int lookup_sd(const u8 hash[SHA1_HASH_SIZE], struct sd_node *node)
96 cmp = hashes_cmp(hash, node->hash);
98 return lookup_sd(hash, node->left);
100 return lookup_sd(hash, node->right);
102 return node->security_id;
105 static int tree_add_sd(struct sd_tree *tree, const u8 *descriptor,
108 u8 hash[SHA1_HASH_SIZE];
114 struct wim_security_data *sd = tree->sd;
115 sha1_buffer(descriptor, size, hash);
117 security_id = lookup_sd(hash, tree->root);
118 if (security_id >= 0)
121 new = MALLOC(sizeof(struct sd_node));
124 descr_copy = MALLOC(size);
127 memcpy(descr_copy, descriptor, size);
128 new->security_id = tree->num_sds++;
131 copy_hash(new->hash, hash);
133 descriptors = REALLOC(sd->descriptors,
134 (sd->num_entries + 1) * sizeof(sd->descriptors[0]));
137 sd->descriptors = descriptors;
138 sizes = REALLOC(sd->sizes,
139 (sd->num_entries + 1) * sizeof(sd->sizes[0]));
143 sd->descriptors[sd->num_entries] = descr_copy;
144 sd->sizes[sd->num_entries] = size;
146 sd->total_length += size + 8;
149 insert_sd_node(tree->root, new);
152 return new->security_id;
161 static int build_sd_tree(struct wim_security_data *sd, struct sd_tree *tree)
164 u32 orig_num_entries = sd->num_entries;
165 u32 orig_total_length = sd->total_length;
171 for (u32 i = 0; i < sd->num_entries; i++) {
172 ret = tree_add_sd(tree, sd->descriptors[i], sd->sizes[i]);
178 sd->num_entries = orig_num_entries;
179 sd->total_length = orig_total_length;
180 free_sd_tree(tree->root);
185 static int ntfs_attr_sha1sum(ntfs_inode *ni, ATTR_RECORD *ar,
186 u8 md[SHA1_HASH_SIZE])
194 na = ntfs_attr_open(ni, ar->type,
195 (ntfschar*)((u8*)ar + le16_to_cpu(ar->name_offset)),
198 ERROR_WITH_ERRNO("Failed to open NTFS attribute");
199 return WIMLIB_ERR_NTFS_3G;
202 bytes_remaining = na->data_size;
205 while (bytes_remaining) {
206 s64 to_read = min(bytes_remaining, sizeof(buf));
207 if (ntfs_attr_pread(na, pos, to_read, buf) != to_read) {
208 ERROR_WITH_ERRNO("Error reading NTFS attribute");
209 return WIMLIB_ERR_NTFS_3G;
211 sha1_update(&ctx, buf, to_read);
213 bytes_remaining -= to_read;
215 sha1_final(md, &ctx);
220 static int __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni,
221 char path[], size_t path_len,
222 struct lookup_table *lookup_table,
223 struct sd_tree *tree)
225 u32 attributes = ntfs_inode_get_attributes(ni);
226 int mrec_flags = ni->mrec->flags;
230 dentry->creation_time = le64_to_cpu(ni->creation_time);
231 dentry->last_write_time = le64_to_cpu(ni->last_data_change_time);
232 dentry->last_access_time = le64_to_cpu(ni->last_access_time);
233 dentry->security_id = le32_to_cpu(ni->security_id);
234 dentry->attributes = le32_to_cpu(attributes);
235 dentry->resolved = true;
237 if (mrec_flags & MFT_RECORD_IS_DIRECTORY) {
238 if (attributes & FILE_ATTR_REPARSE_POINT) {
241 /* Normal directory */
244 if (attributes & FILE_ATTR_REPARSE_POINT) {
245 /* Symbolic link or other reparse point */
248 ntfs_attr_search_ctx *actx;
249 u8 attr_hash[SHA1_HASH_SIZE];
250 struct lookup_table_entry *lte;
252 actx = ntfs_attr_get_search_ctx(ni, NULL);
254 ERROR_WITH_ERRNO("Cannot get attribute search "
256 return WIMLIB_ERR_NTFS_3G;
258 while (!ntfs_attr_lookup(AT_DATA, NULL, 0,
259 CASE_SENSITIVE, 0, NULL, 0, actx))
261 ret = ntfs_attr_sha1sum(ni, actx->attr, attr_hash);
264 lte = __lookup_resource(lookup_table, attr_hash);
268 /*char *file_on_disk = STRDUP(root_disk_path);*/
269 /*if (!file_on_disk) {*/
270 /*ERROR("Failed to allocate memory for file path");*/
271 /*return WIMLIB_ERR_NOMEM;*/
273 /*lte = new_lookup_table_entry();*/
275 /*FREE(file_on_disk);*/
276 /*return WIMLIB_ERR_NOMEM;*/
278 /*lte->file_on_disk = file_on_disk;*/
279 /*lte->resource_location = RESOURCE_IN_FILE_ON_DISK;*/
280 /*lte->resource_entry.original_size = root_stbuf.st_size;*/
281 /*lte->resource_entry.size = root_stbuf.st_size;*/
282 /*copy_hash(lte->hash, hash);*/
283 /*lookup_table_insert(lookup_table, lte);*/
289 ret = ntfs_inode_get_security(ni,
290 OWNER_SECURITY_INFORMATION |
291 GROUP_SECURITY_INFORMATION |
292 DACL_SECURITY_INFORMATION |
293 SACL_SECURITY_INFORMATION,
296 ret = ntfs_inode_get_security(ni,
297 OWNER_SECURITY_INFORMATION |
298 GROUP_SECURITY_INFORMATION |
299 DACL_SECURITY_INFORMATION |
300 SACL_SECURITY_INFORMATION,
301 sd, sd_size, &sd_size);
302 dentry->security_id = tree_add_sd(tree, sd, sd_size);
306 static int build_dentry_tree_ntfs(struct dentry *root_dentry,
308 struct lookup_table *lookup_table,
309 struct wim_security_data *sd,
319 ntfs_volume **ntfs_vol_p = extra_arg;
321 vol = ntfs_mount(device, MS_RDONLY);
323 ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s' read-only",
325 return WIMLIB_ERR_NTFS_3G;
327 root_ni = ntfs_inode_open(vol, FILE_root);
329 ERROR_WITH_ERRNO("Failed to open root inode of NTFS volume "
331 ret = WIMLIB_ERR_NTFS_3G;
337 ret = __build_dentry_tree_ntfs(root_dentry, root_ni, path, 1,
338 lookup_table, &tree);
341 if (ntfs_umount(vol, FALSE) != 0) {
342 ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device);
344 ret = WIMLIB_ERR_NTFS_3G;
349 WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
352 const char *description,
353 const char *flags_element,
356 if (flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) {
357 ERROR("Cannot dereference files when capturing directly from NTFS");
358 return WIMLIB_ERR_INVALID_PARAM;
360 return do_add_image(w, device, name, description, flags_element, flags,
361 build_dentry_tree_ntfs,
365 #else /* WITH_NTFS_3G */
366 WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
369 const char *description,
370 const char *flags_element,
373 ERROR("wimlib was compiled without support for NTFS-3g, so");
374 ERROR("we cannot capture a WIM image directly from a NTFS volume");
375 return WIMLIB_ERR_UNSUPPORTED;
377 #endif /* WITH_NTFS_3G */