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 __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni,
186 struct lookup_table *lookup_table,
187 struct sd_tree *tree)
189 u32 attributes = ntfs_inode_get_attributes(ni);
190 int mrec_flags = ni->mrec->flags;
194 dentry->creation_time = le64_to_cpu(ni->creation_time);
195 dentry->last_write_time = le64_to_cpu(ni->last_data_change_time);
196 dentry->last_access_time = le64_to_cpu(ni->last_access_time);
197 dentry->security_id = le32_to_cpu(ni->security_id);
198 dentry->attributes = le32_to_cpu(attributes);
200 if (mrec_flags & MFT_RECORD_IS_DIRECTORY) {
201 if (attributes & FILE_ATTR_REPARSE_POINT) {
204 /* Normal directory */
207 if (attributes & FILE_ATTR_REPARSE_POINT) {
208 /* Symbolic link or other reparse point */
213 ret = ntfs_inode_get_security(ni,
214 OWNER_SECURITY_INFORMATION |
215 GROUP_SECURITY_INFORMATION |
216 DACL_SECURITY_INFORMATION |
217 SACL_SECURITY_INFORMATION,
220 ret = ntfs_inode_get_security(ni,
221 OWNER_SECURITY_INFORMATION |
222 GROUP_SECURITY_INFORMATION |
223 DACL_SECURITY_INFORMATION |
224 SACL_SECURITY_INFORMATION,
225 sd, sd_size, &sd_size);
226 dentry->security_id = tree_add_sd(tree, sd, sd_size);
231 static int build_dentry_tree_ntfs(struct dentry *root_dentry,
233 struct lookup_table *lookup_table,
240 tree.sd = CALLOC(1, sizeof(struct wim_security_data));
242 return WIMLIB_ERR_NOMEM;
243 tree.sd->total_length = 8;
246 vol = ntfs_mount(device, MS_RDONLY);
248 ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s' read-only",
250 return WIMLIB_ERR_NTFS_3G;
252 root_ni = ntfs_inode_open(vol, FILE_root);
254 ERROR_WITH_ERRNO("Failed to open root inode of NTFS volume "
256 ret = WIMLIB_ERR_NTFS_3G;
259 ret = __build_dentry_tree_ntfs(root_dentry, root_ni, lookup_table, &tree);
262 if (ntfs_umount(vol, FALSE) != 0) {
263 ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device);
265 ret = WIMLIB_ERR_NTFS_3G;
270 WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
273 const char *description,
274 const char *flags_element,
277 if (flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) {
278 ERROR("Cannot dereference files when capturing directly from NTFS");
279 return WIMLIB_ERR_INVALID_PARAM;
281 return do_add_image(w, device, name, description, flags_element, flags,
282 build_dentry_tree_ntfs);
285 #else /* WITH_NTFS_3G */
286 WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
289 const char *description,
290 const char *flags_element,
293 ERROR("wimlib was compiled without support for NTFS-3g, so");
294 ERROR("we cannot capture a WIM image directly from a NTFS volume");
295 return WIMLIB_ERR_UNSUPPORTED;
297 #endif /* WITH_NTFS_3G */