]> wimlib.net Git - wimlib/blobdiff - src/ntfs-apply.c
NTFS test updates and NTFS capture fix
[wimlib] / src / ntfs-apply.c
index 4118a30af74dac5fc5e3f626c39d03aa86ae5a69..ee1982af7f63d610676f59363fede5d46b94650e 100644 (file)
@@ -1,9 +1,8 @@
 /*
  * ntfs-apply.c
  *
- * Apply a WIM image to a NTFS volume, restoring everything we can, including
- * security data and alternate data streams.  There should be no loss of
- * information.
+ * Apply a WIM image to a NTFS volume.  We restore everything we can, including
+ * security data and alternate data streams.
  */
 
 /*
  * This file is part of wimlib, a library for working with WIM files.
  *
  * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
  * any later version.
  *
  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more
  * details.
  *
- * You should have received a copy of the GNU Lesser General Public License
+ * You should have received a copy of the GNU General Public License
  * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
@@ -49,9 +48,12 @@ struct ntfs_apply_args {
        WIMStruct *w;
 };
 
-extern int ntfs_inode_set_security(ntfs_inode *ni, u32 selection,
+
+#ifndef WITH_NEW_NTFS_3G
+extern int ntfs_set_inode_security(ntfs_inode *ni, u32 selection,
                                   const char *attr);
-extern int ntfs_inode_set_attributes(ntfs_inode *ni, s32 attrib);
+extern int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib);
+#endif
 
 /* 
  * Extracts a WIM resource to a NTFS attribute.
@@ -61,7 +63,7 @@ extract_wim_resource_to_ntfs_attr(const struct lookup_table_entry *lte,
                                  ntfs_attr *na)
 {
        u64 bytes_remaining = wim_resource_size(lte);
-       char buf[min(WIM_CHUNK_SIZE, bytes_remaining)];
+       u8 buf[min(WIM_CHUNK_SIZE, bytes_remaining)];
        u64 offset = 0;
        int ret = 0;
        u8 hash[SHA1_HASH_SIZE];
@@ -119,19 +121,38 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
                ntfs_attr *na;
 
                lte = dentry_stream_lte(dentry, stream_idx, w->lookup_table);
-               na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
-               if (!na) {
-                       ERROR_WITH_ERRNO("Failed to open a data stream of "
-                                        "extracted file `%s'",
-                                        dentry->full_path_utf8);
-                       ret = WIMLIB_ERR_NTFS_3G;
-                       break;
+
+               if (stream_name_len) {
+                       /* Create an empty named stream. */
+                       ret = ntfs_attr_add(ni, AT_DATA, stream_name,
+                                           stream_name_len, NULL, 0);
+                       if (ret != 0) {
+                               ERROR_WITH_ERRNO("Failed to create name data "
+                                                "stream for extracted file "
+                                                "`%s'",
+                                                dentry->full_path_utf8);
+                               ret = WIMLIB_ERR_NTFS_3G;
+                               break;
+
+                       }
                }
-               if (lte)
+               /* If there's no lookup table entry, it's an empty stream.
+                * Otherwise, we must open the attribute and extract the data.
+                * */
+               if (lte) {
+                       na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
+                       if (!na) {
+                               ERROR_WITH_ERRNO("Failed to open a data stream of "
+                                                "extracted file `%s'",
+                                                dentry->full_path_utf8);
+                               ret = WIMLIB_ERR_NTFS_3G;
+                               break;
+                       }
                        ret = extract_wim_resource_to_ntfs_attr(lte, na);
-               ntfs_attr_close(na);
-               if (ret != 0)
-                       break;
+                       if (ret != 0)
+                               break;
+                       ntfs_attr_close(na);
+               }
                if (stream_idx == dentry->num_ads)
                        break;
                stream_name = (ntfschar*)dentry->ads_entries[stream_idx].stream_name;
@@ -141,15 +162,6 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
        return ret;
 }
 
