]> wimlib.net Git - wimlib/blobdiff - src/reparse.c
wimlib: strict checks for unassigned flags
[wimlib] / src / reparse.c
index b097212a6738afd803a911553f112dcb2055667d..913ea5ce095de34eafb0c457086acaae07e36ce5 100644 (file)
@@ -86,15 +86,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.
@@ -215,7 +215,8 @@ out_invalid:
  */
 int
 make_reparse_buffer(const struct reparse_data * restrict rpdata,
-                   u8 * restrict rpbuf)
+                   u8 * restrict rpbuf,
+                   u16 * restrict rpbuflen_ret)
 {
        struct reparse_buffer_disk *rpbuf_disk =
                (struct reparse_buffer_disk*)rpbuf;
@@ -252,6 +253,7 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata,
        *(utf16lechar*)data = cpu_to_le16(0);
        data += 2;
        rpbuf_disk->rpdatalen = cpu_to_le16(data - rpbuf - 8);
+       *rpbuflen_ret = data - rpbuf;
        return 0;
 }
 
@@ -270,7 +272,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;
@@ -279,20 +282,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,16 +323,38 @@ 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__)
 
-/* 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.
+ *
+ * @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.
  *
- * 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.  */
+ * @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);
@@ -337,7 +366,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))
@@ -399,6 +429,7 @@ wim_inode_set_symlink(struct wim_inode *inode,
        utf16lechar *name_utf16le;
        size_t name_utf16le_nbytes;
        int ret;
+       u16 rpbuflen;
 
        DEBUG("Creating reparse point data buffer for UNIX "
              "symlink target \"%s\"", target);
@@ -419,8 +450,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.
@@ -481,11 +512,11 @@ wim_inode_set_symlink(struct wim_inode *inode,
                rpdata.rpflags = SYMBOLIC_LINK_RELATIVE;
        }
 
-       ret = make_reparse_buffer(&rpdata, (u8*)&rpbuf_disk);
+       ret = make_reparse_buffer(&rpdata, (u8*)&rpbuf_disk, &rpbuflen);
        if (ret == 0) {
                ret = inode_set_unnamed_stream(inode,
                                               (u8*)&rpbuf_disk + 8,
-                                              le16_to_cpu(rpbuf_disk.rpdatalen),
+                                              rpbuflen - 8,
                                               lookup_table);
        }
        FREE(name_utf16le);
@@ -513,12 +544,13 @@ unix_get_ino_and_dev(const char *path, u64 *ino_ret, u64 *dev_ret)
 
 #endif /* !defined(__WIN32__) */
 
+/* is_rp_path_separator() - characters treated as path separators in absolute
+ * symbolic link targets */
+
 #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
@@ -560,7 +592,7 @@ capture_fixup_absolute_symlink(tchar *dest,
                        /* Link points inside capture root.  Return abbreviated
                         * path. */
                        if (*p == T('\0'))
-                               *(p - 1) = RP_PATH_SEPARATOR;
+                               *(p - 1) = OS_PREFERRED_PATH_SEPARATOR;
                        while (p - 1 >= dest && is_rp_path_separator(*(p - 1)))
                                p--;
                #ifdef __WIN32__