source: mainline/uspace/lib/fmgt/src/copy.c@ 79b77ce

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

Allow retrying failed file/dir creation and file open.

  • Property mode set to 100644
File size: 6.1 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 Copy files and directories.
33 */
34
35#include <errno.h>
36#include <stdbool.h>
37#include <stdlib.h>
38#include <vfs/vfs.h>
39
40#include "fmgt.h"
41#include "fmgt/walk.h"
42#include "../private/fmgt.h"
43
44static errno_t fmgt_copy_dir_enter(void *, const char *, const char *);
45static errno_t fmgt_copy_file(void *, const char *, const char *);
46
47static fmgt_walk_cb_t fmgt_copy_cb = {
48 .dir_enter = fmgt_copy_dir_enter,
49 .file = fmgt_copy_file
50};
51
52static errno_t fmgt_write(fmgt_t *fmgt, int fd, const char *fname,
53 aoff64_t *pos, void *buffer, size_t nbytes)
54{
55 size_t total_written;
56 char *bp = (char *)buffer;
57 fmgt_io_error_t err;
58 fmgt_error_action_t action;
59 size_t nw;
60 errno_t rc;
61
62 total_written = 0;
63 while (total_written < nbytes) {
64 do {
65 rc = vfs_write(fd, pos, bp + total_written,
66 nbytes - total_written, &nw);
67 if (rc == EOK)
68 break;
69
70 /* I/O error */
71 err.fname = fname;
72 err.optype = fmgt_io_write;
73 err.rc = rc;
74 fmgt_timer_stop(fmgt);
75 action = fmgt_io_error_query(fmgt, &err);
76 fmgt_timer_start(fmgt);
77 } while (action == fmgt_er_retry);
78
79 /* Not recovered? */
80 if (rc != EOK)
81 return rc;
82
83 total_written += nw;
84 }
85
86 return EOK;
87}
88
89/** Copy operation - enter directory.
90 *
91 * @param arg Argument (fmgt_t *)
92 * @param fname Source directory name
93 * @param dest Destination directory name
94 * @return EOK on success or an error code
95 */
96static errno_t fmgt_copy_dir_enter(void *arg, const char *src, const char *dest)
97{
98 fmgt_t *fmgt = (fmgt_t *)arg;
99 fmgt_io_error_t err;
100 fmgt_error_action_t action;
101 errno_t rc;
102
103 do {
104 rc = vfs_link_path(dest, KIND_DIRECTORY, NULL);
105
106 /* It is okay if the directory exists. */
107 if (rc == EOK || rc == EEXIST)
108 break;
109
110 /* I/O error */
111 err.fname = dest;
112 err.optype = fmgt_io_create;
113 err.rc = rc;
114
115 fmgt_timer_stop(fmgt);
116 action = fmgt_io_error_query(fmgt, &err);
117 fmgt_timer_start(fmgt);
118 } while (action == fmgt_er_retry);
119
120 return rc;
121}
122
123/** Copy single file.
124 *
125 * @param arg Argument (fmgt_t *)
126 * @param fname Source file name
127 * @param dest Destination file name
128 * @return EOK on success or an error code
129 */
130static errno_t fmgt_copy_file(void *arg, const char *src, const char *dest)
131{
132 fmgt_t *fmgt = (fmgt_t *)arg;
133 int rfd;
134 int wfd;
135 size_t nr;
136 aoff64_t rpos = 0;
137 aoff64_t wpos = 0;
138 char *buffer;
139 fmgt_io_error_t err;
140 fmgt_error_action_t action;
141 errno_t rc;
142
143 buffer = calloc(BUFFER_SIZE, 1);
144 if (buffer == NULL)
145 return ENOMEM;
146
147 do {
148 rc = vfs_lookup_open(src, WALK_REGULAR, MODE_READ, &rfd);
149 if (rc == EOK)
150 break;
151
152 /* I/O error */
153 err.fname = src;
154 err.optype = fmgt_io_open;
155 err.rc = rc;
156 fmgt_timer_stop(fmgt);
157 action = fmgt_io_error_query(fmgt, &err);
158 fmgt_timer_start(fmgt);
159 } while (action == fmgt_er_retry);
160
161 /* Not recovered? */
162 if (rc != EOK) {
163 free(buffer);
164 return rc;
165 }
166
167 do {
168 rc = vfs_lookup_open(dest, WALK_REGULAR | WALK_MAY_CREATE,
169 MODE_WRITE, &wfd);
170 if (rc == EOK)
171 break;
172
173 /* I/O error */
174 err.fname = dest;
175 err.optype = fmgt_io_create;
176 err.rc = rc;
177 fmgt_timer_stop(fmgt);
178 action = fmgt_io_error_query(fmgt, &err);
179 fmgt_timer_start(fmgt);
180 } while (action == fmgt_er_retry);
181
182 if (rc != EOK) {
183 free(buffer);
184 vfs_put(rfd);
185 return rc;
186 }
187
188 fmgt_progress_init_file(fmgt, src);
189
190 do {
191 do {
192 rc = vfs_read(rfd, &rpos, buffer, BUFFER_SIZE, &nr);
193 if (rc == EOK)
194 break;
195
196 /* I/O error */
197 err.fname = src;
198 err.optype = fmgt_io_read;
199 err.rc = rc;
200 fmgt_timer_stop(fmgt);
201 action = fmgt_io_error_query(fmgt, &err);
202 fmgt_timer_start(fmgt);
203 } while (action == fmgt_er_retry);
204
205 /* Not recovered? */
206 if (rc != EOK)
207 goto error;
208
209 rc = fmgt_write(fmgt, wfd, dest, &wpos, buffer, nr);
210 if (rc != EOK)
211 goto error;
212
213 fmgt_progress_incr_bytes(fmgt, nr);
214
215 /* User requested abort? */
216 if (fmgt_abort_query(fmgt)) {
217 rc = EINTR;
218 goto error;
219 }
220 } while (nr > 0);
221
222 free(buffer);
223 vfs_put(rfd);
224 vfs_put(wfd);
225 fmgt_progress_incr_files(fmgt);
226 return EOK;
227error:
228 free(buffer);
229 vfs_put(rfd);
230 vfs_put(wfd);
231 fmgt_final_progress_update(fmgt);
232 return rc;
233}
234
235/** copy files.
236 *
237 * @param fmgt File management object
238 * @param flist File list
239 * @param dest Destination path
240 * @return EOK on success or an error code
241 */
242errno_t fmgt_copy(fmgt_t *fmgt, fmgt_flist_t *flist, const char *dest)
243{
244 fmgt_walk_params_t params;
245 errno_t rc;
246
247 fmgt_walk_params_init(&params);
248
249 params.flist = flist;
250 params.dest = dest;
251 params.cb = &fmgt_copy_cb;
252 params.arg = (void *)fmgt;
253 if (fmgt_is_dir(dest))
254 params.into_dest = true;
255
256 fmgt_progress_init(fmgt);
257
258 fmgt_timer_start(fmgt);
259 fmgt_initial_progress_update(fmgt);
260 rc = fmgt_walk(&params);
261 fmgt_final_progress_update(fmgt);
262 return rc;
263}
264
265/** @}
266 */
Note: See TracBrowser for help on using the repository browser.