diff options
Diffstat (limited to '')
-rw-r--r-- | src/util-path.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/util-path.c b/src/util-path.c new file mode 100644 index 0000000..34c4cc7 --- /dev/null +++ b/src/util-path.c @@ -0,0 +1,315 @@ +/* Copyright (C) 2007-2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien <victor@inliniac.net> + * + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "util-debug.h" +#include "util-path.h" + +#ifdef OS_WIN32 +#define DIRECTORY_SEPARATOR '\\' +#else +#define DIRECTORY_SEPARATOR '/' +#endif + +/** + * \brief Check if a path is absolute + * + * \param path string with the path + * + * \retval 1 absolute + * \retval 0 not absolute + */ +int PathIsAbsolute(const char *path) +{ + if (strlen(path) > 1 && path[0] == '/') { + return 1; + } + +#if (defined OS_WIN32 || defined __CYGWIN__) + if (strlen(path) > 2) { + if (isalpha((unsigned char)path[0]) && path[1] == ':') { + return 1; + } + } +#endif + + return 0; +} + +/** + * \brief Check if a path is relative + * + * \param path string with the path + * + * \retval 1 relative + * \retval 0 not relative + */ +int PathIsRelative(const char *path) +{ + return PathIsAbsolute(path) ? 0 : 1; +} + +int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname) +{ + char path[PATH_MAX]; + if (dir == NULL || strlen(dir) == 0) + return -1; + + size_t r = strlcpy(path, dir, sizeof(path)); + if (r >= sizeof(path)) { + return -1; + } + +#if defined OS_WIN32 || defined __CYGWIN__ + if (path[strlen(path) - 1] != '\\') + r = strlcat(path, "\\\\", sizeof(path)); +#else + if (path[strlen(path) - 1] != '/') + r = strlcat(path, "/", sizeof(path)); +#endif + if (r >= sizeof(path)) { + return -1; + } + r = strlcat(path, fname, sizeof(path)); + if (r >= sizeof(path)) { + return -1; + } + r = strlcpy(out_buf, path, buf_size); + if (r >= buf_size) { + return -1; + } + + return 0; +} + +char *PathMergeAlloc(const char *const dir, const char *const fname) +{ + char path[PATH_MAX]; + if (PathMerge(path, sizeof(path), dir, fname) != 0) + return NULL; + + char *ret = SCStrdup(path); + if (ret == NULL) + return NULL; + + return ret; +} + +/** + * \brief Wrapper to join a directory and filename and resolve using realpath + * _fullpath is used for WIN32 + * + * \param out_buf output buffer. Up to PATH_MAX will be written. Unchanged on exit failure. + * \param buf_size length of output buffer, must be PATH_MAX + * \param dir the directory + * \param fname the filename + * + * \retval 0 on success + * \retval -1 on failure + */ +int PathJoin(char *out_buf, size_t buf_size, const char *const dir, const char *const fname) +{ + SCEnter(); + if (buf_size != PATH_MAX) { + return -1; + } + if (PathMerge(out_buf, buf_size, dir, fname) != 0) { + SCLogError("Could not join filename to path"); + return -1; + } + char *tmp_buf = SCRealPath(out_buf, NULL); + if (tmp_buf == NULL) { + SCLogError("Error resolving path: %s", strerror(errno)); + return -1; + } + memset(out_buf, 0, buf_size); + size_t ret = strlcpy(out_buf, tmp_buf, buf_size); + free(tmp_buf); + if (ret >= buf_size) { + return -1; + } + return 0; +} + +/** + * \brief Wrapper around SCMkDir with default mode arguments. + */ +int SCDefaultMkDir(const char *path) +{ + return SCMkDir(path, S_IRWXU | S_IRGRP | S_IXGRP); +} + +/** + * \brief Recursively create a directory. + * + * \param path Path to create + * \param final true will create the final path component, false will not + * + * \retval 0 on success + * \retval -1 on error + */ +int SCCreateDirectoryTree(const char *path, const bool final) +{ + char pathbuf[PATH_MAX]; + char *p; + size_t len = strlen(path); + + if (len > PATH_MAX - 1) { + return -1; + } + + strlcpy(pathbuf, path, sizeof(pathbuf)); + + for (p = pathbuf + 1; *p; p++) { + if (*p == '/') { + /* Truncate, while creating directory */ + *p = '\0'; + + if (SCDefaultMkDir(pathbuf) != 0) { + if (errno != EEXIST) { + return -1; + } + } + + *p = '/'; + } + } + + if (final) { + if (SCDefaultMkDir(pathbuf) != 0) { + if (errno != EEXIST) { + return -1; + } + } + } + + return 0; +} + +/** + * \brief Check if a path exists. + * + * \param Path to check for existence + * + * \retval true if path exists + * \retval false if path does not exist + */ +bool SCPathExists(const char *path) +{ + struct stat sb; + if (stat(path, &sb) == 0) { + return true; + } + return false; +} + +/** + * \brief OS independent wrapper for directory check + * + * \param dir_entry object to check + * + * \retval True if the object is a regular directory, otherwise false. This directory + * and parent directory will return false. + */ +bool SCIsRegularDirectory(const struct dirent *const dir_entry) +{ +#ifndef OS_WIN32 + if ((dir_entry->d_type == DT_DIR) && + (strcmp(dir_entry->d_name, ".") != 0) && + (strcmp(dir_entry->d_name, "..") != 0)) { + return true; + } +#endif + return false; +} +/** + * \brief OS independent to check for regular file + * + * \param dir_entry object to check + * + * \retval True if the object is a regular file. Otherwise false. + */ +bool SCIsRegularFile(const struct dirent *const dir_entry) +{ +#ifndef OS_WIN32 + return dir_entry->d_type == DT_REG; +#endif + return false; +} + +/** + * \brief OS independent wrapper for realpath + * + * \param path the path to resolve + * \param resolved_path the resolved path; if null, a buffer will be allocated + * + * \retval the resolved_path; or a pointer to a new resolved_path buffer + */ +char *SCRealPath(const char *path, char *resolved_path) +{ +#ifdef OS_WIN32 + return _fullpath(resolved_path, path, PATH_MAX); +#else + return realpath(path, resolved_path); +#endif +} + +/* + * \brief Return the basename of the provided path. + * \param path The path on which to compute the basename + * + * \retval the basename of the path or NULL if the path lacks a non-leaf + */ +const char *SCBasename(const char *path) +{ + if (!path || strlen(path) == 0) + return NULL; + + char *final = strrchr(path, DIRECTORY_SEPARATOR); + if (!final) + return path; + + if (*(final + 1) == '\0') + return NULL; + + return final + 1; +} + +/** + * \brief Check for directory traversal + * + * \param path The path string to check for traversal + * + * \retval true if directory traversal is found, otherwise false + */ +bool SCPathContainsTraversal(const char *path) +{ +#ifdef OS_WIN32 + const char *pattern = "..\\"; +#else + const char *pattern = "../"; +#endif + return strstr(path, pattern) != NULL; +} |