From a78f69d411d4bb9751f2ead3fbb522dcd017c312 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 25 Aug 2012 21:12:08 -0500 Subject: [PATCH] NTFS capture (IN PROGRESS) --- src/lookup_table.h | 11 +++++ src/modify.c | 56 ++++++++++++++----------- src/ntfs-capture.c | 98 +++++++++++++++++++++++++++++++++++++++---- src/wimlib_internal.h | 6 ++- 4 files changed, 136 insertions(+), 35 deletions(-) diff --git a/src/lookup_table.h b/src/lookup_table.h index 0490291e..c15bf404 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -26,6 +26,14 @@ struct lookup_table { struct wimlib_fd; +typedef struct _ntfs_attr ntfs_attr; +typedef struct _ntfs_volume ntfs_volume; +struct ntfs_location { + ntfs_volume *vol; + const char *path; + const char *ads_name; +}; + /* * An entry in the lookup table in the WIM file. * @@ -56,6 +64,7 @@ struct lookup_table_entry { RESOURCE_IN_FILE_ON_DISK, RESOURCE_IN_STAGING_FILE, RESOURCE_IN_ATTACHED_BUFFER, + RESOURCE_IN_NTFS_VOLUME, } resource_location; /* Number of times this lookup table entry is referenced by dentries. */ @@ -84,10 +93,12 @@ struct lookup_table_entry { char *file_on_disk; char *staging_file_name; u8 *attached_buffer; + struct ntfs_location *ntfs_location; }; union { struct lookup_table_entry *next_lte_in_swm; FILE *file_on_disk_fp; + ntfs_attr *attr; }; #ifdef WITH_FUSE /* File descriptors table for this data stream */ diff --git a/src/modify.c b/src/modify.c index cef29abf..ed6b07f4 100644 --- a/src/modify.c +++ b/src/modify.c @@ -73,8 +73,10 @@ void destroy_image_metadata(struct image_metadata *imd,struct lookup_table *lt) * the regular files in the tree into the WIM as file resources. */ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, - struct lookup_table* lookup_table, - int add_flags) + struct lookup_table *lookup_table, + struct wim_security_data *sd, + int add_flags, + void *extra_arg) { DEBUG("%s", root_disk_path); struct stat root_stbuf; @@ -140,7 +142,7 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, if (!child) return WIMLIB_ERR_NOMEM; ret = build_dentry_tree(child, name, lookup_table, - add_flags); + sd, add_flags, extra_arg); link_dentry(child, root); if (ret != 0) break; @@ -263,12 +265,12 @@ static int add_lte_to_dest_wim(struct dentry *dentry, void *arg) * @w: The WIMStruct for the WIM file. * @root_dentry: The root of the directory tree for the image. */ -static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) +static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry, + struct wim_security_data *sd) { struct lookup_table_entry *metadata_lte; struct image_metadata *imd; struct image_metadata *new_imd; - struct wim_security_data *sd; struct link_group_table *lgt; DEBUG("Reallocating image metadata array for image_count = %u", @@ -286,11 +288,6 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) metadata_lte = new_lookup_table_entry(); if (!metadata_lte) goto out_free_imd; - sd = CALLOC(1, sizeof(struct wim_security_data)); - if (!sd) - goto out_free_metadata_lte; - sd->refcnt = 1; - sd->total_length = 8; lgt = new_link_group_table(9001); if (!lgt) @@ -338,6 +335,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, int ret; struct dentry *root; struct wim_pair wims; + struct wim_security_data *sd; if (src_image == WIM_ALL_IMAGES) { if (src_wim->hdr.image_count > 1) { @@ -411,21 +409,16 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, * wimlib_export_image() is documented as leaving dest_wim is an * indeterminate state. */ root = wim_root_dentry(src_wim); + sd = wim_security_data(src_wim); for_dentry_in_tree(root, increment_dentry_refcnt, NULL); wims.src_wim = src_wim; wims.dest_wim = dest_wim; ret = for_dentry_in_tree(root, add_lte_to_dest_wim, &wims); if (ret != 0) return ret; - ret = add_new_dentry_tree(dest_wim, root); + ret = add_new_dentry_tree(dest_wim, root, sd); if (ret != 0) return ret; - /* Bring over old security data */ - struct wim_security_data *sd = wim_security_data(src_wim); - struct image_metadata *new_imd = wim_get_current_image_metadata(dest_wim); - wimlib_assert(sd); - free_security_data(new_imd->security_data); - new_imd->security_data = sd; sd->refcnt++; if (flags & WIMLIB_EXPORT_FLAG_BOOT) { @@ -499,10 +492,13 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name, const char *description, const char *flags_element, int flags, int (*capture_tree)(struct dentry *, const char *, - struct lookup_table *, int)) + struct lookup_table *, + struct wim_security_data *, int, void *), + void *extra_arg) { struct dentry *root_dentry; struct image_metadata *imd; + struct wim_security_data *sd; int ret; DEBUG("Adding dentry tree from dir `%s'.", dir); @@ -528,23 +524,31 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name, if (!root_dentry) return WIMLIB_ERR_NOMEM; + + sd = CALLOC(1, sizeof(struct wim_security_data)); + if (!sd) + goto out_free_dentry_tree; + sd->total_length = 8; + sd->refcnt = 1; + DEBUG("Building dentry tree."); - ret = (*capture_tree)(root_dentry, dir, w->lookup_table, - flags | WIMLIB_ADD_IMAGE_FLAG_ROOT); + ret = (*capture_tree)(root_dentry, dir, w->lookup_table, sd, + flags | WIMLIB_ADD_IMAGE_FLAG_ROOT, + extra_arg); if (ret != 0) { ERROR("Failed to build dentry tree for `%s'", dir); - goto out_free_dentry_tree; + goto out_free_sd; } DEBUG("Calculating full paths of dentries."); ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL); if (ret != 0) - goto out_free_dentry_tree; + goto out_free_sd; - ret = add_new_dentry_tree(w, root_dentry); + ret = add_new_dentry_tree(w, root_dentry, sd); if (ret != 0) - goto out_free_dentry_tree; + goto out_free_sd; DEBUG("Inserting dentries into hard link group table"); ret = for_dentry_in_tree(root_dentry, link_group_table_insert, @@ -567,6 +571,8 @@ out_destroy_imd: w->lookup_table); w->hdr.image_count--; return ret; +out_free_sd: + free_security_data(sd); out_free_dentry_tree: free_dentry_tree(root_dentry, w->lookup_table); return ret; @@ -580,5 +586,5 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, const char *flags_element, int flags) { return do_add_image(w, dir, name, description, flags_element, flags, - build_dentry_tree); + build_dentry_tree, NULL); } diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index 2ca4afad..8eec3ed0 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -182,20 +182,57 @@ 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; +} + 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) { 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) { @@ -208,6 +245,45 @@ static int __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni, /* Symbolic link or other reparse point */ } else { /* Normal file */ + ntfs_attr_search_ctx *actx; + u8 attr_hash[SHA1_HASH_SIZE]; + struct lookup_table_entry *lte; + + 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) + return ret; + lte = __lookup_resource(lookup_table, attr_hash); + if (lte) { + lte->refcnt++; + } else { + /*char *file_on_disk = STRDUP(root_disk_path);*/ + /*if (!file_on_disk) {*/ + /*ERROR("Failed to allocate memory for file path");*/ + /*return WIMLIB_ERR_NOMEM;*/ + /*}*/ + /*lte = new_lookup_table_entry();*/ + /*if (!lte) {*/ + /*FREE(file_on_disk);*/ + /*return WIMLIB_ERR_NOMEM;*/ + /*}*/ + /*lte->file_on_disk = file_on_disk;*/ + /*lte->resource_location = RESOURCE_IN_FILE_ON_DISK;*/ + /*lte->resource_entry.original_size = root_stbuf.st_size;*/ + /*lte->resource_entry.size = root_stbuf.st_size;*/ + /*copy_hash(lte->hash, hash);*/ + /*lookup_table_insert(lookup_table, lte);*/ + } + dentry->lte = lte; + } } } ret = ntfs_inode_get_security(ni, @@ -224,24 +300,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 +331,11 @@ 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); out: if (ntfs_umount(vol, FALSE) != 0) { @@ -279,7 +358,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 */ diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 4f390629..1a2654c9 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -181,6 +181,7 @@ struct wim_header { * a LZ77-based algorithm. */ #define WIM_HDR_FLAG_COMPRESS_LZX 0x00040000 +typedef struct _ntfs_volume ntfs_volume; /* Structure for security data. Each image in the WIM file has its own security * data. */ @@ -265,6 +266,7 @@ typedef struct WIMStruct { int add_flags; int write_flags; bool write_metadata; + ntfs_volume *ntfs_vol; }; /* The currently selected image, indexed starting at 1. If not 0, @@ -338,7 +340,9 @@ extern int do_add_image(WIMStruct *w, const char *dir, const char *name, const char *description, const char *flags_element, int flags, int (*capture_tree)(struct dentry *, const char *, - struct lookup_table *, int)); + struct lookup_table *, + struct wim_security_data *, int, void *), + void *extra_arg); /* resource.c */ extern const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry); -- 2.43.0