libamxp  1.4.0
Patterns C Implementation
amxp_dir.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
58 
59 #include <stdlib.h>
60 #include <string.h>
61 #include <dirent.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 
65 #include <amxc/amxc_macros.h>
66 #include <amxc/amxc.h>
67 
68 #include "amxp/amxp_expression.h"
69 #include "amxp/amxp_dir.h"
70 
72  amxc_var_t* value,
73  const char* path,
74  void* priv) {
75  struct dirent* ep = (struct dirent*) priv;
77 
78  if(strcmp(path, "d_ino") == 0) {
79  amxc_var_set(uint32_t, value, ep->d_ino);
80  } else if(strcmp(path, "d_type") == 0) {
81  amxc_var_set(uint32_t, value, ep->d_type);
82  } else if(strcmp(path, "d_name") == 0) {
83  amxc_var_set(cstring_t, value, ep->d_name);
84  } else if(strcmp(path, "DT_BLK") == 0) {
85  amxc_var_set(uint32_t, value, DT_BLK);
86  } else if(strcmp(path, "DT_CHR") == 0) {
87  amxc_var_set(uint32_t, value, DT_CHR);
88  } else if(strcmp(path, "DT_DIR") == 0) {
89  amxc_var_set(uint32_t, value, DT_DIR);
90  } else if(strcmp(path, "DT_FIFO") == 0) {
91  amxc_var_set(uint32_t, value, DT_FIFO);
92  } else if(strcmp(path, "DT_LNK") == 0) {
93  amxc_var_set(uint32_t, value, DT_LNK);
94  } else if(strcmp(path, "DT_REG") == 0) {
95  amxc_var_set(uint32_t, value, DT_REG);
96  } else if(strcmp(path, "DT_SOCK") == 0) {
97  amxc_var_set(uint32_t, value, DT_SOCK);
98  } else if(strcmp(path, "DT_UNKNOWN") == 0) {
99  amxc_var_set(uint32_t, value, DT_UNKNOWN);
100  } else {
102  }
103 
104  return status;
105 }
106 
107 static int amxp_dir_check_is_empty(UNUSED const char* name, UNUSED void* priv) {
108  return -1;
109 }
110 
111 static int amxp_dir_scan_impl(const char* path,
112  amxp_expr_t* expr,
113  bool recursive,
115  void* priv) {
116  int retval = -1;
117  DIR* dp = NULL;
118  struct dirent* ep = NULL;
119  amxc_string_t filename;
120  size_t path_len = strlen(path);
121  amxc_string_init(&filename, 128);
122  dp = opendir(path);
123  when_null(dp, exit);
124 
125  retval = 0;
126 
127  for(ep = readdir(dp); ep; ep = readdir(dp)) {
128  if(ep->d_name[0] == '.') {
129  continue;
130  }
131  if(path[path_len - 1] == '/') {
132  amxc_string_setf(&filename, "%s%s", path, ep->d_name);
133  } else {
134  amxc_string_setf(&filename, "%s/%s", path, ep->d_name);
135  }
136  if((expr == NULL) || amxp_expr_evaluate(expr, amxp_expr_dir_get_field, ep, NULL)) {
137  if(fn != NULL) {
138  retval = fn(amxc_string_get(&filename, 0), priv);
139  when_failed(retval, exit);
140  }
141  }
142  if(recursive && (ep->d_type == DT_DIR)) {
143  retval = amxp_dir_scan_impl(amxc_string_get(&filename, 0), expr, recursive, fn, priv);
144  when_failed(retval, exit);
145  }
146  }
147 
148 exit:
149  amxc_string_clean(&filename);
150  if(dp != NULL) {
151  closedir(dp);
152  }
153  return retval;
154 }
155 
156 int amxp_dir_owned_make(const char* path, const mode_t mode, uid_t uid, gid_t gid) {
157  int retval = -1;
158  char* dir = NULL;
159  char* current = NULL;
160  struct stat sb;
161 
162  when_str_empty(path, exit);
163 
164  if(stat(path, &sb) == 0) {
165  retval = 0;
166  goto exit;
167  }
168 
169  dir = strdup(path);
170  when_null(dir, exit);
171  /* 'dir' does not exist. Create it, from left to right. */
172  current = strchr(dir, '/');
173 
174  while(current != NULL && *current != 0) {
175  *current = '\0';
176 
177  if(dir[0] == 0) {
178  *current = '/';
179  current = strchr(current + 1, '/');
180  continue;
181  }
182 
183  if(stat(dir, &sb) == 0) {
184  *current = '/';
185  current = strchr(current + 1, '/');
186  continue;
187  }
188 
189  retval = mkdir(dir, mode);
190  when_failed(retval, exit);
191  if((uid != 0) || (gid != 0)) {
192  retval = chown(dir, uid, gid);
193  when_failed(retval, exit);
194  }
195  *current = '/';
196  current = strchr(current + 1, '/');
197  }
198 
199  if(stat(dir, &sb) != 0) {
200  retval = mkdir(dir, mode);
201  when_failed(retval, exit);
202  if((uid != 0) || (gid != 0)) {
203  retval = chown(dir, uid, gid);
204  }
205  }
206 
207 exit:
208  free(dir);
209  return retval;
210 }
211 
212 int amxp_dir_make(const char* path, const mode_t mode) {
213  return amxp_dir_owned_make(path, mode, 0, 0);
214 }
215 
216 int amxp_dir_scan(const char* path,
217  const char* filter,
218  bool recursive,
220  void* priv) {
221  int retval = -1;
222  amxp_expr_t* expr = NULL;
223  char* real_path = NULL;
224 
225  when_str_empty(path, exit);
226 
227  real_path = realpath(path, NULL);
228  when_null(real_path, exit);
229 
230  if((filter != NULL) && (*filter != 0)) {
231  when_failed(amxp_expr_new(&expr, filter), exit);
232  }
233 
234  retval = amxp_dir_scan_impl(real_path, expr, recursive, fn, priv);
235 
236 exit:
237  free(real_path);
238  amxp_expr_delete(&expr);
239  return retval;
240 
241 }
242 
243 bool amxp_dir_is_empty(const char* path) {
244  bool retval = true;
245  when_str_empty(path, exit);
246 
247  when_false(amxp_dir_is_directory(path), exit);
248 
249  if(amxp_dir_scan(path, NULL, false, amxp_dir_check_is_empty, NULL)) {
250  retval = false;
251  }
252 
253 exit:
254  return retval;
255 }
256 
257 bool amxp_dir_is_directory(const char* path) {
258  bool retval = false;
259  struct stat sb;
260  when_str_empty(path, exit);
261 
262  when_false(stat(path, &sb) == 0, exit);
263  when_false((sb.st_mode & S_IFMT) == S_IFDIR, exit);
264 
265  retval = true;
266 
267 exit:
268  return retval;
269 }
static int amxp_dir_scan_impl(const char *path, amxp_expr_t *expr, bool recursive, amxp_dir_match_fn_t fn, void *priv)
Definition: amxp_dir.c:111
static amxp_expr_status_t amxp_expr_dir_get_field(UNUSED amxp_expr_t *expr, amxc_var_t *value, const char *path, void *priv)
Definition: amxp_dir.c:71
static int amxp_dir_check_is_empty(UNUSED const char *name, UNUSED void *priv)
Definition: amxp_dir.c:107
Ambiorix directory utilities.
Ambiorix expression parser and evaluate API header file.
static struct timeval current
Definition: amxp_timer.c:66
#define UNUSED
Definition: main.c:68
int amxp_dir_make(const char *path, const mode_t mode)
Creates sub-directories.
Definition: amxp_dir.c:212
int amxp_dir_scan(const char *path, const char *filter, bool recursive, amxp_dir_match_fn_t fn, void *priv)
Scans a directory and calls a callback function for each matching entry found.
Definition: amxp_dir.c:216
int(* amxp_dir_match_fn_t)(const char *name, void *priv)
Matching file/directory callback function signature.
Definition: amxp_dir.h:96
bool amxp_dir_is_empty(const char *path)
Checks if a directory is empty.
Definition: amxp_dir.c:243
int amxp_dir_owned_make(const char *path, const mode_t mode, uid_t uid, gid_t gid)
Creates sub-directories and changes ownership.
Definition: amxp_dir.c:156
bool amxp_dir_is_directory(const char *path)
Checks if a path is a directory.
Definition: amxp_dir.c:257
amxp_expr_status_t amxp_expr_new(amxp_expr_t **expr, const char *expression)
Allocates and initializes an expression.
bool amxp_expr_evaluate(amxp_expr_t *expr, amxp_expr_get_field_t fn, void *priv, amxp_expr_status_t *status)
Evaluates an expression.
enum _expr_status amxp_expr_status_t
Expression status/error codes.
void amxp_expr_delete(amxp_expr_t **expr)
Deletes a previously allocated expression structure.
@ amxp_expr_status_field_not_found
@ amxp_expr_status_ok
static amxc_string_t path