suricata
util-path.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2023 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 */
24
25#include "suricata-common.h"
26#include "suricata.h"
27#include "util-debug.h"
28#include "util-path.h"
29
30#ifdef OS_WIN32
31#define DIRECTORY_SEPARATOR '\\'
32#else
33#define DIRECTORY_SEPARATOR '/'
34#endif
35
36/**
37 * \brief Check if a path is absolute
38 *
39 * \param path string with the path
40 *
41 * \retval 1 absolute
42 * \retval 0 not absolute
43 */
44int PathIsAbsolute(const char *path)
45{
46 if (strlen(path) > 1 && path[0] == '/') {
47 return 1;
48 }
49
50#if (defined OS_WIN32 || defined __CYGWIN__)
51 if (strlen(path) > 2) {
52 if (isalpha((unsigned char)path[0]) && path[1] == ':') {
53 return 1;
54 }
55 }
56#endif
57
58 return 0;
59}
60
61/**
62 * \brief Check if a path is relative
63 *
64 * \param path string with the path
65 *
66 * \retval 1 relative
67 * \retval 0 not relative
68 */
69int PathIsRelative(const char *path)
70{
71 return PathIsAbsolute(path) ? 0 : 1;
72}
73
74int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname)
75{
76 char path[PATH_MAX];
77 if (dir == NULL || strlen(dir) == 0)
78 return -1;
79
80 size_t r = strlcpy(path, dir, sizeof(path));
81 if (r >= sizeof(path)) {
82 return -1;
83 }
84
85#if defined OS_WIN32 || defined __CYGWIN__
86 if (path[strlen(path) - 1] != '\\')
87 r = strlcat(path, "\\\\", sizeof(path));
88#else
89 if (path[strlen(path) - 1] != '/')
90 r = strlcat(path, "/", sizeof(path));
91#endif
92 if (r >= sizeof(path)) {
93 return -1;
94 }
95 r = strlcat(path, fname, sizeof(path));
96 if (r >= sizeof(path)) {
97 return -1;
98 }
99 r = strlcpy(out_buf, path, buf_size);
100 if (r >= buf_size) {
101 return -1;
102 }
103
104 return 0;
105}
106
107char *PathMergeAlloc(const char *const dir, const char *const fname)
108{
109 char path[PATH_MAX];
110 if (PathMerge(path, sizeof(path), dir, fname) != 0)
111 return NULL;
112
113 char *ret = SCStrdup(path);
114 if (ret == NULL)
115 return NULL;
116
117 return ret;
118}
119
120/**
121 * \brief Wrapper around SCMkDir with default mode arguments.
122 */
123int SCDefaultMkDir(const char *path)
124{
125 return SCMkDir(path, S_IRWXU | S_IRGRP | S_IXGRP);
126}
127
128/**
129 * \brief Recursively create a directory.
130 *
131 * \param path Path to create
132 * \param final true will create the final path component, false will not
133 *
134 * \retval 0 on success
135 * \retval -1 on error
136 */
137int SCCreateDirectoryTree(const char *path, const bool final)
138{
139 char pathbuf[PATH_MAX];
140 char *p;
141 size_t len = strlen(path);
142
143 if (len > PATH_MAX - 1) {
144 return -1;
145 }
146
147 strlcpy(pathbuf, path, sizeof(pathbuf));
148
149 for (p = pathbuf + 1; *p; p++) {
150 if (*p == '/') {
151 /* Truncate, while creating directory */
152 *p = '\0';
153
154 if (SCDefaultMkDir(pathbuf) != 0) {
155 if (errno != EEXIST) {
156 return -1;
157 }
158 }
159
160 *p = '/';
161 }
162 }
163
164 if (final) {
165 if (SCDefaultMkDir(pathbuf) != 0) {
166 if (errno != EEXIST) {
167 return -1;
168 }
169 }
170 }
171
172 return 0;
173}
174
175/**
176 * \brief Check if a path exists.
177 *
178 * \param Path to check for existence
179 *
180 * \retval true if path exists
181 * \retval false if path does not exist
182 */
183bool SCPathExists(const char *path)
184{
185 struct stat sb;
186 if (stat(path, &sb) == 0) {
187 return true;
188 }
189 return false;
190}
191
192/**
193 * \brief OS independent wrapper for directory check
194 *
195 * \param dir_entry object to check
196 *
197 * \retval True if the object is a regular directory, otherwise false. This directory
198 * and parent directory will return false.
199 */
200bool SCIsRegularDirectory(const struct dirent *const dir_entry)
201{
202#ifndef OS_WIN32
203 if ((dir_entry->d_type == DT_DIR) &&
204 (strcmp(dir_entry->d_name, ".") != 0) &&
205 (strcmp(dir_entry->d_name, "..") != 0)) {
206 return true;
207 }
208#endif
209 return false;
210}
211/**
212 * \brief OS independent to check for regular file
213 *
214 * \param dir_entry object to check
215 *
216 * \retval True if the object is a regular file. Otherwise false.
217 */
218bool SCIsRegularFile(const struct dirent *const dir_entry)
219{
220#ifndef OS_WIN32
221 return dir_entry->d_type == DT_REG;
222#endif
223 return false;
224}
225
226/**
227 * \brief OS independent wrapper for realpath
228 *
229 * \param path the path to resolve
230 * \param resolved_path the resolved path; if null, a buffer will be allocated
231 *
232 * \retval the resolved_path; or a pointer to a new resolved_path buffer
233 */
234char *SCRealPath(const char *path, char *resolved_path)
235{
236#ifdef OS_WIN32
237 return _fullpath(resolved_path, path, PATH_MAX);
238#else
239 return realpath(path, resolved_path);
240#endif
241}
242
243/*
244 * \brief Return the basename of the provided path.
245 * \param path The path on which to compute the basename
246 *
247 * \retval the basename of the path or NULL if the path lacks a non-leaf
248 */
249const char *SCBasename(const char *path)
250{
251 if (!path || strlen(path) == 0)
252 return NULL;
253
254 char *final = strrchr(path, DIRECTORY_SEPARATOR);
255 if (!final)
256 return path;
257
258 if (*(final + 1) == '\0')
259 return NULL;
260
261 return final + 1;
262}
263
264/**
265 * \brief Check for directory traversal
266 *
267 * \param path The path string to check for traversal
268 *
269 * \retval true if directory traversal is found, otherwise false
270 */
271bool SCPathContainsTraversal(const char *path)
272{
273#ifdef OS_WIN32
274 const char *pattern = "..\\";
275#else
276 const char *pattern = "../";
277#endif
278 return strstr(path, pattern) != NULL;
279}
uint8_t len
size_t strlcat(char *, const char *src, size_t siz)
size_t strlcpy(char *dst, const char *src, size_t siz)
#define SCStrdup(s)
Definition util-mem.h:56
int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname)
Definition util-path.c:74
char * SCRealPath(const char *path, char *resolved_path)
OS independent wrapper for realpath.
Definition util-path.c:234
bool SCPathContainsTraversal(const char *path)
Check for directory traversal.
Definition util-path.c:271
bool SCPathExists(const char *path)
Check if a path exists.
Definition util-path.c:183
char * PathMergeAlloc(const char *const dir, const char *const fname)
Definition util-path.c:107
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition util-path.c:44
bool SCIsRegularDirectory(const struct dirent *const dir_entry)
OS independent wrapper for directory check.
Definition util-path.c:200
int PathIsRelative(const char *path)
Check if a path is relative.
Definition util-path.c:69
bool SCIsRegularFile(const struct dirent *const dir_entry)
OS independent to check for regular file.
Definition util-path.c:218
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
Definition util-path.c:137
int SCDefaultMkDir(const char *path)
Wrapper around SCMkDir with default mode arguments.
Definition util-path.c:123
const char * SCBasename(const char *path)
Definition util-path.c:249
#define DIRECTORY_SEPARATOR
Definition util-path.c:33
#define SCMkDir(a, b)
Definition util-path.h:45