]> 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                 ERROR("Win32 API: Failed to look up data streams of \"%s\"",
432                       path);
433                 return WIMLIB_ERR_READ;
434         }
435         do {
436                 ret = win32_capture_stream(path, path_utf16,
437                                            path_utf16_nchars,
438                                            inode, lookup_table,
439                                            &dat);
440                 if (ret)
441                         goto out_find_close;
442         } while (FindNextStreamW(hFind, &dat));
443         err = GetLastError();
444         if (err != ERROR_HANDLE_EOF) {
445                 ERROR("Win32 API: Error reading data streams from \"%s\"", path);
446                 win32_error(err);
447                 ret = WIMLIB_ERR_READ;
448         }
449 out_find_close:
450         FindClose(hFind);
451         return ret;
452 }
453 #endif
454
455 /*
456  * build_dentry_tree():
457  *      Recursively builds a tree of WIM dentries from an on-disk directory
458  *      tree.
459  *
460  * @root_ret:   Place to return a pointer to the root of the dentry tree.  Only
461  *              modified if successful.  Set to NULL if the file or directory was
462  *              excluded from capture.
463  *
464  * @root_disk_path:  The path to the root of the directory tree on disk.
465  *
466  * @lookup_table: The lookup table for the WIM file.  For each file added to the
467  *              dentry tree being built, an entry is added to the lookup table,
468  *              unless an identical stream is already in the lookup table.
469  *              These lookup table entries that are added point to the path of
470  *              the file on disk.
471  *
472  * @sd:         Ignored.  (Security data only captured in NTFS mode.)
473  *
474  * @capture_config:
475  *              Configuration for files to be excluded from capture.
476  *
477  * @add_flags:  Bitwise or of WIMLIB_ADD_IMAGE_FLAG_*
478  *
479  * @extra_arg:  Ignored. (Only used in NTFS mode.)
480  *
481  * @return:     0 on success, nonzero on failure.  It is a failure if any of
482  *              the files cannot be `stat'ed, or if any of the needed
483  *              directories cannot be opened or read.  Failure to add the files
484  *              to the WIM may still occur later when trying to actually read
485  *              the on-disk files during a call to wimlib_write() or
486  *              wimlib_overwrite().
487  */
488 static int build_dentry_tree(struct wim_dentry **root_ret,
489                              const char *root_disk_path,
490                              struct wim_lookup_table *lookup_table,
491                              struct wim_security_data *sd,
492                              const struct capture_config *config,
493                              int add_image_flags,
494                              wimlib_progress_func_t progress_func,
495                              void *extra_arg)
496 {
497         struct wim_dentry *root = NULL;
498         int ret = 0;
499         struct wim_inode *inode;
500
501         if (exclude_path(root_disk_path, config, true)) {
502                 if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) {
503                         ERROR("Cannot exclude the root directory from capture");
504                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
505                         goto out;
506                 }
507                 if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
508                     && progress_func)
509                 {
510                         union wimlib_progress_info info;
511                         info.scan.cur_path = root_disk_path;
512                         info.scan.excluded = true;
513                         progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
514                 }
515                 goto out;
516         }
517
518         if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
519             && progress_func)
520         {
521                 union wimlib_progress_info info;
522                 info.scan.cur_path = root_disk_path;
523                 info.scan.excluded = false;
524                 progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info);
525         }
526
527 #if !defined(__CYGWIN__) && !defined(__WIN32__)
528         /* UNIX version of capturing a directory tree */
529         struct stat root_stbuf;
530         int (*stat_fn)(const char *restrict, struct stat *restrict);
531         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)
532                 stat_fn = stat;
533         else
534                 stat_fn = lstat;
535
536         ret = (*stat_fn)(root_disk_path, &root_stbuf);
537         if (ret != 0) {
538                 ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path);
539                 goto out;
540         }
541
542         if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) &&
543               !S_ISDIR(root_stbuf.st_mode))
544         {
545                 /* Do a dereference-stat in case the root is a symbolic link.
546                  * This case is allowed, provided that the symbolic link points
547                  * to a directory. */
548                 ret = stat(root_disk_path, &root_stbuf);
549                 if (ret != 0) {
550                         ERROR_WITH_ERRNO("Failed to stat `%s'", root_disk_path);
551                         ret = WIMLIB_ERR_STAT;
552                         goto out;
553                 }
554                 if (!S_ISDIR(root_stbuf.st_mode)) {
555                         ERROR("`%s' is not a directory", root_disk_path);
556                         ret = WIMLIB_ERR_NOTDIR;
557                         goto out;
558                 }
559         }
560         if (!S_ISREG(root_stbuf.st_mode) && !S_ISDIR(root_stbuf.st_mode)
561             && !S_ISLNK(root_stbuf.st_mode)) {
562                 ERROR("`%s' is not a regular file, directory, or symbolic link.",
563                       root_disk_path);
564                 ret = WIMLIB_ERR_SPECIAL_FILE;
565                 goto out;
566         }
567
568         root = new_dentry_with_timeless_inode(path_basename(root_disk_path));
569         if (!root) {
570                 if (errno == EILSEQ)
571                         ret = WIMLIB_ERR_INVALID_UTF8_STRING;
572                 else if (errno == ENOMEM)
573                         ret = WIMLIB_ERR_NOMEM;
574                 else
575                         ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE;
576                 goto out;
577         }
578
579         inode = root->d_inode;
580
581 #ifdef HAVE_STAT_NANOSECOND_PRECISION
582         inode->i_creation_time = timespec_to_wim_timestamp(&root_stbuf.st_mtim);
583         inode->i_last_write_time = timespec_to_wim_timestamp(&root_stbuf.st_mtim);
584         inode->i_last_access_time = timespec_to_wim_timestamp(&root_stbuf.st_atim);
585 #else
586         inode->i_creation_time = unix_timestamp_to_wim(root_stbuf.st_mtime);
587         inode->i_last_write_time = unix_timestamp_to_wim(root_stbuf.st_mtime);
588         inode->i_last_access_time = unix_timestamp_to_wim(root_stbuf.st_atime);
589 #endif
590         if (sizeof(ino_t) >= 8)
591                 inode->i_ino = (u64)root_stbuf.st_ino;
592         else
593                 inode->i_ino = (u64)root_stbuf.st_ino |
594                                    ((u64)root_stbuf.st_dev << ((sizeof(ino_t) * 8) & 63));
595         inode->i_resolved = 1;
596         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
597                 ret = inode_set_unix_data(inode, root_stbuf.st_uid,
598                                           root_stbuf.st_gid,
599                                           root_stbuf.st_mode,
600                                           lookup_table,
601                                           UNIX_DATA_ALL | UNIX_DATA_CREATE);
602                 if (ret)
603                         goto out;
604         }
605         add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
606         if (S_ISREG(root_stbuf.st_mode)) { /* Archiving a regular file */
607
608                 struct wim_lookup_table_entry *lte;
609                 u8 hash[SHA1_HASH_SIZE];
610
611                 inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
612
613                 /* Empty files do not have to have a lookup table entry. */
614                 if (root_stbuf.st_size == 0)
615                         goto out;
616
617                 /* For each regular file, we must check to see if the file is in
618                  * the lookup table already; if it is, we increment its refcnt;
619                  * otherwise, we create a new lookup table entry and insert it.
620                  * */
621
622                 ret = sha1sum(root_disk_path, hash);
623                 if (ret != 0)
624                         goto out;
625
626                 lte = __lookup_resource(lookup_table, hash);
627                 if (lte) {
628                         lte->refcnt++;
629                         DEBUG("Add lte reference %u for `%s'", lte->refcnt,
630                               root_disk_path);
631                 } else {
632                         char *file_on_disk = STRDUP(root_disk_path);
633                         if (!file_on_disk) {
634                                 ERROR("Failed to allocate memory for file path");
635                                 ret = WIMLIB_ERR_NOMEM;
636                                 goto out;
637                         }
638                         lte = new_lookup_table_entry();
639                         if (!lte) {
640                                 FREE(file_on_disk);
641                                 ret = WIMLIB_ERR_NOMEM;
642                                 goto out;
643                         }
644                         lte->file_on_disk = file_on_disk;
645                         lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
646                         lte->resource_entry.original_size = root_stbuf.st_size;
647                         lte->resource_entry.size = root_stbuf.st_size;
648                         copy_hash(lte->hash, hash);
649                         lookup_table_insert(lookup_table, lte);
650                 }
651                 root->d_inode->i_lte = lte;
652         } else if (S_ISDIR(root_stbuf.st_mode)) { /* Archiving a directory */
653
654                 inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
655
656                 DIR *dir;
657                 struct dirent entry, *result;
658                 struct wim_dentry *child;
659
660                 dir = opendir(root_disk_path);
661                 if (!dir) {
662                         ERROR_WITH_ERRNO("Failed to open the directory `%s'",
663                                          root_disk_path);
664                         ret = WIMLIB_ERR_OPEN;
665                         goto out;
666                 }
667
668                 /* Buffer for names of files in directory. */
669                 size_t len = strlen(root_disk_path);
670                 char name[len + 1 + FILENAME_MAX + 1];
671                 memcpy(name, root_disk_path, len);
672                 name[len] = '/';
673
674                 /* Create a dentry for each entry in the directory on disk, and recurse
675                  * to any subdirectories. */
676                 while (1) {
677                         errno = 0;
678                         ret = readdir_r(dir, &entry, &result);
679                         if (ret != 0) {
680                                 ret = WIMLIB_ERR_READ;
681                                 ERROR_WITH_ERRNO("Error reading the "
682                                                  "directory `%s'",
683                                                  root_disk_path);
684                                 break;
685                         }
686                         if (result == NULL)
687                                 break;
688                         if (result->d_name[0] == '.' && (result->d_name[1] == '\0'
689                               || (result->d_name[1] == '.' && result->d_name[2] == '\0')))
690                                         continue;
691                         strcpy(name + len + 1, result->d_name);
692                         ret = build_dentry_tree(&child, name, lookup_table,
693                                                 NULL, config, add_image_flags,
694                                                 progress_func, NULL);
695                         if (ret != 0)
696                                 break;
697                         if (child)
698                                 dentry_add_child(root, child);
699                 }
700                 closedir(dir);
701         } else { /* Archiving a symbolic link */
702                 inode->i_attributes = FILE_ATTRIBUTE_REPARSE_POINT;
703                 inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
704
705                 /* The idea here is to call readlink() to get the UNIX target of
706                  * the symbolic link, then turn the target into a reparse point
707                  * data buffer that contains a relative or absolute symbolic
708                  * link (NOT a junction point or *full* path symbolic link with
709                  * drive letter).
710                  */
711
712                 char deref_name_buf[4096];
713                 ssize_t deref_name_len;
714
715                 deref_name_len = readlink(root_disk_path, deref_name_buf,
716                                           sizeof(deref_name_buf) - 1);
717                 if (deref_name_len >= 0) {
718                         deref_name_buf[deref_name_len] = '\0';
719                         DEBUG("Read symlink `%s'", deref_name_buf);
720                         ret = inode_set_symlink(root->d_inode, deref_name_buf,
721                                                 lookup_table, NULL);
722                         if (ret == 0) {
723                                 /*
724                                  * Unfortunately, Windows seems to have the
725                                  * concept of "file" symbolic links as being
726                                  * different from "directory" symbolic links...
727                                  * so FILE_ATTRIBUTE_DIRECTORY needs to be set
728                                  * on the symbolic link if the *target* of the
729                                  * symbolic link is a directory.
730                                  */
731                                 struct stat stbuf;
732                                 if (stat(root_disk_path, &stbuf) == 0 &&
733                                     S_ISDIR(stbuf.st_mode))
734                                 {
735                                         inode->i_attributes |= FILE_ATTRIBUTE_DIRECTORY;
736                                 }
737                         }
738                 } else {
739                         ERROR_WITH_ERRNO("Failed to read target of "
740                                          "symbolic link `%s'", root_disk_path);
741                         ret = WIMLIB_ERR_READLINK;
742                 }
743         }
744 #else
745         /* Win32 version of capturing a directory tree */
746
747         wchar_t *path_utf16;
748         size_t path_utf16_nchars;
749         struct sd_set *sd_set;
750         DWORD err;
751
752         if (extra_arg == NULL) {
753                 sd_set = alloca(sizeof(struct sd_set));
754                 sd_set->rb_root.rb_node = NULL,
755                 sd_set->sd = sd;
756         } else {
757                 sd_set = extra_arg;
758         }
759
760         ret = utf8_to_utf16(root_disk_path, strlen(root_disk_path),
761                             (char**)&path_utf16, &path_utf16_nchars);
762         if (ret)
763                 goto out_destroy_sd_set;
764         path_utf16_nchars /= sizeof(wchar_t);
765
766         HANDLE hFile = win32_open_file(path_utf16);
767         if (hFile == INVALID_HANDLE_VALUE) {
768                 err = GetLastError();
769                 ERROR("Win32 API: Failed to open \"%s\"", root_disk_path);
770                 win32_error(err);
771                 ret = WIMLIB_ERR_OPEN;
772                 goto out_free_path_utf16;
773         }
774
775         BY_HANDLE_FILE_INFORMATION file_info;
776         if (!GetFileInformationByHandle(hFile, &file_info)) {
777                 err = GetLastError();
778                 ERROR("Win32 API: Failed to get file information for \"%s\"",
779                       root_disk_path);
780                 win32_error(err);
781                 ret = WIMLIB_ERR_STAT;
782                 goto out_close_handle;
783         }
784
785         /* Create a WIM dentry */
786         root = new_dentry_with_timeless_inode(path_basename(root_disk_path));
787         if (!root) {
788                 if (errno == EILSEQ)
789                         ret = WIMLIB_ERR_INVALID_UTF8_STRING;
790                 else if (errno == ENOMEM)
791                         ret = WIMLIB_ERR_NOMEM;
792                 else
793                         ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE;
794                 goto out_free_path_utf16;
795         }
796
797         /* Start preparing the associated WIM inode */
798         inode = root->d_inode;
799
800         inode->i_attributes = file_info.dwFileAttributes;
801         inode->i_creation_time = FILETIME_to_u64(&file_info.ftCreationTime);
802         inode->i_last_write_time = FILETIME_to_u64(&file_info.ftLastWriteTime);
803         inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime);
804         inode->i_ino = ((u64)file_info.nFileIndexHigh << 32) |
805                         (u64)file_info.nFileIndexLow;
806
807         inode->i_resolved = 1;
808         add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE);
809
810         /* Get DOS name and security descriptor (if any). */
811         ret = win32_get_short_name(root, path_utf16);
812         if (ret)
813                 goto out_close_handle;
814         ret = win32_get_security_descriptor(root, sd_set, path_utf16,
815                                             root_disk_path);
816         if (ret)
817                 goto out_close_handle;
818
819         if (inode_is_directory(inode)) {
820                 /* Directory (not a reparse point) --- recurse to children */
821
822                 /* But first... directories may have alternate data streams that
823                  * need to be captured */
824                 ret = win32_capture_streams(root_disk_path,
825                                             path_utf16,
826                                             path_utf16_nchars,
827                                             inode,
828                                             lookup_table);
829                 if (ret)
830                         goto out_close_handle;
831                 ret = win32_recurse_directory(root,
832                                               root_disk_path,
833                                               lookup_table,
834                                               sd,
835                                               config,
836                                               add_image_flags,
837                                               progress_func,
838                                               sd_set,
839                                               path_utf16,
840                                               path_utf16_nchars);
841         } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
842                 /* Reparse point: save the reparse tag and data */
843
844                 ret = win32_capture_reparse_point(root_disk_path,
845                                                   hFile,
846                                                   inode,
847                                                   lookup_table);
848
849         } else {
850                 /* Not a directory, not a reparse point */
851                 ret = win32_capture_streams(root_disk_path,
852                                             path_utf16,
853                                             path_utf16_nchars,
854                                             inode,
855                                             lookup_table);
856         }
857 out_close_handle:
858         CloseHandle(hFile);
859 out_destroy_sd_set:
860         if (extra_arg == NULL)
861                 destroy_sd_set(sd_set);
862 out_free_path_utf16:
863         FREE(path_utf16);
864 #endif
865 out:
866         if (ret == 0)
867                 *root_ret = root;
868         else
869                 free_dentry_tree(root, lookup_table);
870         return ret;
871 }
872
873 enum pattern_type {
874         NONE = 0,
875         EXCLUSION_LIST,
876         EXCLUSION_EXCEPTION,
877         COMPRESSION_EXCLUSION_LIST,
878         ALIGNMENT_LIST,
879 };
880
881 #define COMPAT_DEFAULT_CONFIG
882
883 /* Default capture configuration file when none is specified. */
884 static const char *default_config =
885 #ifdef COMPAT_DEFAULT_CONFIG /* XXX: This policy is being moved to library
886                                 users.  The next ABI-incompatible library
887                                 version will default to the empty string here. */
888 "[ExclusionList]\n"
889 "\\$ntfs.log\n"
890 "\\hiberfil.sys\n"
891 "\\pagefile.sys\n"
892 "\\System Volume Information\n"
893 "\\RECYCLER\n"
894 "\\Windows\\CSC\n"
895 "\n"
896 "[CompressionExclusionList]\n"
897 "*.mp3\n"
898 "*.zip\n"
899 "*.cab\n"
900 "\\WINDOWS\\inf\\*.pnf\n";
901 #else
902 "";
903 #endif
904
905 static void destroy_pattern_list(struct pattern_list *list)
906 {
907         FREE(list->pats);
908 }
909
910 static void destroy_capture_config(struct capture_config *config)
911 {
912         destroy_pattern_list(&config->exclusion_list);
913         destroy_pattern_list(&config->exclusion_exception);
914         destroy_pattern_list(&config->compression_exclusion_list);
915         destroy_pattern_list(&config->alignment_list);
916         FREE(config->config_str);
917         FREE(config->prefix);
918         memset(config, 0, sizeof(*config));
919 }
920
921 static int pattern_list_add_pattern(struct pattern_list *list,
922                                     const char *pattern)
923 {
924         const char **pats;
925         if (list->num_pats >= list->num_allocated_pats) {
926                 pats = REALLOC(list->pats,
927                                sizeof(list->pats[0]) * (list->num_allocated_pats + 8));
928                 if (!pats)
929                         return WIMLIB_ERR_NOMEM;
930                 list->num_allocated_pats += 8;
931                 list->pats = pats;
932         }
933         list->pats[list->num_pats++] = pattern;
934         return 0;
935 }
936
937 /* Parses the contents of the image capture configuration file and fills in a
938  * `struct capture_config'. */
939 static int init_capture_config(struct capture_config *config,
940                                const char *_config_str, size_t config_len)
941 {
942         char *config_str;
943         char *p;
944         char *eol;
945         char *next_p;
946         size_t bytes_remaining;
947         enum pattern_type type = NONE;
948         int ret;
949         unsigned long line_no = 0;
950
951         DEBUG("config_len = %zu", config_len);
952         bytes_remaining = config_len;
953         memset(config, 0, sizeof(*config));
954         config_str = MALLOC(config_len);
955         if (!config_str) {
956                 ERROR("Could not duplicate capture config string");
957                 return WIMLIB_ERR_NOMEM;
958         }
959
960         memcpy(config_str, _config_str, config_len);
961         next_p = config_str;
962         config->config_str = config_str;
963         while (bytes_remaining) {
964                 line_no++;
965                 p = next_p;
966                 eol = memchr(p, '\n', bytes_remaining);
967                 if (!eol) {
968                         ERROR("Expected end-of-line in capture config file on "
969                               "line %lu", line_no);
970                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
971                         goto out_destroy;
972                 }
973
974                 next_p = eol + 1;
975                 bytes_remaining -= (next_p - p);
976                 if (eol == p)
977                         continue;
978
979                 if (*(eol - 1) == '\r')
980                         eol--;
981                 *eol = '\0';
982
983                 /* Translate backslash to forward slash */
984                 for (char *pp = p; pp != eol; pp++)
985                         if (*pp == '\\')
986                                 *pp = '/';
987
988                 /* Remove drive letter */
989                 if (eol - p > 2 && isalpha(*p) && *(p + 1) == ':')
990                         p += 2;
991
992                 ret = 0;
993                 if (strcmp(p, "[ExclusionList]") == 0)
994                         type = EXCLUSION_LIST;
995                 else if (strcmp(p, "[ExclusionException]") == 0)
996                         type = EXCLUSION_EXCEPTION;
997                 else if (strcmp(p, "[CompressionExclusionList]") == 0)
998                         type = COMPRESSION_EXCLUSION_LIST;
999                 else if (strcmp(p, "[AlignmentList]") == 0)
1000                         type = ALIGNMENT_LIST;
1001                 else if (p[0] == '[' && strrchr(p, ']')) {
1002                         ERROR("Unknown capture configuration section `%s'", p);
1003                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
1004                 } else switch (type) {
1005                 case EXCLUSION_LIST:
1006                         DEBUG("Adding pattern \"%s\" to exclusion list", p);
1007                         ret = pattern_list_add_pattern(&config->exclusion_list, p);
1008                         break;
1009                 case EXCLUSION_EXCEPTION:
1010                         DEBUG("Adding pattern \"%s\" to exclusion exception list", p);
1011                         ret = pattern_list_add_pattern(&config->exclusion_exception, p);
1012                         break;
1013                 case COMPRESSION_EXCLUSION_LIST:
1014                         DEBUG("Adding pattern \"%s\" to compression exclusion list", p);
1015                         ret = pattern_list_add_pattern(&config->compression_exclusion_list, p);
1016                         break;
1017                 case ALIGNMENT_LIST:
1018                         DEBUG("Adding pattern \"%s\" to alignment list", p);
1019                         ret = pattern_list_add_pattern(&config->alignment_list, p);
1020                         break;
1021                 default:
1022                         ERROR("Line %lu of capture configuration is not "
1023                               "in a block (such as [ExclusionList])",
1024                               line_no);
1025                         ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG;
1026                         break;
1027                 }
1028                 if (ret != 0)
1029                         goto out_destroy;
1030         }
1031         return 0;
1032 out_destroy:
1033         destroy_capture_config(config);
1034         return ret;
1035 }
1036
1037 static int capture_config_set_prefix(struct capture_config *config,
1038                                      const char *_prefix)
1039 {
1040         char *prefix = STRDUP(_prefix);
1041
1042         if (!prefix)
1043                 return WIMLIB_ERR_NOMEM;
1044         FREE(config->prefix);
1045         config->prefix = prefix;
1046         config->prefix_len = strlen(prefix);
1047         return 0;
1048 }
1049
1050 static bool match_pattern(const char *path, const char *path_basename,
1051                           const struct pattern_list *list)
1052 {
1053         for (size_t i = 0; i < list->num_pats; i++) {
1054                 const char *pat = list->pats[i];
1055                 const char *string;
1056                 if (pat[0] == '/')
1057                         /* Absolute path from root of capture */
1058                         string = path;
1059                 else {
1060                         if (strchr(pat, '/'))
1061                                 /* Relative path from root of capture */
1062                                 string = path + 1;
1063                         else
1064                                 /* A file name pattern */
1065                                 string = path_basename;
1066                 }
1067                 if (fnmatch(pat, string, FNM_PATHNAME
1068                         #ifdef FNM_CASEFOLD
1069                                         | FNM_CASEFOLD
1070                         #endif
1071                         ) == 0)
1072                 {
1073                         DEBUG("`%s' matches the pattern \"%s\"",
1074                               string, pat);
1075                         return true;
1076                 }
1077         }
1078         return false;
1079 }
1080
1081 /* Return true if the image capture configuration file indicates we should
1082  * exclude the filename @path from capture.
1083  *
1084  * If @exclude_prefix is %true, the part of the path up and including the name
1085  * of the directory being captured is not included in the path for matching
1086  * purposes.  This allows, for example, a pattern like /hiberfil.sys to match a
1087  * file /mnt/windows7/hiberfil.sys if we are capturing the /mnt/windows7
1088  * directory.
1089  */
1090 bool exclude_path(const char *path, const struct capture_config *config,
1091                   bool exclude_prefix)
1092 {
1093         const char *basename = path_basename(path);
1094         if (exclude_prefix) {
1095                 wimlib_assert(strlen(path) >= config->prefix_len);
1096                 if (memcmp(config->prefix, path, config->prefix_len) == 0
1097                      && path[config->prefix_len] == '/')
1098                         path += config->prefix_len;
1099         }
1100         return match_pattern(path, basename, &config->exclusion_list) &&
1101                 !match_pattern(path, basename, &config->exclusion_exception);
1102
1103 }
1104
1105 /* Strip leading and trailing forward slashes from a string.  Modifies it in
1106  * place and returns the stripped string. */
1107 static const char *canonicalize_target_path(char *target_path)
1108 {
1109         char *p;
1110         if (target_path == NULL)
1111                 target_path = "";
1112         for (;;) {
1113                 if (*target_path == '\0')
1114                         return target_path;
1115                 else if (*target_path == '/')
1116                         target_path++;
1117                 else
1118                         break;
1119         }
1120
1121         p = target_path + strlen(target_path) - 1;
1122         while (*p == '/')
1123                 *p-- = '\0';
1124         return target_path;
1125 }
1126
1127 /* Strip leading and trailing slashes from the target paths */
1128 static void canonicalize_targets(struct wimlib_capture_source *sources,
1129                                  size_t num_sources)
1130 {
1131         while (num_sources--) {
1132                 DEBUG("Canonicalizing { source: \"%s\", target=\"%s\"}",
1133                       sources->fs_source_path,
1134                       sources->wim_target_path);
1135                 sources->wim_target_path =
1136                         (char*)canonicalize_target_path(sources->wim_target_path);
1137                 DEBUG("Canonical target: \"%s\"", sources->wim_target_path);
1138                 sources++;
1139         }
1140 }
1141
1142 static int capture_source_cmp(const void *p1, const void *p2)
1143 {
1144         const struct wimlib_capture_source *s1 = p1, *s2 = p2;
1145         return strcmp(s1->wim_target_path, s2->wim_target_path);
1146 }
1147
1148 /* Sorts the capture sources lexicographically by target path.  This occurs
1149  * after leading and trailing forward slashes are stripped.
1150  *
1151  * One purpose of this is to make sure that target paths that are inside other
1152  * target paths are extracted after the containing target paths. */
1153 static void sort_sources(struct wimlib_capture_source *sources,
1154                          size_t num_sources)
1155 {
1156         qsort(sources, num_sources, sizeof(sources[0]), capture_source_cmp);
1157 }
1158
1159 static int check_sorted_sources(struct wimlib_capture_source *sources,
1160                                 size_t num_sources, int add_image_flags)
1161 {
1162         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
1163                 if (num_sources != 1) {
1164                         ERROR("Must specify exactly 1 capture source "
1165                               "(the NTFS volume) in NTFS mode!");
1166                         return WIMLIB_ERR_INVALID_PARAM;
1167                 }
1168                 if (sources[0].wim_target_path[0] != '\0') {
1169                         ERROR("In NTFS capture mode the target path inside "
1170                               "the image must be the root directory!");
1171                         return WIMLIB_ERR_INVALID_PARAM;
1172                 }
1173         } else if (num_sources != 0) {
1174                 /* This code is disabled because the current code
1175                  * unconditionally attempts to do overlays.  So, duplicate
1176                  * target paths are OK. */
1177         #if 0
1178                 if (num_sources > 1 && sources[0].wim_target_path[0] == '\0') {
1179                         ERROR("Cannot specify root target when using multiple "
1180                               "capture sources!");
1181                         return WIMLIB_ERR_INVALID_PARAM;
1182                 }
1183                 for (size_t i = 0; i < num_sources - 1; i++) {
1184                         size_t len = strlen(sources[i].wim_target_path);
1185                         size_t j = i + 1;
1186                         const char *target1 = sources[i].wim_target_path;
1187                         do {
1188                                 const char *target2 = sources[j].wim_target_path;
1189                                 DEBUG("target1=%s, target2=%s",
1190                                       target1,target2);
1191                                 if (strncmp(target1, target2, len) ||
1192                                     target2[len] > '/')
1193                                         break;
1194                                 if (target2[len] == '/') {
1195                                         ERROR("Invalid target `%s': is a prefix of `%s'",
1196                                               target1, target2);
1197                                         return WIMLIB_ERR_INVALID_PARAM;
1198                                 }
1199                                 if (target2[len] == '\0') {
1200                                         ERROR("Invalid target `%s': is a duplicate of `%s'",
1201                                               target1, target2);
1202                                         return WIMLIB_ERR_INVALID_PARAM;
1203                                 }
1204                         } while (++j != num_sources);
1205                 }
1206         #endif
1207         }
1208         return 0;
1209
1210 }
1211
1212 /* Creates a new directory to place in the WIM image.  This is to create parent
1213  * directories that are not part of any target as needed.  */
1214 static struct wim_dentry *
1215 new_filler_directory(const char *name)
1216 {
1217         struct wim_dentry *dentry;
1218         DEBUG("Creating filler directory \"%s\"", name);
1219         dentry = new_dentry_with_inode(name);
1220         if (dentry) {
1221                 /* Set the inode number to 0 for now.  The final inode number
1222                  * will be assigned later by assign_inode_numbers(). */
1223                 dentry->d_inode->i_ino = 0;
1224                 dentry->d_inode->i_resolved = 1;
1225                 dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
1226         }
1227         return dentry;
1228 }
1229
1230 /* Transfers the children of @branch to @target.  It is an error if @target is
1231  * not a directory or if both @branch and @target contain a child dentry with
1232  * the same name. */
1233 static int do_overlay(struct wim_dentry *target, struct wim_dentry *branch)
1234 {
1235         struct rb_root *rb_root;
1236
1237         if (!dentry_is_directory(target)) {
1238                 ERROR("Cannot overlay directory `%s' over non-directory",
1239                       branch->file_name_utf8);
1240                 return WIMLIB_ERR_INVALID_OVERLAY;
1241         }
1242
1243         rb_root = &branch->d_inode->i_children;
1244         while (rb_root->rb_node) { /* While @branch has children... */
1245                 struct wim_dentry *child = rbnode_dentry(rb_root->rb_node);
1246                 /* Move @child to the directory @target */
1247                 unlink_dentry(child);
1248                 if (!dentry_add_child(target, child)) {
1249                         /* Revert the change to avoid leaking the directory tree
1250                          * rooted at @child */
1251                         dentry_add_child(branch, child);
1252                         ERROR("Overlay error: file `%s' already exists "
1253                               "as a child of `%s'",
1254                               child->file_name_utf8, target->file_name_utf8);
1255                         return WIMLIB_ERR_INVALID_OVERLAY;
1256                 }
1257         }
1258         return 0;
1259
1260 }
1261
1262 /* Attach or overlay a branch onto the WIM image.
1263  *
1264  * @root_p:
1265  *      Pointer to the root of the WIM image, or pointer to NULL if it has not
1266  *      been created yet.
1267  * @branch
1268  *      Branch to add.
1269  * @target_path:
1270  *      Path in the WIM image to add the branch, with leading and trailing
1271  *      slashes stripped.
1272  */
1273 static int attach_branch(struct wim_dentry **root_p,
1274                          struct wim_dentry *branch,
1275                          char *target_path)
1276 {
1277         char *slash;
1278         struct wim_dentry *dentry, *parent, *target;
1279
1280         if (*target_path == '\0') {
1281                 /* Target: root directory */
1282                 if (*root_p) {
1283                         /* Overlay on existing root */
1284                         return do_overlay(*root_p, branch);
1285                 } else  {
1286                         /* Set as root */
1287                         *root_p = branch;
1288                         return 0;
1289                 }
1290         }
1291
1292         /* Adding a non-root branch.  Create root if it hasn't been created
1293          * already. */
1294         if (!*root_p) {
1295                 *root_p = new_filler_directory("");
1296                 if (!*root_p)
1297                         return WIMLIB_ERR_NOMEM;
1298         }
1299
1300         /* Walk the path to the branch, creating filler directories as needed.
1301          * */
1302         parent = *root_p;
1303         while ((slash = strchr(target_path, '/'))) {
1304                 *slash = '\0';
1305                 dentry = get_dentry_child_with_name(parent, target_path);
1306                 if (!dentry) {
1307                         dentry = new_filler_directory(target_path);
1308                         if (!dentry)
1309                                 return WIMLIB_ERR_NOMEM;
1310                         dentry_add_child(parent, dentry);
1311                 }
1312                 parent = dentry;
1313                 target_path = slash;
1314                 /* Skip over slashes.  Note: this cannot overrun the length of
1315                  * the string because the last character cannot be a slash, as
1316                  * trailing slashes were tripped.  */
1317                 do {
1318                         ++target_path;
1319                 } while (*target_path == '/');
1320         }
1321
1322         /* If the target path already existed, overlay the branch onto it.
1323          * Otherwise, set the branch as the target path. */
1324         target = get_dentry_child_with_name(parent, branch->file_name_utf8);
1325         if (target) {
1326                 return do_overlay(target, branch);
1327         } else {
1328                 dentry_add_child(parent, branch);
1329                 return 0;
1330         }
1331 }
1332
1333 WIMLIBAPI int wimlib_add_image_multisource(WIMStruct *w,
1334                                            struct wimlib_capture_source *sources,
1335                                            size_t num_sources,
1336                                            const char *name,
1337                                            const char *config_str,
1338                                            size_t config_len,
1339                                            int add_image_flags,
1340                                            wimlib_progress_func_t progress_func)
1341 {
1342         int (*capture_tree)(struct wim_dentry **, const char *,
1343                             struct wim_lookup_table *,
1344                             struct wim_security_data *,
1345                             const struct capture_config *,
1346                             int, wimlib_progress_func_t, void *);
1347         void *extra_arg;
1348         struct wim_dentry *root_dentry;
1349         struct wim_dentry *branch;
1350         struct wim_security_data *sd;
1351         struct capture_config config;
1352         struct wim_image_metadata *imd;
1353         int ret;
1354
1355         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
1356 #ifdef WITH_NTFS_3G
1357                 if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) {
1358                         ERROR("Cannot dereference files when capturing directly from NTFS");
1359                         return WIMLIB_ERR_INVALID_PARAM;
1360                 }
1361                 if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
1362                         ERROR("Capturing UNIX owner and mode not supported "
1363                               "when capturing directly from NTFS");
1364                         return WIMLIB_ERR_INVALID_PARAM;
1365                 }
1366                 capture_tree = build_dentry_tree_ntfs;
1367                 extra_arg = &w->ntfs_vol;
1368 #else
1369                 ERROR("wimlib was compiled without support for NTFS-3g, so\n"
1370                       "        cannot capture a WIM image directly from a NTFS volume!");
1371                 return WIMLIB_ERR_UNSUPPORTED;
1372 #endif
1373         } else {
1374                 capture_tree = build_dentry_tree;
1375                 extra_arg = NULL;
1376         }
1377
1378         if (!name || !*name) {
1379                 ERROR("Must specify a non-empty string for the image name");
1380                 return WIMLIB_ERR_INVALID_PARAM;
1381         }
1382
1383         if (w->hdr.total_parts != 1) {
1384                 ERROR("Cannot add an image to a split WIM");
1385                 return WIMLIB_ERR_SPLIT_UNSUPPORTED;
1386         }
1387
1388         if (wimlib_image_name_in_use(w, name)) {
1389                 ERROR("There is already an image named \"%s\" in `%s'",
1390                       name, w->filename);
1391                 return WIMLIB_ERR_IMAGE_NAME_COLLISION;
1392         }
1393
1394         if (!config_str) {
1395                 DEBUG("Using default capture configuration");
1396                 config_str = default_config;
1397                 config_len = strlen(default_config);
1398         }
1399         ret = init_capture_config(&config, config_str, config_len);
1400         if (ret)
1401                 goto out;
1402
1403         DEBUG("Allocating security data");
1404         sd = CALLOC(1, sizeof(struct wim_security_data));
1405         if (!sd) {
1406                 ret = WIMLIB_ERR_NOMEM;
1407                 goto out_destroy_capture_config;
1408         }
1409         sd->total_length = 8;
1410         sd->refcnt = 1;
1411
1412         DEBUG("Using %zu capture sources", num_sources);
1413         canonicalize_targets(sources, num_sources);
1414         sort_sources(sources, num_sources);
1415         ret = check_sorted_sources(sources, num_sources, add_image_flags);
1416         if (ret) {
1417                 ret = WIMLIB_ERR_INVALID_PARAM;
1418                 goto out_free_security_data;
1419         }
1420
1421         DEBUG("Building dentry tree.");
1422         if (num_sources == 0) {
1423                 root_dentry = new_filler_directory("");
1424                 if (!root_dentry)
1425                         goto out_free_security_data;
1426         } else {
1427                 size_t i;
1428
1429                 root_dentry = NULL;
1430                 i = 0;
1431                 do {
1432                         int flags;
1433                         union wimlib_progress_info progress;
1434
1435                         DEBUG("Building dentry tree for source %zu of %zu "
1436                               "(\"%s\" => \"%s\")", i + 1, num_sources,
1437                               sources[i].fs_source_path,
1438                               sources[i].wim_target_path);
1439                         if (progress_func) {
1440                                 memset(&progress, 0, sizeof(progress));
1441                                 progress.scan.source = sources[i].fs_source_path;
1442                                 progress.scan.wim_target_path = sources[i].wim_target_path;
1443                                 progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, &progress);
1444                         }
1445                         ret = capture_config_set_prefix(&config,
1446                                                         sources[i].fs_source_path);
1447                         if (ret)
1448                                 goto out_free_dentry_tree;
1449                         flags = add_image_flags | WIMLIB_ADD_IMAGE_FLAG_SOURCE;
1450                         if (!*sources[i].wim_target_path)
1451                                 flags |= WIMLIB_ADD_IMAGE_FLAG_ROOT;
1452                         ret = (*capture_tree)(&branch, sources[i].fs_source_path,
1453                                               w->lookup_table, sd,
1454                                               &config,
1455                                               flags,
1456                                               progress_func, extra_arg);
1457                         if (ret) {
1458                                 ERROR("Failed to build dentry tree for `%s'",
1459                                       sources[i].fs_source_path);
1460                                 goto out_free_dentry_tree;
1461                         }
1462                         if (branch) {
1463                                 /* Use the target name, not the source name, for
1464                                  * the root of each branch from a capture
1465                                  * source.  (This will also set the root dentry
1466                                  * of the entire image to be unnamed.) */
1467                                 ret = set_dentry_name(branch,
1468                                                       path_basename(sources[i].wim_target_path));
1469                                 if (ret)
1470                                         goto out_free_branch;
1471
1472                                 ret = attach_branch(&root_dentry, branch,
1473                                                     sources[i].wim_target_path);
1474                                 if (ret)
1475                                         goto out_free_branch;
1476                         }
1477                         if (progress_func)
1478                                 progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, &progress);
1479                 } while (++i != num_sources);
1480         }
1481
1482         DEBUG("Calculating full paths of dentries.");
1483         ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL);
1484         if (ret != 0)
1485                 goto out_free_dentry_tree;
1486
1487         ret = add_new_dentry_tree(w, root_dentry, sd);
1488         if (ret != 0)
1489                 goto out_free_dentry_tree;
1490
1491         imd = &w->image_metadata[w->hdr.image_count - 1];
1492
1493         ret = dentry_tree_fix_inodes(root_dentry, &imd->inode_list);
1494         if (ret != 0)
1495                 goto out_destroy_imd;
1496
1497         DEBUG("Assigning hard link group IDs");
1498         assign_inode_numbers(&imd->inode_list);
1499
1500         ret = xml_add_image(w, name);
1501         if (ret != 0)
1502                 goto out_destroy_imd;
1503
1504         if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
1505                 wimlib_set_boot_idx(w, w->hdr.image_count);
1506         ret = 0;
1507         goto out;
1508 out_destroy_imd:
1509         destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1],
1510                                w->lookup_table);
1511         w->hdr.image_count--;
1512         goto out;
1513 out_free_branch:
1514         free_dentry_tree(branch, w->lookup_table);
1515 out_free_dentry_tree:
1516         free_dentry_tree(root_dentry, w->lookup_table);
1517 out_free_security_data:
1518         free_security_data(sd);
1519 out_destroy_capture_config:
1520         destroy_capture_config(&config);
1521 out:
1522         return ret;
1523 }
1524
1525 WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source,
1526                                const char *name, const char *config_str,
1527                                size_t config_len, int add_image_flags,
1528                                wimlib_progress_func_t progress_func)
1529 {
1530         if (!source || !*source)
1531                 return WIMLIB_ERR_INVALID_PARAM;
1532
1533         char *fs_source_path = STRDUP(source);
1534         int ret;
1535         struct wimlib_capture_source capture_src = {
1536                 .fs_source_path = fs_source_path,
1537                 .wim_target_path = NULL,
1538                 .reserved = 0,
1539         };
1540         ret = wimlib_add_image_multisource(w, &capture_src, 1, name,
1541                                            config_str, config_len,
1542                                            add_image_flags, progress_func);
1543         FREE(fs_source_path);
1544         return ret;
1545 }