-static bool in_same_dir(const char *path1, const char *path2)
-{
-       const char *p1 = strrchr(path1, '/');
-       const char *p2 = strrchr(path2, '/');
-       if (p1 - path1 != p2 - path2)
-               return false;
-       return memcmp(path1, path2,  p1 - path1) == 0;
-}
-
 /*
  * Makes a NTFS hard link
  *
@@ -201,8 +213,7 @@ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
        *p = '\0';
        dir_name = from_dentry->full_path_utf8;
 
-       dir_ni = ntfs_pathname_to_inode(vol, NULL,
-                                       from_dentry->full_path_utf8);
+       dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name);
        if (!dir_ni) {
                ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'",
                                 from_dentry->full_path_utf8);
@@ -231,7 +242,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni,
 {
        DEBUG("Setting NTFS file attributes on `%s' to %#"PRIx32,
              dentry->full_path_utf8, dentry->attributes);
-       if (!ntfs_inode_set_attributes(ni, dentry->attributes)) {
+       if (ntfs_set_inode_attributes(ni, dentry->attributes)) {
                ERROR("Failed to set NTFS file attributes on `%s'",
                       dentry->full_path_utf8);
                return WIMLIB_ERR_NTFS_3G;
@@ -249,8 +260,8 @@ apply_file_attributes_and_security_data(ntfs_inode *ni,
                                DACL_SECURITY_INFORMATION  |
                                SACL_SECURITY_INFORMATION;
                                
-               if (!ntfs_inode_set_security(ni, selection,
-                                            sd->descriptors[dentry->security_id]))
+               if (ntfs_set_inode_security(ni, selection,
+                                           (const char*)sd->descriptors[dentry->security_id]))
                {
                        ERROR_WITH_ERRNO("Failed to set security data on `%s'",
                                        dentry->full_path_utf8);
@@ -268,7 +279,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
 
        wimlib_assert(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT);
 
-       lte = dentry_first_lte(dentry, w->lookup_table);
+       lte = dentry_unnamed_lte(dentry, w->lookup_table);
 
        DEBUG("Applying reparse data to `%s'", dentry->full_path_utf8);
 
@@ -284,8 +295,8 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
                return WIMLIB_ERR_INVALID_DENTRY;
        }
 
-       char reparse_data_buf[8 + wim_resource_size(lte)];
-       char *p = reparse_data_buf;
+       u8 reparse_data_buf[8 + wim_resource_size(lte)];
+       u8 *p = reparse_data_buf;
        p = put_u32(p, dentry->reparse_tag); /* ReparseTag */
        p = put_u16(p, wim_resource_size(lte)); /* ReparseDataLength */
        p = put_u16(p, 0); /* Reserved */
@@ -294,7 +305,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
        if (ret != 0)
                return ret;
 
