]> wimlib.net Git - wimlib/blobdiff - src/reparse.c
win32_common.c: Remove duplicate declaration of func_NtOpenFile
[wimlib] / src / reparse.c
index 465900178df8dac4f12488874f6c634fc95d184b..28976927c0abdbeeda87f954cef5f35e748cd877 100644 (file)
 #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 <alloca.h>
 #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 <sys/stat.h>
-
-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__ */