GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/copymachines.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 71 132 53.8%
Functions: 2 3 66.7%
Branches: 26 90 28.9%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2026, 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 1 gate_result_t gate_stream_copier_init(gate_stream_copier_config_t* config, void* user_param)
34 {
35
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (config)
36 {
37 1 gate_mem_clear(config, sizeof(gate_stream_copier_config_t));
38
39 1 config->block_size = GATE_MAX_COPYBUFFER_LENGTH;
40 1 config->copy_limit = 0; /* no limit */
41 1 config->read_offset = 0; /* at beginning */
42 1 config->write_offset = 0; /* at beginning */
43
44 1 gate_atomic_int_set(&config->cancel, 0);
45 1 config->user_param = user_param;
46 1 return GATE_RESULT_OK;
47 }
48 else
49 {
50 return GATE_RESULT_NULLPOINTER;
51 }
52 }
53
54 1 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 1 gate_result_t ret = GATE_RESULT_OK;
59 1 gate_controlstream_t* input_res = NULL;
60 1 gate_controlstream_t* output_res = NULL;
61 1 gate_int64_t new_position = 0;
62 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
63 1 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 1 gate_uint64_t copy_limit = 0;
70 1 gate_uint64_t bytes_copied = 0;
71 1 gate_uint64_t bytes_to_copy = 0;
72 1 gate_uint64_t input_position = 0;
73 1 gate_uint64_t output_position = 0;
74 1 char const* ptr_msg_buffer = NULL;
75 gate_strbuilder_t msg_builder;
76 char msg_buffer[1024];
77
78 do
79 {
80
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if (!input || !output || !config)
81 {
82 return GATE_RESULT_NULLPOINTER;
83 }
84
85
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (input)
86 {
87 1 gate_object_retain(input);
88 }
89
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (output)
90 {
91 1 gate_object_retain(output);
92 }
93
94 1 block_size_backup = config->block_size;
95
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (config->block_size == 0)
97 {
98 block_size = sizeof(buffer);
99 }
100 else
101 {
102 1 block_size = config->block_size;
103 }
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (GATE_OBJECT_IMPLEMENTS(input, GATE_INTERFACE_NAME_CONTROLSTREAM))
115 {
116 input_res = (gate_controlstream_t*)input;
117 }
118
119
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (GATE_OBJECT_IMPLEMENTS(output, GATE_INTERFACE_NAME_CONTROLSTREAM))
120 {
121 output_res = (gate_controlstream_t*)output;
122 }
123
124
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 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 1 config->total_available = 0;
150 }
151
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (config->copy_limit != 0)
153 {
154 config->total_available = config->copy_limit;
155 }
156
157
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 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 1 output_position = config->write_offset;
172 1 copy_limit = config->copy_limit;
173 1 next_block_size = block_size;
174
175
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 while (gate_atomic_int_set(&config->cancel, 0) == 0)
176 {
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (copy_limit > 0)
178 {
179 bytes_to_copy = copy_limit - bytes_copied;
180 if (bytes_to_copy == 0)
181 {
182 /* copy job completed, limit reached */
183 ret = GATE_RESULT_OK;
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 25 config->block_size = next_block_size;
197
198 25 input_position = config->read_offset + bytes_copied;
199 25 gate_mem_clear(ptr_buffer, next_block_size);
200 25 ret = gate_stream_read_block(input, ptr_buffer, next_block_size, &bytes_retrieved);
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 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
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 24 times.
25 if (bytes_retrieved == 0)
239 {
240 /* end of stream reached */
241 1 break;
242 }
243
244 24 ret = gate_stream_write_block(output, ptr_buffer, bytes_retrieved, &bytes_written);
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 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 24 output_position += bytes_written;
276
277 24 bytes_copied += bytes_retrieved;
278
279
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (config->callback)
280 {
281 24 config->callback(GATE_STREAM_COPIER_STATUS_PROGRESS, input_position, bytes_copied,
282 GATE_RESULT_OK, NULL, config);
283 }
284 }
285 } while (0);
286
287
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (output)
288 {
289 1 gate_object_release(output);
290 }
291
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (input)
292 {
293 1 gate_object_release(input);
294 }
295
296
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if ((ptr_buffer != &buffer[0]) && (ptr_buffer != NULL))
297 {
298 gate_mem_dealloc(ptr_buffer);
299 }
300
301 1 config->block_size = block_size_backup;
302
303
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (config->callback)
304 {
305 1 config->callback(GATE_STREAM_COPIER_STATUS_COMPLETED, input_position, bytes_copied, ret, NULL, config);
306 }
307
308
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (result)
309 {
310 1 result->succeeded = GATE_SUCCEEDED(ret);
311 1 result->bytes_copied = bytes_copied;
312 1 result->error_message[0] = 0;
313 1 ptr_msg_buffer = gate_result_text(ret);
314 1 gate_str_print_text(result->error_message, sizeof(result->error_message),
315 ptr_msg_buffer, gate_str_length(ptr_msg_buffer));
316 }
317
318 1 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