GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/copymachines.c
Date: 2025-09-22 22:57:09
Exec Total Coverage
Lines: 0 132 0.0%
Functions: 0 3 0.0%
Branches: 0 90 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. 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 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/tech/copymachines.h"
30 #include "gate/results.h"
31
32
33 ✗ gate_result_t gate_stream_copier_init(gate_stream_copier_config_t* config, void* user_param)
34 {
35 ✗ if (config)
36 {
37 ✗ gate_mem_clear(config, sizeof(gate_stream_copier_config_t));
38
39 ✗ config->block_size = GATE_MAX_COPYBUFFER_LENGTH;
40 ✗ config->copy_limit = 0; /* no limit */
41 ✗ config->read_offset = 0; /* at beginning */
42 ✗ config->write_offset = 0; /* at beginning */
43
44 ✗ gate_atomic_int_set(&config->cancel, 0);
45 ✗ config->user_param = user_param;
46 ✗ return GATE_RESULT_OK;
47 }
48 else
49 {
50 ✗ return GATE_RESULT_NULLPOINTER;
51 }
52 }
53
54 ✗ gate_result_t gate_stream_copier_run(gate_stream_copier_config_t* config,
55 gate_stream_t* input, gate_stream_t* output,
56 gate_stream_copier_result_t* result)
57 {
58 ✗ gate_result_t ret = GATE_RESULT_OK;
59 ✗ gate_controlstream_t* input_res = NULL;
60 ✗ gate_controlstream_t* output_res = NULL;
61 ✗ gate_int64_t new_position = 0;
62 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
63 ✗ char* ptr_buffer = &buffer[0];
64 gate_size_t block_size;
65 gate_size_t block_size_backup;
66 gate_size_t next_block_size;
67 gate_size_t bytes_retrieved;
68 gate_size_t bytes_written;
69 ✗ gate_uint64_t copy_limit = 0;
70 ✗ gate_uint64_t bytes_copied = 0;
71 ✗ gate_uint64_t bytes_to_copy = 0;
72 ✗ gate_uint64_t input_position = 0;
73 ✗ gate_uint64_t output_position = 0;
74 ✗ char const* ptr_msg_buffer = NULL;
75 gate_strbuilder_t msg_builder;
76 char msg_buffer[1024];
77
78 do
79 {
80 ✗ if (!input || !output || !config)
81 {
82 ✗ return GATE_RESULT_NULLPOINTER;
83 }
84
85 ✗ if (input)
86 {
87 ✗ gate_object_retain(input);
88 }
89 ✗ if (output)
90 {
91 ✗ gate_object_retain(output);
92 }
93
94 ✗ block_size_backup = config->block_size;
95
96 ✗ if (config->block_size == 0)
97 {
98 ✗ block_size = sizeof(buffer);
99 }
100 else
101 {
102 ✗ block_size = config->block_size;
103 }
104 ✗ if (block_size > sizeof(buffer))
105 {
106 ✗ ptr_buffer = gate_mem_alloc(block_size);
107 ✗ if (ptr_buffer == NULL)
108 {
109 ✗ ret = GATE_RESULT_OUTOFMEMORY;
110 ✗ break;
111 }
112 }
113
114 ✗ if (GATE_OBJECT_IMPLEMENTS(input, GATE_INTERFACE_NAME_CONTROLSTREAM))
115 {
116 ✗ input_res = (gate_controlstream_t*)input;
117 }
118
119 ✗ if (GATE_OBJECT_IMPLEMENTS(output, GATE_INTERFACE_NAME_CONTROLSTREAM))
120 {
121 ✗ output_res = (gate_controlstream_t*)output;
122 }
123
124
125 ✗ if (config->read_offset != 0)
126 {
127 ✗ if (!input_res)
128 {
129 ✗ ret = GATE_RESULT_NOTSUPPORTED;
130 ✗ break;
131 }
132 else
133 {
134 ✗ ret = gate_stream_seek(input_res, (gate_int64_t)config->read_offset, GATE_STREAM_SEEK_BEGIN, &new_position);
135 ✗ GATE_BREAK_IF_FAILED(ret);
136 }
137 }
138
139 ✗ if (input_res)
140 {
141 ✗ ret = gate_stream_get_available(input_res, &config->total_available);
142 ✗ if (GATE_FAILED(ret))
143 {
144 ✗ config->total_available = 0;
145 }
146 }
147 else
148 {
149 ✗ config->total_available = 0;
150 }
151
152 ✗ if (config->copy_limit != 0)
153 {
154 ✗ config->total_available = config->copy_limit;
155 }
156
157
158 ✗ if (config->write_offset != 0)
159 {
160 ✗ if (!output_res)
161 {
162 ✗ ret = GATE_RESULT_NOTSUPPORTED;
163 ✗ break;
164 }
165 else
166 {
167 ✗ ret = gate_stream_seek(output_res, (gate_int64_t)config->write_offset, GATE_STREAM_SEEK_BEGIN, &new_position);
168 ✗ GATE_BREAK_IF_FAILED(ret);
169 }
170 }
171 ✗ output_position = config->write_offset;
172 ✗ copy_limit = config->copy_limit;
173 ✗ next_block_size = block_size;
174
175 ✗ while (gate_atomic_int_set(&config->cancel, 0) == 0)
176 {
177 ✗ ret = GATE_RESULT_OK;
178 ✗ if (copy_limit > 0)
179 {
180 ✗ bytes_to_copy = copy_limit - bytes_copied;
181 ✗ if (bytes_to_copy == 0)
182 {
183 /* copy job completed, limit reached */
184 ✗ break;
185 }
186 ✗ if (bytes_to_copy < block_size)
187 {
188 ✗ next_block_size = (gate_size_t)(bytes_to_copy - block_size);
189 }
190 else
191 {
192 ✗ next_block_size = block_size;
193 }
194 }
195
196 ✗ config->block_size = next_block_size;
197
198 ✗ input_position = config->read_offset + bytes_copied;
199 ✗ gate_mem_clear(ptr_buffer, next_block_size);
200 ✗ ret = gate_stream_read_block(input, ptr_buffer, next_block_size, &bytes_retrieved);
201 ✗ if (GATE_FAILED(ret))
202 {
203 /* error during read process */
204 ✗ if (config->callback)
205 {
206 ✗ gate_strbuilder_create_static(&msg_builder, msg_buffer, sizeof(msg_buffer), 0);
207 ✗ gate_strbuilder_append_cstr(&msg_builder, "Failed to read from source stream at position ");
208 ✗ gate_strbuilder_append_int64(&msg_builder, input_position);
209 ✗ gate_strbuilder_ptr(&msg_builder, 0);
210 ✗ config->callback(GATE_STREAM_COPIER_STATUS_INPUTERROR, input_position, bytes_copied,
211 ✗ ret, gate_strbuilder_ptr(&msg_builder, 0), config);
212 ✗ gate_strbuilder_release(&msg_builder);
213 }
214
215 ✗ if (!config->continue_on_read_errors || (input_res == NULL))
216 {
217 /* error cancels further execution */
218 break;
219 }
220
221 /* try to skip the block that could not be read */
222 ✗ ret = gate_stream_seek(input_res, (gate_int64_t)(input_position + next_block_size), GATE_STREAM_SEEK_BEGIN, NULL);
223 ✗ if (GATE_FAILED(ret))
224 {
225 ✗ if (config->callback)
226 {
227 ✗ config->callback(GATE_STREAM_COPIER_STATUS_INPUTERROR, input_position, bytes_copied,
228 ret, "Failed to skip gap in source stream", config);
229 }
230 /* error cancels further execution */
231 ✗ break;
232 }
233 /* ignoring read-errors -> write an empty buffer to target stream */
234 ✗ gate_mem_clear(ptr_buffer, next_block_size);
235 ✗ bytes_retrieved = next_block_size;
236 }
237
238 ✗ if (bytes_retrieved == 0)
239 {
240 /* end of stream reached */
241 ✗ break;
242 }
243
244 ✗ ret = gate_stream_write_block(output, ptr_buffer, bytes_retrieved, &bytes_written);
245 ✗ if (GATE_FAILED(ret))
246 {
247 /* error during write operation */
248 ✗ if (config->callback)
249 {
250 ✗ config->callback(GATE_STREAM_COPIER_STATUS_OUTPUTERROR, output_position, bytes_copied,
251 ret, "Failed to write to target stream", config);
252 }
253 ✗ if (!config->continue_on_write_errors || (input_res == NULL))
254 {
255 break;
256 }
257 else
258 {
259 /* try to skip block that could not be written to */
260 ✗ ret = gate_stream_seek(input_res, (gate_int64_t)(output_position + bytes_retrieved),
261 GATE_STREAM_SEEK_BEGIN, NULL);
262 ✗ if (GATE_FAILED(ret))
263 {
264 ✗ if (config->callback)
265 {
266 ✗ config->callback(GATE_STREAM_COPIER_STATUS_OUTPUTERROR,
267 output_position + bytes_retrieved, bytes_copied,
268 ret, "Failed to skip gap in target stream", config);
269 }
270 ✗ break;
271 }
272 ✗ bytes_written = bytes_retrieved;
273 }
274 }
275 ✗ output_position += bytes_written;
276
277 ✗ bytes_copied += bytes_retrieved;
278
279 ✗ if (config->callback)
280 {
281 ✗ config->callback(GATE_STREAM_COPIER_STATUS_PROGRESS, input_position, bytes_copied,
282 GATE_RESULT_OK, NULL, config);
283 }
284 }
285 } while (0);
286
287 ✗ if (output)
288 {
289 ✗ gate_object_release(output);
290 }
291 ✗ if (input)
292 {
293 ✗ gate_object_release(input);
294 }
295
296 ✗ if ((ptr_buffer != &buffer[0]) && (ptr_buffer != NULL))
297 {
298 ✗ gate_mem_dealloc(ptr_buffer);
299 }
300
301 ✗ config->block_size = block_size_backup;
302
303 ✗ if (config->callback)
304 {
305 ✗ config->callback(GATE_STREAM_COPIER_STATUS_COMPLETED, input_position, bytes_copied, ret, NULL, config);
306 }
307
308 ✗ if (result)
309 {
310 ✗ result->succeeded = GATE_SUCCEEDED(ret);
311 ✗ result->bytes_copied = bytes_copied;
312 ✗ result->error_message[0] = 0;
313 ✗ ptr_msg_buffer = gate_result_text(ret);
314 ✗ gate_str_print_text(result->error_message, sizeof(result->error_message),
315 ptr_msg_buffer, gate_str_length(ptr_msg_buffer));
316 }
317
318 ✗ return ret;
319 }
320
321 ✗ gate_result_t gate_stream_copier_cancel(gate_stream_copier_config_t* config)
322 {
323 ✗ if (config)
324 {
325 ✗ gate_atomic_int_set(&config->cancel, 1);
326 ✗ return GATE_RESULT_OK;
327 }
328 else
329 {
330 ✗ return GATE_RESULT_NULLPOINTER;
331 }
332 }
333
334