]> wimlib.net Git - wimlib/blobdiff - src/reparse.c
Various cleanups
[wimlib] / src / reparse.c
index 2bc421d2a57b424f3e8bea4d82295523132d0355..c27fef6ebe862ff5bc122cc48f783bb02ccd0785 100644 (file)
 /*
  * Copyright (C) 2012, 2013 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
+#include <errno.h>
+
+#include "wimlib/alloca.h"
 #include "wimlib/assert.h"
+#include "wimlib/blob_table.h"
 #include "wimlib/compiler.h"
 #include "wimlib/endianness.h"
-#include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
-#include "wimlib/lookup_table.h"
+#include "wimlib/inode.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
-#include <errno.h>
-#include <stdlib.h>
-
-/* On-disk format of a symbolic link (WIM_IO_REPARSE_TAG_SYMLINK) or junction
- * point (WIM_IO_REPARSE_TAG_MOUNT_POINT) reparse data buffer.  */
-struct reparse_buffer_disk {
-       le32 rptag;
-       le16 rpdatalen;
-       le16 rpreserved;
-       le16 substitute_name_offset;
-       le16 substitute_name_nbytes;
-       le16 print_name_offset;
-       le16 print_name_nbytes;
-       union {
-               struct {
-                       le32 rpflags;
-                       u8 data[REPARSE_POINT_MAX_SIZE - 20];
-               } _packed_attribute symlink;
-               struct {
-                       u8 data[REPARSE_POINT_MAX_SIZE - 16];
-               } _packed_attribute junction;
-       };
-} _packed_attribute;
-
-static const utf16lechar volume_junction_prefix[11] = {
-       cpu_to_le16('\\'),
-       cpu_to_le16('?'),
-       cpu_to_le16('?'),
-       cpu_to_le16('\\'),
-       cpu_to_le16('V'),
-       cpu_to_le16('o'),
-       cpu_to_le16('l'),
-       cpu_to_le16('u'),
-       cpu_to_le16('m'),
-       cpu_to_le16('e'),
-       cpu_to_le16('{'),
-};
-
-/* Parse the "substitute name" (link target) from a symbolic link or junction
- * reparse point.
- *
- * 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)
- * Negative integer:
- *     SUBST_NAME_IS_VOLUME_JUNCTION:
- *             The name is a volume junction.
- *     SUBST_NAME_IS_RELATIVE_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.
- */
-int
-parse_substitute_name(const utf16lechar *substitute_name,
-                     u16 substitute_name_nbytes, u32 rptag)
-{
-       u16 substitute_name_nchars = substitute_name_nbytes / 2;
-
-       if (substitute_name_nchars >= 7 &&
-           substitute_name[0] == cpu_to_le16('\\') &&
-           substitute_name[1] == cpu_to_le16('?') &&
-           substitute_name[2] == cpu_to_le16('?') &&
-           substitute_name[3] == cpu_to_le16('\\') &&
-           substitute_name[4] != cpu_to_le16('\0') &&
-           substitute_name[5] == cpu_to_le16(':') &&
-           substitute_name[6] == cpu_to_le16('\\'))
-       {
-               /* "Full" symlink or junction (\??\x:\ prefixed path) */
-               return 6;
-       } else if (rptag == WIM_IO_REPARSE_TAG_MOUNT_POINT &&
-                  substitute_name_nchars >= 12 &&
-                  memcmp(substitute_name, volume_junction_prefix,
-                         sizeof(volume_junction_prefix)) == 0 &&
-                  substitute_name[substitute_name_nchars - 1] == cpu_to_le16('\\'))
-       {
-               /* Volume junction.  Can't really do anything with it. */
-               return SUBST_NAME_IS_VOLUME_JUNCTION;
-       } else if (rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
-                  substitute_name_nchars >= 3 &&
-                  substitute_name[0] != cpu_to_le16('\0') &&
-                  substitute_name[1] == cpu_to_le16(':') &&
-                  substitute_name[2] == cpu_to_le16('\\'))
-       {
-               /* "Absolute" symlink, with drive letter */
-               return 2;
-       } else if (rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
-                  substitute_name_nchars >= 1)
-       {
-               if (substitute_name[0] == cpu_to_le16('\\'))
-                       /* "Absolute" symlink, without drive letter */
-                       return 0;
-               else
-                       /* "Relative" symlink, without drive letter */
-                       return SUBST_NAME_IS_RELATIVE_LINK;
-       } else {
-               return SUBST_NAME_IS_UNKNOWN;
-       }
-}
-
 /*
  * Read the data from a symbolic link, junction, or mount point reparse point
  * buffer into a `struct reparse_data'.
@@ -171,10 +61,10 @@ parse_reparse_data(const u8 * restrict rpbuf, u16 rpbuflen,
                      rpdata->rptag == WIM_IO_REPARSE_TAG_MOUNT_POINT);
        rpdata->rpdatalen = le16_to_cpu(rpbuf_disk->rpdatalen);
        rpdata->rpreserved = le16_to_cpu(rpbuf_disk->rpreserved);
-       substitute_name_offset = le16_to_cpu(rpbuf_disk->substitute_name_offset);
-       rpdata->substitute_name_nbytes = le16_to_cpu(rpbuf_disk->substitute_name_nbytes);
-       print_name_offset = le16_to_cpu(rpbuf_disk->print_name_offset);
-       rpdata->print_name_nbytes = le16_to_cpu(rpbuf_disk->print_name_nbytes);
+       substitute_name_offset = le16_to_cpu(rpbuf_disk->symlink.substitute_name_offset);
+       rpdata->substitute_name_nbytes = le16_to_cpu(rpbuf_disk->symlink.substitute_name_nbytes);
+       print_name_offset = le16_to_cpu(rpbuf_disk->symlink.print_name_offset);
+       rpdata->print_name_nbytes = le16_to_cpu(rpbuf_disk->symlink.print_name_nbytes);
 
        if ((substitute_name_offset & 1) | (print_name_offset & 1) |
            (rpdata->substitute_name_nbytes & 1) | (rpdata->print_name_nbytes & 1))
@@ -222,37 +112,39 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata,
                (struct reparse_buffer_disk*)rpbuf;
        u8 *data;
 
-       rpbuf_disk->rptag = cpu_to_le32(rpdata->rptag);
-       rpbuf_disk->rpreserved = cpu_to_le16(rpdata->rpreserved);
-       rpbuf_disk->substitute_name_offset = cpu_to_le16(0);
-       rpbuf_disk->substitute_name_nbytes = cpu_to_le16(rpdata->substitute_name_nbytes);
-       rpbuf_disk->print_name_offset = cpu_to_le16(rpdata->substitute_name_nbytes + 2);
-       rpbuf_disk->print_name_nbytes = cpu_to_le16(rpdata->print_name_nbytes);
-
-       if (rpdata->rptag == WIM_IO_REPARSE_TAG_SYMLINK) {
-               rpbuf_disk->symlink.rpflags = cpu_to_le32(rpdata->rpflags);
+       if (rpdata->rptag == WIM_IO_REPARSE_TAG_SYMLINK)
                data = rpbuf_disk->symlink.data;
-       } else {
+       else
                data = rpbuf_disk->junction.data;
-       }
 
-       /* We null-terminate the substitute and print names, although this may
-        * not be strictly necessary.  Note that the byte counts should not
-        * include the null terminators. */
-       if (data + rpdata->substitute_name_nbytes +
+       if ((data - rpbuf) + rpdata->substitute_name_nbytes +
            rpdata->print_name_nbytes +
-           2 * sizeof(utf16lechar) - rpbuf > REPARSE_POINT_MAX_SIZE)
+           2 * sizeof(utf16lechar) > REPARSE_POINT_MAX_SIZE)
        {
                ERROR("Reparse data is too long!");
                return WIMLIB_ERR_INVALID_REPARSE_DATA;
        }
