Win32: Fix drive root detection with \\?\-style paths
[wimlib] / src / paths.c
1 /*
2  * paths.c - Path manipulation routines
3  */
4
5 /*
6  * Copyright (C) 2012, 2013 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option)
13  * any later version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with wimlib; if not, see http://www.gnu.org/licenses/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib/paths.h"
29 #include "wimlib/util.h"
30
31 #include <string.h>
32
33 /* Like the basename() function, but does not modify @path; it just returns a
34  * pointer to it.  This assumes the path separator is the
35  * OS_PREFERRED_PATH_SEPARATOR. */
36 const tchar *
37 path_basename(const tchar *path)
38 {
39         return path_basename_with_len(path, tstrlen(path));
40 }
41
42 /* Like path_basename(), but take an explicit string length. */
43 const tchar *
44 path_basename_with_len(const tchar *path, size_t len)
45 {
46         const tchar *p = &path[len] - 1;
47
48         /* Trailing slashes. */
49         while (1) {
50                 if (p == path - 1)
51                         return T("");
52                 if (*p != OS_PREFERRED_PATH_SEPARATOR)
53                         break;
54                 p--;
55         }
56
57         while ((p != path - 1) && *p != OS_PREFERRED_PATH_SEPARATOR)
58                 p--;
59
60         return p + 1;
61 }
62
63
64 /*
65  * Returns a pointer to the part of @path following the first colon in the last
66  * path component, or NULL if the last path component does not contain a colon.
67  */
68 const tchar *
69 path_stream_name(const tchar *path)
70 {
71         const tchar *base = path_basename(path);
72         const tchar *stream_name = tstrchr(base, T(':'));
73         if (!stream_name)
74                 return NULL;
75         else
76                 return stream_name + 1;
77 }
78
79
80 /* Duplicate a path; return empty string for NULL input. */
81 tchar *
82 canonicalize_fs_path(const tchar *fs_path)
83 {
84         if (!fs_path)
85                 fs_path = T("");
86         return TSTRDUP(fs_path);
87 }
88
89 /* 
90  * canonicalize_wim_path - Given a user-provided path to a file within a WIM
91  * image, translate it into a "canonical" path.
92  *
93  * To do this, we translate all supported path separators
94  * (is_any_path_separator()) into the WIM_PATH_SEPARATOR, and strip any leading
95  * and trailing slashes.  The returned string is allocated.  Note that there
96  * still may be consecutive path separators within the string.  Furthermore, the
97  * string may be empty, which indicates the root dentry of the WIM image.
98  */
99 tchar *
100 canonicalize_wim_path(const tchar *wim_path)
101 {
102         tchar *p;
103         tchar *canonical_path;
104
105         if (wim_path == NULL) {
106                 wim_path = T("");
107         } else {
108                 while (is_any_path_separator(*wim_path))
109                         wim_path++;
110         }
111         canonical_path = TSTRDUP(wim_path);
112         if (canonical_path) {
113                 for (p = canonical_path; *p; p++)
114                         if (is_any_path_separator(*p))
115                                 *p = WIM_PATH_SEPARATOR;
116                 for (p = tstrchr(canonical_path, T('\0')) - 1;
117                      p >= canonical_path && *p == WIM_PATH_SEPARATOR;
118                      p--)
119                 {
120                         *p = T('\0');
121                 }
122         }
123         return canonical_path;
124 }