X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Freparse.c;h=28976927c0abdbeeda87f954cef5f35e748cd877;hb=76a22e5ce6caa1f8985071d4316ab12b86da7f10;hp=465900178df8dac4f12488874f6c634fc95d184b;hpb=2412c8ed80e1283657c97d156061beac04849eb5;p=wimlib diff --git a/src/reparse.c b/src/reparse.c index 46590017..28976927 100644 --- a/src/reparse.c +++ b/src/reparse.c @@ -28,17 +28,13 @@ #include "wimlib/assert.h" #include "wimlib/compiler.h" #include "wimlib/endianness.h" -#include "wimlib/dentry.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 __WIN32__ -# include "wimlib/win32.h" /* for win32_get_file_and_vol_ids() */ -#endif - #ifdef HAVE_ALLOCA_H # include #endif @@ -68,7 +64,7 @@ struct reparse_buffer_disk { static const utf16lechar volume_junction_prefix[11] = { cpu_to_le16('\\'), - cpu_to_le16('\\'), + cpu_to_le16('?'), cpu_to_le16('?'), cpu_to_le16('\\'), cpu_to_le16('V'), @@ -86,15 +82,15 @@ static const utf16lechar volume_junction_prefix[11] = { * Return value is: * * Non-negative integer: - * The name is an absolute symbolic link in one of several formats, - * and the return value is the number of UTF-16LE characters that need to - * be advanced to reach a simple "absolute" path starting with a backslash - * (i.e. skip over \??\ and/or drive letter) + * The name is an absolute symbolic link in one of several formats, + * and the return value is the number of UTF-16LE characters that need to + * be advanced to reach a simple "absolute" path starting with a backslash + * (i.e. skip over \??\ and/or drive letter) * Negative integer: * SUBST_NAME_IS_VOLUME_JUNCTION: - * The name is a volume junction. + * The name is a volume junction. * SUBST_NAME_IS_RELATIVE_LINK: - * The name is a relative symbolic link. + * The name is a relative symbolic link. * SUBST_NAME_IS_UNKNOWN: * The name does not appear to be a valid symbolic link, junction, * or mount point. @@ -272,7 +268,8 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata, int wim_inode_get_reparse_data(const struct wim_inode * restrict inode, u8 * restrict rpbuf, - u16 * restrict rpbuflen_ret) + u16 * restrict rpbuflen_ret, + struct wim_lookup_table_entry *lte_override) { struct wim_lookup_table_entry *lte; int ret; @@ -281,20 +278,24 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode, wimlib_assert(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT); - lte = inode_unnamed_lte_resolved(inode); - if (!lte) { - ERROR("Reparse point has no reparse data!"); - return WIMLIB_ERR_INVALID_REPARSE_DATA; + if (!lte_override) { + lte = inode_unnamed_lte_resolved(inode); + if (!lte) { + ERROR("Reparse point has no reparse data!"); + return WIMLIB_ERR_INVALID_REPARSE_DATA; + } + } else { + lte = lte_override; } - if (wim_resource_size(lte) > REPARSE_POINT_MAX_SIZE - 8) { + if (lte->size > REPARSE_POINT_MAX_SIZE - 8) { ERROR("Reparse data is too long!"); return WIMLIB_ERR_INVALID_REPARSE_DATA; } - rpdatalen = wim_resource_size(lte); + rpdatalen = lte->size; /* Read the data from the WIM file */ - ret = read_full_resource_into_buf(lte, rpbuf + 8); + ret = read_full_stream_into_buf(lte, rpbuf + 8); if (ret) return ret; @@ -316,18 +317,40 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode, } /* UNIX version of getting and setting the data in reparse points */ -#if !defined(__WIN32__) +#ifndef __WIN32__ -/* Get the UNIX symlink target from a WIM inode. The inode may be either a - * "real" symlink (reparse tag WIM_IO_REPARSE_TAG_SYMLINK), or it may be a - * junction point (reparse tag WIM_IO_REPARSE_TAG_MOUNT_POINT). +/* + * 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 + * forward slashes. * - * This has similar semantics to the UNIX readlink() function, except the path - * argument is swapped out with the `struct wim_inode' for a reparse point, and - * on failure a negated error code is returned rather than -1 with errno set. */ + * @inode + * The inode to read the symlink from. It must be a reparse point with + * tag WIM_IO_REPARSE_TAG_SYMLINK (a real symlink) or + * WIM_IO_REPARSE_TAG_MOUNT_POINT (a mount point or junction point). + * + * @buf + * Buffer into which to place the link target. + * + * @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. + * + * 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 + * the symbolic link target was too large to be placed in the buffer, the first + * @bufsize bytes of it are placed in the buffer and + * -ENAMETOOLONG is returned. Otherwise, a negative errno value indicating + * another error is returned. + */ ssize_t wim_inode_readlink(const struct wim_inode * restrict inode, - char * restrict buf, size_t bufsize) + char * restrict buf, size_t bufsize, + struct wim_lookup_table_entry *lte_override) { int ret; struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8); @@ -339,7 +362,8 @@ 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)) + if (wim_inode_get_reparse_data(inode, (u8*)&rpbuf_disk, &rpbuflen, + lte_override)) return -EIO; if (parse_reparse_data((const u8*)&rpbuf_disk, rpbuflen, &rpdata)) @@ -422,8 +446,8 @@ wim_inode_set_symlink(struct wim_inode *inode, * 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 backslashes with forward - * slashes. We do not make any attempt to handle filename character + * 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. @@ -495,94 +519,4 @@ wim_inode_set_symlink(struct wim_inode *inode, return ret; } -#include - -static int -unix_get_ino_and_dev(const char *path, u64 *ino_ret, u64 *dev_ret) -{ - struct stat stbuf; - if (stat(path, &stbuf)) { - if (errno != ENOENT) - WARNING_WITH_ERRNO("Failed to stat \"%s\"", path); - /* Treat as a link pointing outside the capture root (it - * most likely is). */ - return WIMLIB_ERR_STAT; - } else { - *ino_ret = stbuf.st_ino; - *dev_ret = stbuf.st_dev; - return 0; - } -} - -#endif /* !defined(__WIN32__) */ - -#ifdef __WIN32__ -# define RP_PATH_SEPARATOR L'\\' -# define is_rp_path_separator(c) ((c) == L'\\' || (c) == L'/') -# define os_get_ino_and_dev win32_get_file_and_vol_ids -#else -# define RP_PATH_SEPARATOR '/' -# define is_rp_path_separator(c) ((c) == '/') -# define os_get_ino_and_dev unix_get_ino_and_dev -#endif - -/* Fix up absolute symbolic link targets--- mostly shared between UNIX and - * Windows */ -tchar * -capture_fixup_absolute_symlink(tchar *dest, - u64 capture_root_ino, u64 capture_root_dev) -{ - tchar *p = dest; - -#ifdef __WIN32__ - /* Skip drive letter */ - if (!is_rp_path_separator(*dest)) - p += 2; -#endif - - DEBUG("Fixing symlink or junction \"%"TS"\"", dest); - for (;;) { - tchar save; - int ret; - u64 ino; - u64 dev; - - while (is_rp_path_separator(*p)) - p++; - - save = *p; - *p = T('\0'); - ret = os_get_ino_and_dev(dest, &ino, &dev); - *p = save; - - if (ret) /* stat() failed before we got to the capture root--- - assume the link points outside it. */ - return NULL; - - if (ino == capture_root_ino && dev == capture_root_dev) { - /* Link points inside capture root. Return abbreviated - * path. */ - if (*p == T('\0')) - *(p - 1) = RP_PATH_SEPARATOR; - while (p - 1 >= dest && is_rp_path_separator(*(p - 1))) - p--; - #ifdef __WIN32__ - if (!is_rp_path_separator(dest[0])) { - *--p = dest[1]; - *--p = dest[0]; - } - #endif - wimlib_assert(p >= dest); - return p; - } - - if (*p == T('\0')) { - /* Link points outside capture root. */ - return NULL; - } - - do { - p++; - } while (!is_rp_path_separator(*p) && *p != T('\0')); - } -} +#endif /* !__WIN32__ */