]> wimlib.net Git - wimlib/blob - src/add_image.c
Win32 apply
[wimlib] / src / add_image.c
1 /*
2  * add_image.c
3  */
4
5 /*
6  * Copyright (C) 2012, 2013 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option)
13  * any later version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with wimlib; if not, see http://www.gnu.org/licenses/.
22  */
23
24 #include "config.h"
25
26 #if defined(__CYGWIN__) || defined(__WIN32__)
27 #       include <windows.h>
28 #       include <ntdef.h>
29 #       include <wchar.h>
30 #       include <sys/cygwin.h>
31 #       include <fcntl.h>
32 #       ifdef ERROR
33 #               undef ERROR
34 #       endif
35 #       include "security.h"
36 #endif
37
38 #include "wimlib_internal.h"
39 #include "dentry.h"
40 #include "timestamp.h"
41 #include "lookup_table.h"
42 #include "xml.h"
43 #include <string.h>
44 #include <fnmatch.h>
45 #include <stdlib.h>
46 #include <ctype.h>
47 #include <sys/stat.h>
48 #include <dirent.h>
49 #include <errno.h>
50 #include <unistd.h>
51
52 #ifdef HAVE_ALLOCA_H
53 #include <alloca.h>
54 #else
55 #include <stdlib.h>
56 #endif
57
58 #define WIMLIB_ADD_IMAGE_FLAG_ROOT      0x80000000
59 #define WIMLIB_ADD_IMAGE_FLAG_SOURCE    0x40000000
60
61 /*
62  * Adds the dentry tree and security data for a new image to the image metadata
63  * array of the WIMStruct.
64  */
65 int add_new_dentry_tree(WIMStruct *w, struct wim_dentry *root_dentry,
66                         struct wim_security_data *sd)
67 {
68         struct wim_lookup_table_entry *metadata_lte;
69         struct wim_image_metadata *imd;
70         struct wim_image_metadata *new_imd;
71
72         wimlib_assert(root_dentry != NULL);
73
74         DEBUG("Reallocating image metadata array for image_count = %u",
75               w->hdr.image_count + 1);
76         imd = CALLOC((w->hdr.image_count + 1), sizeof(struct wim_image_metadata));
77
78         if (!imd) {
79                 ERROR("Failed to allocate memory for new image metadata array");
80                 goto err;
81         }
82
83         memcpy(imd, w->image_metadata,
84                w->hdr.image_count * sizeof(struct wim_image_metadata));
85
86         metadata_lte = new_lookup_table_entry();
87         if (!metadata_lte)
88                 goto err_free_imd;
89
90         metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA;
91         random_hash(metadata_lte->hash);
92         lookup_table_insert(w->lookup_table, metadata_lte);
93
94         new_imd = &imd[w->hdr.image_count];
95
96         new_imd->root_dentry    = root_dentry;
97         new_imd->metadata_lte   = metadata_lte;
98         new_imd->security_data  = sd;
99         new_imd->modified       = 1;
100
101         FREE(w->image_metadata);
102         w->image_metadata = imd;
103         w->hdr.image_count++;
104         return 0;
105 err_free_imd:
106         FREE(imd);
107 err:
108         return WIMLIB_ERR_NOMEM;
109
110 }
111
112 #if defined(__CYGWIN__) || defined(__WIN32__)
113
114 static u64 FILETIME_to_u64(const FILETIME *ft)
115 {
116         return ((u64)ft->dwHighDateTime << 32) | (u64)ft->dwLowDateTime;
117 }
118
119
120 static int build_dentry_tree(struct wim_dentry **root_ret,
121                              const char *root_disk_path,
122                              struct wim_lookup_table *lookup_table,
123                              struct wim_security_data *sd,
124                              const struct capture_config *config,
125                              int add_image_flags,
126                              wimlib_progress_func_t progress_func,
127                              void *extra_arg);
128
129 static int win32_get_short_name(struct wim_dentry *dentry,
130                                 const wchar_t *path_utf16)
131 {
132         WIN32_FIND_DATAW dat;
133         if (FindFirstFileW(path_utf16, &dat) &&
134             dat.cAlternateFileName[0] != L'\0')
135         {
136                 size_t short_name_len = wcslen(dat.cAlternateFileName) * 2;
137                 size_t n = short_name_len + sizeof(wchar_t);
138                 dentry->short_name = MALLOC(n);
139                 if (!dentry->short_name)
140                         return WIMLIB_ERR_NOMEM;
141                 memcpy(dentry->short_name, dat.cAlternateFileName, n);
142                 dentry->short_name_len = short_name_len;
143         }
144         return 0;
145 }
146
147 static int win32_get_security_descriptor(struct wim_dentry *dentry,
148                                          struct sd_set *sd_set,
149                                          const wchar_t *path_utf16,
150                                          const char *path)
151 {
152         SECURITY_INFORMATION requestedInformation;
153         DWORD lenNeeded = 0;
154         BOOL status;
155         DWORD err;
156
157         requestedInformation = DACL_SECURITY_INFORMATION |
158                                SACL_SECURITY_INFORMATION |
159                                OWNER_SECURITY_INFORMATION |
160                                GROUP_SECURITY_INFORMATION;
161         /* Request length of security descriptor */
162         status = GetFileSecurityW(path_utf16, requestedInformation,
163                                   NULL, 0, &lenNeeded);
164         err = GetLastError();
165
166         /* Error code appears to be ERROR_INSUFFICIENT_BUFFER but
167          * GetFileSecurity is poorly documented... */
168         if (err == ERROR_INSUFFICIENT_BUFFER || err == NO_ERROR) {
169                 DWORD len = lenNeeded;
170                 char buf[len];
171                 if (GetFileSecurityW(path_utf16, requestedInformation,
172                                      buf, len, &lenNeeded))
173                 {
174                         int security_id = sd_set_add_sd(sd_set, buf, len);
175                         if (security_id < 0)
176                                 return WIMLIB_ERR_NOMEM;
177                         else {
178                                 dentry->d_inode->i_security_id = security_id;
179                                 return 0;
180                         }
181                 } else {
182                         err = GetLastError();
183                 }
184         }
185         ERROR("Win32 API: Failed to read security descriptor of \"%s\"",
186               path);
187         win32_error(err);
188         return WIMLIB_ERR_READ;
189 }
190
191
192 static int win32_recurse_directory(struct wim_dentry *root,
193                                    const char *root_disk_path,
194                                    struct wim_lookup_table *lookup_table,
195                                    struct wim_security_data *sd,
196                                    const struct capture_config *config,
197                                    int add_image_flags,
198                                    wimlib_progress_func_t progress_func,
199                                    struct sd_set *sd_set,
200                                    const wchar_t *path_utf16,
201                                    size_t path_utf16_nchars)
202 {
203         WIN32_FIND_DATAW dat;
204         HANDLE hFind;
205         DWORD err;
206         int ret;
207
208         {
209                 wchar_t pattern_buf[path_utf16_nchars + 3];
210                 memcpy(pattern_buf, path_utf16,
211                        path_utf16_nchars * sizeof(wchar_t));
212                 pattern_buf[path_utf16_nchars] = L'/';
213                 pattern_buf[path_utf16_nchars + 1] = L'*';
214                 pattern_buf[path_utf16_nchars + 2] = L'\0';
215                 hFind = FindFirstFileW(pattern_buf, &dat);
216         }
217         if (hFind == INVALID_HANDLE_VALUE) {
218                 err = GetLastError();
219                 if (err == ERROR_FILE_NOT_FOUND) {
220                         return 0;
221                 } else {
222                         ERROR("Win32 API: Failed to read directory \"%s\"",
223                               root_disk_path);
224                         win32_error(err);
225                         return WIMLIB_ERR_READ;
226                 }
227         }
228         ret = 0;
229         do {
230                 if (!(dat.cFileName[0] == L'.' &&
231                       (dat.cFileName[1] == L'\0' ||
232                        (dat.cFileName[1] == L'.' && dat.cFileName[2] == L'\0'))))
233                 {
234                         struct wim_dentry *child;
235
236                         char *utf8_name;
237                         size_t utf8_name_nbytes;
238                         ret = utf16_to_utf8((const char*)dat.cFileName,
239                                             wcslen(dat.cFileName) * sizeof(wchar_t),
240                                             &utf8_name,
241                                             &utf8_name_nbytes);
242                         if (ret)
243                                 goto out_find_close;
244
245                         char name[strlen(root_disk_path) + utf8_name_nbytes + 1];
246                         sprintf(name, "%s/%s", root_disk_path, utf8_name);
247                         FREE(utf8_name);
248                         ret = build_dentry_tree(&child, name, lookup_table,
249                                                 sd, config, add_image_flags,
250                                                 progress_func, sd_set);
251                         if (ret)
252                                 goto out_find_close;
253                         if (child)
254                                 dentry_add_child(root, child);
255                 }
256         } while (FindNextFileW(hFind, &dat));
257         err = GetLastError();
258         if (err != ERROR_NO_MORE_FILES) {
259                 ERROR("Win32 API: Failed to read directory \"%s\"", root_disk_path);
260                 win32_error(err);
261                 if (ret == 0)
262                         ret = WIMLIB_ERR_READ;
263         }
264 out_find_close:
265         FindClose(hFind);
266         return ret;
267 }
268
269 static int win32_capture_reparse_point(const char *path,
270                                        HANDLE hFile,
271                                        struct wim_inode *inode,
272                                        struct wim_lookup_table *lookup_table)
273 {
274         /* "Reparse point data, including the tag and optional GUID,
275          * cannot exceed 16 kilobytes." - MSDN  */
276         char reparse_point_buf[16 * 1024];
277         DWORD bytesReturned;
278         const REPARSE_DATA_BUFFER *buf;
279
280         if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT,
281                              NULL, 0, reparse_point_buf,
282                              sizeof(reparse_point_buf), &bytesReturned, NULL))
283         {
284                 ERROR("Win32 API: Failed to get reparse data of \"%s\"", path);
285                 return WIMLIB_ERR_READ;
286         }
287         buf = (const REPARSE_DATA_BUFFER*)reparse_point_buf;
288         inode->i_reparse_tag = buf->ReparseTag;
289         return inode_add_ads_with_data(inode, "", (const u8*)buf + 8,
290                                        bytesReturned - 8, lookup_table);
291 }
292
293 static int win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE])
294 {
295         HANDLE hFile;
296         SHA_CTX ctx;
297         u8 buf[32768];
298         DWORD bytesRead;
299         int ret;
300
301         hFile = win32_open_file(path);
302         if (hFile == INVALID_HANDLE_VALUE)
303                 return WIMLIB_ERR_OPEN;
304
305         sha1_init(&ctx);
306         for (;;) {
307                 if (!ReadFile(hFile, buf, sizeof(buf), &bytesRead, NULL)) {
308                         ret = WIMLIB_ERR_READ;
309                         goto out_close_handle;
310                 }
311                 if (bytesRead == 0)
312                         break;
313                 sha1_update(&ctx, buf, bytesRead);
314         }
315         ret = 0;
316         sha1_final(hash, &ctx);
317 out_close_handle:
318         CloseHandle(hFile);
319         return ret;
320 }
321
322 static int win32_capture_stream(const char *path,
323                                 const wchar_t *path_utf16,
324                                 size_t path_utf16_nchars,
325                                 struct wim_inode *inode,
326                                 struct wim_lookup_table *lookup_table,
327                                 WIN32_FIND_STREAM_DATA *dat)
328 {
329         struct wim_ads_entry *ads_entry;
330         u8 hash[SHA1_HASH_SIZE];
331         struct wim_lookup_table_entry *lte;
332         int ret;
333         wchar_t *p, *colon;
334         bool is_named_stream;
335         wchar_t *spath;
336         size_t spath_nchars;
337         DWORD err;
338
339         p = dat->cStreamName;
340         wimlib_assert(*p == L':');
341         p += 1;
342         colon = wcschr(p, L':');
343         wimlib_assert(colon != NULL);
344
345         if (wcscmp(colon + 1, L"$DATA")) {
346                 /* Not a DATA stream */
347                 ret = 0;
348                 goto out;
349         }
350
351         is_named_stream = (p != colon);
352
353         if (is_named_stream) {
354                 char *utf8_stream_name;
355                 size_t utf8_stream_name_len;
356                 ret = utf16_to_utf8((const char *)p,
357                                     (colon - p) * sizeof(wchar_t),
358                                     &utf8_stream_name,
359                                     &utf8_stream_name_len);
360                 if (ret)
361                         goto out;
362                 ads_entry = inode_add_ads(inode, utf8_stream_name);
363                 FREE(utf8_stream_name);
364                 if (!ads_entry) {
365                         ret = WIMLIB_ERR_NOMEM;
366                         goto out;
367                 }
368         }
369
370         *colon = '\0';
371         spath_nchars = path_utf16_nchars;
372         if (is_named_stream)
373                 spath_nchars += colon - p + 1;
374
375         spath = MALLOC((spath_nchars + 1) * sizeof(wchar_t));
376         memcpy(spath, path_utf16, path_utf16_nchars * sizeof(wchar_t));
377         if (is_named_stream) {
378                 spath[path_utf16_nchars] = L':';
379                 memcpy(&spath[path_utf16_nchars + 1], p, (colon - p) * sizeof(wchar_t));
380         }
381         spath[spath_nchars] = L'\0';
382
383         ret = win32_sha1sum(spath, hash);
384         if (ret) {
385                 err = GetLastError();
386                 ERROR("Win32 API: Failed to read \"%s\" to calculate SHA1sum", path);
387                 win32_error(err);
388                 goto out_free_spath;
389         }
390
391         lte = __lookup_resource(lookup_table, hash);
392         if (lte) {
393                 lte->refcnt++;
394         } else {
395                 lte = new_lookup_table_entry();
396                 if (!lte) {
397                         ret = WIMLIB_ERR_NOMEM;
398                         goto out_free_spath;
399                 }
400                 lte->file_on_disk = (char*)spath;
401                 spath = NULL;
402                 lte->resource_location = RESOURCE_WIN32;
403                 lte->resource_entry.original_size = (uint64_t)dat->StreamSize.QuadPart;
404                 lte->resource_entry.size = (uint64_t)dat->StreamSize.QuadPart;
405                 copy_hash(lte->hash, hash);
406                 lookup_table_insert(lookup_table, lte);
407         }
408         if (is_named_stream)
409                 ads_entry->lte = lte;
410         else
411                 inode->i_lte = lte;
412 out_free_spath:
413         FREE(spath);
414 out:
415         return ret;
416 }
417
418 static int win32_capture_streams(const char *path,
419                                  const wchar_t *path_utf16,
420                                  size_t path_utf16_nchars,
421                                  struct wim_inode *inode,
422                                  struct wim_lookup_table *lookup_table)
423 {
424         WIN32_FIND_STREAM_DATA dat;
425         int ret;
426         HANDLE hFind;
427         DWORD err;
428
429         hFind = FindFirstStreamW(path_utf16, FindStreamInfoStandard, &dat, 0);
430         if (hFind == INVALID_HANDLE_VALUE) {
431                 err = GetLastError();
432
433                 /* Seems legal for this to return ERROR_HANDLE_EOF on reparse
434                  * points and directories */
435                 if ((inode->i_attributes &
436                     (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
437                     && err == ERROR_HANDLE_EOF)
438                 {
439                         return 0;
440                 } else {
441                         ERROR("Win32 API: Failed to look up data streams of \"%s\"",
442                               path);
443                         win32_error(err);
444                         return WIMLIB_ERR_READ;
445                 }
446         }
447         do {
448                 ret = win32_capture_stream(path, path_utf16,
449                                            path_utf16_nchars,
450                                            inode, lookup_table,
451                                            &dat);
452                 if (ret)
453                         goto out_find_close;
454         } while (FindNextStreamW(hFind, &dat));
455         err = GetLastError();
456         if (err != ERROR_HANDLE_EOF) {
457                 ERROR("Win32 API: Error reading data streams from \"%s\"", path);
458                 win32_error(err);
459                 ret = WIMLIB_ERR_READ;
460         }
461 out_find_close:
462         FindClose(hFind);
463         return ret;
464 }
465 #endif
466
467 /*
468  * build_dentry_tree():
469  *      Recursively builds a tree of WIM dentries from an on-disk directory
470  *      tree.
471  *
472  * @root_ret:   Place to return a pointer to the root of the dentry tree.  Only
473  *              modified if successful.  Set to NULL if the file or directory was
474  *              excluded from capture.
475  *
476  * @root_disk_path:  The path to the root of the directory tree on disk.
477  *
478  * @lookup_table: The lookup table for the WIM file.  For each file added to the
479  *              dentry tree being built, an entry is added to the lookup table,
480  *              unless an identical stream is already in the lookup table.
481  *              These lookup table entries that are added point to the path of
482  *              the file on disk.
483  *
484  * @sd:         Ignored.  (Security data only captured in NTFS mode.)
485  *
486  * @capture_config:
487  *              Configuration for files to be excluded from capture.
488  *
489  * @add_flags:  Bitwise or of WIMLIB_ADD_IMAGE_FLAG_*
490  *
491  * @extra_arg:  Ignored. (Only used in NTFS mode.)
492  *
493  * @return:     0 on success, nonzero on failure.  It is a failure if any of
494  *              the files cannot be `stat'ed, or if any of the needed
495  *              directories cannot be opened or read.  Failure to add the files
496  *              to the WIM may still occur later when trying to actually read
497  *              the on-disk files during a call to wimlib_write() or
498  *              wimlib_overwrite().
499  */
500 static int build_dentry_tree(struct wim_dentry **root_ret,
501                              const char *root_disk_path,
502                              struct wim_lookup_table *lookup_table,
503                              struct wim_security_data *sd,
504                              const struct capture_config *config,
505                              int add_image_flags,
506                              wimlib_progress_func_t progress_func,
507                              void *extra_arg)
508 {
509         struct wim_dentry *root = NULL;
510         int ret = 0;
511         struct wim_inode *inode;
512
513         if (exclude_path(root_disk_path, config, true)) {
514                 if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
515                         ERROR("Cannot exclude the root directory from capture");
516                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
517                         goto out;
518                 }
519                 if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
520                     && progress_func)
521                 {
522                         union wimlib_progress_info info;
523                         info.scan.cur_path = root_disk_path;
524                         info.scan.excluded = true;
525                         progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
526                 }
527                 goto out;
528         }
529
530         if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
531             && progress_func)
532         {
533                 union wimlib_progress_info info;
534                 info.scan.cur_path = root_disk_path;
535                 info.scan.excluded = false;
536                 progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
537         }
538
539 #if !defined(__CYGWIN__) && !defined(__WIN32__)
540         /* UNIX version of capturing a directory tree */
541         struct stat root_stbuf;
542         int (*stat_fn)(const char *restrict, struct stat *restrict);
543         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)
544                 stat_fn = stat;
545         else
546                 stat_fn = lstat;
547
548         ret = (*stat_fn)(root_disk_path, &root_stbuf);
549         if (ret != 0) {
550                 ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path);
551                 goto out;
552         }
553
554         if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
555               !S_ISDIR(root_stbuf.st_mode))
556         {
557                 /* Do a dereference-stat in case the root is a symbolic link.
558                  * This case is allowed, provided that the symbolic link points
559                  * to a directory. */
560                 ret = stat(root_disk_path, &root_stbuf);
561                 if (ret != 0) {
562                         ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path);
563                         ret = WIMLIB_ERR_STAT;
564                         goto out;
565                 }
566                 if (!S_ISDIR(root_stbuf.st_mode)) {
567                         ERROR("`%s' is not a directory", root_disk_path);
568                         ret = WIMLIB_ERR_NOTDIR;
569                         goto out;
570                 }
571         }
572         if (!S_ISREG(root_stbuf.st_mode) && !S_ISDIR(root_stbuf.st_mode)
573             && !S_ISLNK(root_stbuf.st_mode)) {
574                 ERROR("`%s' is not a regular file, directory, or symbolic link.",
575                       root_disk_path);
576                 ret = WIMLIB_ERR_SPECIAL_FILE;
577                 goto out;
578         }
579
580         root = new_dentry_with_timeless_inode(path_basename(root_disk_path));
581         if (!root) {
582                 if (errno == EILSEQ)
583                         ret = WIMLIB_ERR_INVALID_UTF8_STRING;
584                 else if (errno == ENOMEM)
585                         ret = WIMLIB_ERR_NOMEM;
586                 else
587                         ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE;
588                 goto out;
589         }
590
591         inode = root->d_inode;
592
593 #ifdef HAVE_STAT_NANOSECOND_PRECISION
594         inode->i_creation_time = timespec_to_wim_timestamp(&root_stbuf.st_mtim);
595         inode->i_last_write_time = timespec_to_wim_timestamp(&root_stbuf.st_mtim);
596         inode->i_last_access_time = timespec_to_wim_timestamp(&root_stbuf.st_atim);
597 #else
598         inode->i_creation_time = unix_timestamp_to_wim(root_stbuf.st_mtime);
599         inode->i_last_write_time = unix_timestamp_to_wim(root_stbuf.st_mtime);
600         inode->i_last_access_time = unix_timestamp_to_wim(root_stbuf.st_atime);
601 #endif
602         if (sizeof(ino_t) >= 8)
603                 inode->i_ino = (u64)root_stbuf.st_ino;
604         else
605                 inode->i_ino = (u64)root_stbuf.st_ino |
606                                    ((u64)root_stbuf.st_dev << ((sizeof(ino_t) * 8) & 63));
607         inode->i_resolved = 1;
608         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
609                 ret = inode_set_unix_data(inode, root_stbuf.st_uid,
610                                           root_stbuf.st_gid,
611                                           root_stbuf.st_mode,
612                                           lookup_table,
613                                           UNIX_DATA_ALL | UNIX_DATA_CREATE);
614                 if (ret)
615                         goto out;
616         }
617         add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
618         if (S_ISREG(root_stbuf.st_mode)) { /* Archiving a regular file */
619
620                 struct wim_lookup_table_entry *lte;
621                 u8 hash[SHA1_HASH_SIZE];
622
623                 inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
624
625                 /* Empty files do not have to have a lookup table entry. */
626                 if (root_stbuf.st_size == 0)
627                         goto out;
628
629                 /* For each regular file, we must check to see if the file is in
630                  * the lookup table already; if it is, we increment its refcnt;
631                  * otherwise, we create a new lookup table entry and insert it.
632                  * */
633
634                 ret = sha1sum(root_disk_path, hash);
635                 if (ret != 0)
636                         goto out;
637
638                 lte = __lookup_resource(lookup_table, hash);
639                 if (lte) {
640                         lte->refcnt++;
641                         DEBUG("Add lte reference %u for `%s'", lte->refcnt,
642                               root_disk_path);
643                 } else {
644                         char *file_on_disk = STRDUP(root_disk_path);
645                         if (!file_on_disk) {
646                                 ERROR("Failed to allocate memory for file path");
647                                 ret = WIMLIB_ERR_NOMEM;
648                                 goto out;
649                         }
650                         lte = new_lookup_table_entry();
651                         if (!lte) {
652                                 FREE(file_on_disk);
653                                 ret = WIMLIB_ERR_NOMEM;
654                                 goto out;
655                         }
656                         lte->file_on_disk = file_on_disk;
657                         lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
658                         lte->resource_entry.original_size = root_stbuf.st_size;
659                         lte->resource_entry.size = root_stbuf.st_size;
660                         copy_hash(lte->hash, hash);
661                         lookup_table_insert(lookup_table, lte);
662                 }
663                 root->d_inode->i_lte = lte;
664         } else if (S_ISDIR(root_stbuf.st_mode)) { /* Archiving a directory */
665
666                 inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
667
668                 DIR *dir;
669                 struct dirent entry, *result;
670                 struct wim_dentry *child;
671
672                 dir = opendir(root_disk_path);
673                 if (!dir) {
674                         ERROR_WITH_ERRNO("Failed to open the directory `%s'",
675                                          root_disk_path);
676                         ret = WIMLIB_ERR_OPEN;
677                         goto out;
678                 }
679
680                 /* Buffer for names of files in directory. */
681                 size_t len = strlen(root_disk_path);
682                 char name[len + 1 + FILENAME_MAX + 1];
683                 memcpy(name, root_disk_path, len);
684                 name[len] = '/';
685
686                 /* Create a dentry for each entry in the directory on disk, and recurse
687                  * to any subdirectories. */
688                 while (1) {
689                         errno = 0;
690                         ret = readdir_r(dir, &entry, &result);
691                         if (ret != 0) {
692                                 ret = WIMLIB_ERR_READ;
693                                 ERROR_WITH_ERRNO("Error reading the "
694                                                  "directory `%s'",
695                                                  root_disk_path);
696                                 break;
697                         }
698                         if (result == NULL)
699                                 break;
700                         if (result->d_name[0] == '.' && (result->d_name[1] == '\0'
701                               || (result->d_name[1] == '.' && result->d_name[2] == '\0')))
702                                         continue;
703                         strcpy(name + len + 1, result->d_name);
704                         ret = build_dentry_tree(&child, name, lookup_table,
705                                                 NULL, config, add_image_flags,
706                                                 progress_func, NULL);
707                         if (ret != 0)
708                                 break;
709                         if (child)
710                                 dentry_add_child(root, child);
711                 }
712                 closedir(dir);
713         } else { /* Archiving a symbolic link */
714                 inode->i_attributes = FILE_ATTRIBUTE_REPARSE_POINT;
715                 inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
716
717                 /* The idea here is to call readlink() to get the UNIX target of
718                  * the symbolic link, then turn the target into a reparse point
719                  * data buffer that contains a relative or absolute symbolic
720                  * link (NOT a junction point or *full* path symbolic link with
721                  * drive letter).
722                  */
723
724                 char deref_name_buf[4096];
725                 ssize_t deref_name_len;
726
727                 deref_name_len = readlink(root_disk_path, deref_name_buf,
728                                           sizeof(deref_name_buf) - 1);
729                 if (deref_name_len >= 0) {
730                         deref_name_buf[deref_name_len] = '\0';
731                         DEBUG("Read symlink `%s'", deref_name_buf);
732                         ret = inode_set_symlink(root->d_inode, deref_name_buf,
733                                                 lookup_table, NULL);
734                         if (ret == 0) {
735                                 /*
736                                  * Unfortunately, Windows seems to have the
737                                  * concept of "file" symbolic links as being
738                                  * different from "directory" symbolic links...
739                                  * so FILE_ATTRIBUTE_DIRECTORY needs to be set
740                                  * on the symbolic link if the *target* of the
741                                  * symbolic link is a directory.
742                                  */
743                                 struct stat stbuf;
744                                 if (stat(root_disk_path, &stbuf) == 0 &&
745                                     S_ISDIR(stbuf.st_mode))
746                                 {
747                                         inode->i_attributes |= FILE_ATTRIBUTE_DIRECTORY;
748                                 }
749                         }
750                 } else {
751                         ERROR_WITH_ERRNO("Failed to read target of "
752                                          "symbolic link `%s'", root_disk_path);
753                         ret = WIMLIB_ERR_READLINK;
754                 }
755         }
756 #else
757         /* Win32 version of capturing a directory tree */
758
759         wchar_t *path_utf16;
760         size_t path_utf16_nchars;
761         struct sd_set *sd_set;
762         DWORD err;
763
764         if (extra_arg == NULL) {
765                 sd_set = alloca(sizeof(struct sd_set));
766                 sd_set->rb_root.rb_node = NULL,
767                 sd_set->sd = sd;
768         } else {
769                 sd_set = extra_arg;
770         }
771
772         ret = utf8_to_utf16(root_disk_path, strlen(root_disk_path),
773                             (char**)&path_utf16, &path_utf16_nchars);
774         if (ret)
775                 goto out_destroy_sd_set;
776         path_utf16_nchars /= sizeof(wchar_t);
777
778         HANDLE hFile = win32_open_file(path_utf16);
779         if (hFile == INVALID_HANDLE_VALUE) {
780                 err = GetLastError();
781                 ERROR("Win32 API: Failed to open \"%s\"", root_disk_path);
782                 win32_error(err);
783                 ret = WIMLIB_ERR_OPEN;
784                 goto out_free_path_utf16;
785         }
786
787         BY_HANDLE_FILE_INFORMATION file_info;
788         if (!GetFileInformationByHandle(hFile, &file_info)) {
789                 err = GetLastError();
790                 ERROR("Win32 API: Failed to get file information for \"%s\"",
791                       root_disk_path);
792                 win32_error(err);
793                 ret = WIMLIB_ERR_STAT;
794                 goto out_close_handle;
795         }
796
797         /* Create a WIM dentry */
798         root = new_dentry_with_timeless_inode(path_basename(root_disk_path));
799         if (!root) {
800                 if (errno == EILSEQ)
801                         ret = WIMLIB_ERR_INVALID_UTF8_STRING;
802                 else if (errno == ENOMEM)
803                         ret = WIMLIB_ERR_NOMEM;
804                 else
805                         ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE;
806                 goto out_free_path_utf16;
807         }
808
809         /* Start preparing the associated WIM inode */
810         inode = root->d_inode;
811
812         inode->i_attributes = file_info.dwFileAttributes;
813         inode->i_creation_time = FILETIME_to_u64(&file_info.ftCreationTime);
814         inode->i_last_write_time = FILETIME_to_u64(&file_info.ftLastWriteTime);
815         inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime);
816         inode->i_ino = ((u64)file_info.nFileIndexHigh << 32) |
817                         (u64)file_info.nFileIndexLow;
818
819         inode->i_resolved = 1;
820         add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
821
822         /* Get DOS name and security descriptor (if any). */
823         ret = win32_get_short_name(root, path_utf16);
824         if (ret)
825                 goto out_close_handle;
826         ret = win32_get_security_descriptor(root, sd_set, path_utf16,
827                                             root_disk_path);
828         if (ret)
829                 goto out_close_handle;
830
831         if (inode_is_directory(inode)) {
832                 /* Directory (not a reparse point) --- recurse to children */
833
834                 /* But first... directories may have alternate data streams that
835                  * need to be captured (maybe?) */
836                 ret = win32_capture_streams(root_disk_path,
837                                             path_utf16,
838                                             path_utf16_nchars,
839                                             inode,
840                                             lookup_table);
841                 if (ret)
842                         goto out_close_handle;
843                 ret = win32_recurse_directory(root,
844                                               root_disk_path,
845                                               lookup_table,
846                                               sd,
847                                               config,
848                                               add_image_flags,
849                                               progress_func,
850                                               sd_set,
851                                               path_utf16,
852                                               path_utf16_nchars);
853         } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
854                 /* Reparse point: save the reparse tag and data */
855
856                 ret = win32_capture_reparse_point(root_disk_path,
857                                                   hFile,
858                                                   inode,
859                                                   lookup_table);
860
861         } else {
862                 /* Not a directory, not a reparse point */
863                 ret = win32_capture_streams(root_disk_path,
864                                             path_utf16,
865                                             path_utf16_nchars,
866                                             inode,
867                                             lookup_table);
868         }
869 out_close_handle:
870         CloseHandle(hFile);
871 out_destroy_sd_set:
872         if (extra_arg == NULL)
873                 destroy_sd_set(sd_set);
874 out_free_path_utf16:
875         FREE(path_utf16);
876 #endif
877 out:
878         if (ret == 0)
879                 *root_ret = root;
880         else
881                 free_dentry_tree(root, lookup_table);
882         return ret;
883 }
884
885 enum pattern_type {
886         NONE = 0,
887         EXCLUSION_LIST,
888         EXCLUSION_EXCEPTION,
889         COMPRESSION_EXCLUSION_LIST,
890         ALIGNMENT_LIST,
891 };
892
893 #define COMPAT_DEFAULT_CONFIG
894
895 /* Default capture configuration file when none is specified. */
896 static const char *default_config =
897 #ifdef COMPAT_DEFAULT_CONFIG /* XXX: This policy is being moved to library
898                                 users.  The next ABI-incompatible library
899                                 version will default to the empty string here. */
900 "[ExclusionList]\n"
901 "\\$ntfs.log\n"
902 "\\hiberfil.sys\n"
903 "\\pagefile.sys\n"
904 "\\System Volume Information\n"
905 "\\RECYCLER\n"
906 "\\Windows\\CSC\n"
907 "\n"
908 "[CompressionExclusionList]\n"
909 "*.mp3\n"
910 "*.zip\n"
911 "*.cab\n"
912 "\\WINDOWS\\inf\\*.pnf\n";
913 #else
914 "";
915 #endif
916
917 static void destroy_pattern_list(struct pattern_list *list)
918 {
919         FREE(list->pats);
920 }
921
922 static void destroy_capture_config(struct capture_config *config)
923 {
924         destroy_pattern_list(&config->exclusion_list);
925         destroy_pattern_list(&config->exclusion_exception);
926         destroy_pattern_list(&config->compression_exclusion_list);
927         destroy_pattern_list(&config->alignment_list);
928         FREE(config->config_str);
929         FREE(config->prefix);
930         memset(config, 0, sizeof(*config));
931 }
932
933 static int pattern_list_add_pattern(struct pattern_list *list,
934                                     const char *pattern)
935 {
936         const char **pats;
937         if (list->num_pats >= list->num_allocated_pats) {
938                 pats = REALLOC(list->pats,
939                                sizeof(list->pats[0]) * (list->num_allocated_pats + 8));
940                 if (!pats)
941                         return WIMLIB_ERR_NOMEM;
942                 list->num_allocated_pats += 8;
943                 list->pats = pats;
944         }
945         list->pats[list->num_pats++] = pattern;
946         return 0;
947 }
948
949 /* Parses the contents of the image capture configuration file and fills in a
950  * `struct capture_config'. */
951 static int init_capture_config(struct capture_config *config,
952                                const char *_config_str, size_t config_len)
953 {
954         char *config_str;
955         char *p;
956         char *eol;
957         char *next_p;
958         size_t bytes_remaining;
959         enum pattern_type type = NONE;
960         int ret;
961         unsigned long line_no = 0;
962
963         DEBUG("config_len = %zu", config_len);
964         bytes_remaining = config_len;
965         memset(config, 0, sizeof(*config));
966         config_str = MALLOC(config_len);
967         if (!config_str) {
968                 ERROR("Could not duplicate capture config string");
969                 return WIMLIB_ERR_NOMEM;
970         }
971
972         memcpy(config_str, _config_str, config_len);
973         next_p = config_str;
974         config->config_str = config_str;
975         while (bytes_remaining) {
976                 line_no++;
977                 p = next_p;
978                 eol = memchr(p, '\n', bytes_remaining);
979                 if (!eol) {
980                         ERROR("Expected end-of-line in capture config file on "
981                               "line %lu", line_no);
982                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
983                         goto out_destroy;
984                 }
985
986                 next_p = eol + 1;
987                 bytes_remaining -= (next_p - p);
988                 if (eol == p)
989                         continue;
990
991                 if (*(eol - 1) == '\r')
992                         eol--;
993                 *eol = '\0';
994
995                 /* Translate backslash to forward slash */
996                 for (char *pp = p; pp != eol; pp++)
997                         if (*pp == '\\')
998                                 *pp = '/';
999
1000                 /* Remove drive letter */
1001                 if (eol - p > 2 && isalpha(*p) && *(p + 1) == ':')
1002                         p += 2;
1003
1004                 ret = 0;
1005                 if (strcmp(p, "[ExclusionList]") == 0)
1006                         type = EXCLUSION_LIST;
1007                 else if (strcmp(p, "[ExclusionException]") == 0)
1008                         type = EXCLUSION_EXCEPTION;
1009                 else if (strcmp(p, "[CompressionExclusionList]") == 0)
1010                         type = COMPRESSION_EXCLUSION_LIST;
1011                 else if (strcmp(p, "[AlignmentList]") == 0)
1012                         type = ALIGNMENT_LIST;
1013                 else if (p[0] == '[' && strrchr(p, ']')) {
1014                         ERROR("Unknown capture configuration section `%s'", p);
1015                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
1016                 } else switch (type) {
1017                 case EXCLUSION_LIST:
1018                         DEBUG("Adding pattern \"%s\" to exclusion list", p);
1019                         ret = pattern_list_add_pattern(&config->exclusion_list, p);
1020                         break;
1021                 case EXCLUSION_EXCEPTION:
1022                         DEBUG("Adding pattern \"%s\" to exclusion exception list", p);
1023                         ret = pattern_list_add_pattern(&config->exclusion_exception, p);
1024                         break;
1025                 case COMPRESSION_EXCLUSION_LIST:
1026                         DEBUG("Adding pattern \"%s\" to compression exclusion list", p);
1027                         ret = pattern_list_add_pattern(&config->compression_exclusion_list, p);
1028                         break;
1029                 case ALIGNMENT_LIST:
1030                         DEBUG("Adding pattern \"%s\" to alignment list", p);
1031                         ret = pattern_list_add_pattern(&config->alignment_list, p);
1032                         break;
1033                 default:
1034                         ERROR("Line %lu of capture configuration is not "
1035                               "in a block (such as [ExclusionList])",
1036                               line_no);
1037                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
1038                         break;
1039                 }
1040                 if (ret != 0)
1041                         goto out_destroy;
1042         }
1043         return 0;
1044 out_destroy:
1045         destroy_capture_config(config);
1046         return ret;
1047 }
1048
1049 static int capture_config_set_prefix(struct capture_config *config,
1050                                      const char *_prefix)
1051 {
1052         char *prefix = STRDUP(_prefix);
1053
1054         if (!prefix)
1055                 return WIMLIB_ERR_NOMEM;
1056         FREE(config->prefix);
1057         config->prefix = prefix;
1058         config->prefix_len = strlen(prefix);
1059         return 0;
1060 }
1061
1062 static bool match_pattern(const char *path, const char *path_basename,
1063                           const struct pattern_list *list)
1064 {
1065         for (size_t i = 0; i < list->num_pats; i++) {
1066                 const char *pat = list->pats[i];
1067                 const char *string;
1068                 if (pat[0] == '/')
1069                         /* Absolute path from root of capture */
1070                         string = path;
1071                 else {
1072                         if (strchr(pat, '/'))
1073                                 /* Relative path from root of capture */
1074                                 string = path + 1;
1075                         else
1076                                 /* A file name pattern */
1077                                 string = path_basename;
1078                 }
1079                 if (fnmatch(pat, string, FNM_PATHNAME
1080                         #ifdef FNM_CASEFOLD
1081                                         | FNM_CASEFOLD
1082                         #endif
1083                         ) == 0)
1084                 {
1085                         DEBUG("`%s' matches the pattern \"%s\"",
1086                               string, pat);
1087                         return true;
1088                 }
1089         }
1090         return false;
1091 }
1092
1093 /* Return true if the image capture configuration file indicates we should
1094  * exclude the filename @path from capture.
1095  *
1096  * If @exclude_prefix is %true, the part of the path up and including the name
1097  * of the directory being captured is not included in the path for matching
1098  * purposes.  This allows, for example, a pattern like /hiberfil.sys to match a
1099  * file /mnt/windows7/hiberfil.sys if we are capturing the /mnt/windows7
1100  * directory.
1101  */
1102 bool exclude_path(const char *path, const struct capture_config *config,
1103                   bool exclude_prefix)
1104 {
1105         const char *basename = path_basename(path);
1106         if (exclude_prefix) {
1107                 wimlib_assert(strlen(path) >= config->prefix_len);
1108                 if (memcmp(config->prefix, path, config->prefix_len) == 0
1109                      && path[config->prefix_len] == '/')
1110                         path += config->prefix_len;
1111         }
1112         return match_pattern(path, basename, &config->exclusion_list) &&
1113                 !match_pattern(path, basename, &config->exclusion_exception);
1114
1115 }
1116
1117 /* Strip leading and trailing forward slashes from a string.  Modifies it in
1118  * place and returns the stripped string. */
1119 static const char *canonicalize_target_path(char *target_path)
1120 {
1121         char *p;
1122         if (target_path == NULL)
1123                 target_path = "";
1124         for (;;) {
1125                 if (*target_path == '\0')
1126                         return target_path;
1127                 else if (*target_path == '/')
1128                         target_path++;
1129                 else
1130                         break;
1131         }
1132
1133         p = target_path + strlen(target_path) - 1;
1134         while (*p == '/')
1135                 *p-- = '\0';
1136         return target_path;
1137 }
1138
1139 /* Strip leading and trailing slashes from the target paths */
1140 static void canonicalize_targets(struct wimlib_capture_source *sources,
1141                                  size_t num_sources)
1142 {
1143         while (num_sources--) {
1144                 DEBUG("Canonicalizing { source: \"%s\", target=\"%s\"}",
1145                       sources->fs_source_path,
1146                       sources->wim_target_path);
1147                 sources->wim_target_path =
1148                         (char*)canonicalize_target_path(sources->wim_target_path);
1149                 DEBUG("Canonical target: \"%s\"", sources->wim_target_path);
1150                 sources++;
1151         }
1152 }
1153
1154 static int capture_source_cmp(const void *p1, const void *p2)
1155 {
1156         const struct wimlib_capture_source *s1 = p1, *s2 = p2;
1157         return strcmp(s1->wim_target_path, s2->wim_target_path);
1158 }
1159
1160 /* Sorts the capture sources lexicographically by target path.  This occurs
1161  * after leading and trailing forward slashes are stripped.
1162  *
1163  * One purpose of this is to make sure that target paths that are inside other
1164  * target paths are extracted after the containing target paths. */
1165 static void sort_sources(struct wimlib_capture_source *sources,
1166                          size_t num_sources)
1167 {
1168         qsort(sources, num_sources, sizeof(sources[0]), capture_source_cmp);
1169 }
1170
1171 static int check_sorted_sources(struct wimlib_capture_source *sources,
1172                                 size_t num_sources, int add_image_flags)
1173 {
1174         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
1175                 if (num_sources != 1) {
1176                         ERROR("Must specify exactly 1 capture source "
1177                               "(the NTFS volume) in NTFS mode!");
1178                         return WIMLIB_ERR_INVALID_PARAM;
1179                 }
1180                 if (sources[0].wim_target_path[0] != '\0') {
1181                         ERROR("In NTFS capture mode the target path inside "
1182                               "the image must be the root directory!");
1183                         return WIMLIB_ERR_INVALID_PARAM;
1184                 }
1185         } else if (num_sources != 0) {
1186                 /* This code is disabled because the current code
1187                  * unconditionally attempts to do overlays.  So, duplicate
1188                  * target paths are OK. */
1189         #if 0
1190                 if (num_sources > 1 && sources[0].wim_target_path[0] == '\0') {
1191                         ERROR("Cannot specify root target when using multiple "
1192                               "capture sources!");
1193                         return WIMLIB_ERR_INVALID_PARAM;
1194                 }
1195                 for (size_t i = 0; i < num_sources - 1; i++) {
1196                         size_t len = strlen(sources[i].wim_target_path);
1197                         size_t j = i + 1;
1198                         const char *target1 = sources[i].wim_target_path;
1199                         do {
1200                                 const char *target2 = sources[j].wim_target_path;
1201                                 DEBUG("target1=%s, target2=%s",
1202                                       target1,target2);
1203                                 if (strncmp(target1, target2, len) ||
1204                                     target2[len] > '/')
1205                                         break;
1206                                 if (target2[len] == '/') {
1207                                         ERROR("Invalid target `%s': is a prefix of `%s'",
1208                                               target1, target2);
1209                                         return WIMLIB_ERR_INVALID_PARAM;
1210                                 }
1211                                 if (target2[len] == '\0') {
1212                                         ERROR("Invalid target `%s': is a duplicate of `%s'",
1213                                               target1, target2);
1214                                         return WIMLIB_ERR_INVALID_PARAM;
1215                                 }
1216                         } while (++j != num_sources);
1217                 }
1218         #endif
1219         }
1220         return 0;
1221
1222 }
1223
1224 /* Creates a new directory to place in the WIM image.  This is to create parent
1225  * directories that are not part of any target as needed.  */
1226 static struct wim_dentry *
1227 new_filler_directory(const char *name)
1228 {
1229         struct wim_dentry *dentry;
1230         DEBUG("Creating filler directory \"%s\"", name);
1231         dentry = new_dentry_with_inode(name);
1232         if (dentry) {
1233                 /* Set the inode number to 0 for now.  The final inode number
1234                  * will be assigned later by assign_inode_numbers(). */
1235                 dentry->d_inode->i_ino = 0;
1236                 dentry->d_inode->i_resolved = 1;
1237                 dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
1238         }
1239         return dentry;
1240 }
1241
1242 /* Transfers the children of @branch to @target.  It is an error if @target is
1243  * not a directory or if both @branch and @target contain a child dentry with
1244  * the same name. */
1245 static int do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
1246 {
1247         struct rb_root *rb_root;
1248
1249         if (!dentry_is_directory(target)) {
1250                 ERROR("Cannot overlay directory `%s' over non-directory",
1251                       branch->file_name_utf8);
1252                 return WIMLIB_ERR_INVALID_OVERLAY;
1253         }
1254
1255         rb_root = &branch->d_inode->i_children;
1256         while (rb_root->rb_node) { /* While @branch has children... */
1257                 struct wim_dentry *child = rbnode_dentry(rb_root->rb_node);
1258                 /* Move @child to the directory @target */
1259                 unlink_dentry(child);
1260                 if (!dentry_add_child(target, child)) {
1261                         /* Revert the change to avoid leaking the directory tree
1262                          * rooted at @child */
1263                         dentry_add_child(branch, child);
1264                         ERROR("Overlay error: file `%s' already exists "
1265                               "as a child of `%s'",
1266                               child->file_name_utf8, target->file_name_utf8);
1267                         return WIMLIB_ERR_INVALID_OVERLAY;
1268                 }
1269         }
1270         return 0;
1271
1272 }
1273
1274 /* Attach or overlay a branch onto the WIM image.
1275  *
1276  * @root_p:
1277  *      Pointer to the root of the WIM image, or pointer to NULL if it has not
1278  *      been created yet.
1279  * @branch
1280  *      Branch to add.
1281  * @target_path:
1282  *      Path in the WIM image to add the branch, with leading and trailing
1283  *      slashes stripped.
1284  */
1285 static int attach_branch(struct wim_dentry **root_p,
1286                          struct wim_dentry *branch,
1287                          char *target_path)
1288 {
1289         char *slash;
1290         struct wim_dentry *dentry, *parent, *target;
1291
1292         if (*target_path == '\0') {
1293                 /* Target: root directory */
1294                 if (*root_p) {
1295                         /* Overlay on existing root */
1296                         return do_overlay(*root_p, branch);
1297                 } else  {
1298                         /* Set as root */
1299                         *root_p = branch;
1300                         return 0;
1301                 }
1302         }
1303
1304         /* Adding a non-root branch.  Create root if it hasn't been created
1305          * already. */
1306         if (!*root_p) {
1307                 *root_p = new_filler_directory("");
1308                 if (!*root_p)
1309                         return WIMLIB_ERR_NOMEM;
1310         }
1311
1312         /* Walk the path to the branch, creating filler directories as needed.
1313          * */
1314         parent = *root_p;
1315         while ((slash = strchr(target_path, '/'))) {
1316                 *slash = '\0';
1317                 dentry = get_dentry_child_with_name(parent, target_path);
1318                 if (!dentry) {
1319                         dentry = new_filler_directory(target_path);
1320                         if (!dentry)
1321                                 return WIMLIB_ERR_NOMEM;
1322                         dentry_add_child(parent, dentry);
1323                 }
1324                 parent = dentry;
1325                 target_path = slash;
1326                 /* Skip over slashes.  Note: this cannot overrun the length of
1327                  * the string because the last character cannot be a slash, as
1328                  * trailing slashes were tripped.  */
1329                 do {
1330                         ++target_path;
1331                 } while (*target_path == '/');
1332         }
1333
1334         /* If the target path already existed, overlay the branch onto it.
1335          * Otherwise, set the branch as the target path. */
1336         target = get_dentry_child_with_name(parent, branch->file_name_utf8);
1337         if (target) {
1338                 return do_overlay(target, branch);
1339         } else {
1340                 dentry_add_child(parent, branch);
1341                 return 0;
1342         }
1343 }
1344
1345 WIMLIBAPI int wimlib_add_image_multisource(WIMStruct *w,
1346                                            struct wimlib_capture_source *sources,
1347                                            size_t num_sources,
1348                                            const char *name,
1349                                            const char *config_str,
1350                                            size_t config_len,
1351                                            int add_image_flags,
1352                                            wimlib_progress_func_t progress_func)
1353 {
1354         int (*capture_tree)(struct wim_dentry **, const char *,
1355                             struct wim_lookup_table *,
1356                             struct wim_security_data *,
1357                             const struct capture_config *,
1358                             int, wimlib_progress_func_t, void *);
1359         void *extra_arg;
1360         struct wim_dentry *root_dentry;
1361         struct wim_dentry *branch;
1362         struct wim_security_data *sd;
1363         struct capture_config config;
1364         struct wim_image_metadata *imd;
1365         int ret;
1366
1367         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
1368 #ifdef WITH_NTFS_3G
1369                 if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) {
1370                         ERROR("Cannot dereference files when capturing directly from NTFS");
1371                         return WIMLIB_ERR_INVALID_PARAM;
1372                 }
1373                 if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
1374                         ERROR("Capturing UNIX owner and mode not supported "
1375                               "when capturing directly from NTFS");
1376                         return WIMLIB_ERR_INVALID_PARAM;
1377                 }
1378                 capture_tree = build_dentry_tree_ntfs;
1379                 extra_arg = &w->ntfs_vol;
1380 #else
1381                 ERROR("wimlib was compiled without support for NTFS-3g, so\n"
1382                       "        cannot capture a WIM image directly from a NTFS volume!");
1383                 return WIMLIB_ERR_UNSUPPORTED;
1384 #endif
1385         } else {
1386                 capture_tree = build_dentry_tree;
1387                 extra_arg = NULL;
1388         }
1389
1390 #if defined(__CYGWIN__) || defined(__WIN32__)
1391         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
1392                 ERROR("Capturing UNIX-specific data is not supported on Windows");
1393                 return WIMLIB_ERR_INVALID_PARAM;
1394         }
1395         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) {
1396                 ERROR("Dereferencing symbolic links is not supported on Windows");
1397                 return WIMLIB_ERR_INVALID_PARAM;
1398         }
1399 #endif
1400
1401         if (!name || !*name) {
1402                 ERROR("Must specify a non-empty string for the image name");
1403                 return WIMLIB_ERR_INVALID_PARAM;
1404         }
1405
1406         if (w->hdr.total_parts != 1) {
1407                 ERROR("Cannot add an image to a split WIM");
1408                 return WIMLIB_ERR_SPLIT_UNSUPPORTED;
1409         }
1410
1411         if (wimlib_image_name_in_use(w, name)) {
1412                 ERROR("There is already an image named \"%s\" in `%s'",
1413                       name, w->filename);
1414                 return WIMLIB_ERR_IMAGE_NAME_COLLISION;
1415         }
1416
1417         if (!config_str) {
1418                 DEBUG("Using default capture configuration");
1419                 config_str = default_config;
1420                 config_len = strlen(default_config);
1421         }
1422         ret = init_capture_config(&config, config_str, config_len);
1423         if (ret)
1424                 goto out;
1425
1426         DEBUG("Allocating security data");
1427         sd = CALLOC(1, sizeof(struct wim_security_data));
1428         if (!sd) {
1429                 ret = WIMLIB_ERR_NOMEM;
1430                 goto out_destroy_capture_config;
1431         }
1432         sd->total_length = 8;
1433         sd->refcnt = 1;
1434
1435         DEBUG("Using %zu capture sources", num_sources);
1436         canonicalize_targets(sources, num_sources);
1437         sort_sources(sources, num_sources);
1438         ret = check_sorted_sources(sources, num_sources, add_image_flags);
1439         if (ret) {
1440                 ret = WIMLIB_ERR_INVALID_PARAM;
1441                 goto out_free_security_data;
1442         }
1443
1444         DEBUG("Building dentry tree.");
1445         if (num_sources == 0) {
1446                 root_dentry = new_filler_directory("");
1447                 if (!root_dentry)
1448                         goto out_free_security_data;
1449         } else {
1450                 size_t i;
1451
1452                 root_dentry = NULL;
1453                 i = 0;
1454                 do {
1455                         int flags;
1456                         union wimlib_progress_info progress;
1457
1458                         DEBUG("Building dentry tree for source %zu of %zu "
1459                               "(\"%s\" => \"%s\")", i + 1, num_sources,
1460                               sources[i].fs_source_path,
1461                               sources[i].wim_target_path);
1462                         if (progress_func) {
1463                                 memset(&progress, 0, sizeof(progress));
1464                                 progress.scan.source = sources[i].fs_source_path;
1465                                 progress.scan.wim_target_path = sources[i].wim_target_path;
1466                                 progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, &progress);
1467                         }
1468                         ret = capture_config_set_prefix(&config,
1469                                                         sources[i].fs_source_path);
1470                         if (ret)
1471                                 goto out_free_dentry_tree;
1472                         flags = add_image_flags | WIMLIB_ADD_IMAGE_FLAG_SOURCE;
1473                         if (!*sources[i].wim_target_path)
1474                                 flags |= WIMLIB_ADD_IMAGE_FLAG_ROOT;
1475                         ret = (*capture_tree)(&branch, sources[i].fs_source_path,
1476                                               w->lookup_table, sd,
1477                                               &config,
1478                                               flags,
1479                                               progress_func, extra_arg);
1480                         if (ret) {
1481                                 ERROR("Failed to build dentry tree for `%s'",
1482                                       sources[i].fs_source_path);
1483                                 goto out_free_dentry_tree;
1484                         }
1485                         if (branch) {
1486                                 /* Use the target name, not the source name, for
1487                                  * the root of each branch from a capture
1488                                  * source.  (This will also set the root dentry
1489                                  * of the entire image to be unnamed.) */
1490                                 ret = set_dentry_name(branch,
1491                                                       path_basename(sources[i].wim_target_path));
1492                                 if (ret)
1493                                         goto out_free_branch;
1494
1495                                 ret = attach_branch(&root_dentry, branch,
1496                                                     sources[i].wim_target_path);
1497                                 if (ret)
1498                                         goto out_free_branch;
1499                         }
1500                         if (progress_func)
1501                                 progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, &progress);
1502                 } while (++i != num_sources);
1503         }
1504
1505         DEBUG("Calculating full paths of dentries.");
1506         ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL);
1507         if (ret != 0)
1508                 goto out_free_dentry_tree;
1509
1510         ret = add_new_dentry_tree(w, root_dentry, sd);
1511         if (ret != 0)
1512                 goto out_free_dentry_tree;
1513
1514         imd = &w->image_metadata[w->hdr.image_count - 1];
1515
1516         ret = dentry_tree_fix_inodes(root_dentry, &imd->inode_list);
1517         if (ret != 0)
1518                 goto out_destroy_imd;
1519
1520         DEBUG("Assigning hard link group IDs");
1521         assign_inode_numbers(&imd->inode_list);
1522
1523         ret = xml_add_image(w, name);
1524         if (ret != 0)
1525                 goto out_destroy_imd;
1526
1527         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
1528                 wimlib_set_boot_idx(w, w->hdr.image_count);
1529         ret = 0;
1530         goto out;
1531 out_destroy_imd:
1532         destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1],
1533                                w->lookup_table);
1534         w->hdr.image_count--;
1535         goto out;
1536 out_free_branch:
1537         free_dentry_tree(branch, w->lookup_table);
1538 out_free_dentry_tree:
1539         free_dentry_tree(root_dentry, w->lookup_table);
1540 out_free_security_data:
1541         free_security_data(sd);
1542 out_destroy_capture_config:
1543         destroy_capture_config(&config);
1544 out:
1545         return ret;
1546 }
1547
1548 WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source,
1549                                const char *name, const char *config_str,
1550                                size_t config_len, int add_image_flags,
1551                                wimlib_progress_func_t progress_func)
1552 {
1553         if (!source || !*source)
1554                 return WIMLIB_ERR_INVALID_PARAM;
1555
1556         char *fs_source_path = STRDUP(source);
1557         int ret;
1558         struct wimlib_capture_source capture_src = {
1559                 .fs_source_path = fs_source_path,
1560                 .wim_target_path = NULL,
1561                 .reserved = 0,
1562         };
1563         ret = wimlib_add_image_multisource(w, &capture_src, 1, name,
1564                                            config_str, config_len,
1565                                            add_image_flags, progress_func);
1566         FREE(fs_source_path);
1567         return ret;
1568 }