source: mainline/uspace/lib/fmgt/src/walk.c@ 2309891

Last change on this file since 2309891 was 2309891, checked in by Jiri Svoboda <jiri@…>, 5 days ago

Copy files (Navigator and command line).

TODO Overwrite query, new I/O error types.

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*
2 * Copyright (c) 2025 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fmgt
30 * @{
31 */
32/** @file File system tree walker.
33 */
34
35#include <adt/list.h>
36#include <dirent.h>
37#include <errno.h>
38#include <mem.h>
39#include <stdbool.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <str.h>
43#include <vfs/vfs.h>
44
45#include "fmgt.h"
46#include "fmgt/walk.h"
47
48static errno_t fmgt_walk_subtree(fmgt_walk_params_t *, const char *,
49 const char *);
50
51/** Initialize walk parameters.
52 *
53 * Every walk parameters structure must be initialized first using this
54 * function.
55 *
56 * @param params Pointer to walk parameters structure.
57 */
58void fmgt_walk_params_init(fmgt_walk_params_t *params)
59{
60 memset(params, 0, sizeof(fmgt_walk_params_t));
61}
62
63/** Walk file (invoke file callback).
64 *
65 * @param params Walk parameters
66 * @param fname Source path
67 * @param dest Destination path
68 *
69 * @return EOK on success or an error code
70 */
71static errno_t fmgt_walk_file(fmgt_walk_params_t *params, const char *fname,
72 const char *dest)
73{
74 if (params->cb->file != NULL)
75 return params->cb->file(params->arg, fname, dest);
76 else
77 return EOK;
78}
79
80/** Enter directory (invoke directory entry callback).
81 *
82 * @param params Walk parameters
83 * @param dname Source directory
84 * @param dest Destination path
85 * @return EOK on success or an error code
86 */
87static errno_t fmgt_walk_dir_enter(fmgt_walk_params_t *params,
88 const char *dname, const char *dest)
89{
90 if (params->cb->dir_enter != NULL)
91 return params->cb->dir_enter(params->arg, dname, dest);
92 else
93 return EOK;
94}
95
96/** Leave directory (invoke directory exit callback).
97 *
98 * @param params Walk parameters
99 * @param dname Directory path
100 * @param dest Destination path
101 * @return EOK on success or an error code
102 */
103static errno_t fmgt_walk_dir_leave(fmgt_walk_params_t *params,
104 const char *dname, const char *dest)
105{
106 if (params->cb->dir_leave != NULL)
107 return params->cb->dir_leave(params->arg, dname, dest);
108 else
109 return EOK;
110}
111
112/** Walk directory.
113 *
114 * @param params Walk parameters
115 * @param dname Directory name
116 * @param dest Destination path or @c NULL
117 * @return EOK on success or an error code
118 */
119static errno_t fmgt_walk_dir(fmgt_walk_params_t *params, const char *dname,
120 const char *dest)
121{
122 DIR *dir = NULL;
123 struct dirent *de;
124 errno_t rc;
125 char *srcpath = NULL;
126 char *destpath = NULL;
127 int rv;
128
129 rc = fmgt_walk_dir_enter(params, dname, dest);
130 if (rc != EOK)
131 goto error;
132
133 dir = opendir(dname);
134 if (dir == NULL) {
135 rc = EIO;
136 goto error;
137 }
138
139 de = readdir(dir);
140 while (de != NULL) {
141 rv = asprintf(&srcpath, "%s/%s", dname, de->d_name);
142 if (rv < 0) {
143 rc = ENOMEM;
144 goto error;
145 }
146
147 if (dest != NULL) {
148 rv = asprintf(&destpath, "%s/%s", dest, de->d_name);
149 if (rv < 0) {
150 rc = ENOMEM;
151 free(srcpath);
152 goto error;
153 }
154 }
155
156 rc = fmgt_walk_subtree(params, srcpath, destpath);
157 if (rc != EOK) {
158 free(srcpath);
159 if (destpath != NULL)
160 free(destpath);
161 goto error;
162 }
163
164 free(srcpath);
165 if (destpath != NULL)
166 free(destpath);
167 de = readdir(dir);
168 }
169
170 rc = fmgt_walk_dir_leave(params, dname, dest);
171 if (rc != EOK)
172 return rc;
173
174 closedir(dir);
175 return EOK;
176error:
177 if (dir != NULL)
178 closedir(dir);
179 return rc;
180}
181
182/** Walk subtree.
183 *
184 * @param params Walk parameters.
185 * @param fname Subtree path.
186 * @param dest Destination path
187 *
188 * @return EOK on success or an error code.
189 */
190static errno_t fmgt_walk_subtree(fmgt_walk_params_t *params, const char *fname,
191 const char *dest)
192{
193 vfs_stat_t stat;
194 errno_t rc;
195
196 rc = vfs_stat_path(fname, &stat);
197 if (rc != EOK)
198 return rc;
199
200 if (stat.is_directory) {
201 /* Directory */
202 rc = fmgt_walk_dir(params, fname, dest);
203 if (rc != EOK)
204 return rc;
205 } else {
206 /* Not a directory */
207 rc = fmgt_walk_file(params, fname, dest);
208 if (rc != EOK)
209 return rc;
210 }
211
212 return EOK;
213}
214
215/** Perform a file system walk.
216 *
217 * Walks the list of files/directories in @a params->flist. Directories
218 * are walked recursively. Callbacks are involved for each file, directory,
219 * if defined.in @a params->cb, the callback argument is @a params->arg.
220 *
221 * @param params Walk parameters
222 * @return EOK on success or an error code.
223 */
224errno_t fmgt_walk(fmgt_walk_params_t *params)
225{
226 fmgt_flist_entry_t *entry;
227 char *destname;
228 errno_t rc;
229 int rv;
230
231 entry = fmgt_flist_first(params->flist);
232 while (entry != NULL) {
233 if (params->into_dest) {
234 rv = asprintf(&destname, "%s/%s",
235 params->dest, fmgt_basename(entry->fname));
236 if (rv < 0)
237 return ENOMEM;
238 } else {
239 destname = NULL;
240 }
241
242 rc = fmgt_walk_subtree(params, entry->fname,
243 destname != NULL ? destname : params->dest);
244 if (rc != EOK)
245 return rc;
246
247 entry = fmgt_flist_next(entry);
248 }
249
250 return EOK;
251}
252
253/** @}
254 */
Note: See TracBrowser for help on using the repository browser.