-       ret = ntfs_set_ntfs_reparse_data(ni, reparse_data_buf,
+       ret = ntfs_set_ntfs_reparse_data(ni, (char*)reparse_data_buf,
                                         wim_resource_size(lte) + 8, 0);
        if (ret != 0) {
                ERROR_WITH_ERRNO("Failed to set NTFS reparse data on `%s'",
@@ -319,13 +330,9 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
                                         ntfs_inode **dir_ni_p,
                                         WIMStruct *w)
 {
-       int ret;
        struct dentry *other;
        struct dentry *dentry_with_dos_name;
 
-       if (dentry->link_group_list.next == &dentry->link_group_list)
-               return 0;
-
        dentry_with_dos_name = NULL;
        list_for_each_entry(other, &dentry->link_group_list,
                            link_group_list)
@@ -341,10 +348,13 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
                }
        }
        /* If there's a dentry with a DOS name, extract it first */
-       if (dentry_with_dos_name && !dentry_with_dos_name->extracted_file) {
+       if (dentry_with_dos_name
+           && !dentry_with_dos_name->extracted_file)
+       {
                char *p;
                const char *dir_name;
                char orig;
+               int ret;
                ntfs_volume *vol = (*dir_ni_p)->vol;
 
                DEBUG("pre-applying DOS name `%s'",
@@ -398,9 +408,12 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
 
                /* Apply hard-linked directory in same directory with DOS name
                 * (if there is one) before this dentry */
-               ret = preapply_dentry_with_dos_name(dentry, &dir_ni, w);
-               if (ret != 0)
-                       return ret;
+               if (dentry->short_name_len == 0) {
+                       ret = preapply_dentry_with_dos_name(dentry,
+                                                           &dir_ni, w);
+                       if (ret != 0)
+                               return ret;
+               }
 
                type = S_IFREG;
                /* See if we can make a hard link */
@@ -413,19 +426,16 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
                                ret = wim_apply_hardlink_ntfs(dentry, other,
                                                              dir_ni, &ni);
                                is_hardlink = true;
-                               if (ret != 0)
+                               if (ret) {
                                        goto out_close_dir_ni;
-                               else
+                               } else {
+                                       dentry->extracted_file = dentry->full_path_utf8;
                                        goto out_set_dos_name;
+                               }
                        }
                }
                /* Can't make a hard link; extract the file itself */
-               FREE(dentry->extracted_file);
-               dentry->extracted_file = STRDUP(dentry->full_path_utf8);
-               if (!dentry->extracted_file) {
-                       ERROR("Failed to allocate memory for filename");
-                       return WIMLIB_ERR_NOMEM;
-               }
+               dentry->extracted_file = dentry->full_path_utf8;
        }
 
        /* 
@@ -543,7 +553,6 @@ out_close_dir_ni:
                        ret = WIMLIB_ERR_NTFS_3G;
                ERROR_WITH_ERRNO("Failed to close directory inode");
        }
-out_close_ni:
        if (ni && ntfs_inode_close(ni) != 0) {
                if (ret == 0)
                        ret = WIMLIB_ERR_NTFS_3G;
@@ -582,10 +591,8 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
        int extract_flags            = args->extract_flags;
        WIMStruct *w                 = args->w;
        ntfs_inode *dir_ni;
-       int ret;
        char *p;
        char orig;
-       ntfs_inode *close_after_dir;
        const char *dir_name;
 
        if (dentry->extracted_file)
@@ -611,8 +618,6 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
        dir_name = dentry->full_path_utf8;
 
        dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name);
-       if (dir_ni)
-               DEBUG("Found NTFS inode for `%s'", dir_name);
        *p = orig;
        if (!dir_ni) {
                ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'",
@@ -626,10 +631,8 @@ static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
 {
        struct ntfs_apply_args *args = arg;
        ntfs_volume *vol             = args->vol;
-       int extract_flags            = args->extract_flags;
-       WIMStruct *w                 = args->w;
-       char *p;
-       char buf[24];
+       u8 *p;
+       u8 buf[24];
        ntfs_inode *ni;
        int ret = 0;
 
@@ -647,7 +650,7 @@ static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
        p = put_u64(p, dentry->creation_time);
        p = put_u64(p, dentry->last_write_time);
        p = put_u64(p, dentry->last_access_time);
-       ret = ntfs_inode_set_times(ni, buf, 3 * sizeof(u64), 0);
+       ret = ntfs_inode_set_times(ni, (const char*)buf, 3 * sizeof(u64), 0);
        if (ret != 0) {
                ERROR_WITH_ERRNO("Failed to set NTFS timestamps on `%s'",
                                 dentry->full_path_utf8);
@@ -663,10 +666,20 @@ static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
        return ret;
 }
 
+static int dentry_clear_extracted_file(struct dentry *dentry, void *ignore)
+{
+       if (dentry->extracted_file != dentry->full_path_utf8)
+               FREE(dentry->extracted_file);
+       dentry->extracted_file = NULL;
+       return 0;
+}
+
 static int do_wim_apply_image_ntfs(WIMStruct *w, const char *device, int extract_flags)
 {
        ntfs_volume *vol;
        int ret;
+       struct dentry *root;
+       struct ntfs_apply_args args;
        
        DEBUG("Mounting NTFS volume `%s'", device);
        vol = ntfs_mount(device, 0);
@@ -674,20 +687,29 @@ static int do_wim_apply_image_ntfs(WIMStruct *w, const char *device, int extract
                ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s'", device);
                return WIMLIB_ERR_NTFS_3G;
        }
-       struct ntfs_apply_args args = {
-               .vol           = vol,
-               .extract_flags = extract_flags,
-               .w             = w,
-       };
-       ret = for_dentry_in_tree(wim_root_dentry(w), wim_apply_dentry_ntfs,
-                                &args);
+       args.vol = vol;
+       args.extract_flags = extract_flags;
+       args.w = w;
+       root = wim_root_dentry(w);
 
+       for_dentry_in_tree(root, dentry_clear_extracted_file, NULL);
+
+       ret = for_dentry_in_tree(root, wim_apply_dentry_ntfs, &args);
        if (ret != 0)
                goto out;
-       DEBUG("Setting NTFS timestamps");
-       ret = for_dentry_in_tree_depth(wim_root_dentry(w),
-                                      wim_apply_dentry_timestamps,
+
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
+               printf("Setting timestamps of extracted files on NTFS "
+                      "volume `%s'\n", device);
+       ret = for_dentry_in_tree_depth(root, wim_apply_dentry_timestamps,
                                       &args);
+
+       if (ret == 0 && (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE))
+               printf("Finished applying image %d of %s to NTFS "
+                      "volume `%s'\n",
+                      w->current_image,
+                      w->filename ? w->filename : "WIM",
+                      device);
 out:
        DEBUG("Unmounting NTFS volume `%s'", device);
        if (ntfs_umount(vol, FALSE) != 0) {