1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00
samba-mirror/source3/lib/util_path.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

351 lines
7.5 KiB
C
Raw Normal View History

/*
* Unix SMB/CIFS implementation.
* Samba utility functions
* Copyright (C) Andrew Tridgell 1992-1998
* Copyright (C) Jeremy Allison 2001-2007
* Copyright (C) Simo Sorce 2001
* Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
* Copyright (C) James Peach 2006
*
* This program 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.
*
* This program 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 details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "replace.h"
#include <talloc.h>
#include "lib/util/debug.h"
#include "lib/util/samba_util.h"
#include "lib/util_path.h"
struct loadparm_substitution;
struct share_params;
#include "source3/param/param_proto.h"
/**
* @brief Returns an absolute path to a file concatenating the provided
* @a rootpath and @a basename
*
* @param name Filename, relative to @a rootpath
*
* @retval Pointer to a string containing the full path.
**/
static char *xx_path(TALLOC_CTX *mem_ctx,
const char *name,
const char *rootpath)
{
char *fname = NULL;
fname = talloc_strdup(mem_ctx, rootpath);
if (!fname) {
return NULL;
}
trim_string(fname,"","/");
if (!directory_create_or_exist(fname, 0755)) {
return NULL;
}
return talloc_asprintf_append(fname, "/%s", name);
}
/**
* @brief Returns an absolute path to a file in the Samba lock directory.
*
* @param name File to find, relative to LOCKDIR.
*
* @retval Pointer to a talloc'ed string containing the full path.
**/
char *lock_path(TALLOC_CTX *mem_ctx, const char *name)
{
return xx_path(mem_ctx, name, lp_lock_directory());
}
/**
* @brief Returns an absolute path to a file in the Samba state directory.
*
* @param name File to find, relative to STATEDIR.
*
* @retval Pointer to a talloc'ed string containing the full path.
**/
char *state_path(TALLOC_CTX *mem_ctx, const char *name)
{
return xx_path(mem_ctx, name, lp_state_directory());
}
/**
* @brief Returns an absolute path to a file in the Samba cache directory.
*
* @param name File to find, relative to CACHEDIR.
*
* @retval Pointer to a talloc'ed string containing the full path.
**/
char *cache_path(TALLOC_CTX *mem_ctx, const char *name)
{
return xx_path(mem_ctx, name, lp_cache_directory());
}
/**
* @brief Removes any invalid path components in an absolute POSIX path.
*
* @param ctx Talloc context to return string.
*
* @param abs_path Absolute path string to process.
*
* @retval Pointer to a talloc'ed string containing the absolute full path.
**/
char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *pathname_in)
{
/*
* Note we use +2 here so if pathname_in=="" then we
* have space to return "/".
*/
char *pathname = talloc_array(ctx, char, strlen(pathname_in)+2);
const char *s = pathname_in;
char *p = pathname;
if (pathname == NULL) {
return NULL;
}
/* Always start with a '/'. */
*p++ = '/';
while (*s) {
/* Deal with '/' or multiples of '/'. */
if (s[0] == '/') {
while (s[0] == '/') {
/* Eat trailing '/' */
s++;
}
/* Update target with one '/' */
if (p[-1] != '/') {
*p++ = '/';
}
continue;
}
if (p[-1] == '/') {
/* Deal with "./" or ".\0" */
if (s[0] == '.' &&
(s[1] == '/' || s[1] == '\0')) {
/* Eat the dot. */
s++;
while (s[0] == '/') {
/* Eat any trailing '/' */
s++;
}
/* Don't write anything to target. */
continue;
}
/* Deal with "../" or "..\0" */
if (s[0] == '.' && s[1] == '.' &&
(s[2] == '/' || s[2] == '\0')) {
/* Eat the dot dot. */
s += 2;
while (s[0] == '/') {
/* Eat any trailing '/' */
s++;
}
/*
* As we're on the slash, we go back
* one character to point p at the
* slash we just saw.
*/
if (p > pathname) {
p--;
}
/*
* Now go back to the slash
* before the one that p currently points to.
*/
while (p > pathname) {
p--;
if (p[0] == '/') {
break;
}
}
/*
* Step forward one to leave the
* last written '/' alone.
*/
p++;
/* Don't write anything to target. */
continue;
}
}
/* Non-separator character, just copy. */
*p++ = *s++;
}
if (p[-1] == '/') {
/*
* We finished on a '/'.
* Remove the trailing '/', but not if it's
* the sole character in the path.
*/
if (p > pathname + 1) {
p--;
}
}
/* Terminate and we're done ! */
*p++ = '\0';
return pathname;
}
static bool find_snapshot_token(
const char *filename,
char sep,
const char **_start,
const char **_next_component,
NTTIME *twrp)
{
const char *start = NULL;
const char *end = NULL;
struct tm tm;
time_t t;
start = strstr_m(filename, "@GMT-");
if (start == NULL) {
return false;
}
if ((start > filename) && (start[-1] != sep)) {
/* the GMT-token does not start a path-component */
return false;
}
end = strptime(start, GMT_FORMAT, &tm);
if (end == NULL) {
/* Not a valid timestring. */
return false;
}
if ((end[0] != '\0') && (end[0] != sep)) {
/*
* It is not a complete path component, i.e. the path
* component continues after the gmt-token.
*/
return false;
}
tm.tm_isdst = -1;
t = timegm(&tm);
unix_to_nt_time(twrp, t);
DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
nt_time_string(talloc_tos(), *twrp));
*_start = start;
if (end[0] == sep) {
end += 1;
}
*_next_component = end;
return true;
}
bool clistr_is_previous_version_path(const char *path)
{
const char *start = NULL;
const char *next = NULL;
NTTIME twrp;
bool ok;
ok = find_snapshot_token(path, '\\', &start, &next, &twrp);
return ok;
}
static bool extract_snapshot_token_internal(char *fname, NTTIME *twrp, char sep)
{
const char *start = NULL;
const char *next = NULL;
size_t remaining;
bool found;
found = find_snapshot_token(fname, sep, &start, &next, twrp);
if (!found) {
return false;
}
remaining = strlen(next);
memmove(discard_const_p(char, start), next, remaining+1);
return true;
}
bool extract_snapshot_token(char *fname, NTTIME *twrp)
{
return extract_snapshot_token_internal(fname, twrp, '/');
}
bool clistr_smb2_extract_snapshot_token(char *fname, NTTIME *twrp)
{
return extract_snapshot_token_internal(fname, twrp, '\\');
}
/*
* Take two absolute paths, figure out if "subdir" is a proper
* subdirectory of "parent". Return the component relative to the
* "parent" without the potential "/". Take care of "parent"
* possibly ending in "/".
*/
bool subdir_of(const char *parent,
size_t parent_len,
const char *subdir,
const char **_relative)
{
const char *relative = NULL;
bool matched;
SMB_ASSERT(parent[0] == '/');
SMB_ASSERT(subdir[0] == '/');
if (parent_len == 1) {
/*
* Everything is below "/"
*/
*_relative = subdir+1;
return true;
}
if (parent[parent_len-1] == '/') {
parent_len -= 1;
}
matched = (strncmp(subdir, parent, parent_len) == 0);
if (!matched) {
return false;
}
relative = &subdir[parent_len];
if (relative[0] == '\0') {
*_relative = relative; /* nothing left */
return true;
}
if (relative[0] == '/') {
/* End of parent must match a '/' in subdir. */
*_relative = relative+1;
return true;
}
return false;
}