3 #include "lookup_table.h"
6 * Find the symlink target of a symbolic link or junction point in the WIM.
8 * See http://msdn.microsoft.com/en-us/library/cc232006(v=prot.10).aspx
9 * Except the first 8 bytes aren't included in the resource (presumably because
10 * we already know the reparse tag from the dentry, and we already know the
11 * reparse tag len from the lookup table entry resource length).
13 static ssize_t get_symlink_name(const u8 *resource, size_t resource_len,
14 char *buf, size_t buf_len,
15 bool is_junction_point)
17 const u8 *p = resource;
18 u16 substitute_name_offset;
19 u16 substitute_name_len;
20 u16 print_name_offset;
23 size_t link_target_len;
26 char *translated_target;
29 if (resource_len < 12)
31 p = get_u16(p, &substitute_name_offset);
32 p = get_u16(p, &substitute_name_len);
33 p = get_u16(p, &print_name_offset);
34 p = get_u16(p, &print_name_len);
35 if (is_junction_point) {
39 p = get_u32(p, &flags);
40 is_absolute = (flags & 1) ? false : true;
43 if (header_size + substitute_name_offset + substitute_name_len > resource_len)
45 link_target = utf16_to_utf8(p + substitute_name_offset,
52 if (link_target_len + 1 > buf_len) {
57 translated_target = link_target;
58 if (is_junction_point || is_absolute) {
59 if (link_target_len < 7
60 || memcmp(translated_target, "\\??\\", 4) != 0
61 || translated_target[4] == '\0'
62 || translated_target[5] != ':'
63 || translated_target[6] != '\\') {
67 translated_target += 4;
70 for (size_t i = 0; i < link_target_len; i++)
71 if (translated_target[i] == '\\')
72 translated_target[i] = '/';
74 memcpy(buf, translated_target, link_target_len + 1);
75 ret = link_target_len;
81 void *make_symlink_reparse_data_buf(const char *symlink_target, size_t *len_ret)
83 size_t utf8_len = strlen(symlink_target);
85 char *name_utf16 = utf8_to_utf16(symlink_target, utf8_len, &utf16_len);
88 /*DEBUG("utf16_len = %zu", utf16_len);*/
89 for (size_t i = 0; i < utf16_len / 2; i++)
90 if (((u16*)name_utf16)[i] == to_le16('/'))
91 ((u16*)name_utf16)[i] = to_le16('\\');
92 size_t len = 12 + utf16_len * 2;
93 void *buf = MALLOC(len);
98 p = put_u16(p, 0); /* Substitute name offset */
99 p = put_u16(p, utf16_len); /* Substitute name length */
100 p = put_u16(p, utf16_len); /* Print name offset */
101 p = put_u16(p, utf16_len); /* Print name length */
102 p = put_u32(p, (symlink_target[0] == '/') ? 0 : 1);
103 p = put_bytes(p, utf16_len, name_utf16);
104 p = put_bytes(p, utf16_len, name_utf16);
105 /*DEBUG("utf16_len = %zu, len = %zu", utf16_len, len);*/
112 /* Get the symlink target from a dentry that's already checked to be either a
113 * "real" symlink or a junction point. */
114 ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len,
117 struct ads_entry *ads;
118 struct lookup_table_entry *entry;
119 struct resource_entry *res_entry;
120 bool is_junction_point;
122 wimlib_assert(dentry_is_symlink(dentry));
124 if (dentry->reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK) {
125 is_junction_point = false;
127 * This is of course not actually documented, but what I think is going
128 * on here is that the symlink dentries have 2 alternate data streams;
129 * one is the default data stream, which is not used and is empty, and
130 * one is the symlink buffer data stream, which is confusingly also
131 * unnamed, but isn't empty as it contains the symlink target within the
134 if (dentry->num_ads != 2)
136 if ((entry = lookup_resource(w->lookup_table, dentry->ads_entries[0].hash)))
138 if ((entry = lookup_resource(w->lookup_table, dentry->ads_entries[1].hash)))
141 wimlib_assert(dentry->reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT);
143 is_junction_point = true;
145 if ((entry = lookup_resource(w->lookup_table, dentry->hash)))
150 res_entry = &entry->resource_entry;
151 if (res_entry->original_size > 10000)
153 char res_buf[res_entry->original_size];
154 if (read_full_resource(w->fp, res_entry->size,
155 res_entry->original_size,
157 wim_resource_compression_type(w, res_entry),
160 return get_symlink_name(res_buf, res_entry->original_size, buf,
161 buf_len, is_junction_point);