2 * Unix SMB/CIFS implementation.
3 * Samba utility functions
4 * Copyright (C) Andrew Tridgell 1992-1998
5 * Copyright (C) Jeremy Allison 2001-2007
6 * Copyright (C) Simo Sorce 2001
7 * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
8 * Copyright (C) James Peach 2006
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "lib/util/debug.h"
27 #include "lib/util/samba_util.h"
28 #include "lib/util_path.h"
30 struct loadparm_substitution
;
32 #include "source3/param/param_proto.h"
35 * @brief Returns an absolute path to a file concatenating the provided
36 * @a rootpath and @a basename
38 * @param name Filename, relative to @a rootpath
40 * @retval Pointer to a string containing the full path.
43 static char *xx_path(TALLOC_CTX
*mem_ctx
,
49 fname
= talloc_strdup(mem_ctx
, rootpath
);
53 trim_string(fname
,"","/");
55 if (!directory_create_or_exist(fname
, 0755)) {
59 return talloc_asprintf_append(fname
, "/%s", name
);
63 * @brief Returns an absolute path to a file in the Samba lock directory.
65 * @param name File to find, relative to LOCKDIR.
67 * @retval Pointer to a talloc'ed string containing the full path.
70 char *lock_path(TALLOC_CTX
*mem_ctx
, const char *name
)
72 return xx_path(mem_ctx
, name
, lp_lock_directory());
76 * @brief Returns an absolute path to a file in the Samba state directory.
78 * @param name File to find, relative to STATEDIR.
80 * @retval Pointer to a talloc'ed string containing the full path.
83 char *state_path(TALLOC_CTX
*mem_ctx
, const char *name
)
85 return xx_path(mem_ctx
, name
, lp_state_directory());
89 * @brief Returns an absolute path to a file in the Samba cache directory.
91 * @param name File to find, relative to CACHEDIR.
93 * @retval Pointer to a talloc'ed string containing the full path.
96 char *cache_path(TALLOC_CTX
*mem_ctx
, const char *name
)
98 return xx_path(mem_ctx
, name
, lp_cache_directory());
102 * @brief Removes any invalid path components in an absolute POSIX path.
104 * @param ctx Talloc context to return string.
106 * @param abs_path Absolute path string to process.
108 * @retval Pointer to a talloc'ed string containing the absolute full path.
111 char *canonicalize_absolute_path(TALLOC_CTX
*ctx
, const char *pathname_in
)
114 * Note we use +2 here so if pathname_in=="" then we
115 * have space to return "/".
117 char *pathname
= talloc_array(ctx
, char, strlen(pathname_in
)+2);
118 const char *s
= pathname_in
;
121 if (pathname
== NULL
) {
125 /* Always start with a '/'. */
129 /* Deal with '/' or multiples of '/'. */
131 while (s
[0] == '/') {
132 /* Eat trailing '/' */
135 /* Update target with one '/' */
142 /* Deal with "./" or ".\0" */
144 (s
[1] == '/' || s
[1] == '\0')) {
147 while (s
[0] == '/') {
148 /* Eat any trailing '/' */
151 /* Don't write anything to target. */
154 /* Deal with "../" or "..\0" */
155 if (s
[0] == '.' && s
[1] == '.' &&
156 (s
[2] == '/' || s
[2] == '\0')) {
157 /* Eat the dot dot. */
159 while (s
[0] == '/') {
160 /* Eat any trailing '/' */
164 * As we're on the slash, we go back
165 * one character to point p at the
172 * Now go back to the slash
173 * before the one that p currently points to.
175 while (p
> pathname
) {
182 * Step forward one to leave the
183 * last written '/' alone.
187 /* Don't write anything to target. */
191 /* Non-separator character, just copy. */
196 * We finished on a '/'.
197 * Remove the trailing '/', but not if it's
198 * the sole character in the path.
200 if (p
> pathname
+ 1) {
204 /* Terminate and we're done ! */
209 static bool find_snapshot_token(
210 const char *filename
,
213 const char **_next_component
,
216 const char *start
= NULL
;
217 const char *end
= NULL
;
221 start
= strstr_m(filename
, "@GMT-");
227 if ((start
> filename
) && (start
[-1] != sep
)) {
228 /* the GMT-token does not start a path-component */
232 end
= strptime(start
, GMT_FORMAT
, &tm
);
234 /* Not a valid timestring. */
238 if ((end
[0] != '\0') && (end
[0] != sep
)) {
240 * It is not a complete path component, i.e. the path
241 * component continues after the gmt-token.
248 unix_to_nt_time(twrp
, t
);
250 DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
251 nt_time_string(talloc_tos(), *twrp
));
258 *_next_component
= end
;
263 bool clistr_is_previous_version_path(const char *path
)
265 const char *start
= NULL
;
266 const char *next
= NULL
;
270 ok
= find_snapshot_token(path
, '\\', &start
, &next
, &twrp
);
274 static bool extract_snapshot_token_internal(char *fname
, NTTIME
*twrp
, char sep
)
276 const char *start
= NULL
;
277 const char *next
= NULL
;
281 found
= find_snapshot_token(fname
, sep
, &start
, &next
, twrp
);
286 remaining
= strlen(next
);
287 memmove(discard_const_p(char, start
), next
, remaining
+1);
292 bool extract_snapshot_token(char *fname
, NTTIME
*twrp
)
294 return extract_snapshot_token_internal(fname
, twrp
, '/');
297 bool clistr_smb2_extract_snapshot_token(char *fname
, NTTIME
*twrp
)
299 return extract_snapshot_token_internal(fname
, twrp
, '\\');
303 * Take two absolute paths, figure out if "subdir" is a proper
304 * subdirectory of "parent". Return the component relative to the
305 * "parent" without the potential "/". Take care of "parent"
306 * possibly ending in "/".
308 bool subdir_of(const char *parent
,
311 const char **_relative
)
313 const char *relative
= NULL
;
316 SMB_ASSERT(parent
[0] == '/');
317 SMB_ASSERT(subdir
[0] == '/');
319 if (parent_len
== 1) {
321 * Everything is below "/"
323 *_relative
= subdir
+1;
327 if (parent
[parent_len
-1] == '/') {
331 matched
= (strncmp(subdir
, parent
, parent_len
) == 0);
336 relative
= &subdir
[parent_len
];
338 if (relative
[0] == '\0') {
339 *_relative
= relative
; /* nothing left */
343 if (relative
[0] == '/') {
344 /* End of parent must match a '/' in subdir. */
345 *_relative
= relative
+1;