X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Freparse.c;h=0ae053b9cb06fa749d88dc8fb89edd5c6c88d82f;hb=33cc99f8a087d4232085234aee3f3134e15d5905;hp=cf9fc686139696980cb9e17145430f7f836e6619;hpb=3071e89c11d1be71cf45b694432e5908e0c4ded9;p=wimlib diff --git a/src/reparse.c b/src/reparse.c index cf9fc686..0ae053b9 100644 --- a/src/reparse.c +++ b/src/reparse.c @@ -23,22 +23,19 @@ # include "config.h" #endif +#include + +#include "wimlib/alloca.h" #include "wimlib/assert.h" +#include "wimlib/blob_table.h" #include "wimlib/compiler.h" #include "wimlib/endianness.h" #include "wimlib/encoding.h" #include "wimlib/error.h" #include "wimlib/inode.h" -#include "wimlib/lookup_table.h" #include "wimlib/reparse.h" #include "wimlib/resource.h" -#ifdef HAVE_ALLOCA_H -# include -#endif -#include -#include - /* * Read the data from a symbolic link, junction, or mount point reparse point * buffer into a `struct reparse_data'. @@ -147,7 +144,7 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata, data = mempcpy(data, rpdata->print_name, rpdata->print_name_nbytes); *(utf16lechar*)data = cpu_to_le16(0); data += 2; - rpbuf_disk->rpdatalen = cpu_to_le16(data - rpbuf - 8); + rpbuf_disk->rpdatalen = cpu_to_le16(data - rpbuf - REPARSE_DATA_OFFSET); *rpbuflen_ret = data - rpbuf; return 0; } @@ -160,41 +157,47 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata, * * Note: in the WIM format, the first 8 bytes of the reparse point data buffer * are omitted, presumably because we already know the reparse tag from the - * dentry, and we already know the reparse tag length from the lookup table - * entry resource length. However, we reconstruct the first 8 bytes in the - * buffer returned by this function. + * dentry, and we already know the reparse tag length from the blob length. + * However, we reconstruct the first 8 bytes in the buffer returned by this + * function. */ -int +static int wim_inode_get_reparse_data(const struct wim_inode * restrict inode, u8 * restrict rpbuf, u16 * restrict rpbuflen_ret, - struct wim_lookup_table_entry *lte_override) + struct blob_descriptor *blob_override) { - struct wim_lookup_table_entry *lte; + struct blob_descriptor *blob; int ret; struct reparse_buffer_disk *rpbuf_disk; u16 rpdatalen; wimlib_assert(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT); - if (!lte_override) { - lte = inode_unnamed_lte_resolved(inode); - if (!lte) { + if (blob_override) { + blob = blob_override; + } else { + struct wim_inode_stream *strm; + + strm = inode_get_unnamed_stream(inode, STREAM_TYPE_REPARSE_POINT); + if (strm) + blob = stream_blob_resolved(strm); + else + blob = NULL; + if (!blob) { ERROR("Reparse point has no reparse data!"); return WIMLIB_ERR_INVALID_REPARSE_DATA; } - } else { - lte = lte_override; } - if (lte->size > REPARSE_POINT_MAX_SIZE - 8) { + if (blob->size > REPARSE_DATA_MAX_SIZE) { ERROR("Reparse data is too long!"); return WIMLIB_ERR_INVALID_REPARSE_DATA; } - rpdatalen = lte->size; + rpdatalen = blob->size; - /* Read the data from the WIM file */ - ret = read_full_stream_into_buf(lte, rpbuf + 8); + /* Read the reparse data from blob */ + ret = read_full_blob_into_buf(blob, rpbuf + REPARSE_DATA_OFFSET); if (ret) return ret; @@ -211,7 +214,7 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode, * XXX this could be one of the unknown fields in the WIM dentry. */ rpbuf_disk->rpreserved = cpu_to_le16(0); - *rpbuflen_ret = rpdatalen + 8; + *rpbuflen_ret = rpdatalen + REPARSE_DATA_OFFSET; return 0; } @@ -307,7 +310,7 @@ parse_substitute_name(const utf16lechar *substitute_name, /* * Get the UNIX-style symlink target from the WIM inode for a reparse point. * Specifically, this translates the target from UTF-16 to the current multibyte - * encoding, strips the drive prefix if present, and replaces backslashes with + * encoding, strips the drive prefix if present, and swaps backslashes and * forward slashes. * * @inode @@ -321,9 +324,9 @@ parse_substitute_name(const utf16lechar *substitute_name, * @bufsize * Available space in @buf, in bytes. * - * @lte_override - * If not NULL, the stream from which to read the reparse data. Otherwise, - * the reparse data will be read from the unnamed stream of @inode. + * @blob_override + * If not NULL, the blob from which to read the reparse data. Otherwise, + * the reparse data will be read from the reparse point stream of @inode. * * If the entire symbolic link target was placed in the buffer, returns the * number of bytes written. The resulting string is not null-terminated. If @@ -335,7 +338,7 @@ parse_substitute_name(const utf16lechar *substitute_name, ssize_t wim_inode_readlink(const struct wim_inode * restrict inode, char * restrict buf, size_t bufsize, - struct wim_lookup_table_entry *lte_override) + struct blob_descriptor *blob_override) { int ret; struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8); @@ -348,7 +351,7 @@ wim_inode_readlink(const struct wim_inode * restrict inode, wimlib_assert(inode_is_symlink(inode)); if (wim_inode_get_reparse_data(inode, (u8*)&rpbuf_disk, &rpbuflen, - lte_override)) + blob_override)) return -EIO; if (parse_reparse_data((const u8*)&rpbuf_disk, rpbuflen, &rpdata)) @@ -381,9 +384,12 @@ wim_inode_readlink(const struct wim_inode * restrict inode, } out_translate_slashes: - for (size_t i = 0; i < link_target_len; i++) + for (size_t i = 0; i < link_target_len; i++) { if (translated_target[i] == '\\') translated_target[i] = '/'; + else if (translated_target[i] == '/') + translated_target[i] = '\\'; + } out_have_link: if (link_target_len > bufsize) { link_target_len = bufsize; @@ -397,10 +403,11 @@ out_free_link_target: return ret; } +/* Given a UNIX-style symbolic link target, create a Windows-style reparse point + * buffer and assign it to the specified inode. */ int -wim_inode_set_symlink(struct wim_inode *inode, - const char *target, - struct wim_lookup_table *lookup_table) +wim_inode_set_symlink(struct wim_inode *inode, const char *target, + struct blob_table *blob_table) { struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8); @@ -418,11 +425,14 @@ wim_inode_set_symlink(struct wim_inode *inode, ret = tstr_to_utf16le(target, strlen(target), &name_utf16le, &name_utf16le_nbytes); if (ret) - return ret; + goto out; - for (size_t i = 0; i < name_utf16le_nbytes / 2; i++) + for (size_t i = 0; i < name_utf16le_nbytes / 2; i++) { if (name_utf16le[i] == cpu_to_le16('/')) name_utf16le[i] = cpu_to_le16('\\'); + else if (name_utf16le[i] == cpu_to_le16('\\')) + name_utf16le[i] = cpu_to_le16('/'); + } /* Compatability notes: * @@ -430,12 +440,9 @@ wim_inode_set_symlink(struct wim_inode *inode, * is a relative symbolic link. (Quite simple compared to the various * ways to provide Windows paths.) * - * To change a UNIX relative symbolic link to Windows format, we only - * need to translate it to UTF-16LE and replace forward slashes with - * backslashes. We do not make any attempt to handle filename character - * problems, such as a link target that itself contains backslashes on - * UNIX. Then, for these relative links, we set the reparse header - * @flags field to SYMBOLIC_LINK_RELATIVE. + * To change a UNIX relative symbolic link to Windows format, we need to + * translate it to UTF-16LE, swap forward slashes and backslashes, and + * set 'rpflags' to SYMBOLIC_LINK_RELATIVE. * * For UNIX absolute symbolic links, we must set the @flags field to 0. * Then, there are multiple options as to actually represent the @@ -494,13 +501,22 @@ wim_inode_set_symlink(struct wim_inode *inode, } ret = make_reparse_buffer(&rpdata, (u8*)&rpbuf_disk, &rpbuflen); - if (ret == 0) { - ret = inode_set_unnamed_stream(inode, - (u8*)&rpbuf_disk + 8, - rpbuflen - 8, - lookup_table); - } + if (ret) + goto out_free_name; + + ret = WIMLIB_ERR_NOMEM; + if (!inode_add_stream_with_data(inode, + STREAM_TYPE_REPARSE_POINT, + NO_STREAM_NAME, + (u8*)&rpbuf_disk + REPARSE_DATA_OFFSET, + rpbuflen - REPARSE_DATA_OFFSET, + blob_table)) + goto out_free_name; + + ret = 0; +out_free_name: FREE(name_utf16le); +out: return ret; }