#define WIM_ADS_ENTRY_DISK_SIZE 38
-#ifndef WITH_NTFS_3G
/*
* Reparse tags documented at
* http://msdn.microsoft.com/en-us/library/dd541667(v=prot.10).aspx
*
* IO_REPARSE_TAG_SYMLINK is the only one we really care about.
*/
-#define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000
-#define IO_REPARSE_TAG_RESERVED_ONE 0x00000001
-#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
-#define IO_REPARSE_TAG_HSM 0xC0000004
-#define IO_REPARSE_TAG_HSM2 0x80000006
-#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
-#define IO_REPARSE_TAG_SIS 0x80000007
-#define IO_REPARSE_TAG_DFS 0x8000000A
-#define IO_REPARSE_TAG_DFSR 0x80000012
-#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
-#define IO_REPARSE_TAG_SYMLINK 0xA000000C
-#endif /* !WITH_NTFS_3G */
+#define WIM_IO_REPARSE_TAG_RESERVED_ZERO 0x00000000
+#define WIM_IO_REPARSE_TAG_RESERVED_ONE 0x00000001
+#define WIM_IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#define WIM_IO_REPARSE_TAG_HSM 0xC0000004
+#define WIM_IO_REPARSE_TAG_HSM2 0x80000006
+#define WIM_IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005
+#define WIM_IO_REPARSE_TAG_SIS 0x80000007
+#define WIM_IO_REPARSE_TAG_DFS 0x8000000A
+#define WIM_IO_REPARSE_TAG_DFSR 0x80000012
+#define WIM_IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B
+#define WIM_IO_REPARSE_TAG_SYMLINK 0xA000000C
#define FILE_ATTRIBUTE_READONLY 0x00000001
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
return (dentry->attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
+static inline bool dentry_is_symlink(const struct dentry *dentry)
+{
+ return (dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ && (dentry->reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK);
+}
+
static inline bool dentry_is_regular_file(const struct dentry *dentry)
{
return !dentry_is_directory(dentry);
#include "sha1.h"
#include "lookup_table.h"
#include "xml.h"
+#include "io.h"
#include "timestamp.h"
#include <stdlib.h>
#include <unistd.h>
return 0;
do {
- memset(&st, 0, sizeof(st));
- if (filler(buf, child->file_name_utf8, &st, 0))
+ if (filler(buf, child->file_name_utf8, NULL, 0))
return 0;
child = child->next;
} while (child != parent->children);
return 0;
}
+/*
+ * Find the symlink target of a symbolic link dentry in the WIM.
+ *
+ * See http://msdn.microsoft.com/en-us/library/cc232006(v=prot.10).aspx
+ * Except the first 8 bytes aren't included in the resource (presumably because
+ * we already know the reparse tag from the dentry, and we already know the
+ * reparse tag len from the lookup table entry resource length).
+ */
+static int get_symlink_name(const u8 *resource, size_t resource_len,
+ char *buf, size_t buf_len)
+{
+ const u8 *p = resource;
+ u16 substitute_name_offset;
+ u16 substitute_name_len;
+ u16 print_name_offset;
+ u16 print_name_len;
+ u32 flags;
+ char *link_target;
+ size_t link_target_len;
+ int ret;
+ if (resource_len < 12)
+ return -EIO;
+ p = get_u16(p, &substitute_name_offset);
+ p = get_u16(p, &substitute_name_len);
+ p = get_u16(p, &print_name_offset);
+ p = get_u16(p, &print_name_len);
+ p = get_u32(p, &flags);
+ if (12 + substitute_name_offset + substitute_name_len > resource_len)
+ return -EIO;
+ link_target = utf16_to_utf8(p + substitute_name_offset,
+ substitute_name_len,
+ &link_target_len);
+ if (!link_target)
+ return -EIO;
+ if (link_target_len + 1 > buf_len) {
+ ret = -ENAMETOOLONG;
+ goto out;
+ }
+ memcpy(buf, link_target, link_target_len + 1);
+ ret = 0;
+out:
+ free(link_target);
+ return ret;
+}
+
+static int wimfs_readlink(const char *path, char *buf, size_t buf_len)
+{
+ struct dentry *dentry = get_dentry(w, path);
+ struct ads_entry *ads;
+ struct lookup_table_entry *entry;
+ struct resource_entry *res_entry;
+ if (!dentry)
+ return -ENOENT;
+ if (!dentry_is_symlink(dentry))
+ return -EINVAL;
+
+ /*
+ * This is of course not actually documented, but what I think is going
+ * on here is that the symlink dentries have 2 alternate data streams;
+ * one is the default data stream, which is not used and is empty, and
+ * one is the symlink buffer data stream, which is confusingly also
+ * unnamed, but isn't empty as it contains the symlink target within the
+ * resource.
+ */
+ if (dentry->num_ads != 2)
+ return -EIO;
+ if ((entry = lookup_resource(w->lookup_table, dentry->ads_entries[0].hash)))
+ goto do_readlink;
+ if ((entry = lookup_resource(w->lookup_table, dentry->ads_entries[1].hash)))
+ goto do_readlink;
+ return -EIO;
+do_readlink:
+ res_entry = &entry->resource_entry;
+ char res_buf[res_entry->original_size];
+ if (read_full_resource(w->fp, res_entry->size,
+ res_entry->original_size,
+ res_entry->offset,
+ wim_resource_compression_type(w, res_entry),
+ res_buf) != 0)
+ return -EIO;
+ return get_symlink_name(res_buf, res_entry->original_size, buf, buf_len);
+}
+
/* Close a file. */
static int wimfs_release(const char *path, struct fuse_file_info *fi)
{
.opendir = wimfs_opendir,
.read = wimfs_read,
.readdir = wimfs_readdir,
+ .readlink = wimfs_readlink,
.release = wimfs_release,
.rename = wimfs_rename,
.rmdir = wimfs_rmdir,