+
+       rpbuf_disk->rptag = cpu_to_le32(rpdata->rptag);
+       rpbuf_disk->rpreserved = cpu_to_le16(rpdata->rpreserved);
+       rpbuf_disk->symlink.substitute_name_offset = cpu_to_le16(0);
+       rpbuf_disk->symlink.substitute_name_nbytes = cpu_to_le16(rpdata->substitute_name_nbytes);
+       rpbuf_disk->symlink.print_name_offset = cpu_to_le16(rpdata->substitute_name_nbytes + 2);
+       rpbuf_disk->symlink.print_name_nbytes = cpu_to_le16(rpdata->print_name_nbytes);
+
+       if (rpdata->rptag == WIM_IO_REPARSE_TAG_SYMLINK)
+               rpbuf_disk->symlink.rpflags = cpu_to_le32(rpdata->rpflags);
+
+       /* We null-terminate the substitute and print names, although this may
+        * not be strictly necessary.  Note that the byte counts should not
+        * include the null terminators. */
        data = mempcpy(data, rpdata->substitute_name, rpdata->substitute_name_nbytes);
        *(utf16lechar*)data = cpu_to_le16(0);
        data += 2;
        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;
 }
@@ -265,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;
 
@@ -316,12 +214,98 @@ 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;
 }
 
 /* UNIX version of getting and setting the data in reparse points */
