NTFS capture (IN PROGRESS)
[wimlib] / src / ntfs-capture.c
index 2ca4afad9e41630afbc2b0ac2a74fdf030d1406e..f49a7eeaa95332d914d0859133e8dbabbfbf3c62 100644 (file)
@@ -182,34 +182,144 @@ out_revert:
 }
 #endif
 
+static int ntfs_attr_sha1sum(ntfs_inode *ni, ATTR_RECORD *ar,
+                            u8 md[SHA1_HASH_SIZE])
+{
+       s64 pos = 0;
+       s64 bytes_remaining;
+       char buf[4096];
+       ntfs_attr *na;
+       SHA_CTX ctx;
+
+       na = ntfs_attr_open(ni, ar->type,
+                           (ntfschar*)((u8*)ar + le16_to_cpu(ar->name_offset)),
+                           ar->name_length);
+       if (!na) {
+               ERROR_WITH_ERRNO("Failed to open NTFS attribute");
+               return WIMLIB_ERR_NTFS_3G;
+       }
+
+       bytes_remaining = na->data_size;
+       sha1_init(&ctx);
+
+       while (bytes_remaining) {
+               s64 to_read = min(bytes_remaining, sizeof(buf));
+               if (ntfs_attr_pread(na, pos, to_read, buf) != to_read) {
+                       ERROR_WITH_ERRNO("Error reading NTFS attribute");
+                       return WIMLIB_ERR_NTFS_3G;
+               }
+               sha1_update(&ctx, buf, to_read);
+               pos += to_read;
+               bytes_remaining -= to_read;
+       }
+       sha1_final(md, &ctx);
+       ntfs_attr_close(na);
+       return 0;
+}
+
+/* Load a normal file in the NTFS volume into the WIM lookup table */
+static int capture_normal_ntfs_file(struct dentry *dentry, ntfs_inode *ni,
+                                   char path[], size_t path_len,
+                                   struct lookup_table *lookup_table,
+                                   ntfs_volume **ntfs_vol_p)
+{
+
+       ntfs_attr_search_ctx *actx;
+       u8 attr_hash[SHA1_HASH_SIZE];
+       struct ntfs_location *ntfs_loc;
+       struct lookup_table_entry *lte;
+       int ret = 0;
+
+       actx = ntfs_attr_get_search_ctx(ni, NULL);
+       if (!actx) {
+               ERROR_WITH_ERRNO("Cannot get attribute search "
+                                "context");
+               return WIMLIB_ERR_NTFS_3G;
+       }
+       while (!ntfs_attr_lookup(AT_DATA, NULL, 0,
+                                CASE_SENSITIVE, 0, NULL, 0, actx))
+       {
+               ret = ntfs_attr_sha1sum(ni, actx->attr, attr_hash);
+               if (ret != 0)
+                       goto out_put_actx;
+               lte = __lookup_resource(lookup_table, attr_hash);
+               if (lte) {
+                       lte->refcnt++;
+               } else {
+                       struct ntfs_location *ntfs_loc;
+
+                       ret = WIMLIB_ERR_NOMEM;
+
+                       ntfs_loc = CALLOC(1, sizeof(*ntfs_loc));
+                       if (!ntfs_loc) {
+                               goto out_put_actx;
+                       }
+                       ntfs_loc->path_utf8 = MALLOC(path_len + 1);
+                       if (!ntfs_loc->path_utf8)
+                               goto out_put_actx;
+                       memcpy(ntfs_loc->path_utf8, path, path_len + 1);
+                       ntfs_loc->stream_name_utf16 = MALLOC(actx->attr->name_length * 2);
+                       if (!ntfs_loc->stream_name_utf16)
+                               goto out_put_actx;
+                       memcpy(ntfs_loc->stream_name_utf16,
+                              (u8*)actx->attr +
+                                       le16_to_cpu(actx->attr->name_offset),
+                              actx->attr->name_length * 2);
+
+                       ntfs_loc->stream_name_utf16_num_chars = actx->attr->name_length;
+                       lte = new_lookup_table_entry();
+                       if (!lte)
+                               goto out_put_actx;
+                       lte->ntfs_loc = ntfs_loc;
+                       lte->resource_location = RESOURCE_IN_NTFS_VOLUME;
+                       lte->resource_entry.original_size = actx->attr->data_size;
+                       lte->resource_entry.size = actx->attr->data_size;
+                       copy_hash(lte->hash, attr_hash);
+                       lookup_table_insert(lookup_table, lte);
+               }
+               dentry->lte = lte;
+       }
+       goto out_put_actx;
+out_free_ntfs_loc:
+       if (ntfs_loc) {
+               FREE(ntfs_loc->path_utf8);
+               FREE(ntfs_loc->stream_name_utf16);
+               FREE(ntfs_loc);
+       }
+out_put_actx:
+       ntfs_attr_put_search_ctx(actx);
+       return ret;
+}
+
 static int __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni,
