From: Eric Biggers Date: Sun, 26 Aug 2012 00:57:46 +0000 (-0500) Subject: NTFS capture (IN PROGRESS) X-Git-Tag: v1.0.0~81 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=ca28b6f865975bd84933a97fd902b81c6b284851 NTFS capture (IN PROGRESS) --- diff --git a/src/dentry.h b/src/dentry.h index 613f6259..e030acf0 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -134,7 +134,7 @@ struct dentry { * entry's child files. 0 if the directory entry has no children. */ u64 subdir_offset; - /* Timestamps for the entry. The timestamps are the number of + /* Timestamps for the dentry. The timestamps are the number of * 100-nanosecond intervals that have elapsed since 12:00 A.M., January * 1st, 1601, UTC. */ u64 creation_time; diff --git a/src/endianness.h b/src/endianness.h index ba66b27a..e0042167 100644 --- a/src/endianness.h +++ b/src/endianness.h @@ -48,6 +48,10 @@ static inline uint64_t bswap64(uint64_t n) #define to_be32(n) (n) #define to_be64(n) (n) +#define le16_to_cpu(n) bswap16(n) +#define le32_to_cpu(n) bswap32(n) +#define le64_to_cpu(n) bswap64(n) + /* In place */ #define TO_LE16(n) ((n) = to_le16(n)) #define TO_LE32(n) ((n) = to_le32(n)) @@ -78,6 +82,10 @@ static inline void array_to_le64(uint64_t *p, uint64_t n) #define to_le32(n) (n) #define to_le64(n) (n) +#define le16_to_cpu(n) (n) +#define le32_to_cpu(n) (n) +#define le64_to_cpu(n) (n) + #define to_be16(n) (bswap16(n)) #define to_be32(n) (bswap32(n)) #define to_be64(n) (bswap64(n)) diff --git a/src/modify.c b/src/modify.c index dcd0b6d3..cef29abf 100644 --- a/src/modify.c +++ b/src/modify.c @@ -495,12 +495,11 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image) return 0; } -/* - * Adds an image to a WIM file from a directory tree on disk. - */ -WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, - const char *name, const char *description, - const char *flags_element, int flags) +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 dentry *root_dentry; struct image_metadata *imd; @@ -530,8 +529,8 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, return WIMLIB_ERR_NOMEM; DEBUG("Building dentry tree."); - ret = build_dentry_tree(root_dentry, dir, w->lookup_table, - flags | WIMLIB_ADD_IMAGE_FLAG_ROOT); + ret = (*capture_tree)(root_dentry, dir, w->lookup_table, + flags | WIMLIB_ADD_IMAGE_FLAG_ROOT); if (ret != 0) { ERROR("Failed to build dentry tree for `%s'", dir); @@ -572,3 +571,14 @@ out_free_dentry_tree: free_dentry_tree(root_dentry, w->lookup_table); return ret; } + +/* + * Adds an image to a WIM file from a directory tree on disk. + */ +WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, + const char *name, const char *description, + const char *flags_element, int flags) +{ + return do_add_image(w, dir, name, description, flags_element, flags, + build_dentry_tree); +} diff --git a/src/ntfs-3g_security.c b/src/ntfs-3g_security.c index 22faa9ec..a596b28c 100644 --- a/src/ntfs-3g_security.c +++ b/src/ntfs-3g_security.c @@ -4681,6 +4681,28 @@ int ntfs_set_file_security(struct SECURITY_API *scapi, return (res); } #endif + +int ntfs_inode_get_security(ntfs_inode *ni, u32 selection, char *buf, + u32 buflen, u32 *psize) +{ + char *attr; + int res = 0; + + attr = getsecurityattr(ni->vol, ni); + if (attr) { + if (feedsecurityattr(attr,selection, + buf,buflen,psize)) { + if (test_nino_flag(ni, v3_Extensions) + && ni->security_id) + res = le32_to_cpu( + ni->security_id); + else + res = -1; + } + free(attr); + } + return (res); +} /* * Check the validity of the ACEs in a DACL or SACL */ @@ -4955,6 +4977,20 @@ BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi, } #endif +int ntfs_inode_get_attributes(ntfs_inode *ni) +{ + s32 attrib; + + attrib = le32_to_cpu(ni->flags); + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY); + else + attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY); + if (!attrib) + attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL); + return (attrib); +} + /* * Set attributes of a NTFS file given an inode * diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index 66b78c00..2ca4afad 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -43,6 +43,229 @@ #include #include +extern int ntfs_inode_get_security(ntfs_inode *ni, u32 selection, char *buf, + u32 buflen, u32 *psize); + +extern int ntfs_inode_get_attributes(ntfs_inode *ni); + +struct sd_tree { + u32 num_sds; + struct wim_security_data *sd; + struct sd_node *root; +}; + +struct sd_node { + int security_id; + u8 hash[SHA1_HASH_SIZE]; + struct sd_node *left; + struct sd_node *right; +}; + +static void free_sd_tree(struct sd_node *root) +{ + if (root) { + free_sd_tree(root->left); + free_sd_tree(root->right); + FREE(root); + } +} + +static void insert_sd_node(struct sd_node *new, struct sd_node *root) +{ + int cmp = hashes_cmp(root->hash, new->hash); + if (cmp < 0) { + if (root->left) + insert_sd_node(new, root->left); + else + root->left = new; + } else if (cmp > 0) { + if (root->right) + insert_sd_node(new, root->right); + else + root->right = new; + } else { + wimlib_assert(0); + } +} + +static int lookup_sd(const u8 hash[SHA1_HASH_SIZE], struct sd_node *node) +{ + int cmp; + if (!node) + return -1; + cmp = hashes_cmp(hash, node->hash); + if (cmp < 0) + return lookup_sd(hash, node->left); + else if (cmp > 0) + return lookup_sd(hash, node->right); + else + return node->security_id; +} + +static int tree_add_sd(struct sd_tree *tree, const u8 *descriptor, + size_t size) +{ + u8 hash[SHA1_HASH_SIZE]; + int security_id; + struct sd_node *new; + u8 **descriptors; + u64 *sizes; + u8 *descr_copy; + struct wim_security_data *sd = tree->sd; + sha1_buffer(descriptor, size, hash); + + security_id = lookup_sd(hash, tree->root); + if (security_id >= 0) + return security_id; + + new = MALLOC(sizeof(struct sd_node)); + if (!new) + return -1; + descr_copy = MALLOC(size); + if (!descr_copy) + goto out_free_node; + memcpy(descr_copy, descriptor, size); + new->security_id = tree->num_sds++; + new->left = NULL; + new->right = NULL; + copy_hash(new->hash, hash); + + descriptors = REALLOC(sd->descriptors, + (sd->num_entries + 1) * sizeof(sd->descriptors[0])); + if (!descriptors) + goto out_free_descr; + sd->descriptors = descriptors; + sizes = REALLOC(sd->sizes, + (sd->num_entries + 1) * sizeof(sd->sizes[0])); + if (!sizes) + goto out_free_descr; + sd->sizes = sizes; + sd->descriptors[sd->num_entries] = descr_copy; + sd->sizes[sd->num_entries] = size; + sd->num_entries++; + sd->total_length += size + 8; + + if (tree->root) + insert_sd_node(tree->root, new); + else + tree->root = new; + return new->security_id; +out_free_descr: + FREE(descr_copy); +out_free_node: + FREE(new); + return -1; +} + +#if 0 +static int build_sd_tree(struct wim_security_data *sd, struct sd_tree *tree) +{ + int ret; + u32 orig_num_entries = sd->num_entries; + u32 orig_total_length = sd->total_length; + + tree->num_sds = 0; + tree->sd = sd; + tree->root = NULL; + + for (u32 i = 0; i < sd->num_entries; i++) { + ret = tree_add_sd(tree, sd->descriptors[i], sd->sizes[i]); + if (ret < 0) + goto out_revert; + } + return 0; +out_revert: + sd->num_entries = orig_num_entries; + sd->total_length = orig_total_length; + free_sd_tree(tree->root); + return ret; +} +#endif + +static int __build_dentry_tree_ntfs(struct dentry *dentry, ntfs_inode *ni, + 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; + + 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); + + if (mrec_flags & MFT_RECORD_IS_DIRECTORY) { + if (attributes & FILE_ATTR_REPARSE_POINT) { + /* Junction point */ + } else { + /* Normal directory */ + } + } else { + if (attributes & FILE_ATTR_REPARSE_POINT) { + /* Symbolic link or other reparse point */ + } else { + /* Normal file */ + } + } + ret = ntfs_inode_get_security(ni, + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | + SACL_SECURITY_INFORMATION, + NULL, 0, &sd_size); + u8 sd[sd_size]; + ret = ntfs_inode_get_security(ni, + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | + 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) +{ + 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.root = NULL; + + vol = ntfs_mount(device, MS_RDONLY); + if (!vol) { + ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s' read-only", + device); + return WIMLIB_ERR_NTFS_3G; + } + root_ni = ntfs_inode_open(vol, FILE_root); + if (!root_ni) { + ERROR_WITH_ERRNO("Failed to open root inode of NTFS volume " + "`%s'", device); + ret = WIMLIB_ERR_NTFS_3G; + goto out; + } + ret = __build_dentry_tree_ntfs(root_dentry, root_ni, lookup_table, &tree); + +out: + if (ntfs_umount(vol, FALSE) != 0) { + ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device); + if (ret == 0) + ret = WIMLIB_ERR_NTFS_3G; + } + return ret; +} WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w, const char *device, @@ -51,15 +274,12 @@ WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w, const char *flags_element, int flags) { - int ret; - - if (!device) - return WIMLIB_ERR_INVALID_PARAM; if (flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) { ERROR("Cannot dereference files when capturing directly from NTFS"); return WIMLIB_ERR_INVALID_PARAM; } - return 0; + return do_add_image(w, device, name, description, flags_element, flags, + build_dentry_tree_ntfs); } #else /* WITH_NTFS_3G */ diff --git a/src/sha1.h b/src/sha1.h index c44b9f40..a5d695d6 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -25,6 +25,11 @@ static inline bool hashes_equal(const u8 h1[SHA1_HASH_SIZE], { return memcmp(h1, h2, SHA1_HASH_SIZE) == 0; } +static inline int hashes_cmp(const u8 h1[SHA1_HASH_SIZE], + const u8 h2[SHA1_HASH_SIZE]) +{ + return memcmp(h1, h2, SHA1_HASH_SIZE); +} /* Prints a hash code field. */ static inline void print_hash(const u8 hash[SHA1_HASH_SIZE]) diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index abd0b86c..4f390629 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -334,6 +334,11 @@ extern int check_wim_integrity(WIMStruct *w, int show_progress, int *status); /* modify.c */ extern void destroy_image_metadata(struct image_metadata *imd, struct lookup_table *lt); +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)); /* resource.c */ extern const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry);