]> wimlib.net Git - wimlib/blob - src/ntfs-capture.c
NTFS capture (IN PROGRESS)
[wimlib] / src / ntfs-capture.c
1 /*
2  * ntfs-capture.c
3  *
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
6  * of information.
7  */
8
9 /*
10  * Copyright (C) 2012 Eric Biggers
11  *
12  * This file is part of wimlib, a library for working with WIM files.
13  *
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)
17  * any later version.
18  *
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
22  * details.
23  *
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/.
26  */
27
28 #include "config.h"
29 #include "wimlib_internal.h"
30
31
32 #ifdef WITH_NTFS_3G
33 #include "dentry.h"
34 #include "lookup_table.h"
35 #include "io.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>
43 #include <stdlib.h>
44 #include <unistd.h>
45
46 extern int ntfs_inode_get_security(ntfs_inode *ni, u32 selection, char *buf,
47                                    u32 buflen, u32 *psize);
48
49 extern int ntfs_inode_get_attributes(ntfs_inode *ni);
50
51 struct sd_tree {
52         u32 num_sds;
53         struct wim_security_data *sd;
54         struct sd_node *root;
55 };
56
57 struct sd_node {
58         int security_id;
59         u8 hash[SHA1_HASH_SIZE];
60         struct sd_node *left;
61         struct sd_node *right;
62 };
63
64 static void free_sd_tree(struct sd_node *root)
65 {
66         if (root) {
67                 free_sd_tree(root->left);
68                 free_sd_tree(root->right);
69                 FREE(root);
70         }
71 }
72
73 static void insert_sd_node(struct sd_node *new, struct sd_node *root)
74 {
75         int cmp = hashes_cmp(root->hash, new->hash);
76         if (cmp < 0) {
77                 if (root->left)
78                         insert_sd_node(new, root->left);
79                 else 
80                         root->left = new;
81         } else if (cmp > 0) {
82                 if (root->right)
83                         insert_sd_node(new, root->right);
84                 else 
85                         root->right = new;
86         } else {
87                 wimlib_assert(0);
88         }
89 }
90
91 static int lookup_sd(const u8 hash[SHA1_HASH_SIZE], struct sd_node *node)
92 {
93         int cmp;
94         if (!node)
95                 return -1;
96         cmp = hashes_cmp(hash, node->hash);
97         if (cmp < 0)
98                 return lookup_sd(hash, node->left);
99         else if (cmp > 0)
100                 return lookup_sd(hash, node->right);
101         else
102                 return node->security_id;
103 }
104
105 static int tree_add_sd(struct sd_tree *tree, const u8 *descriptor,
106                        size_t size)
107 {
108         u8 hash[SHA1_HASH_SIZE];
109         int security_id;
110         struct sd_node *new;
111         u8 **descriptors;
112         u64 *sizes;
113         u8 *descr_copy;
114         struct wim_security_data *sd = tree->sd;
115         sha1_buffer(descriptor, size, hash);
116
117         security_id = lookup_sd(hash, tree->root);
118         if (security_id >= 0)
119                 return security_id;
120
121         new = MALLOC(sizeof(struct sd_node));
122         if (!new)
123                 return -1;
124         descr_copy = MALLOC(size);
125         if (!descr_copy)
126                 goto out_free_node;
127         memcpy(descr_copy, descriptor, size);
128         new->security_id = tree->num_sds++;
129         new->left = NULL;
130         new->right = NULL;
131         copy_hash(new->hash, hash);
132
133         descriptors = REALLOC(sd->descriptors,
134                               (sd->num_entries + 1) * sizeof(sd->descriptors[0]));
135         if (!descriptors)
136                 goto out_free_descr;
137         sd->descriptors = descriptors;
138         sizes = REALLOC(sd->sizes,
139                         (sd->num_entries + 1) * sizeof(sd->sizes[0]));
140         if (!sizes)
141                 goto out_free_descr;
142         sd->sizes = sizes;
143         sd->descriptors[sd->num_entries] = descr_copy;
144         sd->sizes[sd->num_entries] = size;
145         sd->num_entries++;
146         sd->total_length += size + 8;
147
148         if (tree->root)
149                 insert_sd_node(tree->root, new);
150         else
151                 tree->root = new;
152         return new->security_id;
153 out_free_descr:
154         FREE(descr_copy);
155 out_free_node:
156         FREE(new);
157         return -1;
158 }
159
160 #if 0
161 static int build_sd_tree(struct wim_security_data *sd, struct sd_tree *tree)
162 {
163         int ret;
164         u32 orig_num_entries = sd->num_entries;
165         u32 orig_total_length = sd->total_length;
166
167         tree->num_sds = 0;
168         tree->sd = sd;
169         tree->root = NULL;
170
171         for (u32 i = 0; i < sd->num_entries; i++) {
172                 ret = tree_add_sd(tree, sd->descriptors[i], sd->sizes[i]);
173                 if (ret < 0)
174                         goto out_revert;
175         }
176         return 0;
177 out_revert:
178         sd->num_entries = orig_num_entries;
179         sd->total_length = orig_total_length;
180         free_sd_tree(tree->root);
181         return ret;
182 }
183 #endif
184
185 static int __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni,
186                                     struct lookup_table *lookup_table,
187                                     struct sd_tree *tree)
188 {
189         u32 attributes = ntfs_inode_get_attributes(ni);
190         int mrec_flags = ni->mrec->flags;
191         u32 sd_size;
192         int ret;
193
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);
199
200         if (mrec_flags & MFT_RECORD_IS_DIRECTORY) {
201                 if (attributes & FILE_ATTR_REPARSE_POINT) {
202                         /* Junction point */
203                 } else {
204                         /* Normal directory */
205                 }
206         } else {
207                 if (attributes & FILE_ATTR_REPARSE_POINT) {
208                         /* Symbolic link or other reparse point */
209                 } else {
210                         /* Normal file */
211                 }
212         }
213         ret = ntfs_inode_get_security(ni,
214                                       OWNER_SECURITY_INFORMATION |
215                                       GROUP_SECURITY_INFORMATION |
216                                       DACL_SECURITY_INFORMATION  |
217                                       SACL_SECURITY_INFORMATION,
218                                       NULL, 0, &sd_size);
219         u8 sd[sd_size];
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);
227
228         return 0;
229 }
230
231 static int build_dentry_tree_ntfs(struct dentry *root_dentry,
232                                   const char *device,
233                                   struct lookup_table *lookup_table,
234                                   int flags)
235 {
236         ntfs_volume *vol;
237         ntfs_inode *root_ni;
238         int ret = 0;
239         struct sd_tree tree;
240         tree.sd = CALLOC(1, sizeof(struct wim_security_data));
241         if (!tree.sd)
242                 return WIMLIB_ERR_NOMEM;
243         tree.sd->total_length = 8;
244         tree.root = NULL;
245         
246         vol = ntfs_mount(device, MS_RDONLY);
247         if (!vol) {
248                 ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s' read-only",
249                                  device);
250                 return WIMLIB_ERR_NTFS_3G;
251         }
252         root_ni = ntfs_inode_open(vol, FILE_root);
253         if (!root_ni) {
254                 ERROR_WITH_ERRNO("Failed to open root inode of NTFS volume "
255                                  "`%s'", device);
256                 ret = WIMLIB_ERR_NTFS_3G;
257                 goto out;
258         }
259         ret = __build_dentry_tree_ntfs(root_dentry, root_ni, lookup_table, &tree);
260
261 out:
262         if (ntfs_umount(vol, FALSE) != 0) {
263                 ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device);
264                 if (ret == 0)
265                         ret = WIMLIB_ERR_NTFS_3G;
266         }
267         return ret;
268 }
269
270 WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
271                                                 const char *device,
272                                                 const char *name,
273                                                 const char *description,
274                                                 const char *flags_element,
275                                                 int flags)
276 {
277         if (flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) {
278                 ERROR("Cannot dereference files when capturing directly from NTFS");
279                 return WIMLIB_ERR_INVALID_PARAM;
280         }
281         return do_add_image(w, device, name, description, flags_element, flags,
282                             build_dentry_tree_ntfs);
283 }
284
285 #else /* WITH_NTFS_3G */
286 WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
287                                                 const char *device,
288                                                 const char *name,
289                                                 const char *description,
290                                                 const char *flags_element,
291                                                 int flags)
292 {
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;
296 }
297 #endif /* WITH_NTFS_3G */