+                                   char path[], size_t path_len,
                                    struct lookup_table *lookup_table,
-                                   struct sd_tree *tree)
+                                   struct sd_tree *tree,
+                                   ntfs_volume **ntfs_vol_p)
 {
        u32 attributes = ntfs_inode_get_attributes(ni);
        int mrec_flags = ni->mrec->flags;
        u32 sd_size;
-       int ret;
+       int ret = 0;
 
        dentry->creation_time    = le64_to_cpu(ni->creation_time);
        dentry->last_write_time  = le64_to_cpu(ni->last_data_change_time);
        dentry->last_access_time = le64_to_cpu(ni->last_access_time);
        dentry->security_id      = le32_to_cpu(ni->security_id);
        dentry->attributes       = le32_to_cpu(attributes);
+       dentry->resolved = true;
 
-       if (mrec_flags & MFT_RECORD_IS_DIRECTORY) {
-               if (attributes & FILE_ATTR_REPARSE_POINT) {
-                       /* Junction point */
-               } else {
-                       /* Normal directory */
-               }
+       if (attributes & FILE_ATTR_REPARSE_POINT) {
+               /* Junction point, symbolic link, or other reparse point */
+       } else if (mrec_flags & MFT_RECORD_IS_DIRECTORY) {
+               /* Normal directory */
        } else {
-               if (attributes & FILE_ATTR_REPARSE_POINT) {
-                       /* Symbolic link or other reparse point */
-               } else {
-                       /* Normal file */
-               }
+               /* Normal file */
+               ret = capture_normal_ntfs_file(dentry, ni, path, path_len,
+                                              lookup_table, ntfs_vol_p);
        }
+       if (ret != 0)
+               return ret;
        ret = ntfs_inode_get_security(ni,
                                      OWNER_SECURITY_INFORMATION |
                                      GROUP_SECURITY_INFORMATION |
@@ -224,24 +334,23 @@ static int __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni,
                                      SACL_SECURITY_INFORMATION,
                                      sd, sd_size, &sd_size);
        dentry->security_id = tree_add_sd(tree, sd, sd_size);
-
        return 0;
 }
 
 static int build_dentry_tree_ntfs(struct dentry *root_dentry,
                                  const char *device,
                                  struct lookup_table *lookup_table,
-                                 int flags)
+                                 struct wim_security_data *sd,
+                                 int flags,
+                                 void *extra_arg)
 {
        ntfs_volume *vol;
        ntfs_inode *root_ni;
        int ret = 0;
        struct sd_tree tree;
-       tree.sd = CALLOC(1, sizeof(struct wim_security_data));
-       if (!tree.sd)
-               return WIMLIB_ERR_NOMEM;
-       tree.sd->total_length = 8;
+       tree.sd = sd;
        tree.root = NULL;
+       ntfs_volume **ntfs_vol_p = extra_arg;
        
        vol = ntfs_mount(device, MS_RDONLY);
        if (!vol) {
@@ -256,7 +365,12 @@ static int build_dentry_tree_ntfs(struct dentry *root_dentry,
                ret = WIMLIB_ERR_NTFS_3G;
                goto out;
        }
-       ret = __build_dentry_tree_ntfs(root_dentry, root_ni, lookup_table, &tree);
+       char path[4096];
+       path[0] = '/';
+       path[1] = '\0';
+       ret = __build_dentry_tree_ntfs(root_dentry, root_ni, path, 1,
+                                      lookup_table, &tree, ntfs_vol_p);
+       ntfs_inode_close(root_ni);
 
 out:
        if (ntfs_umount(vol, FALSE) != 0) {
@@ -279,7 +393,8 @@ WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
                return WIMLIB_ERR_INVALID_PARAM;
        }
        return do_add_image(w, device, name, description, flags_element, flags,
-                           build_dentry_tree_ntfs);
+                           build_dentry_tree_ntfs,
+                           &w->ntfs_vol);
 }
 
 #else /* WITH_NTFS_3G */