+ remove_dentry(dentry, w->lookup_table);
+ return 0;
+}
+
+#ifdef ENABLE_XATTR
+/* Write an alternate data stream through the XATTR interface */
+static int wimfs_setxattr(const char *path, const char *name,
+ const char *value, size_t size, int flags)
+{
+ struct ads_entry *existing_ads_entry;
+ struct ads_entry *new_ads_entry;
+ struct lookup_table_entry *existing_lte;
+ struct lookup_table_entry *lte;
+ struct inode *inode;
+ u8 value_hash[SHA1_HASH_SIZE];
+ u16 ads_idx;
+
+ if (!(mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
+ return -ENOTSUP;
+
+ if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
+ return -ENOATTR;
+ name += 5;
+
+ inode = wim_pathname_to_inode(w, path);
+ if (!inode)
+ return -ENOENT;
+
+ existing_ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
+ if (existing_ads_entry) {
+ if (flags & XATTR_CREATE)
+ return -EEXIST;
+ inode_remove_ads(inode, ads_idx, w->lookup_table);
+ } else {
+ if (flags & XATTR_REPLACE)
+ return -ENOATTR;
+ }
+ new_ads_entry = inode_add_ads(inode, name);
+ if (!new_ads_entry)
+ return -ENOMEM;
+
+ sha1_buffer((const u8*)value, size, value_hash);
+
+ existing_lte = __lookup_resource(w->lookup_table, value_hash);
+
+ if (existing_lte) {
+ lte = existing_lte;
+ lte->refcnt++;
+ } else {
+ u8 *value_copy;
+ lte = new_lookup_table_entry();
+ if (!lte)
+ return -ENOMEM;
+ value_copy = MALLOC(size);
+ if (!value_copy) {
+ FREE(lte);
+ return -ENOMEM;
+ }
+ memcpy(value_copy, value, size);
+ lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+ lte->attached_buffer = value_copy;
+ lte->resource_entry.original_size = size;
+ lte->resource_entry.size = size;
+ lte->resource_entry.flags = 0;
+ copy_hash(lte->hash, value_hash);
+ lookup_table_insert(w->lookup_table, lte);
+ }
+ new_ads_entry->lte = lte;
+ return 0;
+}
+#endif
+
+static int wimfs_symlink(const char *to, const char *from)
+{
+ struct dentry *dentry_parent, *dentry;
+ const char *link_name;
+ struct inode *inode;
+
+ dentry_parent = get_parent_dentry(w, from);
+ if (!dentry_parent)
+ return -ENOENT;
+ if (!dentry_is_directory(dentry_parent))
+ return -ENOTDIR;
+
+ link_name = path_basename(from);
+
+ if (get_dentry_child_with_name(dentry_parent, link_name))
+ return -EEXIST;
+ dentry = new_dentry_with_inode(link_name);
+ if (!dentry)
+ return -ENOMEM;
+ inode = dentry->d_inode;
+
+ inode->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
+ inode->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
+ inode->ino = next_ino++;
+ inode->resolved = true;
+
+ if (inode_set_symlink(inode, to, w->lookup_table, NULL) != 0)
+ goto out_free_dentry;
+
+ link_dentry(dentry, dentry_parent);