return NULL;
inode->num_ads = num_ads;
ads_entries[num_ads - 1] = new_entry;
+#ifdef WITH_FUSE
+ new_entry->stream_id = inode->next_stream_id++;
+#endif
return new_entry;
}
stats.file_count = file_count_ret;
stats.total_bytes = total_bytes_ret;
stats.hard_link_bytes = hard_link_bytes_ret;
- for_lookup_table_entry(table, zero_out_refcnts, NULL);
+ for_lookup_table_entry(table, lte_zero_out_refcnt, NULL);
for_dentry_in_tree(root, calculate_dentry_statistics, &stats);
}
ads_entries[i] = cur_entry;
+ #ifdef WITH_FUSE
+ ads_entries[i]->stream_id = i + 1;
+ #endif
+
/* Read the base stream entry, excluding the stream name. */
if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) {
ERROR("Stream entries go past end of metadata resource");
remaining_size -= total_length;
}
inode->ads_entries = ads_entries;
+#ifdef WITH_FUSE
+ inode->next_stream_id = inode->num_ads + 1;
+#endif
return 0;
out_free_ads_entries:
for (u16 i = 0; i < num_ads; i++)
return ret;
}
-/* Run some miscellaneous verifications on a WIM dentry */
-int verify_dentry(struct dentry *dentry, void *wim)
+int verify_inode(struct inode *inode, const WIMStruct *w)
{
- const WIMStruct *w = wim;
const struct lookup_table *table = w->lookup_table;
const struct wim_security_data *sd = wim_const_security_data(w);
- const struct inode *inode = dentry->inode;
+ const struct dentry *first_dentry = inode_first_dentry(inode);
int ret = WIMLIB_ERR_INVALID_DENTRY;
/* Check the security ID */
if (inode->security_id < -1) {
ERROR("Dentry `%s' has an invalid security ID (%d)",
- dentry->full_path_utf8, inode->security_id);
+ first_dentry->full_path_utf8, inode->security_id);
goto out;
}
if (inode->security_id >= sd->num_entries) {
ERROR("Dentry `%s' has an invalid security ID (%d) "
"(there are only %u entries in the security table)",
- dentry->full_path_utf8, inode->security_id,
+ first_dentry->full_path_utf8, inode->security_id,
sd->num_entries);
goto out;
}
lte = __lookup_resource(table, hash);
if (!lte && !is_zero_hash(hash)) {
ERROR("Could not find lookup table entry for stream "
- "%u of dentry `%s'", i, dentry->full_path_utf8);
+ "%u of dentry `%s'", i, first_dentry->full_path_utf8);
goto out;
}
+ if (lte && (lte->real_refcnt += inode->link_count) > lte->refcnt)
+ {
+ #ifdef ENABLE_ERROR_MESSAGES
+ WARNING("The following lookup table entry "
+ "has a reference count of %u, but",
+ lte->refcnt);
+ WARNING("We found %zu references to it",
+ lte->real_refcnt);
+ WARNING("(One dentry referencing it is at `%s')",
+ first_dentry->full_path_utf8);
+
+ print_lookup_table_entry(lte);
+ #endif
+ /* Guess what! install.wim for Windows 8
+ * contains a stream with 2 dentries referencing
+ * it, but the lookup table entry has reference
+ * count of 1. So we will need to handle this
+ * case and not just make it be an error... I'm
+ * just setting the reference count to the
+ * number of references we found.
+ * (Unfortunately, even after doing this, the
+ * reference count could be too low if it's also
+ * referenced in other WIM images) */
+
+ #if 1
+ lte->refcnt = lte->real_refcnt;
+ WARNING("Fixing reference count");
+ #else
+ goto out;
+ #endif
+ }
}
}
}
if (num_unnamed_streams > 1) {
ERROR("Dentry `%s' has multiple (%u) un-named streams",
- dentry->full_path_utf8, num_unnamed_streams);
+ first_dentry->full_path_utf8, num_unnamed_streams);
goto out;
}
+ inode->verified = true;
+ ret = 0;
+out:
+ return ret;
+}
+
+
+/* Run some miscellaneous verifications on a WIM dentry */
+int verify_dentry(struct dentry *dentry, void *wim)
+{
+ const WIMStruct *w = wim;
+ const struct inode *inode = dentry->inode;
+ int ret = WIMLIB_ERR_INVALID_DENTRY;
+
+ if (!dentry->inode->verified) {
+ ret = verify_inode(dentry->inode, w);
+ if (ret != 0)
+ goto out;
+ }
/* Cannot have a short name but no long name */
if (dentry->short_name_len && !dentry->file_name_len) {
struct lookup_table_entry *lte;
};
- /* Length of stream name (UTF-16) */
+ /* Length of stream name (UTF-16). This is in bytes, not characters,
+ * and does not include the terminating null character */
u16 stream_name_len;
/* Length of stream name (UTF-8) */
* the @lte field is valid, but the @hash field is not valid)
*
* (This is not an on-disk field.) */
- bool resolved;
+ u8 resolved : 1;
+
+ u8 verified : 1;
u16 num_ads;
/* List of dentries in the hard link set */
struct list_head inode_dentry_list;
- struct list_head tmp_list;
+ union {
+ struct list_head tmp_list;
+ bool is_extracted;
+ };
};
+static inline bool dentry_is_extracted(const struct dentry *dentry)
+{
+ return dentry->is_extracted;
+}
+
extern struct ads_entry *inode_get_ads_entry(struct inode *inode,
const char *stream_name,
extern int print_dentry_full_path(struct dentry *entry, void *ignore);
extern struct dentry *get_dentry(struct WIMStruct *w, const char *path);
-extern struct inode *wim_pathname_to_inode(WIMStruct *w, const char *path);
+extern struct inode *wim_pathname_to_inode(struct WIMStruct *w,
+ const char *path);
extern struct dentry *get_parent_dentry(struct WIMStruct *w, const char *path);
extern struct dentry *get_dentry_child_with_name(const struct dentry *dentry,
const char *name);
static inline struct dentry *inode_first_dentry(struct inode *inode)
{
+ wimlib_assert(inode->dentry_list.next != &inode->dentry_list);
return container_of(inode->dentry_list.next, struct dentry,
inode_dentry_list);
}
-
static inline bool dentry_is_root(const struct dentry *dentry)
{
return dentry->parent == dentry;
if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) {
- if (++lte->out_refcnt != 1)
+ if (lte->extracted_file) {
return extract_regular_file_linked(dentry, output_dir,
output_path,
extract_flags, lte);
- FREE(lte->extracted_file);
- lte->extracted_file = STRDUP(output_path);
- if (!lte->extracted_file)
- return WIMLIB_ERR_NOMEM;
+ } else {
+ lte->extracted_file = STRDUP(output_path);
+ if (!lte->extracted_file)
+ return WIMLIB_ERR_NOMEM;
+ }
}
return extract_regular_file_unlinked(w, dentry, output_path,
w->lookup_table = joined_tab;
}
-
- for_lookup_table_entry(w->lookup_table, zero_out_refcnts, NULL);
+ for_lookup_table_entry(w->lookup_table, lte_free_extracted_file, NULL);
if (image == WIM_ALL_IMAGES) {
flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
* next available inode ID. */
u64 assign_inode_numbers(struct hlist_head *inode_list)
{
+ DEBUG("Assigning inode numbers");
struct inode *inode;
struct hlist_node *cur;
u64 cur_ino = 1;
}
-static void
-print_inode_dentries(const struct inode *inode)
+static void print_inode_dentries(const struct inode *inode)
{
struct dentry *dentry;
list_for_each_entry(dentry, &inode->dentry_list, inode_dentry_list)
}
/*
- * Goes through each inode and shares the inodes among members of a hard
- * inode.
+ * Goes through each hard link group (dentries sharing the same hard link group
+ * ID field) that's been inserted into the inode table and shars the `struct
+ * inode's among members of each hard link group.
*
- * In the process, the dentries in each inode are checked for consistency.
- * If they contain data features that indicate they cannot really be in the same
- * inode, this should be an error, but in reality this case needs to
- * be handled, so we split the dentries into different inodes.
+ * In the process, the dentries belonging to each inode are checked for
+ * consistency. If they contain data features that indicate they cannot really
+ * correspond to the same inode, this should be an error, but in reality this
+ * case needs to be handled, so we split the dentries into different inodes.
*/
int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
{
}
+int lte_zero_real_refcnt(struct lookup_table_entry *lte, void *ignore)
+{
+ lte->real_refcnt = 0;
+ return 0;
+}
+
+int lte_zero_out_refcnt(struct lookup_table_entry *lte, void *ignore)
+{
+ lte->out_refcnt = 0;
+ return 0;
+}
-int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore)
+int lte_free_extracted_file(struct lookup_table_entry *lte, void *ignone)
{
- entry->out_refcnt = 0;
+ FREE(lte->extracted_file);
+ lte->extracted_file = NULL;
return 0;
}
return 0;
}
-static int inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
+static void inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
{
struct lookup_table_entry *lte;
lte = __lookup_resource(table, cur_entry->hash);
cur_entry->lte = lte;
}
- return 0;
}
/* Resolve a dentry's lookup table entries
*/
int dentry_resolve_ltes(struct dentry *dentry, void *table)
{
- if (dentry->inode->resolved)
- return 0;
- else
- return inode_resolve_ltes(dentry->inode, table);
+ if (!dentry->inode->resolved)
+ inode_resolve_ltes(dentry->inode, table);
+ return 0;
}
-
-
-
-/* Return the lookup table entry for the unnamed data stream of a inode, or
+/* Return the lookup table entry for the unnamed data stream of an inode, or
* NULL if there is none.
*
* You'd think this would be easier than it actually is, since the unnamed data
* stream should be the one referenced from the inode itself. Alas, if there
* are named data streams, Microsoft's "imagex.exe" program will put the unnamed
- * data stream in one of the alternate data streams instead of inside the
- * inode. So we need to check the alternate data streams too.
+ * data stream in one of the alternate data streams instead of inside the WIM
+ * dentry itself. So we need to check the alternate data streams too.
*
- * Also, note that a inode may appear to have than one unnamed stream, but if
+ * Also, note that a dentry may appear to have than one unnamed stream, but if
* the SHA1 message digest is all 0's then the corresponding stream does not
* really "count" (this is the case for the inode's own file stream when the
* file stream that should be there is actually in one of the alternate stream
* dentries. */
u32 out_refcnt;
+ u32 real_refcnt;
+
/* When a WIM file is written, @output_resource_entry is filled
* in with the resource entry for the output WIM. This will not
* necessarily be the same as the @resource_entry since:
struct lookup_table_entry **lte_ret,
u16 *stream_idx_ret);
-extern int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore);
+extern int lte_zero_out_refcnt(struct lookup_table_entry *entry, void *ignore);
+extern int lte_zero_real_refcnt(struct lookup_table_entry *entry, void *ignore);
+extern int lte_free_extracted_file(struct lookup_table_entry *lte, void *ignone);
extern void print_lookup_table_entry(const struct lookup_table_entry *entry);
static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
{
WIMStruct *src_wim, *dest_wim;
+ struct inode *inode;
src_wim = ((struct wim_pair*)arg)->src_wim;
dest_wim = ((struct wim_pair*)arg)->dest_wim;
+ inode = dentry->inode;
- wimlib_assert(!dentry->inode->resolved);
+ wimlib_assert(!inode->resolved);
- for (unsigned i = 0; i < (unsigned)dentry->inode->num_ads + 1; i++) {
+ for (unsigned i = 0; i <= inode->num_ads; i++) {
struct lookup_table_entry *src_lte, *dest_lte;
- src_lte = inode_stream_lte_unresolved(dentry->inode, i,
+ src_lte = inode_stream_lte_unresolved(inode, i,
src_wim->lookup_table);
if (!src_lte)
continue;
- dest_lte = inode_stream_lte_unresolved(dentry->inode, i,
+ dest_lte = inode_stream_lte_unresolved(inode, i,
dest_wim->lookup_table);
if (dest_lte) {
dest_lte->refcnt++;
static const u16 fds_per_alloc = 8;
static const u16 max_fds = 0xffff;
+ DEBUG("Allocate wimlib fd");
+
if (inode->num_opened_fds == inode->num_allocated_fds) {
struct wimlib_fd **fds;
u16 num_new_fds;
*fd_ret = fd;
inode->fds[i] = fd;
inode->num_opened_fds++;
- lte->num_opened_fds++;
+ if (lte)
+ lte->num_opened_fds++;
+ DEBUG("Allocated fd");
return 0;
}
}
struct lookup_table_entry *lte;
unsigned i;
- for (i = 0; <= inode->num_ads; i++) {
+ for (i = 0; i <= inode->num_ads; i++) {
lte = inode_stream_lte_resolved(inode, i);
if (lte)
lte_decrement_refcnt(lte, lookup_table);
new_lte->staging_file_name = staging_file_name;
new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
+ if (stream_id == 0)
+ inode->lte = new_lte;
+ else
+ for (u16 i = 0; i < inode->num_ads; i++)
+ if (inode->ads_entries[i]->stream_id == stream_id)
+ inode->ads_entries[i]->lte = new_lte;
+
lookup_table_insert(w->lookup_table, new_lte);
list_add(&new_lte->staging_list, &staging_list);
*lte = new_lte;
if (ret != 0)
return ret;
+ DEBUG("dentry = %p", dentry);
+
inode = dentry->inode;
+ DEBUG("stream_idx = %u", stream_idx);
+
if (stream_idx == 0)
stream_id = 0;
else
stream_id = inode->ads_entries[stream_idx - 1]->stream_id;
+ DEBUG("stream_id = %u", stream_id);
+
/* The file resource may be in the staging directory (read-write mounts
* only) or in the WIM. If it's in the staging directory, we need to
* open a native file descriptor for the corresponding file. Otherwise,
/* Opens a directory. */
static int wimfs_opendir(const char *path, struct fuse_file_info *fi)
{
- struct dentry *dentry;
struct inode *inode;
int ret;
struct wimlib_fd *fd = NULL;
- dentry = get_dentry(w, path);
- if (!dentry)
+ inode = wim_pathname_to_inode(w, path);
+ if (!inode)
return -ENOENT;
-
- inode = dentry->inode;
-
if (!inode_is_directory(inode))
return -ENOTDIR;
ret = alloc_wimlib_fd(inode, 0, NULL, &fd);
static int wimfs_setxattr(const char *path, const char *name,
const char *value, size_t size, int flags)
{
- struct dentry *dentry;
struct ads_entry *existing_ads_entry;
struct ads_entry *new_ads_entry;
struct lookup_table_entry *existing_lte;
return -ENOATTR;
name += 5;
- dentry = get_dentry(w, path);
- if (!dentry)
+ inode = wim_pathname_to_inode(w, path);
+ if (!inode)
return -ENOENT;
- inode = dentry->inode;
existing_ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
if (existing_ads_entry) {
if (flags & XATTR_CREATE)
return -EEXIST;
- inode_remove_ads(dentry->inode, ads_idx, w->lookup_table);
+ inode_remove_ads(inode, ads_idx, w->lookup_table);
} else {
if (flags & XATTR_REPLACE)
return -ENOATTR;
}
- new_ads_entry = inode_add_ads(dentry, name);
+ new_ads_entry = inode_add_ads(inode, name);
if (!new_ads_entry)
return -ENOMEM;
{
struct dentry *dentry_parent, *dentry;
const char *link_name;
- struct lookup_table_entry *lte;
+ struct inode *inode;
dentry_parent = get_parent_dentry(w, from);
if (!dentry_parent)
if (get_dentry_child_with_name(dentry_parent, link_name))
return -EEXIST;
- dentry = new_dentry(link_name);
+ dentry = new_dentry_with_inode(link_name);
if (!dentry)
return -ENOMEM;
+ inode = dentry->inode;
- dentry->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
- dentry->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
- dentry->link_group_id = next_link_group_id++;
+ inode->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
+ inode->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
+ inode->ino = next_ino++;
- if (dentry_set_symlink(dentry, to, w->lookup_table, <e) != 0)
+ if (inode_set_symlink(inode, to, w->lookup_table, NULL) != 0)
goto out_free_dentry;
- wimlib_assert(lte);
-
- dentry->ads_entries[1].lte_group_list.type = STREAM_TYPE_ADS;
- list_add(&dentry->ads_entries[1].lte_group_list.list,
- <e->lte_group_list);
- wimlib_assert(dentry->resolved);
-
link_dentry(dentry, dentry_parent);
return 0;
out_free_dentry:
struct dentry *dentry;
struct lookup_table_entry *lte;
int ret;
- unsigned stream_idx;
+ u16 stream_idx;
+ u32 stream_id;
+ struct inode *inode;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
<e, &stream_idx);
if (!lte) /* Already a zero-length file */
return 0;
+ inode = dentry->inode;
+
+ if (stream_idx == 0)
+ stream_id = 0;
+ else
+ stream_id = inode->ads_entries[stream_idx - 1]->stream_id;
+
if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
wimlib_assert(lte->staging_file_name);
ret = truncate(lte->staging_file_name, size);
wimlib_assert(lte->resource_location == RESOURCE_IN_WIM);
/* File in WIM. Extract it to the staging directory, but only
* the first @size bytes of it. */
- ret = extract_resource_to_staging_dir(dentry, stream_idx,
+ ret = extract_resource_to_staging_dir(inode, stream_id,
<e, size);
}
return ret;
struct lookup_table_entry *lte;
struct inode *inode;
int ret;
- unsigned stream_idx;
+ u16 stream_idx;
unsigned i;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
};
-static int check_lte_refcnt(struct lookup_table_entry *lte, void *ignore)
-{
- size_t lte_group_size = 0;
- struct list_head *cur;
- list_for_each(cur, <e->lte_group_list)
- lte_group_size++;
- if (lte_group_size > lte->refcnt) {
-#ifdef ENABLE_ERROR_MESSAGES
- struct dentry *example_dentry;
- struct list_head *next;
- struct stream_list_head *head;
- WARNING("The following lookup table entry has a reference count "
- "of %u, but", lte->refcnt);
- WARNING("We found %zu references to it", lte_group_size);
- next = lte->lte_group_list.next;
- head = container_of(next, struct stream_list_head, list);
- if (head->type == STREAM_TYPE_NORMAL) {
- example_dentry = container_of(head, struct dentry,
- lte_group_list);
- WARNING("(One dentry referencing it is at `%s')",
- example_dentry->full_path_utf8);
- }
- print_lookup_table_entry(lte);
-#endif
- /* Guess what! install.wim for Windows 8 contains a stream with
- * 2 dentries referencing it, but the lookup table entry has
- * reference count of 1. So we will need to handle this case
- * and not just make it be an error... I'm just setting the
- * reference count to the number of references we found. */
-
- #if 1
- lte->refcnt = lte_group_size;
- WARNING("Fixing reference count");
- #else
- return WIMLIB_ERR_INVALID_DENTRY;
- #endif
- }
- return 0;
-}
-
/* Mounts a WIM file. */
WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
int flags, WIMStruct **additional_swms,
int ret;
char *p;
struct lookup_table *joined_tab, *wim_tab_save;
+ struct image_metadata *imd;
DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
wim, image, dir, flags);
if (ret != 0)
goto out;
+ imd = &wim->image_metadata[image - 1];
+
DEBUG("Selected image %d", image);
- next_link_group_id = assign_link_group_ids(wim->image_metadata[image - 1].lgt);
+ next_ino = assign_inode_numbers(&imd->inode_list);
+
+ DEBUG("(next_ino = %"PRIu64")", next_ino);
- DEBUG("Resolving lookup table entries");
/* Resolve all the lookup table entries of the dentry tree */
- for_dentry_in_tree(wim_root_dentry(wim), dentry_resolve_ltes,
+ DEBUG("Resolving lookup table entries");
+ for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes,
wim->lookup_table);
- DEBUG("Checking lookup table entry reference counts");
-
- ret = for_lookup_table_entry(wim->lookup_table, check_lte_refcnt, NULL);
- if (ret != 0)
- goto out;
-
if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
- wim_get_current_image_metadata(wim)->modified = true;
+ imd->modified = true;
if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
/* Writes the data streams to a NTFS file
*
* @ni: The NTFS inode for the file.
- * @dentry: The directory entry in the WIM file.
+ * @inode: The WIM dentry that has an inode containing the streams.
* @w: The WIMStruct for the WIM containing the image we are applying.
*
* Returns 0 on success, nonzero on failure.
unsigned stream_idx = 0;
ntfschar *stream_name = AT_UNNAMED;
u32 stream_name_len = 0;
+ const struct inode *inode = dentry->inode;
DEBUG("Writing %u NTFS data stream%s for `%s'",
- dentry->num_ads + 1,
- (dentry->num_ads == 0 ? "" : "s"),
+ inode->num_ads + 1,
+ (inode->num_ads == 0 ? "" : "s"),
dentry->full_path_utf8);
while (1) {
struct lookup_table_entry *lte;
ntfs_attr *na;
- lte = dentry_stream_lte(dentry, stream_idx, w->lookup_table);
+ lte = inode_stream_lte(inode, stream_idx, w->lookup_table);
if (stream_name_len) {
/* Create an empty named stream. */
break;
ntfs_attr_close(na);
}
- if (stream_idx == dentry->num_ads)
+ if (stream_idx == inode->num_ads)
break;
- stream_name = (ntfschar*)dentry->ads_entries[stream_idx].stream_name;
- stream_name_len = dentry->ads_entries[stream_idx].stream_name_len / 2;
+ stream_name = (ntfschar*)inode->ads_entries[stream_idx]->stream_name;
+ stream_name_len = inode->ads_entries[stream_idx]->stream_name_len / 2;
stream_idx++;
}
return ret;
*
* It is named @from_dentry->file_name and is located under the directory
* specified by @dir_ni, and it is made to point to the previously extracted
- * file located at @to_dentry->extracted_file.
+ * file located at @inode->extracted_file.
*
* Return 0 on success, nonzero on failure.
*/
static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
- const struct dentry *to_dentry,
+ const struct inode *inode,
ntfs_inode *dir_ni,
ntfs_inode **to_ni_ret)
{
ntfs_volume *vol;
wimlib_assert(dentry_is_regular_file(from_dentry)
- && dentry_is_regular_file(to_dentry));
+ && inode_is_regular_file(inode));
if (ntfs_inode_close(dir_ni) != 0) {
ERROR_WITH_ERRNO("Error closing directory");
vol = dir_ni->vol;
DEBUG("Extracting NTFS hard link `%s' => `%s'",
- from_dentry->full_path_utf8, to_dentry->extracted_file);
+ from_dentry->full_path_utf8, inode->extracted_file);
- to_ni = ntfs_pathname_to_inode(vol, NULL,
- to_dentry->extracted_file);
+ to_ni = ntfs_pathname_to_inode(vol, NULL, inode->extracted_file);
if (!to_ni) {
ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'",
- to_dentry->extracted_file);
+ inode->extracted_file);
return WIMLIB_ERR_NTFS_3G;
}
p = from_dentry->full_path_utf8 + from_dentry->full_path_utf8_len;
if (ret != 0) {
ERROR_WITH_ERRNO("Could not create hard link `%s' => `%s'",
from_dentry->full_path_utf8,
- to_dentry->extracted_file);
+ inode->extracted_file);
ret = WIMLIB_ERR_NTFS_3G;
}
*to_ni_ret = to_ni;
const WIMStruct *w)
{
DEBUG("Setting NTFS file attributes on `%s' to %#"PRIx32,
- dentry->full_path_utf8, dentry->attributes);
+ dentry->full_path_utf8, dentry->inode->attributes);
int ret;
#ifdef HAVE_NTFS_INODE_FUNCTIONS
- ret = ntfs_set_inode_attributes(ni, dentry->attributes);
+ ret = ntfs_set_inode_attributes(ni, dentry->inode->attributes);
#else
struct SECURITY_CONTEXT ctx;
u32 attributes_le32;
- attributes_le32 = cpu_to_le32(dentry->attributes);
+ attributes_le32 = cpu_to_le32(dentry->inode->attributes);
memset(&ctx, 0, sizeof(ctx));
ctx.vol = ni->vol;
ret = ntfs_xattr_system_setxattr(&ctx, XATTR_NTFS_ATTRIB,
dentry->full_path_utf8);
return WIMLIB_ERR_NTFS_3G;
}
- if (dentry->security_id != -1) {
+ if (dentry->inode->security_id != -1) {
const struct wim_security_data *sd;
const char *descriptor;
sd = wim_const_security_data(w);
- wimlib_assert(dentry->security_id < sd->num_entries);
- descriptor = sd->descriptors[dentry->security_id];
+ wimlib_assert(dentry->inode->security_id < sd->num_entries);
+ descriptor = sd->descriptors[dentry->inode->security_id];
DEBUG("Applying security descriptor %d to `%s'",
- dentry->security_id, dentry->full_path_utf8);
+ dentry->inode->security_id, dentry->full_path_utf8);
#ifdef HAVE_NTFS_INODE_FUNCTIONS
u32 selection = OWNER_SECURITY_INFORMATION |
#else
ret = ntfs_xattr_system_setxattr(&ctx, XATTR_NTFS_ACL,
ni, dir_ni, descriptor,
- sd->sizes[dentry->security_id], 0);
+ sd->sizes[dentry->inode->security_id], 0);
#endif
if (ret != 0) {
struct lookup_table_entry *lte;
int ret = 0;
- wimlib_assert(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT);
+ wimlib_assert(dentry->inode->attributes & FILE_ATTRIBUTE_REPARSE_POINT);
- lte = dentry_unnamed_lte(dentry, w->lookup_table);
+ lte = inode_unnamed_lte(dentry->inode, w->lookup_table);
DEBUG("Applying reparse data to `%s'", dentry->full_path_utf8);
u8 reparse_data_buf[8 + wim_resource_size(lte)];
u8 *p = reparse_data_buf;
- p = put_u32(p, dentry->reparse_tag); /* ReparseTag */
+ p = put_u32(p, dentry->inode->reparse_tag); /* ReparseTag */
p = put_u16(p, wim_resource_size(lte)); /* ReparseDataLength */
p = put_u16(p, 0); /* Reserved */
struct dentry *dentry_with_dos_name;
dentry_with_dos_name = NULL;
- list_for_each_entry(other, &dentry->link_group_list,
- link_group_list)
- {
- if (dentry->parent == other->parent && other->short_name_len) {
+ inode_for_each_dentry(other, dentry->inode) {
+ if (other != dentry && (dentry->parent == other->parent)
+ && other->short_name_len)
+ {
if (dentry_with_dos_name) {
ERROR("Found multiple DOS names for file `%s' "
"in the same directory",
}
/* If there's a dentry with a DOS name, extract it first */
if (dentry_with_dos_name
- && !dentry_with_dos_name->extracted_file)
+ && !dentry_with_dos_name->inode->extracted_file)
{
char *p;
const char *dir_name;
ntfs_inode *ni = NULL;
bool is_hardlink = false;
ntfs_volume *vol = dir_ni->vol;
+ struct inode *inode = dentry->inode;
- if (dentry->attributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (inode->attributes & FILE_ATTRIBUTE_DIRECTORY) {
type = S_IFDIR;
} else {
struct dentry *other;
}
type = S_IFREG;
- /* See if we can make a hard link */
- list_for_each_entry(other, &dentry->link_group_list,
- link_group_list) {
- if (other->extracted_file) {
- /* Already extracted another dentry in the hard
- * link group. We can make a hard link instead
- * of extracting the file data. */
- ret = wim_apply_hardlink_ntfs(dentry, other,
+
+ if (inode->link_count > 1) {
+ /* Already extracted another dentry in the hard link
+ * group. We can make a hard link instead of extracting
+ * the file data. */
+ if (inode->extracted_file) {
+ ret = wim_apply_hardlink_ntfs(dentry, inode,
dir_ni, &ni);
is_hardlink = true;
- if (ret) {
+ if (ret)
goto out_close_dir_ni;
- } else {
- dentry->extracted_file = dentry->full_path_utf8;
+ else
goto out_set_dos_name;
- }
}
+ /* Can't make a hard link; extract the file itself */
+ FREE(inode->extracted_file);
+ inode->extracted_file = STRDUP(dentry->full_path_utf8);
+ if (!inode->extracted_file)
+ return WIMLIB_ERR_NOMEM;
}
- /* Can't make a hard link; extract the file itself */
- dentry->extracted_file = dentry->full_path_utf8;
}
/*
/* Write the data streams, unless this is a directory or reparse point
* */
- if (!dentry_is_directory(dentry) &&
- !(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ if (!(inode->attributes & (FILE_ATTRIBUTE_REPARSE_POINT |
+ FILE_ATTRIBUTE_DIRECTORY))) {
ret = write_ntfs_data_streams(ni, dentry, w);
if (ret != 0)
goto out_close_dir_ni;
if (ret != 0)
goto out_close_dir_ni;
- if (dentry->attributes & FILE_ATTR_REPARSE_POINT) {
+ if (inode->attributes & FILE_ATTR_REPARSE_POINT) {
ret = apply_reparse_data(ni, dentry, w);
if (ret != 0)
goto out_close_dir_ni;
char orig;
const char *dir_name;
- if (dentry->extracted_file)
+ if (dentry_is_extracted(dentry))
return 0;
wimlib_assert(dentry->full_path_utf8);
}
p = buf;
- p = put_u64(p, dentry->creation_time);
- p = put_u64(p, dentry->last_write_time);
- p = put_u64(p, dentry->last_access_time);
+ p = put_u64(p, dentry->inode->creation_time);
+ p = put_u64(p, dentry->inode->last_write_time);
+ p = put_u64(p, dentry->inode->last_access_time);
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'",
return ret;
}
-static int dentry_clear_extracted_file(struct dentry *dentry, void *ignore)
+static int dentry_set_unextracted(struct dentry *dentry, void *ignore)
{
- if (dentry->extracted_file != dentry->full_path_utf8)
- FREE(dentry->extracted_file);
- dentry->extracted_file = NULL;
+ dentry->is_extracted = false;
return 0;
}
args.w = w;
root = wim_root_dentry(w);
- for_dentry_in_tree(root, dentry_clear_extracted_file, NULL);
-
+ for_dentry_in_tree(root, dentry_set_unextracted, NULL);
ret = for_dentry_in_tree(root, wim_apply_dentry_ntfs, &args);
if (ret != 0)
goto out;
lte->ntfs_loc = ntfs_loc;
lte->resource_location = RESOURCE_IN_NTFS_VOLUME;
if (type == AT_REPARSE_POINT) {
- dentry->reparse_tag = reparse_tag;
+ dentry->inode->reparse_tag = reparse_tag;
ntfs_loc->is_reparse_point = true;
lte->resource_entry.original_size = data_size - 8;
lte->resource_entry.size = data_size - 8;
}
if (name_length == 0) {
/* Unnamed data stream. Put the reference to it in the
- * dentry. */
- if (dentry->lte) {
+ * dentry's inode. */
+ if (dentry->inode->lte) {
ERROR("Found two un-named data streams for "
"`%s'", path);
ret = WIMLIB_ERR_NTFS_3G;
goto out_free_lte;
}
- dentry->lte = lte;
+ dentry->inode->lte = lte;
} else {
/* Named data stream. Put the reference to it in the
* alternate data stream entries */
&stream_name_utf8_len);
if (!stream_name_utf8)
goto out_free_lte;
- new_ads_entry = dentry_add_ads(dentry, stream_name_utf8);
+ new_ads_entry = inode_add_ads(dentry->inode, stream_name_utf8);
FREE(stream_name_utf8);
if (!new_ads_entry)
goto out_free_lte;
if (flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
printf("Scanning `%s'\n", path);
- root = new_dentry(path_basename(path));
+ root = new_dentry_with_inode(path_basename(path));
if (!root)
return WIMLIB_ERR_NOMEM;
*root_p = root;
}
}
- root->creation_time = le64_to_cpu(ni->creation_time);
- root->last_write_time = le64_to_cpu(ni->last_data_change_time);
- root->last_access_time = le64_to_cpu(ni->last_access_time);
- root->attributes = le32_to_cpu(attributes);
- root->link_group_id = ni->mft_no;
- root->resolved = true;
+ root->inode->creation_time = le64_to_cpu(ni->creation_time);
+ root->inode->last_write_time = le64_to_cpu(ni->last_data_change_time);
+ root->inode->last_access_time = le64_to_cpu(ni->last_access_time);
+ root->inode->attributes = le32_to_cpu(attributes);
+ root->inode->ino = ni->mft_no;
+ root->inode->resolved = true;
if (attributes & FILE_ATTR_REPARSE_POINT) {
/* Junction point, symbolic link, or other reparse point */
ni, dir_ni, sd, ret);
}
if (ret > 0) {
- root->security_id = sd_set_add_sd(sd_set, sd, ret);
- if (root->security_id == -1) {
+ root->inode->security_id = sd_set_add_sd(sd_set, sd, ret);
+ if (root->inode->security_id == -1) {
ERROR("Out of memory");
return WIMLIB_ERR_NOMEM;
}
DEBUG("Added security ID = %u for `%s'",
- root->security_id, path);
+ root->inode->security_id, path);
ret = 0;
} else if (ret < 0) {
ERROR_WITH_ERRNO("Failed to get security information from "
"`%s'", path);
ret = WIMLIB_ERR_NTFS_3G;
} else {
- root->security_id = -1;
+ root->inode->security_id = -1;
DEBUG("No security ID for `%s'", path);
}
#endif
dentry->prev = dentry;
if (ret != 0)
goto out_free_dentry_tree;
- list_add(&dentry->inode_dentry_list, &dentry->inode->dentry_list);
+ inode_add_dentry(dentry, dentry->inode);
/* Now read the entire directory entry tree into memory. */
DEBUG("Reading dentry tree");
for_dentry_in_tree(dentry, inode_table_insert, &inode_tab);
- DEBUG("Fixing inconsistencies in the link groups");
+ DEBUG("Fixing inconsistencies in the hard link groups");
ret = fix_inodes(&inode_tab, &inode_list);
destroy_inode_table(&inode_tab);
if (ret != 0)
goto out_free_dentry_tree;
DEBUG("Running miscellaneous verifications on the dentry tree");
+ for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL);
ret = for_dentry_in_tree(dentry, verify_dentry, w);
if (ret != 0)
goto out_free_dentry_tree;
DEBUG("Done reading image metadata");
imd->root_dentry = dentry;
+ imd->inode_list = inode_list;
goto out_free_buf;
out_free_dentry_tree:
free_dentry_tree(dentry, NULL);
* resource. */
struct lookup_table_entry *metadata_lte;
+ struct hlist_head inode_list;
+
/* True if the filesystem of the image has been modified. If this is
* the case, the memory for the filesystem is not freed when switching
* to a different WIM image. */
if (ret != 0)
goto done;
- for_lookup_table_entry(w->lookup_table, zero_out_refcnts, NULL);
+ for_lookup_table_entry(w->lookup_table, lte_zero_out_refcnt, NULL);
w->write_flags = flags;
}
cleanup() {
+ fusermount -u tmp &> /dev/null || true
rm -rf dir* tmp* *.wim *.swm
}
-trap cleanup exit
-fusermount -u tmp || true
-rm -rf tmp || true
+cleanup
# Make test directory
mkdir dir
echo "**********************************************************"
echo " Basic imagex tests passed "
echo "**********************************************************"
+cleanup