X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fhardlink.c;h=042b0576a88cfab159a7d18184cd226c586ea606;hp=e2f6ca0cb77fd29c867a350c4352b3d53044eb9c;hb=86a767c28bfb9df8921ef9ff61a32c971beb51aa;hpb=c6aa9e6bfdeee0e08407d0efe02270f2ba4b62c6 diff --git a/src/hardlink.c b/src/hardlink.c index e2f6ca0c..042b0576 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -23,10 +23,14 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ -#include "wimlib_internal.h" -#include "dentry.h" -#include "list.h" -#include "lookup_table.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wimlib/capture.h" +#include "wimlib/dentry.h" +#include "wimlib/error.h" +#include "wimlib/lookup_table.h" /* NULL NULL * ^ ^ @@ -101,6 +105,15 @@ inode_table_insert(struct wim_dentry *dentry, void *_table) pos = d_inode->i_ino % table->capacity; hlist_for_each_entry(inode, cur, &table->array[pos], i_hlist) { if (inode->i_ino == d_inode->i_ino) { + if (unlikely((inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) || + (d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))) + { + ERROR("Unsupported directory hard link " + "\"%"TS"\" <=> \"%"TS"\"", + dentry_full_path(dentry), + dentry_full_path(inode_first_dentry(inode))); + return WIMLIB_ERR_INVALID_DENTRY; + } inode_add_dentry(dentry, inode); inode->i_nlink++; return 0; @@ -168,25 +181,32 @@ inode_ref_streams(struct wim_inode *inode) */ int inode_table_new_dentry(struct wim_inode_table *table, const tchar *name, - u64 ino, u64 devno, struct wim_dentry **dentry_ret) + u64 ino, u64 devno, bool noshare, + struct wim_dentry **dentry_ret) { struct wim_dentry *dentry; struct wim_inode *inode; int ret; - ret = new_dentry(name, &dentry); - if (ret) - return ret; - - inode = inode_table_get_inode(table, ino, devno); - if (!inode) { - free_dentry(dentry); - return WIMLIB_ERR_NOMEM; + if (noshare) { + ret = new_dentry_with_timeless_inode(name, &dentry); + if (ret) + return ret; + list_add_tail(&dentry->d_inode->i_list, &table->extra_inodes); + } else { + ret = new_dentry(name, &dentry); + if (ret) + return ret; + inode = inode_table_get_inode(table, ino, devno); + if (!inode) { + free_dentry(dentry); + return WIMLIB_ERR_NOMEM; + } + if (inode->i_nlink > 1) + inode_ref_streams(inode); + dentry->d_inode = inode; + inode_add_dentry(dentry, inode); } - if (inode->i_nlink > 1) - inode_ref_streams(inode); - dentry->d_inode = inode; - inode_add_dentry(dentry, inode); *dentry_ret = dentry; return 0; } @@ -298,8 +318,6 @@ fix_true_inode(struct wim_inode *inode, struct list_head *inode_list) return WIMLIB_ERR_INVALID_DENTRY; } /* Free the unneeded `struct wim_inode'. */ - dentry->d_inode->i_hlist.next = NULL; - dentry->d_inode->i_hlist.pprev = NULL; free_inode(dentry->d_inode); dentry->d_inode = ref_inode; ref_inode->i_nlink++; @@ -337,6 +355,13 @@ fix_nominal_inode(struct wim_inode *inode, struct list_head *inode_list, wimlib_assert(inode->i_nlink == inode_link_count(inode)); + if (inode->i_nlink > 1 && + (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)) + { + ERROR("Found unsupported directory hard link!"); + return WIMLIB_ERR_INVALID_DENTRY; + } + LIST_HEAD(dentries_with_data_streams); LIST_HEAD(dentries_with_no_data_streams); HLIST_HEAD(true_inodes); @@ -458,6 +483,7 @@ fix_inodes(struct wim_inode_table *table, struct list_head *inode_list, INIT_LIST_HEAD(inode_list); for (u64 i = 0; i < table->capacity; i++) { hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], i_hlist) { + INIT_LIST_HEAD(&inode->i_list); ret = fix_nominal_inode(inode, inode_list, ino_changes_needed); if (ret) return ret; @@ -505,16 +531,19 @@ dentry_tree_fix_inodes(struct wim_dentry *root, struct list_head *inode_list) DEBUG("Inserting dentries into inode table"); ret = init_inode_table(&inode_tab, 9001); if (ret) - return ret; + goto out; - for_dentry_in_tree(root, inode_table_insert, &inode_tab); + ret = for_dentry_in_tree(root, inode_table_insert, &inode_tab); + if (ret) + goto out_destroy_image_table; DEBUG("Cleaning up the hard link groups"); ino_changes_needed = false; ret = fix_inodes(&inode_tab, inode_list, &ino_changes_needed); - destroy_inode_table(&inode_tab); + if (ret) + goto out_destroy_image_table; - if (ret == 0 && ino_changes_needed) { + if (ino_changes_needed) { u64 cur_ino = 1; struct wim_inode *inode; @@ -526,6 +555,10 @@ dentry_tree_fix_inodes(struct wim_dentry *root, struct list_head *inode_list) inode->i_ino = 0; } } + ret = 0; +out_destroy_image_table: + destroy_inode_table(&inode_tab); +out: return ret; } @@ -539,7 +572,13 @@ inode_table_prepare_inode_list(struct wim_inode_table *table, struct hlist_node *cur, *tmp; u64 cur_ino = 1; - INIT_LIST_HEAD(head); + list_for_each_entry(inode, head, i_list) { + if (inode->i_nlink > 1) + inode->i_ino = cur_ino++; + else + inode->i_ino = 0; + } + for (size_t i = 0; i < table->capacity; i++) { hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], i_hlist) {