-#if !defined(__WIN32__)
+#ifndef __WIN32__
+
+static const utf16lechar volume_junction_prefix[11] = {
+       cpu_to_le16('\\'),
+       cpu_to_le16('?'),
+       cpu_to_le16('?'),
+       cpu_to_le16('\\'),
+       cpu_to_le16('V'),
+       cpu_to_le16('o'),
+       cpu_to_le16('l'),
+       cpu_to_le16('u'),
+       cpu_to_le16('m'),
+       cpu_to_le16('e'),
+       cpu_to_le16('{'),
+};
+
+enum {
+       SUBST_NAME_IS_RELATIVE_LINK = -1,
+       SUBST_NAME_IS_VOLUME_JUNCTION = -2,
+       SUBST_NAME_IS_UNKNOWN = -3,
+};
+
+/* Parse the "substitute name" (link target) from a symbolic link or junction
+ * reparse point.
+ *
+ * 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)
+ * Negative integer:
+ *     SUBST_NAME_IS_VOLUME_JUNCTION:
+ *             The name is a volume junction.
+ *     SUBST_NAME_IS_RELATIVE_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.
+ */
+static int
+parse_substitute_name(const utf16lechar *substitute_name,
+                     u16 substitute_name_nbytes, u32 rptag)
+{
+       u16 substitute_name_nchars = substitute_name_nbytes / 2;
+
+       if (substitute_name_nchars >= 7 &&
+           substitute_name[0] == cpu_to_le16('\\') &&
+           substitute_name[1] == cpu_to_le16('?') &&
+           substitute_name[2] == cpu_to_le16('?') &&
+           substitute_name[3] == cpu_to_le16('\\') &&
+           substitute_name[4] != cpu_to_le16('\0') &&
+           substitute_name[5] == cpu_to_le16(':') &&
+           substitute_name[6] == cpu_to_le16('\\'))
+       {
+               /* "Full" symlink or junction (\??\x:\ prefixed path) */
+               return 6;
+       } else if (rptag == WIM_IO_REPARSE_TAG_MOUNT_POINT &&
+                  substitute_name_nchars >= 12 &&
+                  memcmp(substitute_name, volume_junction_prefix,
+                         sizeof(volume_junction_prefix)) == 0 &&
+                  substitute_name[substitute_name_nchars - 1] == cpu_to_le16('\\'))
+       {
+               /* Volume junction.  Can't really do anything with it. */
+               return SUBST_NAME_IS_VOLUME_JUNCTION;
+       } else if (rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
+                  substitute_name_nchars >= 3 &&
+                  substitute_name[0] != cpu_to_le16('\0') &&
+                  substitute_name[1] == cpu_to_le16(':') &&
+                  substitute_name[2] == cpu_to_le16('\\'))
+       {
+               /* "Absolute" symlink, with drive letter */
+               return 2;
+       } else if (rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
+                  substitute_name_nchars >= 1)
+       {
+               if (substitute_name[0] == cpu_to_le16('\\'))
+                       /* "Absolute" symlink, without drive letter */
+                       return 0;
+               else
+                       /* "Relative" symlink, without drive letter */
+                       return SUBST_NAME_IS_RELATIVE_LINK;
+       } else {
+               return SUBST_NAME_IS_UNKNOWN;
+       }
+}
 
 /*
  * Get the UNIX-style symlink target from the WIM inode for a reparse point.
@@ -340,9 +324,9 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
  * @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
@@ -354,7 +338,7 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
 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);
@@ -367,11 +351,11 @@ 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))
-               return -EIO;
+               return -EINVAL;
 
        ret = utf16le_to_tstr(rpdata.substitute_name,
                              rpdata.substitute_name_nbytes,
@@ -416,10 +400,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);
@@ -437,7 +422,7 @@ 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++)
                if (name_utf16le[i] == cpu_to_le16('/'))
@@ -513,105 +498,23 @@ 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;
 }
 
-#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__) */
-
-/* is_rp_path_separator() - characters treated as path separators in absolute
- * symbolic link targets */
-
-#ifdef __WIN32__
-#  define is_rp_path_separator(c) ((c) == L'\\' || (c) == L'/')
-#  define os_get_ino_and_dev win32_get_file_and_vol_ids
-#else
-#  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) = OS_PREFERRED_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__ */