GCC Code Coverage Report


Directory: src/gate/
File: src/gate/files.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 702 887 79.1%
Functions: 57 63 90.5%
Branches: 324 602 53.8%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
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 #include "gate/files.h"
29 #include "gate/results.h"
30 #include "gate/atomics.h"
31 #include "gate/debugging.h"
32 #include "gate/utilities.h"
33
34
35 #if defined(GATE_SYS_WIN)
36 # define GATE_CORE_FILES_WINAPI_IMPL 1
37 #elif defined(GATE_SYS_WASM)
38 # define GATE_CORE_FILES_WASM_IMPL 1
39 #elif defined(GATE_SYS_POSIX)
40 # define GATE_CORE_FILES_POSIX_IMPL 1
41 #elif defined(GATE_SYS_DOS)
42 # define GATE_CORE_FILES_DOS_IMPL 1
43 #elif defined(GATE_SYS_EFI)
44 # define GATE_CORE_FILES_EFI_IMPL 1
45 #else
46 # define GATE_CORE_FILES_NO_IMPL 1
47 #endif
48
49 136 static gate_bool_t gate_file_is_hidden_entry(gate_string_t const* path)
50 {
51
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 136 times.
136 if (gate_string_is_empty(path))
52 {
53 return true; /* empty paths are invalid and therefore hidden */
54 }
55 else
56 {
57 136 const gate_size_t path_separator_found = gate_string_char_pos_last(
58 path, gate_file_path_separator_char);
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 if (path_separator_found == GATE_STR_NPOS)
60 {
61 /* filename only */
62 return gate_string_starts_with_char(path, '.');
63 }
64 else
65 {
66 /* path */
67 136 return path->str[path_separator_found + 1] == '.';
68 }
69 }
70 }
71
72 15 char GATE_CALL gate_file_path_separator_character(void)
73 {
74 15 return gate_file_path_separator_char;
75 }
76
77 360 gate_size_t gate_file_build_path(char* dest, gate_size_t dest_size, char const* path, gate_size_t path_size,
78 char const* subpath, gate_size_t subpath_size)
79 {
80 360 gate_size_t ret = 0;
81 gate_size_t len;
82
83
1/2
✓ Branch 0 taken 380 times.
✗ Branch 1 not taken.
380 while (path_size > 0)
84 {
85
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 20 times.
380 if (path[path_size - 1] != gate_file_path_separator_char)
86 {
87 360 break;
88 }
89 20 --path_size;
90 }
91
1/2
✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
360 while (subpath_size > 0)
92 {
93
1/2
✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
360 if (subpath[0] != gate_file_path_separator_char)
94 {
95 360 break;
96 }
97 ++subpath;
98 --subpath_size;
99 }
100
101 360 ret = gate_str_print_text(dest, dest_size, path, path_size);
102 360 len = gate_str_print_text(&dest[ret], dest_size - ret, &gate_file_path_separator_char, 1);
103 360 ret += len;
104 360 len = gate_str_print_text(&dest[ret], dest_size - ret, subpath, subpath_size);
105 360 ret += len;
106 360 return ret;
107 }
108
109 12 gate_string_t* gate_file_build_path_string(gate_string_t* dest, gate_string_t const* path, gate_string_t const* subpath)
110 {
111 12 gate_string_t* ret = NULL;
112 12 gate_size_t path_len = gate_string_length(path);
113 12 gate_size_t subpath_len = gate_string_length(subpath);
114 12 gate_strbuilder_t builder = GATE_INIT_EMPTY;
115 12 gate_string_t strs[2] = GATE_INIT_EMPTY;
116 gate_result_t result;
117
118 do
119 {
120 12 gate_string_duplicate(&strs[0], path);
121 12 gate_string_duplicate(&strs[1], subpath);
122
123 12 gate_strbuilder_create(&builder, path_len + subpath_len + 2);
124
125 12 result = gate_file_build_path_components(&builder, gate_file_path_separator_char, strs, sizeof(strs) / sizeof(strs[0]));
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 GATE_BREAK_IF_FAILED(result);
127
128 12 ret = gate_strbuilder_to_string(&builder, dest);
129
130 } while (0);
131
132 12 gate_string_release(&strs[1]);
133 12 gate_string_release(&strs[0]);
134
135 12 gate_strbuilder_release(&builder);
136 12 return ret;
137 }
138
139 12 gate_result_t gate_file_build_path_components(gate_strbuilder_t* builder, char separator_char,
140 gate_string_t const* component_array, gate_size_t component_array_length)
141 {
142 12 gate_result_t ret = GATE_RESULT_OK;
143 gate_size_t ndx;
144 gate_string_t separator;
145
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (separator_char == 0)
147 {
148 separator_char = gate_file_path_separator_char;
149 }
150
151 12 gate_string_create_static_len(&separator, &separator_char, 1);
152
153
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (ndx = 0; ndx != component_array_length; ++ndx)
154 {
155 24 gate_string_t const* ptr_str = &component_array[ndx];
156 24 gate_size_t pos = 0;
157 24 gate_size_t pos_end = gate_string_find_last_not_of(ptr_str, &separator);
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (pos_end == GATE_STR_NPOS)
159 {
160 continue;
161 }
162
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (ndx != 0)
163 {
164 12 pos = gate_string_find_first_not_of(ptr_str, &separator, 0);
165 12 gate_strbuilder_append_text(builder, &separator_char, 1);
166 }
167 24 gate_strbuilder_append_text(builder, gate_string_ptr(ptr_str, pos), pos_end - pos + 1);
168 }
169 12 return ret;
170 }
171
172 11 gate_result_t gate_file_split_path(gate_string_t const* src_path, gate_string_t* parent_path, gate_string_t* name)
173 {
174 11 char const* ptr = src_path->str;
175 11 gate_size_t len = src_path->length;
176 gate_size_t parent_len;
177
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 while (len > 0)
178 {
179
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (ptr[len - 1] != gate_file_path_separator_char)
180 {
181 11 break;
182 }
183 1 --len;
184 }
185
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 1 times.
136 for (parent_len = len; parent_len > 0; --parent_len)
186 {
187
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 125 times.
135 if (ptr[parent_len - 1] == gate_file_path_separator_char)
188 {
189
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
10 if (parent_path)
190 {
191 7 gate_string_substr(parent_path, src_path, 0, parent_len);
192 }
193
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
10 if (name)
194 {
195 7 gate_string_substr(name, src_path, parent_len, len - parent_len);
196 }
197 10 return GATE_RESULT_OK;
198 }
199 }
200 1 return GATE_RESULT_NOMATCH;
201 }
202
203 1 gate_size_t gate_file_split_path_components(gate_string_t const* src_path, char separator_char,
204 gate_string_t* out_array, gate_size_t out_array_capacity)
205 {
206 1 gate_size_t ret = 0;
207 1 gate_string_t separator = GATE_STRING_INIT_EMPTY;
208 gate_size_t pos;
209 gate_size_t pos_end;
210 1 gate_string_t path = GATE_STRING_INIT_EMPTY;
211
212 do
213 {
214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (separator_char == 0)
215 {
216 separator_char = gate_file_path_separator_char;
217 }
218
219 1 gate_string_create_static_len(&separator, &separator_char, 1);
220 1 pos = gate_string_find_first_not_of(src_path, &separator, 0);
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (pos == GATE_STR_NPOS)
222 {
223 /* path-less string */
224 ret = 0;
225 break;
226 }
227 1 pos_end = gate_string_find_last_not_of(src_path, &separator);
228 1 gate_string_substr(&path, src_path, pos, pos_end - pos + 1);
229
230 1 pos = 0;
231
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 while (ret < out_array_capacity)
232 {
233 3 pos_end = gate_string_char_pos(&path, separator_char, pos);
234
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
3 if ((pos_end == GATE_STR_NPOS) || (ret == out_array_capacity - 1))
235 {
236 /* last component found */
237 1 gate_string_substr(&out_array[ret], &path, pos, GATE_STR_NPOS);
238 1 ++ret;
239 1 break;
240 }
241
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (pos_end > pos) /* ignore double separator occurences */
242 {
243 2 gate_string_substr(&out_array[ret], &path, pos, pos_end - pos);
244 2 ++ret;
245 }
246 2 pos = pos_end + 1;
247 }
248
249 } while (0);
250
251 1 gate_string_release(&path);
252 1 gate_string_release(&separator);
253
254 1 return ret;
255 }
256
257 2 gate_result_t gate_file_extract_path(char const* src_path, gate_size_t src_path_len,
258 char* name_buffer, gate_size_t name_buffer_len,
259 char* parent_buffer, gate_size_t parent_buffer_len)
260 {
261 2 char const* ptr = src_path;
262 2 gate_size_t len = src_path_len;
263 gate_size_t parent_len;
264
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 while (len > 0)
265 {
266
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ptr[len - 1] != gate_file_path_separator_char)
267 {
268 2 break;
269 }
270 --len;
271 }
272
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 for (parent_len = len; parent_len > 0; --parent_len)
273 {
274
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (ptr[parent_len - 1] == gate_file_path_separator_char)
275 {
276
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (name_buffer && name_buffer_len > 0)
277 {
278 2 gate_str_print_text(name_buffer, name_buffer_len, &ptr[parent_len], len - parent_len);
279 }
280
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (parent_buffer && parent_buffer_len > 0)
281 {
282 2 gate_str_print_text(parent_buffer, parent_buffer_len, ptr, parent_len - 1);
283 }
284 2 return GATE_RESULT_OK;
285 }
286 }
287 return GATE_RESULT_NOMATCH;
288 }
289
290 1 gate_result_t gate_file_extract_path_string(gate_string_t const* src_path, gate_string_t* name, gate_string_t* parent)
291 {
292 char namebuffer[GATE_MAX_FILENAME_LENGTH];
293 char parentbuffer[GATE_MAX_FILEPATH_LENGTH];
294 gate_result_t result;
295
296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(src_path != NULL);
297
298 2 result = gate_file_extract_path(
299 1 gate_string_ptr(src_path, 0), gate_string_length(src_path),
300 namebuffer, sizeof(namebuffer),
301 parentbuffer, sizeof(parentbuffer)
302 );
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_RETURN_IF_FAILED(result);
304
305
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (name != NULL)
306 {
307
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (NULL == gate_string_create(name, namebuffer, gate_str_length_max(namebuffer, sizeof(namebuffer))))
308 {
309 return GATE_RESULT_OUTOFMEMORY;
310 }
311 }
312
313
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (parent != NULL)
314 {
315
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (NULL == gate_string_create(parent, parentbuffer, gate_str_length_max(parentbuffer, sizeof(parentbuffer))))
316 {
317 if (name)
318 {
319 gate_string_release(name);
320 }
321 return GATE_RESULT_OUTOFMEMORY;
322 }
323 }
324 1 return GATE_RESULT_OK;
325 }
326
327 1 static gate_result_t gate_file_copy_internal(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
328 {
329 gate_result_t ret;
330 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
331 1 gate_file_t src_handle = GATE_FILE_INVALID;
332 1 gate_file_t dst_handle = GATE_FILE_INVALID;
333 gate_size_t bytes_read;
334 gate_size_t bytes_written;
335 gate_size_t bytes_copied;
336
337 do
338 {
339
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!GATE_FLAG_ENABLED(flags, GATE_FILE_COPY_OVERWRITE))
340 {
341 1 ret = gate_file_exists(dstfilepath);
342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_SUCCEEDED(ret))
343 {
344 ret = GATE_RESULT_ALREADYEXISTS;
345 break;
346 }
347 }
348 1 ret = gate_file_open(srcfilepath, GATE_STREAM_OPEN_READ, &src_handle);
349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
350 1 ret = gate_file_open(dstfilepath, GATE_STREAM_OPEN_WRITE, &dst_handle);
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
352
353
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 while (GATE_SUCCEEDED(ret))
354 {
355 2 bytes_read = 0;
356 2 ret = gate_file_read(src_handle, buffer, sizeof(buffer), &bytes_read);
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
358
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (bytes_read == 0)
359 {
360 1 break;
361 }
362 1 bytes_copied = 0;
363
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 while (bytes_copied < bytes_read)
364 {
365 1 ret = gate_file_write(dst_handle, &buffer[bytes_copied], bytes_read - bytes_copied, &bytes_written);
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
367 1 bytes_copied += bytes_written;
368 }
369 }
370
371 } while (0);
372
373
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (src_handle != GATE_FILE_INVALID)
374 {
375 1 gate_file_close(src_handle);
376 }
377
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (dst_handle != GATE_FILE_INVALID)
378 {
379 1 gate_file_close(dst_handle);
380 }
381 1 return ret;
382 }
383
384 static gate_result_t gate_file_move_internal(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
385 {
386 gate_result_t ret;
387 ret = gate_file_copy(srcfilepath, dstfilepath, 0);
388 if (GATE_SUCCEEDED(ret))
389 {
390 ret = gate_file_delete(srcfilepath);
391 }
392 return ret;
393 }
394
395
396 1 static gate_result_t gate_file_copy_list_create_path(gate_string_t const* path)
397 {
398 1 gate_string_t parent = GATE_STRING_INIT_EMPTY;
399 gate_result_t ret;
400 1 ret = gate_file_exists(path);
401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(ret))
402 {
403 ret = gate_file_split_path(path, &parent, NULL);
404 if (GATE_SUCCEEDED(ret))
405 {
406 ret = gate_file_copy_list_create_path(&parent);
407 if (GATE_SUCCEEDED(ret))
408 {
409 ret = gate_file_dir_create(path, GATE_FILE_DIR_CREATE_DEFAULT);
410 }
411 gate_string_release(&parent);
412 }
413 }
414 1 return ret;
415 }
416
417 1 static gate_result_t gate_file_copy_list_entry(gate_string_t const* source, gate_string_t const* dest,
418 gate_set_t* existing_dirs, gate_enumint_t flags)
419 {
420 1 gate_result_t ret = GATE_RESULT_FAILED;
421 1 gate_string_t dest_parent = GATE_STRING_INIT_EMPTY;
422
423 do
424 {
425 1 ret = gate_file_split_path(dest, &dest_parent, NULL);
426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
427
428
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (!gate_set_iterator_valid(gate_set_get(existing_dirs, &dest_parent)))
429 {
430 1 ret = gate_file_copy_list_create_path(&dest_parent);
431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
432 1 gate_set_add(existing_dirs, &dest_parent);
433 }
434 1 ret = gate_file_copy(source, dest, flags);
435 } while (0);
436
437 1 gate_string_release(&dest_parent);
438 1 return ret;
439 }
440
441 1 gate_result_t gate_file_copy_list(gate_map_t const* path_map, gate_enumint_t flags,
442 gate_file_copy_list_callback callback, void* user_param)
443 {
444 1 gate_result_t ret = GATE_RESULT_FAILED;
445 gate_result_t result;
446 1 gate_set_t existing_dirs = GATE_INIT_EMPTY;
447 gate_map_iterator_t iter;
448 gate_string_t const* source;
449 gate_string_t const* dest;
450 char source_buffer[GATE_MAX_COPYBUFFER_LENGTH];
451 char dest_buffer[GATE_MAX_COPYBUFFER_LENGTH];
452 do
453 {
454
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == gate_util_stringset_create(&existing_dirs))
455 {
456 ret = GATE_RESULT_OUTOFMEMORY;
457 break;
458 }
459
460 1 ret = GATE_RESULT_OK;
461
2/2
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
2 for (iter = gate_map_first(path_map); gate_map_iterator_valid(iter); iter = gate_map_iterator_next(iter))
462 {
463 1 source = (gate_string_t const*)gate_map_iterator_key(iter);
464 1 dest = (gate_string_t const*)gate_map_iterator_value(iter);
465
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (source && dest)
466 {
467 1 result = gate_file_copy_list_entry(source, dest, &existing_dirs, flags);
468
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (callback)
469 {
470 1 gate_string_to_buffer(source, source_buffer, sizeof(source_buffer));
471 1 gate_string_to_buffer(dest, dest_buffer, sizeof(dest_buffer));
472
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!callback(source_buffer, dest_buffer, result, user_param))
473 {
474 break;
475 }
476 }
477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (GATE_FAILED(result))
478 {
479 if (!GATE_FLAG_ENABLED(flags, GATE_FILE_COPY_IGNORE_ERROR))
480 {
481 ret = result;
482 break;
483 }
484 }
485 }
486 }
487 } while (0);
488
489 1 gate_map_destroy(&existing_dirs);
490
491 1 return ret;
492 }
493
494 2 gate_result_t gate_file_dir_delete_recursive(gate_string_t const* dirpath)
495 {
496 gate_result_t result;
497 gate_file_dirreader_t reader;
498 char path[GATE_MAX_FILEPATH_LENGTH];
499 gate_size_t path_len;
500 2 gate_string_t entry = GATE_STRING_INIT_EMPTY;
501
502 do
503 {
504 2 result = gate_file_dir_exists(dirpath);
505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(result);
506
507 2 result = gate_file_dir_open(dirpath, &reader);
508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(result);
509
510
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
6 while (0 != (path_len = gate_file_dir_read(&reader, path, sizeof(path), false)))
511 {
512 4 gate_string_create_static_len(&entry, path, path_len);
513 4 result = gate_file_dir_exists(&entry);
514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_SUCCEEDED(result))
515 {
516 /* subdirectory */
517 result = gate_file_dir_delete_recursive(&entry);
518 }
519 else
520 {
521 /* file */
522 4 result = gate_file_delete(&entry);
523 }
524 4 gate_string_release(&entry);
525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 GATE_BREAK_IF_FAILED(result);
526 }
527
528 2 gate_file_dir_close(&reader);
529
530
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(result);
531
532 2 result = gate_file_dir_delete(dirpath);
533
534 } while (0);
535 2 return result;
536 }
537
538
539
540
541 struct gate_file_find_param
542 {
543 gate_file_filter_t const* filter;
544 gate_file_list_callback_t callback;
545 void* userparam;
546 };
547
548 30 static gate_bool_t GATE_CALL gate_file_find_callback(gate_file_entry_t const* entry, void* userparam)
549 {
550 30 struct gate_file_find_param* param = (struct gate_file_find_param*)userparam;
551 gate_string_t path;
552 30 gate_bool_t ret = true;
553 30 gate_bool_t is_dir = GATE_FLAG_ENABLED(entry->props.attribs, GATE_FILEENTRY_ATTRIB_DIRECTORY);
554
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (param->filter)
555 {
556 30 gate_string_create_static(&path, entry->path);
557
558 do
559 {
560
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 if (!gate_string_is_empty(&param->filter->pattern))
561 {
562
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 if (!gate_string_like_one_of(&path, &param->filter->pattern, ';'))
563 {
564 break;
565 }
566 }
567
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 1 times.
30 if (!is_dir)
568 {
569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (param->filter->from_size > 0)
570 {
571 if (entry->props.size < param->filter->from_size)
572 {
573 break;
574 }
575 }
576
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (param->filter->to_size != 0)
577 {
578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (entry->props.size > param->filter->to_size)
579 {
580 break;
581 }
582 }
583 }
584
585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (entry->props.time_modified < param->filter->from_modified)
586 {
587 break;
588 }
589
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
30 if ((param->filter->to_modified != 0) && (entry->props.time_modified > param->filter->to_modified))
590 {
591 break;
592 }
593
594
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (param->filter->from_size > 0)
595 {
596 if (entry->props.size < param->filter->from_size)
597 {
598 break;
599 }
600 }
601
602 30 ret = param->callback(entry, param->userparam);
603
604 } while (0);
605
606
3/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 29 times.
30 if (param->filter->recursive && is_dir)
607 {
608 1 gate_file_find(&path, param->filter, param->callback, param->userparam);
609 }
610 }
611 else
612 {
613 ret = param->callback(entry, param->userparam);
614 }
615 30 return ret;
616 }
617
618 2 gate_result_t gate_file_find(gate_string_t const* dirpath, gate_file_filter_t const* filter,
619 gate_file_list_callback_t callback, void* userparam)
620 {
621 struct gate_file_find_param param;
622 2 param.filter = filter;
623 2 param.callback = callback;
624 2 param.userparam = userparam;
625
626 2 return gate_file_list(dirpath, &gate_file_find_callback, &param);
627 }
628
629 11 gate_result_t gate_file_dir_create_all(gate_string_t const* dirpath, gate_enumint_t flags)
630 {
631 gate_result_t ret;
632 11 gate_string_t parent = GATE_STRING_INIT_EMPTY;
633 11 gate_string_t name = GATE_STRING_INIT_EMPTY;
634
635 do
636 {
637 11 ret = gate_file_dir_exists(dirpath);
638
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (GATE_SUCCEEDED(ret))
639 {
640 /* path does already exist -> nothing to do */
641 9 break;
642 }
643
644 2 ret = gate_file_split_path(dirpath, &parent, &name);
645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
646
647 /* ensure that parents exist */
648 2 ret = gate_file_dir_create_all(&parent, flags);
649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
650
651 /* now try to create the deepest path component */
652 2 ret = gate_file_dir_create(dirpath, flags);
653 } while (0);
654
655 11 gate_string_release(&parent);
656 11 gate_string_release(&name);
657 11 return ret;
658 }
659
660
661 87 gate_result_t gate_file_get_content_buffer(gate_string_t const* filepath, char* content_buffer, gate_size_t* content_buffer_len)
662 {
663 gate_result_t ret;
664 87 gate_file_t filehandle = GATE_FILE_INVALID;
665 87 gate_size_t copied = 0;
666 87 gate_size_t bufferlen = *content_buffer_len;
667 gate_size_t bufferused;
668
669 do
670 {
671
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 82 times.
87 GATE_BREAK_IF_FAILED(ret = gate_file_open(filepath, GATE_STREAM_OPEN_READ, &filehandle));
672
1/2
✓ Branch 0 taken 164 times.
✗ Branch 1 not taken.
164 while (copied < bufferlen)
673 {
674
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
164 GATE_BREAK_IF_FAILED(ret = gate_file_read(filehandle, &content_buffer[copied], bufferlen - copied, &bufferused));
675
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 82 times.
164 if (bufferused == 0) break;
676 82 copied += bufferused;
677 }
678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 GATE_BREAK_IF_FAILED(ret);
679
680 /* success case: */
681 82 *content_buffer_len = copied;
682 82 ret = GATE_RESULT_OK;
683 } while (0);
684
685
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 5 times.
87 if (filehandle != GATE_FILE_INVALID)
686 {
687 82 gate_file_close(filehandle);
688 }
689 87 return ret;
690 }
691
692
693 2 gate_result_t gate_file_get_content(gate_string_t const* filepath, gate_string_t* content_buffer)
694 {
695 gate_result_t ret;
696 2 gate_file_t filehandle = GATE_FILE_INVALID;
697 gate_int64_t filesize;
698 2 gate_int64_t copied = 0;
699 gate_strbuilder_t builder;
700 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
701 gate_size_t bufferused;
702
703 2 gate_strbuilder_create(&builder, 0);
704
705 do
706 {
707
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret = gate_file_open(filepath, GATE_STREAM_OPEN_READ, &filehandle));
708
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret = gate_file_size(filehandle, &filesize));
709
710 2 gate_strbuilder_create(&builder, (gate_size_t)filesize);
711
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 while (copied != filesize)
712 {
713
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret = gate_file_read(filehandle, buffer, sizeof(buffer), &bufferused));
714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (bufferused == 0) break;
715
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (0 == gate_strbuilder_append_text(&builder, buffer, bufferused))
716 {
717 ret = GATE_RESULT_OUTOFMEMORY;
718 break;
719 }
720 2 copied += bufferused;
721 }
722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
723
724
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (NULL == gate_strbuilder_to_string(&builder, content_buffer))
725 {
726 ret = GATE_RESULT_OUTOFMEMORY;
727 break;
728 }
729
730 /* success case: */
731 2 ret = GATE_RESULT_OK;
732 } while (0);
733
734
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (filehandle != GATE_FILE_INVALID)
735 {
736 2 gate_file_close(filehandle);
737 }
738 2 gate_strbuilder_release(&builder);
739
740 2 return ret;
741 }
742 1 gate_result_t gate_file_get_content_lines(gate_string_t const* filepath, gate_arraylist_t string_array)
743 {
744 1 gate_result_t ret = GATE_RESULT_FAILED;
745 char buffer[GATE_MAX_COPYBUFFER_LENGTH * 3];
746 gate_size_t bufferused;
747 1 gate_controlstream_t* stream = NULL;
748 gate_string_t line;
749
750 do
751 {
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (string_array == NULL)
753 {
754 ret = GATE_RESULT_NULLPOINTER;
755 break;
756 }
757
758 1 ret = gate_file_openstream(filepath, GATE_STREAM_OPEN_READ, &stream);
759
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
760
761
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 while (GATE_SUCCEEDED(ret = gate_stream_read_line((gate_stream_t*)stream, buffer, sizeof(buffer), &bufferused)))
762 {
763
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (bufferused == 0)
764 {
765 1 break;
766 }
767
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (buffer[bufferused - 1] == '\n')
768 {
769 1 --bufferused;
770 }
771
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
2 if ((bufferused != 0) && (buffer[bufferused - 1] == '\r'))
772 {
773 1 --bufferused;
774 }
775
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (NULL != gate_string_create(&line, buffer, bufferused))
776 {
777 2 gate_util_stringarray_add(string_array, &line);
778 2 gate_string_release(&line);
779 }
780 }
781 } while (0);
782
783
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stream != NULL)
784 {
785 1 gate_object_release(stream);
786 }
787 1 return ret;
788 }
789
790 7 static gate_result_t gate_file_write_block(gate_file_t filehandle, gate_string_t const* content_buffer)
791 {
792 7 gate_result_t ret = GATE_RESULT_OK;
793 7 gate_size_t pos = 0;
794 gate_size_t written;
795
796
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 while (pos < content_buffer->length)
797 {
798 7 ret = gate_file_write(filehandle, &content_buffer->str[pos], content_buffer->length - pos, &written);
799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 GATE_BREAK_IF_FAILED(ret);
800 7 pos += written;
801 }
802 7 return ret;
803 }
804
805 3 gate_result_t gate_file_set_content(gate_string_t const* filepath, gate_string_t const* content_buffer)
806 {
807 gate_result_t ret;
808 3 gate_file_t filehandle = GATE_FILE_INVALID;
809
810
811 do
812 {
813 3 ret = gate_file_open(filepath, GATE_STREAM_OPEN_WRITE, &filehandle);
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 GATE_BREAK_IF_FAILED(ret);
815 3 ret = gate_file_write_block(filehandle, content_buffer);
816 } while (0);
817
818
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (filehandle != GATE_FILE_INVALID)
819 {
820 3 gate_file_close(filehandle);
821 }
822
823 3 return ret;
824 }
825
826 1 gate_result_t gate_file_set_content_buffer(gate_string_t const* filepath, char const* content_buffer, gate_size_t content_buffer_len)
827 {
828 gate_result_t ret;
829 1 gate_string_t text = GATE_STRING_INIT_EMPTY;
830
831 1 gate_string_create_static_len(&text, content_buffer, content_buffer_len);
832 1 ret = gate_file_set_content(filepath, &text);
833 1 gate_string_release(&text);
834
835 1 return ret;
836 }
837
838 1 gate_result_t gate_file_set_content_lines(gate_string_t const* filepath, gate_arraylist_t string_array)
839 {
840 gate_result_t ret;
841 1 gate_file_t filehandle = GATE_FILE_INVALID;
842 1 gate_size_t count = gate_arraylist_length(string_array);
843 gate_size_t index;
844 gate_string_t const* ptr;
845 static gate_string_t const new_line = { GATE_STR_NEWLINE, GATE_STR_NEWLINE_LENGTH, NULL };
846
847 do
848 {
849 1 ret = gate_file_open(filepath, GATE_STREAM_OPEN_WRITE, &filehandle);
850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_BREAK_IF_FAILED(ret);
851
852
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (index = 0; index != count; ++index)
853 {
854 2 ptr = (gate_string_t const*)gate_arraylist_get(string_array, index);
855 2 ret = gate_file_write_block(filehandle, ptr);
856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
857 2 ret = gate_file_write_block(filehandle, &new_line);
858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
859 }
860 } while (0);
861
862
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (filehandle != GATE_FILE_INVALID)
863 {
864 1 gate_file_close(filehandle);
865 }
866
867 1 return ret;
868 }
869
870
871
872 #if defined(GATE_CORE_FILES_WINAPI_IMPL)
873
874 #include "gate/platforms.h"
875 #include "gate/memalloc.h"
876 #include "gate/strings.h"
877
878 #if defined(GATE_COMPILER_MSVC) && !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WINSTORE)
879 #pragma comment(lib, "Mpr.lib")
880 #endif
881
882 GATE_CORE_API char const gate_file_path_separator_char = '\\';
883 GATE_CORE_API char const* const gate_file_path_separator = "\\";
884
885 #if defined(GATE_SYS_WINSTORE)
886 # define MoveFile(lpExistingFileName, lpNewFileName) MoveFileEx(lpExistingFileName, lpNewFileName, (MOVEFILE_COPY_ALLOWED))
887 #endif
888
889 #if defined(GATE_SYS_WIN16)
890 # include <direct.h>
891 # include <tchar.h>
892
893
894 static DWORD WINAPI GetLogicalDrives()
895 {
896 DWORD ret = 0;
897 int n;
898 UINT tp;
899 for (n = 0; n < 25; ++n)
900 {
901 tp = GetDriveType(n);
902 if (tp != 0)
903 {
904 ret |= (DWORD)(1UL << n);
905 }
906 }
907 return ret;
908 }
909
910 #endif
911
912 typedef WORD GATE_FILEOP_FLAGS;
913
914 typedef struct _GATE_SHFILEOPSTRUCT
915 {
916 HWND hwnd;
917 UINT wFunc;
918 TCHAR const* pFrom; /* terminated by double zero */
919 TCHAR const* pTo; /* terminated by double zero */
920 GATE_FILEOP_FLAGS fFlags;
921 BOOL fAnyOperationsAborted;
922 LPVOID hNameMappings;
923 PCSTR lpszProgressTitle;
924 } GATE_SHFILEOPSTRUCT, * GATE_LPSHFILEOPSTRUCT;
925
926 #if defined(GATE_WIN32_UNICODE)
927 # define shell32_shfileop_name "SHFileOperationW"
928 #else
929 # define shell32_shfileop_name "SHFileOperationA"
930 #endif
931
932 typedef int(WINAPI* shell32_shfileop_t)(GATE_LPSHFILEOPSTRUCT lpFileOp);
933 static shell32_shfileop_t shell32_shfileop = NULL;
934 static gate_atomic_flag_t shell32_shfileop_loaded = GATE_ATOMIC_FLAG_INIT;
935
936 #define GATE_WIN32_SHFILEOP_MOVE 0x0001
937 #define GATE_WIN32_SHFILEOP_COPY 0x0002
938 #define GATE_WIN32_SHFILEOP_DELETE 0x0003
939 #define GATE_WIN32_SHFILEOP_RENAME 0x0004
940
941
942 #ifndef FOF_SILENT
943 #define FOF_SILENT 0x0004
944 #endif
945 #ifndef FOF_NOCONFIRMATION
946 #define FOF_NOCONFIRMATION 0x0010
947 #endif
948 #ifndef FOF_NOCONFIRMMKDIR
949 #define FOF_NOCONFIRMMKDIR 0x0200
950 #endif
951 #ifndef FOF_NOERRORUI
952 #define FOF_NOERRORUI 0x0400
953 #endif
954 #ifndef FOF_NORECURSION
955 #define FOF_NORECURSION 0x1000
956 #endif
957 #ifndef FOF_NO_UI
958 #define FOF_NO_UI (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR)
959 #endif
960
961 static gate_bool_t load_shell32_shfileop()
962 {
963 HMODULE hmod_shell32 = gate_win32_get_shell_module();
964
965 if (hmod_shell32)
966 {
967 if (!gate_atomic_flag_set(&shell32_shfileop_loaded))
968 {
969 // execute only once:
970 gate_win32_get_proc_address(hmod_shell32, shell32_shfileop_name, &shell32_shfileop);
971 }
972 }
973 return shell32_shfileop != NULL;
974 }
975
976 static gate_bool_t gate_win32_shfileop(unsigned operation, TCHAR const* fromZZ, TCHAR const* toZZ)
977 {
978 GATE_SHFILEOPSTRUCT fileop;
979 int result;
980
981 if (!load_shell32_shfileop())
982 {
983 return false;
984 }
985
986 gate_mem_clear(&fileop, sizeof(fileop));
987 fileop.hwnd = (HWND)NULL;
988 fileop.wFunc = operation;
989 fileop.pFrom = fromZZ;
990 fileop.pTo = toZZ;
991 fileop.fFlags = FOF_NORECURSION | FOF_NO_UI;
992 result = shell32_shfileop(&fileop);
993 return result == 0;
994 }
995
996
997 #if defined(GATE_SYS_WIN16)
998
999 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
1000 {
1001 char path[GATE_MAX_FILEPATH_LENGTH];
1002 gate_platform_stream_t ps;
1003 gate_result_t result;
1004
1005 gate_string_to_buffer(filepath, path, sizeof(path));
1006 result = gate_platform_stream_open(path, flags, 0, &ps);
1007 if (GATE_SUCCEEDED(result) && filehandle)
1008 {
1009 *filehandle = (gate_file_t)ps;
1010 }
1011 return result;
1012 }
1013
1014 #else /* !defined(GATE_SYS_WIN16) */
1015
1016
1017 #ifndef SECURITY_WORLD_SID_AUTHORITY
1018 #define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1}
1019 #endif
1020
1021 #ifndef SECURITY_NT_AUTHORITY
1022 #define SECURITY_NT_AUTHORITY {0,0,0,0,0,5}
1023 #endif
1024
1025 static const SID_IDENTIFIER_AUTHORITY gate_win32_world_sid = { SECURITY_WORLD_SID_AUTHORITY };
1026 static const SID_IDENTIFIER_AUTHORITY gate_win32_nt_sid = { SECURITY_NT_AUTHORITY };
1027
1028 static LPSECURITY_ATTRIBUTES gate_win32_create_security_attribs(
1029 gate_enumint_t flags, LPSECURITY_ATTRIBUTES secattributes,
1030 gate_win32_sidstruct_t* sidowner, gate_win32_sidstruct_t* sidgroup, gate_win32_sidstruct_t* sideveryone,
1031 SECURITY_DESCRIPTOR* secdescr, BYTE* aclBuffer)
1032 {
1033 LPSECURITY_ATTRIBUTES ret = NULL; /* by default or in error cases -> inherit default security descriptor */
1034 gate_bool_t restrictowner = GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEOWNERRESTRICTED);
1035 gate_bool_t restrictgroup = GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEGROUPRESTRICTED);
1036 gate_bool_t unrestricted = GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEUNRESTRICTED);
1037
1038 if (!restrictowner && !restrictgroup && !unrestricted)
1039 {
1040 /* return NULL to inherit default security descriptor */
1041 GATE_UNUSED_ARG(secattributes);
1042 GATE_UNUSED_ARG(sidowner);
1043 GATE_UNUSED_ARG(sidgroup);
1044 GATE_UNUSED_ARG(sideveryone);
1045 GATE_UNUSED_ARG(secdescr);
1046 GATE_UNUSED_ARG(aclBuffer);
1047 }
1048 else
1049 {
1050 #if !defined(GATE_SYS_WINSTORE) && !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
1051 PSID psidAll = (PSID)sideveryone;
1052 PSID psidGroup = (PSID)sidgroup;
1053 PSID psidOwner = (PSID)sidowner;
1054
1055 HANDLE hToken = (HWND)NULL;
1056 HANDLE hProc;
1057 char userBuffer[1024] = { 0 };
1058 PTOKEN_USER pUser = (PTOKEN_USER)&userBuffer[0];
1059 PACL pacl = (PACL)&aclBuffer[0];
1060
1061 DWORD dwLen = sizeof(userBuffer);
1062 DWORD dwACLFlags = GENERIC_READ | GENERIC_WRITE | DELETE | GENERIC_EXECUTE;
1063
1064 do
1065 {
1066 hProc = GetCurrentProcess();
1067
1068 gate_mem_clear(sideveryone, sizeof(gate_win32_sidstruct_t));
1069 sideveryone->Revision = SID_REVISION;
1070 sideveryone->IdentifierAuthority = gate_win32_world_sid;
1071 sideveryone->SubAuthCount = 1;
1072
1073 gate_mem_clear(sidgroup, sizeof(gate_win32_sidstruct_t));
1074 sidgroup->Revision = SID_REVISION;
1075 sidgroup->IdentifierAuthority = gate_win32_nt_sid;
1076 sidgroup->SubAuthCount = 2;
1077 sidgroup->SubAuthorities[0] = SECURITY_BUILTIN_DOMAIN_RID;
1078 sidgroup->SubAuthorities[1] = DOMAIN_ALIAS_RID_USERS;
1079
1080 gate_mem_clear(sidowner, sizeof(gate_win32_sidstruct_t));
1081 sidowner->Revision = SID_REVISION;
1082
1083 /* check, if the platform supports all required functions */
1084 if ((gate_platform.AdvOpenProcessToken == NULL)
1085 || (gate_platform.AdvGetTokenInformation == NULL)
1086 || (gate_platform.AdvInitializeSecurityDescriptor == NULL)
1087 || (gate_platform.AdvInitializeAcl == NULL)
1088 || (gate_platform.AdvAddAccessAllowedAce == NULL)
1089 || (gate_platform.AdvSetSecurityDescriptorDacl == NULL)
1090 )
1091 {
1092 break;
1093 }
1094
1095 if (!gate_platform.AdvOpenProcessToken(hProc, TOKEN_READ, &hToken))
1096 {
1097 break;
1098 }
1099
1100 if (!gate_platform.AdvGetTokenInformation(hToken, TokenUser, &userBuffer[0], sizeof(userBuffer), &dwLen))
1101 {
1102 break;
1103 }
1104
1105 gate_win32_sid_export(pUser->User.Sid, sidowner);
1106
1107 if (!gate_platform.AdvInitializeSecurityDescriptor(secdescr, SECURITY_DESCRIPTOR_REVISION))
1108 {
1109 break;
1110 }
1111 if (!gate_platform.AdvInitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION))
1112 {
1113 break;
1114 }
1115
1116 if (unrestricted)
1117 {
1118 if (!gate_platform.AdvAddAccessAllowedAce(pacl, ACL_REVISION, dwACLFlags, psidAll))
1119 {
1120 break;
1121 }
1122 }
1123 else
1124 {
1125 if (restrictowner)
1126 {
1127 if (!gate_platform.AdvAddAccessAllowedAce(pacl, ACL_REVISION, dwACLFlags, psidOwner))
1128 {
1129 break;
1130 }
1131 }
1132 if (restrictgroup)
1133 {
1134 if (!gate_platform.AdvAddAccessAllowedAce(pacl, ACL_REVISION, dwACLFlags, psidGroup))
1135 {
1136 break;
1137 }
1138 }
1139 }
1140
1141 if (!gate_platform.AdvSetSecurityDescriptorDacl(secdescr, TRUE, pacl, FALSE))
1142 {
1143 break;
1144 }
1145
1146 secattributes->nLength = sizeof(SECURITY_ATTRIBUTES);
1147 secattributes->bInheritHandle = FALSE;
1148 secattributes->lpSecurityDescriptor = secdescr;
1149
1150 ret = secattributes;
1151 } while (0);
1152
1153 gate_win32_closehandle(hToken);
1154 #endif
1155 }
1156
1157
1158 return ret;
1159 }
1160
1161 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
1162 {
1163 TCHAR path[GATE_MAX_FILEPATH_LENGTH];
1164 DWORD accessmode = 0;
1165 DWORD sharemode = 0;
1166 DWORD createdispo = 0;
1167 DWORD fileattribs = FILE_ATTRIBUTE_NORMAL;
1168 gate_bool_t truncate = false;
1169 gate_bool_t append = false;
1170 HANDLE hfile;
1171 gate_result_t ret;
1172 gate_win32_sidstruct_t sideveryone;
1173 gate_win32_sidstruct_t sidowner;
1174 gate_win32_sidstruct_t sidgroup;
1175 LPSECURITY_ATTRIBUTES ptr_secattributes = NULL;
1176 SECURITY_ATTRIBUTES secattributes;
1177 SECURITY_DESCRIPTOR secdescr;
1178 BYTE aclBuffer[1024];
1179
1180 gate_win32_utf8_2_winstr(filepath->str, filepath->length, path, sizeof(path) / sizeof(path[0]));
1181
1182 switch (flags & GATE_STREAM_OPEN_FLAGS_MASK)
1183 {
1184 case GATE_STREAM_OPEN_READ:
1185 {
1186 accessmode = (GENERIC_READ);
1187 sharemode = (FILE_SHARE_READ);
1188 createdispo = (OPEN_EXISTING);
1189 break;
1190 }
1191 case GATE_STREAM_OPEN_WRITE:
1192 {
1193 accessmode = (GENERIC_WRITE);
1194 sharemode = (FILE_SHARE_READ);
1195 createdispo = (CREATE_ALWAYS);
1196 fileattribs = FILE_ATTRIBUTE_ARCHIVE;
1197 truncate = true;
1198 break;
1199 }
1200 case GATE_STREAM_OPEN_READWRITE:
1201 {
1202 accessmode = (GENERIC_READ | GENERIC_WRITE);
1203 sharemode = (FILE_SHARE_READ);
1204 createdispo = (OPEN_ALWAYS);
1205 fileattribs = FILE_ATTRIBUTE_ARCHIVE;
1206 break;
1207 }
1208 case GATE_STREAM_OPEN_APPENDWRITE:
1209 {
1210 accessmode = (GENERIC_WRITE);
1211 sharemode = (FILE_SHARE_READ);
1212 createdispo = (OPEN_ALWAYS);
1213 fileattribs = FILE_ATTRIBUTE_ARCHIVE;
1214 append = true;
1215 break;
1216 }
1217 case GATE_STREAM_OPEN_APPENDREADWRITE:
1218 {
1219 accessmode = (GENERIC_READ | GENERIC_WRITE);
1220 createdispo = (OPEN_ALWAYS);
1221 fileattribs = FILE_ATTRIBUTE_ARCHIVE;
1222 append = true;
1223 break;
1224 }
1225 default:
1226 {
1227 return GATE_RESULT_INVALIDARG;
1228 }
1229 }
1230
1231 sharemode = (FILE_SHARE_READ);
1232 if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_SHARED))
1233 {
1234 sharemode |= FILE_SHARE_WRITE;
1235 }
1236
1237 /* generate a security descriptor for the file, if supported by the platform, otherwise NULL: */
1238 ptr_secattributes = gate_win32_create_security_attribs(flags, &secattributes, &sidowner, &sidgroup, &sideveryone, &secdescr, aclBuffer);
1239
1240 hfile = gate_win32_createfile(path, accessmode, sharemode, createdispo, fileattribs, 0, ptr_secattributes);
1241 if (hfile == (HANDLE)INVALID_HANDLE_VALUE)
1242 {
1243 gate_win32_print_lasterror(&ret, NULL, 0);
1244 return ret;
1245 }
1246
1247 if (truncate)
1248 {
1249 gate_win32_setendoffile(hfile);
1250 }
1251
1252 if (filehandle == NULL)
1253 {
1254 gate_win32_closehandle(hfile);
1255 return GATE_RESULT_OK;
1256 }
1257
1258 *filehandle = (gate_file_t)hfile;
1259
1260 if (append)
1261 {
1262 gate_file_seek(*filehandle, 0, GATE_FILE_SEEK_ORIGIN_END, NULL);
1263 }
1264 return GATE_RESULT_OK;
1265 }
1266 #endif
1267
1268 gate_result_t gate_file_read(gate_file_t filehandle, char* buffer, gate_size_t bufferlength, gate_size_t* bufferused)
1269 {
1270 gate_result_t ret;
1271 DWORD bytesreceived = 0;
1272 HANDLE hfile = (HANDLE)filehandle;
1273 if (gate_win32_readfile(hfile, (LPVOID)buffer, (DWORD)bufferlength, &bytesreceived, NULL))
1274 {
1275 if (bufferused)
1276 {
1277 *bufferused = (gate_size_t)bytesreceived;
1278 }
1279 ret = GATE_RESULT_OK;
1280 }
1281 else
1282 {
1283 gate_win32_print_lasterror(&ret, NULL, 0);
1284 }
1285 return ret;
1286 }
1287 gate_result_t gate_file_write(gate_file_t filehandle, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
1288 {
1289 gate_result_t ret;
1290 DWORD byteswritten = 0;
1291 HANDLE hfile = (HANDLE)filehandle;
1292 if (gate_win32_writefile(hfile, (LPVOID)buffer, (DWORD)bufferlength, &byteswritten, NULL))
1293 {
1294 *written = (gate_size_t)byteswritten;
1295 ret = GATE_RESULT_OK;
1296 }
1297 else
1298 {
1299 gate_win32_print_lasterror(&ret, NULL, 0);
1300 }
1301 return ret;
1302 }
1303 gate_result_t gate_file_flush(gate_file_t filehandle)
1304 {
1305 gate_result_t ret;
1306 if (gate_win32_flushfilebuffers((HANDLE)filehandle))
1307 {
1308 ret = GATE_RESULT_OK;
1309 }
1310 else
1311 {
1312 gate_win32_print_lasterror(&ret, NULL, 0);
1313 }
1314 return ret;
1315 }
1316
1317 gate_result_t gate_file_close(gate_file_t filehandle)
1318 {
1319 gate_result_t ret;
1320 HANDLE hfile = (HANDLE)filehandle;
1321 if (gate_win32_closehandle(hfile))
1322 {
1323 ret = GATE_RESULT_OK;
1324 }
1325 else
1326 {
1327 gate_win32_print_lasterror(&ret, NULL, 0);
1328 }
1329 return ret;
1330 }
1331 gate_result_t gate_file_seek(gate_file_t filehandle, gate_int64_t position, gate_enumint_t origin, gate_int64_t* newposition)
1332 {
1333 HANDLE hfile = (HANDLE)filehandle;
1334 DWORD movemethod = 0;
1335 LARGE_INTEGER li;
1336
1337 gate_win32_write_largeint(position, &li);
1338
1339 switch (origin)
1340 {
1341 case GATE_FILE_SEEK_ORIGIN_BEGIN: movemethod = FILE_BEGIN; break;
1342 case GATE_FILE_SEEK_ORIGIN_CURPOS: movemethod = FILE_CURRENT; break;
1343 case GATE_FILE_SEEK_ORIGIN_END: movemethod = FILE_END; break;
1344 default: return GATE_RESULT_INVALIDARG;
1345 }
1346
1347 if (gate_win32_setfilepointer(hfile, li, &li, movemethod))
1348 {
1349 if (newposition != NULL)
1350 {
1351 gate_win32_read_largeint(&li, newposition);
1352 }
1353 return GATE_RESULT_OK;
1354 }
1355 return GATE_RESULT_FAILED;
1356 }
1357 gate_result_t gate_file_pos(gate_file_t filehandle, gate_int64_t* position)
1358 {
1359 HANDLE hfile = (HANDLE)filehandle;
1360 LARGE_INTEGER li;
1361 gate_win32_write_largeint(0, &li);
1362
1363 if (gate_win32_setfilepointer(hfile, li, &li, FILE_CURRENT))
1364 {
1365 if (position == NULL)
1366 {
1367 return GATE_RESULT_INVALIDARG;
1368 }
1369 gate_win32_read_largeint(&li, position);
1370 return GATE_RESULT_OK;
1371 }
1372 return GATE_RESULT_FAILED;
1373 }
1374 gate_result_t gate_file_size(gate_file_t filehandle, gate_int64_t* size)
1375 {
1376 HANDLE hfile = (HANDLE)filehandle;
1377 LARGE_INTEGER li;
1378 if (gate_win32_getfilesize(hfile, &li))
1379 {
1380 if (size == NULL)
1381 {
1382 return GATE_RESULT_INVALIDARG;
1383 }
1384 gate_win32_read_largeint(&li, size);
1385 return GATE_RESULT_OK;
1386 }
1387 return GATE_RESULT_FAILED;
1388 }
1389
1390 gate_result_t gate_file_truncate(gate_file_t filehandle)
1391 {
1392 gate_result_t ret = GATE_RESULT_FAILED;
1393 HANDLE hfile = (HANDLE)filehandle;
1394 if (gate_win32_setendoffile(hfile))
1395 {
1396 ret = GATE_RESULT_OK;
1397 }
1398 else
1399 {
1400 gate_win32_print_lasterror(&ret, NULL, 0);
1401 }
1402 return ret;
1403 }
1404
1405 static DWORD const default_lock_length_low = 0xffffffff;
1406 #if defined(GATE_WIN32_ANSI)
1407 static DWORD const default_lock_length_high = 0x00000000;
1408 #else
1409 static DWORD const default_lock_length_high = 0x7fffffff;
1410 #endif
1411
1412 #if defined(GATE_SYS_WINCE) || defined(GATE_SYS_WIN16)
1413 #if defined(__MINGW32CE__) || (_WIN32_WCE < 0x500) || defined(GATE_SYS_WIN16)
1414
1415 #ifndef LOCKFILE_EXCLUSIVE_LOCK
1416 #define LOCKFILE_EXCLUSIVE_LOCK 1
1417 #endif
1418
1419 #ifndef LOCKFILE_FAIL_IMMEDIATELY
1420 #define LOCKFILE_FAIL_IMMEDIATELY 2
1421 #endif
1422
1423 #if defined(GATE_COMPILER_MSVC)
1424 #define GATE_FILES_HELPER_API static
1425 #else
1426 #define GATE_FILES_HELPER_API
1427 #endif
1428
1429 GATE_FILES_HELPER_API BOOL LockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh)
1430 {
1431 GATE_UNUSED_ARG(hFile);
1432 GATE_UNUSED_ARG(dwFileOffsetLow);
1433 GATE_UNUSED_ARG(dwFileOffsetHigh);
1434 GATE_UNUSED_ARG(nNumberOfBytesToLockLow);
1435 GATE_UNUSED_ARG(nNumberOfBytesToLockHigh);
1436 return FALSE;
1437 }
1438
1439 GATE_FILES_HELPER_API BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved,
1440 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
1441 LPOVERLAPPED lpOverlapped)
1442 {
1443 GATE_UNUSED_ARG(hFile);
1444 GATE_UNUSED_ARG(dwFlags);
1445 GATE_UNUSED_ARG(dwReserved);
1446 GATE_UNUSED_ARG(nNumberOfBytesToLockLow);
1447 GATE_UNUSED_ARG(nNumberOfBytesToLockHigh);
1448 GATE_UNUSED_ARG(lpOverlapped);
1449 return FALSE;
1450 }
1451
1452 GATE_FILES_HELPER_API BOOL UnlockFile(HANDLE hFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh)
1453 {
1454 GATE_UNUSED_ARG(hFile);
1455 GATE_UNUSED_ARG(dwFileOffsetLow);
1456 GATE_UNUSED_ARG(dwFileOffsetHigh);
1457 GATE_UNUSED_ARG(nNumberOfBytesToUnlockLow);
1458 GATE_UNUSED_ARG(nNumberOfBytesToUnlockHigh);
1459 return FALSE;
1460 }
1461
1462 GATE_FILES_HELPER_API BOOL UnlockFileEx(HANDLE hFile, DWORD dwReserved,
1463 DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh,
1464 LPOVERLAPPED lpOverlapped)
1465 {
1466 GATE_UNUSED_ARG(hFile);
1467 GATE_UNUSED_ARG(dwReserved);
1468 GATE_UNUSED_ARG(nNumberOfBytesToLockLow);
1469 GATE_UNUSED_ARG(nNumberOfBytesToLockHigh);
1470 GATE_UNUSED_ARG(lpOverlapped);
1471 return FALSE;
1472 }
1473
1474 #endif
1475 #endif
1476
1477 #ifndef ERROR_LOCK_VIOLATION
1478 #define ERROR_LOCK_VIOLATION 0x21
1479 #endif
1480
1481 gate_result_t gate_file_lock(gate_file_t filehandle, gate_bool_t wait)
1482 {
1483 gate_result_t ret = GATE_RESULT_FAILED;
1484
1485 do
1486 {
1487 HANDLE const hfile = (HANDLE)filehandle;
1488 BOOL succeeded;
1489 gate_int64_t current_pos;
1490 ret = gate_file_pos(filehandle, &current_pos);
1491 GATE_BREAK_IF_FAILED(ret);
1492 #if defined(GATE_WIN32_ANSI)
1493 GATE_UNUSED_ARG(wait);
1494 succeeded = LockFile(hfile, 0, 0, default_lock_length_low, default_lock_length_high);
1495 #else
1496 do
1497 {
1498 OVERLAPPED ov;
1499 DWORD dwFlags = LOCKFILE_EXCLUSIVE_LOCK;
1500
1501 ret = gate_file_seek(filehandle, 0, GATE_FILE_SEEK_ORIGIN_BEGIN, NULL);
1502 GATE_BREAK_IF_FAILED(ret);
1503
1504 gate_mem_clear(&ov, sizeof(ov));
1505 if (!wait)
1506 {
1507 dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
1508 }
1509
1510 succeeded = LockFileEx(hfile, dwFlags, 0, default_lock_length_low, default_lock_length_high, &ov);
1511 gate_file_seek(filehandle, current_pos, GATE_FILE_SEEK_ORIGIN_BEGIN, NULL);
1512 } while(0);
1513 GATE_BREAK_IF_FAILED(ret);
1514 #endif
1515 if (succeeded)
1516 {
1517 ret = GATE_RESULT_OK;
1518 }
1519 else
1520 {
1521 if (gate_win32_getlasterror() == ERROR_LOCK_VIOLATION)
1522 {
1523 ret = GATE_RESULT_ACCESSDENIED;
1524 }
1525 else
1526 {
1527 gate_win32_print_lasterror(&ret, NULL, 0);
1528 }
1529 }
1530 } while (0);
1531
1532 return ret;
1533 }
1534 gate_result_t gate_file_unlock(gate_file_t filehandle)
1535 {
1536 gate_result_t ret = GATE_RESULT_FAILED;
1537 HANDLE hfile = (HANDLE)filehandle;
1538 gate_int64_t current_pos = 0;
1539 BOOL succeeded;
1540 #if !defined(GATE_WIN32_ANSI)
1541 OVERLAPPED ov;
1542 #endif
1543
1544 do
1545 {
1546 ret = gate_file_pos(filehandle, &current_pos);
1547 GATE_BREAK_IF_FAILED(ret);
1548
1549 #if defined(GATE_WIN32_ANSI)
1550 succeeded = UnlockFile(hfile, 0, 0, default_lock_length_low, default_lock_length_high);
1551 #else
1552 ret = gate_file_seek(filehandle, 0, GATE_FILE_SEEK_ORIGIN_BEGIN, NULL);
1553 GATE_BREAK_IF_FAILED(ret);
1554
1555 gate_mem_clear(&ov, sizeof(ov));
1556 succeeded = UnlockFileEx(hfile, 0, default_lock_length_low, default_lock_length_high, &ov);
1557 #endif
1558 if (succeeded)
1559 {
1560 ret = GATE_RESULT_OK;
1561 }
1562 else
1563 {
1564 gate_win32_print_lasterror(&ret, NULL, 0);
1565 }
1566
1567 gate_file_seek(filehandle, current_pos, GATE_FILE_SEEK_ORIGIN_BEGIN, NULL);
1568 } while (0);
1569
1570 return ret;
1571 }
1572
1573 static gate_bool_t gate_file_is_server_path(LPTSTR path, gate_bool_t stripshare)
1574 {
1575 #if defined(GATE_SYS_WIN16)
1576 GATE_UNUSED_ARG(path);
1577 GATE_UNUSED_ARG(stripshare);
1578 return false;
1579 #else
1580 gate_size_t pathlength = gate_win32_str_len(path);
1581 gate_size_t pos;
1582 if (pathlength < 2)
1583 {
1584 return false;
1585 }
1586 if (gate_win32_str_pos(path, pathlength, _T("\\\\"), 2, 0) != 0)
1587 {
1588 return false;
1589 }
1590
1591 /* path starts with double-backslashes */
1592 if (stripshare)
1593 {
1594 pos = gate_win32_str_pos(path, pathlength, _T("\\"), 1, 2);
1595 if (pos != GATE_STR_NPOS)
1596 {
1597 path[pos] = 0;
1598 }
1599 }
1600 return true;
1601 #endif
1602 }
1603
1604 static gate_bool_t gate_file_is_server_share_path(LPTSTR path, gate_bool_t stripsubpath)
1605 {
1606 #if defined(GATE_SYS_WIN16)
1607 GATE_UNUSED_ARG(path);
1608 GATE_UNUSED_ARG(stripsubpath);
1609 return false;
1610 #else
1611 gate_size_t pathlength = gate_win32_str_len(path);
1612 gate_size_t pos;
1613 gate_size_t shareendpos;
1614 if (pathlength < 2)
1615 {
1616 return false;
1617 }
1618 if (gate_win32_str_pos(path, pathlength, _T("\\\\"), 2, 0) != 0)
1619 {
1620 return false;
1621 }
1622
1623 /* path starts with double-backslashes */
1624
1625 pos = gate_win32_str_pos(path, pathlength, _T("\\"), 1, 2);
1626 if ((pos == GATE_STR_NPOS) || (pos + 1 == pathlength))
1627 {
1628 return false;
1629 }
1630
1631 if (stripsubpath)
1632 {
1633 shareendpos = gate_win32_str_pos(path, pathlength, _T("\\"), 1, pos);
1634 if (shareendpos != GATE_STR_NPOS)
1635 {
1636 path[shareendpos] = 0;
1637 }
1638 }
1639 return true;
1640 #endif
1641 }
1642
1643 static gate_bool_t gate_win32_is_volume_path(TCHAR const* path, gate_size_t path_len)
1644 {
1645 #if defined(GATE_SYS_WINCE)
1646 return (path_len == 1) && (path[0] == '\\');
1647 #else
1648 TCHAR drive;
1649 if ((path_len < 2) || (path_len > 3))
1650 {
1651 return false;
1652 }
1653 if (path[1] != _T(':'))
1654 {
1655 return false;
1656 }
1657 if ((path_len == 3) && (path[2] != _T('\\')))
1658 {
1659 return false;
1660 }
1661 drive = path[0];
1662 return ((drive >= _T('A')) && (drive <= _T('Z')))
1663 || ((drive >= _T('a')) && (drive <= _T('z')));
1664 #endif
1665 }
1666
1667 gate_result_t gate_file_exists(gate_string_t const* filepath)
1668 {
1669 WIN32_FIND_DATA data;
1670 HANDLE hfind;
1671 TCHAR path[GATE_MAX_FILEPATH_LENGTH];
1672 gate_size_t pathlen = gate_win32_utf8_2_winstr(filepath->str, filepath->length, path, sizeof(path) / sizeof(path[0]));
1673 if ((pathlen > 0) && (path[pathlen - 1] == '\\'))
1674 {
1675 --pathlen;
1676 path[pathlen] = 0;
1677 }
1678
1679 if (gate_file_is_server_path(path, false))
1680 {
1681 return GATE_RESULT_OK;
1682 }
1683 if (gate_file_is_server_share_path(path, false))
1684 {
1685 return GATE_RESULT_OK;
1686 }
1687
1688 #if !defined(GATE_SYS_WINCE)
1689 if (gate_win32_is_volume_path(path, pathlen))
1690 {
1691 DWORD drives = GetLogicalDrives();
1692 DWORD drivebit = (DWORD)(1 << (gate_char_uppercase(path[0]) - 'A'));
1693 if ((drives & drivebit) == 0)
1694 {
1695 return GATE_RESULT_NOTAVAILABLE;
1696 }
1697 return GATE_RESULT_OK;
1698 }
1699 #endif
1700
1701 hfind = gate_win32_findfirstfile(&path[0], &data);
1702 if ((HANDLE)INVALID_HANDLE_VALUE == hfind)
1703 {
1704 return GATE_RESULT_NOTAVAILABLE;
1705 }
1706 gate_win32_findclose(hfind);
1707 return GATE_RESULT_OK;
1708 }
1709
1710 gate_result_t gate_file_copy(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
1711 {
1712 #if defined(GATE_SYS_WIN16)
1713 return gate_file_copy_internal(srcfilepath, dstfilepath, flags);
1714 #else
1715 gate_result_t ret;
1716 if (GATE_FLAG_ENABLED(flags, GATE_FILE_COPY_SIMPLE))
1717 {
1718 ret = gate_file_copy_internal(srcfilepath, dstfilepath, flags);
1719 }
1720 else
1721 {
1722 TCHAR srcpath[GATE_MAX_FILEPATH_LENGTH];
1723 TCHAR dstpath[GATE_MAX_FILEPATH_LENGTH];
1724 const gate_size_t srcpathlen = gate_win32_string_2_winstr(srcfilepath, srcpath, sizeof(srcpath) / sizeof(srcpath[0]));
1725 const gate_size_t dstpathlen = gate_win32_string_2_winstr(dstfilepath, dstpath, sizeof(dstpath) / sizeof(dstpath[0]));
1726
1727 if ((srcpathlen == 0) || (dstpathlen == 0))
1728 {
1729 ret = GATE_RESULT_INVALIDARG;
1730 }
1731 else
1732 {
1733 if (CopyFile(srcpath, dstpath, GATE_FLAG_ENABLED(flags, GATE_FILE_COPY_OVERWRITE) ? TRUE : FALSE))
1734 {
1735 ret = GATE_RESULT_OK;
1736 }
1737 else
1738 {
1739 gate_win32_print_lasterror(&ret, NULL, 0);
1740 }
1741 }
1742 }
1743 return ret;
1744 #endif
1745 }
1746 gate_result_t gate_file_move(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
1747 {
1748 #if defined(GATE_SYS_WIN16)
1749 return gate_file_move_internal(srcfilepath, dstfilepath);
1750 #else
1751 gate_result_t ret;
1752 TCHAR srcpath[GATE_MAX_FILEPATH_LENGTH];
1753 TCHAR dstpath[GATE_MAX_FILEPATH_LENGTH];
1754 gate_size_t srcpathlen = gate_win32_string_2_winstr(srcfilepath, srcpath, sizeof(srcpath) / sizeof(srcpath[0]));
1755 gate_size_t dstpathlen = gate_win32_string_2_winstr(dstfilepath, dstpath, sizeof(dstpath) / sizeof(dstpath[0]));
1756
1757 if ((srcpathlen == 0) || (dstpathlen == 0))
1758 {
1759 ret = GATE_RESULT_INVALIDARG;
1760 }
1761 else
1762 {
1763 if (MoveFile(srcpath, dstpath))
1764 {
1765 ret = GATE_RESULT_OK;
1766 }
1767 else
1768 {
1769 gate_win32_print_lasterror(&ret, NULL, 0);
1770 }
1771 }
1772 return ret;
1773 #endif
1774 }
1775
1776 #if defined(GATE_SYS_WIN16)
1777 static BOOL DeleteFile(LPCSTR lpFileName)
1778 {
1779 OFSTRUCT of;
1780 HFILE hf = OpenFile(lpFileName, &of, OF_DELETE);
1781 if (hf == HFILE_ERROR)
1782 {
1783 return FALSE;
1784 }
1785 return TRUE;
1786 }
1787 #endif
1788
1789
1790 gate_result_t gate_file_delete(gate_string_t const* filepath)
1791 {
1792 gate_result_t ret;
1793 TCHAR path[GATE_MAX_FILEPATH_LENGTH];
1794 gate_size_t pathlen = gate_win32_string_2_winstr(filepath, path, sizeof(path) / sizeof(path[0]) - 1);
1795 DWORD dw_error;
1796
1797 if (pathlen == 0)
1798 {
1799 ret = GATE_RESULT_INVALIDARG;
1800 }
1801 else
1802 {
1803 path[pathlen + 1] = 0; /* ensure double zero for shell-file-ops */
1804 if (DeleteFile(path))
1805 {
1806 ret = GATE_RESULT_OK;
1807 }
1808 else
1809 {
1810 dw_error = gate_win32_getlasterror();
1811 gate_win32_print_lasterror_code(dw_error, &ret, NULL, 0);
1812 /* try fallback */
1813 if (gate_win32_shfileop(GATE_WIN32_SHFILEOP_DELETE, path, NULL))
1814 {
1815 ret = GATE_RESULT_OK;
1816 }
1817 else
1818 {
1819 gate_win32_setlasterror(dw_error);
1820 }
1821 }
1822 }
1823 return ret;
1824 }
1825
1826
1827 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
1828 #define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
1829 #endif
1830
1831 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
1832 #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
1833 #endif
1834
1835 #ifndef INVALID_FILE_ATTRIBUTES
1836 #define INVALID_FILE_ATTRIBUTES ((DWORD)(-1))
1837 #endif
1838
1839 #if defined(GATE_SYS_WIN16)
1840 static DWORD GetFileAttributes(LPCSTR lpFileName)
1841 {
1842 DWORD ret;
1843 struct _finddata_t fd;
1844 intptr_t h = _findfirst(lpFileName, &fd);
1845 if (h != -1)
1846 {
1847 _findclose(h);
1848 ret = 0;
1849 GATE_FLAG_SET(ret, FILE_ATTRIBUTE_READONLY, GATE_FLAG_ENABLED(fd.attrib, _A_RDONLY));
1850 GATE_FLAG_SET(ret, FILE_ATTRIBUTE_SYSTEM, GATE_FLAG_ENABLED(fd.attrib, _A_SYSTEM));
1851 GATE_FLAG_SET(ret, FILE_ATTRIBUTE_HIDDEN, GATE_FLAG_ENABLED(fd.attrib, _A_HIDDEN));
1852 GATE_FLAG_SET(ret, FILE_ATTRIBUTE_DIRECTORY, GATE_FLAG_ENABLED(fd.attrib, _A_SUBDIR));
1853 GATE_FLAG_SET(ret, FILE_ATTRIBUTE_ARCHIVE, GATE_FLAG_ENABLED(fd.attrib, _A_ARCH));
1854 }
1855 else
1856 {
1857 ret = INVALID_FILE_ATTRIBUTES;
1858 }
1859 return ret;
1860 }
1861 #endif
1862
1863 static gate_size_t gate_file_build_abs_path(gate_string_t const* srcpath, TCHAR* targetpath, gate_size_t targetpathcapacity)
1864 {
1865 TCHAR tmppath[GATE_MAX_FILEPATH_LENGTH];
1866 gate_size_t tmppathlen = gate_win32_string_2_winstr(srcpath, tmppath, sizeof(tmppath) / sizeof(tmppath[0]) - 1);
1867 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
1868 DWORD fulllen = GetFullPathName(tmppath, (DWORD)targetpathcapacity, targetpath, NULL);
1869 if (fulllen != 0)
1870 {
1871 return (gate_size_t)fulllen;
1872 }
1873 else
1874 #endif
1875 {
1876 return gate_win32_winstr_print_text(targetpath, targetpathcapacity, tmppath, tmppathlen);
1877 }
1878 }
1879
1880 gate_result_t gate_file_real_path(gate_string_t const* relativepath, gate_string_t* absolutepath)
1881 {
1882 TCHAR tmppath[GATE_MAX_FILEPATH_LENGTH];
1883 gate_size_t tmppathlen;
1884 if (!relativepath || !absolutepath)
1885 {
1886 return GATE_RESULT_NULLPOINTER;
1887 }
1888
1889 tmppathlen = gate_file_build_abs_path(relativepath, tmppath, sizeof(tmppath) / sizeof(tmppath[0]) - 1);
1890 if (NULL == gate_win32_winstr_2_utf8_string(tmppath, tmppathlen, absolutepath))
1891 {
1892 return GATE_RESULT_OUTOFMEMORY;
1893 }
1894 return GATE_RESULT_OK;
1895 }
1896
1897
1898 gate_result_t gate_file_create_link(gate_string_t const* targetfile, gate_string_t const* linkfile)
1899 {
1900 #if defined(GATE_SYS_WIN16) || defined(GATE_SYS_WINCE)
1901 GATE_UNUSED_ARG(targetfile);
1902 GATE_UNUSED_ARG(linkfile);
1903 return GATE_RESULT_NOTIMPLEMENTED;
1904 #else
1905 gate_result_t ret;
1906 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
1907 TCHAR linkpath[GATE_MAX_FILEPATH_LENGTH];
1908 gate_size_t targetpathlen = gate_file_build_abs_path(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
1909 gate_size_t linkpathlen = gate_win32_string_2_winstr(linkfile, linkpath, sizeof(linkpath) / sizeof(linkpath[0]));
1910 DWORD dwFlags = 0;
1911 DWORD dwAttribs;
1912
1913 do
1914 {
1915 if ((targetpathlen == 0) || (linkpathlen == 0))
1916 {
1917 ret = GATE_RESULT_INVALIDARG;
1918 break;
1919 }
1920
1921 if (gate_platform.Win32CreateSymbolicLink == NULL)
1922 {
1923 /* symbolic-link API not available (pre-Vista) */
1924 ret = GATE_RESULT_NOTSUPPORTED;
1925 break;
1926 }
1927
1928 dwAttribs = GetFileAttributes(targetpath);
1929 if (INVALID_FILE_ATTRIBUTES == dwAttribs)
1930 {
1931 /* target path not available, so we cannot determine the file type */
1932 ret = GATE_RESULT_NOTAVAILABLE;
1933 break;
1934 }
1935
1936 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_DIRECTORY))
1937 {
1938 dwFlags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
1939 }
1940
1941 if (!gate_platform.Win32CreateSymbolicLink(linkpath, targetpath, dwFlags))
1942 {
1943 DWORD lasterr = gate_win32_getlasterror();
1944 if (lasterr == ERROR_PRIVILEGE_NOT_HELD)
1945 {
1946 /* try optional Win10+ support for unpriviledged link-creation */
1947 dwFlags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
1948 if (gate_platform.Win32CreateSymbolicLink(linkpath, targetpath, dwFlags))
1949 {
1950 /* Yay! Win-Devmode is active */
1951 ret = GATE_RESULT_OK;
1952 break;
1953 }
1954 else
1955 {
1956 /* reset error code for proper handling by caller */
1957 gate_win32_setlasterror(lasterr);
1958 }
1959 }
1960 gate_win32_print_lasterror_code(lasterr, &ret, NULL, 0);
1961 break;
1962 }
1963
1964 /* success case reached */
1965 ret = GATE_RESULT_OK;
1966 } while (0);
1967
1968 return ret;
1969 #endif
1970 }
1971
1972 #ifndef FILE_NAME_NORMALIZED
1973 #define FILE_NAME_NORMALIZED 0x00
1974 #endif
1975
1976 #if !defined(GATE_SYS_WIN16)
1977
1978 typedef struct _GATE_REPARSE_DATA_BUFFER {
1979 ULONG ReparseTag;
1980 USHORT ReparseDataLength;
1981 USHORT Reserved;
1982 union {
1983 struct {
1984 USHORT SubstituteNameOffset;
1985 USHORT SubstituteNameLength;
1986 USHORT PrintNameOffset;
1987 USHORT PrintNameLength;
1988 ULONG Flags;
1989 WCHAR PathBuffer[1];
1990 } SymbolicLinkReparseBuffer;
1991 struct {
1992 USHORT SubstituteNameOffset;
1993 USHORT SubstituteNameLength;
1994 USHORT PrintNameOffset;
1995 USHORT PrintNameLength;
1996 WCHAR PathBuffer[1];
1997 } MountPointReparseBuffer;
1998 struct {
1999 UCHAR DataBuffer[1];
2000 } GenericReparseBuffer;
2001 } UnionItems;
2002 } GATE_REPARSE_DATA_BUFFER, * PGATE_REPARSE_DATA_BUFFER;
2003 #endif
2004
2005 #ifndef FILE_DEVICE_FILE_SYSTEM
2006 #define FILE_DEVICE_FILE_SYSTEM 0x00000009
2007 #endif
2008
2009 #ifndef METHOD_BUFFERED
2010 #define METHOD_BUFFERED 0
2011 #endif
2012
2013 #ifndef FILE_ANY_ACCESS
2014 #define FILE_ANY_ACCESS 0
2015 #endif
2016
2017 #ifndef CTL_CODE
2018 #define CTL_CODE( DeviceType, Function, Method, Access ) ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) )
2019 #endif
2020
2021 #ifndef FSCTL_GET_REPARSE_POINT
2022 #define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
2023 #endif
2024
2025 #ifndef IO_REPARSE_TAG_SYMLINK
2026 #define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
2027 #endif
2028
2029 gate_result_t gate_file_read_link(gate_string_t const* linkfile, gate_string_t* realpath)
2030 {
2031 #if defined(GATE_SYS_WINCE) || defined(GATE_SYS_WIN16)
2032 GATE_UNUSED_ARG(linkfile);
2033 GATE_UNUSED_ARG(realpath);
2034 return GATE_RESULT_NOTIMPLEMENTED;
2035 #else
2036 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
2037 HANDLE hsearch = INVALID_HANDLE_VALUE;
2038 HANDLE hfile = INVALID_HANDLE_VALUE;
2039 TCHAR linkpath[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
2040 gate_size_t linkpathlen = gate_win32_string_2_winstr(linkfile, linkpath, sizeof(linkpath) / sizeof(linkpath[0]));
2041 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
2042 DWORD len_used = 0;
2043 BOOL privilege_enabled = FALSE;
2044 gate_bool_t reset_privilege = false;
2045 WIN32_FIND_DATA searchdata = GATE_INIT_EMPTY;
2046 gate_bool_t is_sym_link = true;
2047 DWORD bytes_returned = 0;
2048 GATE_REPARSE_DATA_BUFFER* ptr_reparse_buffer = NULL;
2049
2050 do
2051 {
2052 if (linkpathlen == 0)
2053 {
2054 ret = GATE_RESULT_INVALIDARG;
2055 break;
2056 }
2057 hsearch = gate_win32_findfirstfile(linkpath, &searchdata);
2058 if (INVALID_HANDLE_VALUE != hsearch)
2059 {
2060 switch (searchdata.dwReserved0)
2061 {
2062 case IO_REPARSE_TAG_SYMLINK:
2063 is_sym_link = true;
2064 break;
2065 default:
2066 is_sym_link = false;
2067 break;
2068 }
2069 }
2070
2071 if (gate_platform.Win32GetFinalPathNameByHandle == NULL)
2072 {
2073 ret = GATE_RESULT_NOTSUPPORTED;
2074 break;
2075 }
2076
2077 hfile = gate_win32_createfile(linkpath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING,
2078 FILE_ATTRIBUTE_NORMAL, 0, NULL);
2079 if ((INVALID_HANDLE_VALUE == hfile) || (NULL == hfile))
2080 {
2081 if (gate_win32_token_privilege_is_enabled(NULL, SE_BACKUP_NAME, &privilege_enabled))
2082 {
2083 if (!privilege_enabled)
2084 {
2085 if (gate_win32_token_privilege_enable(NULL, SE_BACKUP_NAME, TRUE))
2086 {
2087 reset_privilege = true;
2088 }
2089 }
2090 }
2091
2092 hfile = gate_win32_createfile(linkpath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING,
2093 0, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
2094 if ((INVALID_HANDLE_VALUE == hfile) || (NULL == hfile))
2095 {
2096 gate_win32_print_lasterror(&ret, NULL, 0);
2097 }
2098 else
2099 {
2100 ret = GATE_RESULT_OK;
2101 }
2102 if (reset_privilege)
2103 {
2104 gate_win32_token_privilege_enable(NULL, SE_BACKUP_NAME, FALSE);
2105 }
2106 GATE_BREAK_IF_FAILED(ret);
2107 }
2108
2109 if (is_sym_link)
2110 {
2111 /* get final path name of symlink */
2112 len_used = gate_platform.Win32GetFinalPathNameByHandle(hfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]), FILE_NAME_NORMALIZED);
2113 if (0 == len_used)
2114 {
2115 gate_win32_print_lasterror(&ret, NULL, 0);
2116 break;
2117 }
2118 else
2119 {
2120 if (NULL == gate_win32_winstr_2_utf8_string(targetpath, len_used, realpath))
2121 {
2122 ret = GATE_RESULT_OUTOFMEMORY;
2123 break;
2124 }
2125 }
2126 }
2127 else
2128 {
2129 /* get reparse point */
2130 ptr_reparse_buffer = (GATE_REPARSE_DATA_BUFFER*)&targetpath[0];
2131 if (!DeviceIoControl(hfile, FSCTL_GET_REPARSE_POINT, NULL, 0, ptr_reparse_buffer, sizeof(targetpath), &bytes_returned, NULL))
2132 {
2133 ret = GATE_RESULT_FAILED;
2134 break;
2135 }
2136
2137 if (NULL == gate_string_create_utf16(realpath,
2138 &ptr_reparse_buffer->UnionItems.MountPointReparseBuffer.PathBuffer[0],
2139 gate_str16_length(&ptr_reparse_buffer->UnionItems.MountPointReparseBuffer.PathBuffer[0])
2140 ))
2141 {
2142 ret = GATE_RESULT_OUTOFMEMORY;
2143 break;
2144 }
2145 }
2146
2147 /* reached SUCCESS case ;) */
2148 ret = GATE_RESULT_OK;
2149 } while (0);
2150
2151 gate_win32_closehandle(hfile);
2152 gate_win32_findclose(hsearch);
2153
2154 return ret;
2155 #endif
2156 }
2157 gate_result_t gate_file_create_hardlink(gate_string_t const* targetfile, gate_string_t const* linkfile)
2158 {
2159 #if defined(GATE_SYS_WIN16)
2160 GATE_UNUSED_ARG(targetfile);
2161 GATE_UNUSED_ARG(linkfile);
2162 return GATE_RESULT_NOTIMPLEMENTED;
2163 #else
2164 gate_result_t ret;
2165 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
2166 TCHAR linkpath[GATE_MAX_FILEPATH_LENGTH];
2167 gate_size_t targetpathlen = gate_win32_string_2_winstr(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
2168 gate_size_t linkpathlen = gate_win32_string_2_winstr(linkfile, linkpath, sizeof(linkpath) / sizeof(linkpath[0]));
2169
2170 if ((targetpathlen == 0) || (linkpathlen == 0))
2171 {
2172 ret = GATE_RESULT_INVALIDARG;
2173 }
2174 else
2175 {
2176 if (gate_platform.Win32CreateHardLink == NULL)
2177 {
2178 ret = GATE_RESULT_NOTSUPPORTED;
2179 }
2180 else
2181 {
2182 if (gate_platform.Win32CreateHardLink(linkpath, targetpath, NULL))
2183 {
2184 ret = GATE_RESULT_OK;
2185 }
2186 else
2187 {
2188 gate_win32_print_lasterror(&ret, NULL, 0);
2189 }
2190 }
2191 }
2192 return ret;
2193 #endif
2194 }
2195
2196
2197 static gate_timestamp_t gate_win32_to_timestamp(FILETIME const* ft)
2198 {
2199 gate_uint64_t tmp = ((gate_uint64_t)ft->dwHighDateTime << 32) | (gate_uint64_t)ft->dwLowDateTime;
2200 tmp /= 10;
2201 return (gate_timestamp_t)tmp;
2202 }
2203
2204 static void gate_win32_convert_timestamp(gate_timestamp_t src, FILETIME* dest)
2205 {
2206 gate_uint64_t tmp = src * 10;
2207 dest->dwHighDateTime = (DWORD)(tmp >> 32);
2208 dest->dwLowDateTime = (DWORD)(tmp & 0xffffffff);
2209 }
2210
2211 gate_result_t gate_file_get_attributes(gate_string_t const* targetfile, gate_enumint_t* attribs, gate_enumint_t* access_bits)
2212 {
2213 gate_result_t ret;
2214 DWORD dwAttribs;
2215 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
2216 gate_size_t targetpathlen = gate_win32_string_2_winstr(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
2217
2218 do
2219 {
2220 if (targetpathlen == 0)
2221 {
2222 ret = GATE_RESULT_INVALIDARG;
2223 break;
2224 }
2225
2226 if (attribs)
2227 {
2228 dwAttribs = GetFileAttributes(targetpath);
2229 if (INVALID_FILE_ATTRIBUTES == dwAttribs)
2230 {
2231 ret = GATE_RESULT_FAILED;
2232 break;
2233 }
2234
2235 if (attribs == NULL)
2236 {
2237 ret = GATE_RESULT_INVALIDARG;
2238 break;
2239 }
2240 *attribs = 0;
2241
2242 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_DIRECTORY))
2243 {
2244 *attribs |= GATE_FILEENTRY_ATTRIB_DIRECTORY;
2245 }
2246 else
2247 {
2248 *attribs |= GATE_FILEENTRY_ATTRIB_FILE;
2249 }
2250 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_ARCHIVE)) *attribs |= GATE_FILEENTRY_ATTRIB_ARCHIVE;
2251 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_HIDDEN)) *attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
2252 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_READONLY)) *attribs |= GATE_FILEENTRY_ATTRIB_READONLY;
2253 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_SYSTEM)) *attribs |= GATE_FILEENTRY_ATTRIB_SYSTEM;
2254 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_COMPRESSED)) *attribs |= GATE_FILEENTRY_ATTRIB_COMPRESSED;
2255 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_TEMPORARY)) *attribs |= GATE_FILEENTRY_ATTRIB_TEMP;
2256 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_REPARSE_POINT)) *attribs |= GATE_FILEENTRY_ATTRIB_LINK;
2257
2258 if (gate_file_is_hidden_entry(targetfile))
2259 {
2260 *attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
2261 }
2262 }
2263
2264 if (access_bits)
2265 {
2266 *access_bits = 0;
2267 if (gate_string_ends_with_str_ic(targetfile, ".exe"))
2268 {
2269 *access_bits |= (GATE_FILEENTRY_ACCESS_OWNEREXECUTE | GATE_FILEENTRY_ACCESS_GROUPEXECUTE | GATE_FILEENTRY_ACCESS_ALLEXECUTE);
2270 }
2271 }
2272
2273 ret = GATE_RESULT_OK;
2274 } while (0);
2275 return ret;
2276 }
2277
2278
2279 static void gate_win32_update_attribute_flags(DWORD* dwAttribs, gate_enumint_t attribs, gate_enumint_t mask,
2280 gate_enumint_t gate_flag, DWORD win_flag)
2281 {
2282 if (GATE_FLAG_ENABLED(mask, gate_flag))
2283 {
2284 if (GATE_FLAG_ENABLED(attribs, gate_flag))
2285 {
2286 *dwAttribs |= win_flag;
2287 }
2288 else
2289 {
2290 *dwAttribs &= ~win_flag;
2291 }
2292 }
2293 }
2294
2295 #if defined(GATE_SYS_WIN16)
2296
2297 static BOOL SetFileAttributes(LPCSTR lpFileName, DWORD dwFileAttributes)
2298 {
2299 GATE_UNUSED_ARG(lpFileName);
2300 GATE_UNUSED_ARG(dwFileAttributes);
2301 return FALSE;
2302 }
2303
2304 #endif
2305
2306 gate_result_t gate_file_set_attributes(gate_string_t const* targetfile,
2307 gate_enumint_t attribs, gate_enumint_t attribs_mask,
2308 gate_enumint_t access_bits, gate_enumint_t access_mask)
2309 {
2310 gate_result_t ret = GATE_RESULT_OK;
2311 DWORD dwAttribs = 0;
2312 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
2313 gate_size_t targetpathlen = gate_win32_string_2_winstr(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
2314
2315 do
2316 {
2317 if (targetpathlen == 0)
2318 {
2319 ret = GATE_RESULT_INVALIDARG;
2320 break;
2321 }
2322
2323 if (attribs_mask != 0)
2324 {
2325 dwAttribs = GetFileAttributes(targetpath);
2326 if (INVALID_FILE_ATTRIBUTES == dwAttribs)
2327 {
2328 ret = GATE_RESULT_FAILED;
2329 break;
2330 }
2331
2332 gate_win32_update_attribute_flags(&dwAttribs, attribs, attribs_mask, GATE_FILEENTRY_ATTRIB_READONLY, FILE_ATTRIBUTE_READONLY);
2333 gate_win32_update_attribute_flags(&dwAttribs, attribs, attribs_mask, GATE_FILEENTRY_ATTRIB_SYSTEM, FILE_ATTRIBUTE_SYSTEM);
2334 gate_win32_update_attribute_flags(&dwAttribs, attribs, attribs_mask, GATE_FILEENTRY_ATTRIB_HIDDEN, GATE_FILEENTRY_ATTRIB_HIDDEN);
2335 gate_win32_update_attribute_flags(&dwAttribs, attribs, attribs_mask, GATE_FILEENTRY_ATTRIB_ARCHIVE, GATE_FILEENTRY_ATTRIB_ARCHIVE);
2336
2337 if (!SetFileAttributes(targetpath, dwAttribs))
2338 {
2339 ret = GATE_RESULT_FAILED;
2340 break;
2341 }
2342 }
2343
2344 if (access_mask != 0)
2345 {
2346 /* TODO update file ACL */
2347 GATE_UNUSED_ARG(access_bits);
2348 ret = GATE_RESULT_NOTSUPPORTED;
2349 break;
2350 }
2351
2352 } while (0);
2353
2354 return ret;
2355 }
2356
2357 gate_result_t gate_file_get_size(gate_string_t const* targetfile, gate_int64_t* filesize)
2358 {
2359 gate_result_t ret;
2360 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
2361 gate_size_t targetpathlen = gate_win32_string_2_winstr(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
2362 HANDLE hfile = (HANDLE)INVALID_HANDLE_VALUE;
2363 LARGE_INTEGER large_int;
2364 #if defined(GATE_SYS_WINSTORE)
2365 WIN32_FILE_ATTRIBUTE_DATA attrData;
2366 #endif
2367
2368 do
2369 {
2370 if (targetpathlen == 0)
2371 {
2372 ret = GATE_RESULT_INVALIDARG;
2373 break;
2374 }
2375 #if defined(GATE_SYS_WINSTORE)
2376 if (!GetFileAttributesEx(targetpath, GetFileExInfoStandard, &attrData))
2377 {
2378 ret = GATE_RESULT_FAILED;
2379 break;
2380 }
2381 large_int.QuadPart = (LONGLONG)((((gate_uint64_t)attrData.nFileSizeHigh) << 32) + (gate_uint64_t)attrData.nFileSizeLow);
2382 #else /* GATE_SYS_WINSTORE */
2383 hfile = gate_win32_createfile(targetpath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING,
2384 0, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2385 if (hfile == (HANDLE)INVALID_HANDLE_VALUE)
2386 {
2387 ret = GATE_RESULT_FAILED;
2388 break;
2389 }
2390 if (!gate_win32_getfilesize(hfile, &large_int))
2391 {
2392 ret = GATE_RESULT_FAILED;
2393 break;
2394 }
2395 #endif /* GATE_SYS_WINSTORE */
2396
2397 if (filesize)
2398 {
2399 gate_win32_read_largeint(&large_int, filesize);
2400 }
2401 ret = GATE_RESULT_OK;
2402 break;
2403
2404 } while (0);
2405
2406 gate_win32_closehandle(hfile);
2407 return ret;
2408 }
2409
2410
2411 gate_result_t gate_file_get_times(gate_string_t const* targetfile, gate_timestamp_t* modified,
2412 gate_timestamp_t* accessed, gate_timestamp_t* created)
2413 {
2414 gate_result_t ret;
2415 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
2416 gate_size_t targetpathlen = gate_win32_string_2_winstr(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
2417 HANDLE hfile = (HANDLE)INVALID_HANDLE_VALUE;
2418 FILETIME ftModified, ftAccessed, ftCreated;
2419 #if defined(GATE_SYS_WINCE)
2420 DWORD dwAttribs = 0;
2421 #endif
2422 #if defined(GATE_SYS_WINSTORE)
2423 WIN32_FILE_ATTRIBUTE_DATA attrData;
2424 #endif
2425
2426 do
2427 {
2428 if (targetpathlen == 0)
2429 {
2430 ret = GATE_RESULT_INVALIDARG;
2431 break;
2432 }
2433 #if defined(GATE_SYS_WINCE)
2434 dwAttribs = GetFileAttributes(targetpath);
2435 if (dwAttribs == 0xFFFFFFFF)
2436 {
2437 ret = GATE_RESULT_FAILED;
2438 break;
2439 }
2440 if (GATE_FLAG_ENABLED(dwAttribs, FILE_ATTRIBUTE_DIRECTORY))
2441 {
2442 if (created) *created = 0;
2443 if (accessed) *accessed = 0;
2444 if (modified) *modified = 0;
2445 ret = GATE_RESULT_OK;
2446 break;
2447 }
2448 #endif
2449
2450 #if defined(GATE_SYS_WINSTORE)
2451 if (!GetFileAttributesEx(targetpath, GetFileExInfoStandard, &attrData))
2452 {
2453 ret = GATE_RESULT_FAILED;
2454 break;
2455 }
2456 ftCreated = attrData.ftCreationTime;
2457 ftAccessed = attrData.ftLastAccessTime;
2458 ftModified = attrData.ftLastWriteTime;
2459 #elif defined(GATE_SYS_WIN16)
2460 ret = GATE_RESULT_NOTSUPPORTED;
2461 #else /* GATE_SYS_WINSTORE */
2462 hfile = gate_win32_createfile(targetpath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING,
2463 0, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2464 if (INVALID_HANDLE_VALUE == hfile)
2465 {
2466 ret = GATE_RESULT_FAILED;
2467 break;
2468 }
2469 if (!GetFileTime(hfile, &ftCreated, &ftAccessed, &ftModified))
2470 {
2471 ret = GATE_RESULT_FAILED;
2472 }
2473 else
2474 {
2475 ret = GATE_RESULT_OK;
2476 }
2477 #endif /* GATE_SYS_WINSTORE */
2478 if (created) *created = gate_win32_to_timestamp(&ftCreated);
2479 if (accessed) *accessed = gate_win32_to_timestamp(&ftAccessed);
2480 if (modified) *modified = gate_win32_to_timestamp(&ftModified);
2481
2482 } while (0);
2483
2484 gate_win32_closehandle(hfile);
2485 return ret;
2486 }
2487
2488
2489 gate_result_t gate_file_set_times(gate_string_t const* targetfile, gate_timestamp_t const* modified,
2490 gate_timestamp_t const* accessed, gate_timestamp_t const* created)
2491 {
2492 gate_result_t ret;
2493 TCHAR targetpath[GATE_MAX_FILEPATH_LENGTH];
2494 gate_size_t targetpathlen = gate_win32_string_2_winstr(targetfile, targetpath, sizeof(targetpath) / sizeof(targetpath[0]));
2495 HANDLE hfile = (HANDLE)INVALID_HANDLE_VALUE;
2496 FILETIME ftModified, ftAccessed, ftCreated;
2497 do
2498 {
2499 if (targetpathlen == 0)
2500 {
2501 ret = GATE_RESULT_INVALIDARG;
2502 break;
2503 }
2504
2505 if (created) gate_win32_convert_timestamp(*created, &ftCreated);
2506 if (accessed) gate_win32_convert_timestamp(*accessed, &ftAccessed);
2507 if (modified) gate_win32_convert_timestamp(*modified, &ftModified);
2508
2509 #if defined(GATE_SYS_WINSTORE) || defined(GATE_SYS_WIN16)
2510 ret = GATE_RESULT_NOTSUPPORTED;
2511 break;
2512 #else
2513 hfile = gate_win32_createfile(targetpath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2514 if (hfile == INVALID_HANDLE_VALUE)
2515 {
2516 ret = GATE_RESULT_FAILED;
2517 break;
2518 }
2519
2520 if (!SetFileTime(hfile, (created ? &ftCreated : NULL), (accessed ? &ftAccessed : NULL), (modified ? &ftModified : NULL)))
2521 {
2522 ret = GATE_RESULT_FAILED;
2523 }
2524 else
2525 {
2526 ret = GATE_RESULT_OK;
2527 }
2528 #endif
2529 } while (0);
2530
2531 gate_win32_closehandle(hfile);
2532 return ret;
2533 }
2534
2535 #ifndef OWNER_SECURITY_INFORMATION
2536 #define OWNER_SECURITY_INFORMATION (0x00000001L)
2537 #endif
2538
2539 #ifndef GROUP_SECURITY_INFORMATION
2540 #define GROUP_SECURITY_INFORMATION (0x00000002L)
2541 #endif
2542
2543 gate_result_t gate_file_get_owner(gate_string_t const* targetpath,
2544 gate_uint32_t* owner_id, gate_string_t* owner_name)
2545 {
2546 #if defined(GATE_SYS_WINSTORE) || defined(GATE_SYS_WINCE) || defined(GATE_SYS_WIN16)
2547 GATE_UNUSED_ARG(targetpath);
2548 GATE_UNUSED_ARG(owner_id);
2549 GATE_UNUSED_ARG(owner_name);
2550 return GATE_RESULT_NOTSUPPORTED;
2551 #else
2552
2553 gate_result_t ret = GATE_RESULT_FAILED;
2554 HANDLE hfile = INVALID_HANDLE_VALUE;
2555 PSECURITY_DESCRIPTOR descriptor = NULL;
2556 DWORD sec_info = 0;
2557 PSID owner_sid = NULL;
2558 PSID group_sid = NULL;
2559 DWORD owner_rid = 0;
2560 DWORD result;
2561 TCHAR filepath[GATE_MAX_FILEPATH_LENGTH] = GATE_INIT_EMPTY;
2562 char owner_buffer[512] = GATE_INIT_EMPTY;
2563
2564 do
2565 {
2566 if (!gate_platform.AdvGetSecurityInfo)
2567 {
2568 ret = GATE_RESULT_NOTSUPPORTED;
2569 break;
2570 }
2571
2572 gate_win32_string_2_winstr(targetpath, filepath, sizeof(filepath) / sizeof(filepath[0]));
2573 hfile = gate_win32_createfile(filepath, READ_CONTROL, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, 0, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2574 if (hfile == INVALID_HANDLE_VALUE)
2575 {
2576 ret = gate_platform_print_last_error(NULL, 0);
2577 break;
2578 }
2579 sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION;
2580 result = gate_platform.AdvGetSecurityInfo(hfile, GATE_SE_FILE_OBJECT, sec_info, &owner_sid, &group_sid, NULL, NULL, &descriptor);
2581 if (0 != result)
2582 {
2583 ret = GATE_RESULT_FAILED;
2584 break;
2585 }
2586
2587 ret = GATE_RESULT_OK;
2588 if (owner_id)
2589 {
2590 if (gate_win32_sid_local_id(owner_sid, &owner_rid))
2591 {
2592 *owner_id = owner_rid;
2593 }
2594 else
2595 {
2596 *owner_id = 0;
2597 }
2598 }
2599 if (owner_name)
2600 {
2601 if (gate_win32_sid_resolve(owner_sid, owner_buffer, sizeof(owner_buffer)))
2602 {
2603 if (NULL == gate_string_create(owner_name, owner_buffer, gate_str_length(owner_buffer)))
2604 {
2605 ret = GATE_RESULT_OUTOFMEMORY;
2606 }
2607 }
2608 else
2609 {
2610 gate_string_create_empty(owner_name);
2611 }
2612 }
2613 } while (0);
2614
2615 if (descriptor != NULL)
2616 {
2617 LocalFree(descriptor);
2618 }
2619 gate_win32_closehandle(hfile);
2620 return ret;
2621 #endif
2622 }
2623
2624
2625
2626 #ifndef IO_REPARSE_TAG_SYMLINK
2627 #define IO_REPARSE_TAG_SYMLINK (0xA000000C)
2628 #endif
2629
2630 static void gate_win32_load_direntry(WIN32_FIND_DATA const* filedata, gate_file_entry_t* direntry,
2631 char const* filepath, gate_size_t filepathlen)
2632 {
2633 DWORD fileAttribs = filedata->dwFileAttributes;
2634 gate_string_t filepathstr;
2635
2636 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WINSTORE) && !defined(GATE_SYS_WIN16)
2637 /* SymLink detection code */
2638
2639 BY_HANDLE_FILE_INFORMATION handleinfo;
2640 TCHAR tmppath[GATE_MAX_FILEPATH_LENGTH];
2641 HANDLE hfile;
2642
2643 direntry->props.attribs = 0;
2644
2645 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_REPARSE_POINT))
2646 {
2647 direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_LINK;
2648 if (filedata->dwReserved0 == IO_REPARSE_TAG_SYMLINK)
2649 {
2650
2651 if (!GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_DIRECTORY))
2652 {
2653 /* load data from real file */
2654 gate_win32_utf8_2_winstr(filepath, filepathlen, tmppath, sizeof(tmppath) / sizeof(tmppath[0]));
2655 hfile = gate_win32_createfile(tmppath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2656 OPEN_EXISTING, 0, 0, NULL);
2657 if (hfile != INVALID_HANDLE_VALUE)
2658 {
2659 if (GetFileInformationByHandle(hfile, &handleinfo))
2660 {
2661 fileAttribs = handleinfo.dwFileAttributes;
2662 direntry->props.size = ((gate_uint64_t)handleinfo.nFileSizeHigh << 32) + (gate_uint64_t)(handleinfo.nFileSizeLow);
2663 direntry->props.time_created = gate_win32_to_timestamp(&handleinfo.ftCreationTime);
2664 direntry->props.time_accessed = gate_win32_to_timestamp(&handleinfo.ftLastAccessTime);
2665 direntry->props.time_modified = gate_win32_to_timestamp(&handleinfo.ftLastWriteTime);
2666 }
2667 gate_win32_closehandle(hfile);
2668 }
2669 }
2670 }
2671 }
2672 #else
2673 direntry->props.attribs = 0;
2674 #endif
2675
2676 direntry->props.size = ((gate_uint64_t)filedata->nFileSizeHigh << 32) + (gate_uint64_t)(filedata->nFileSizeLow);
2677
2678 direntry->props.time_created = gate_win32_to_timestamp(&filedata->ftCreationTime);
2679 direntry->props.time_accessed = gate_win32_to_timestamp(&filedata->ftLastAccessTime);
2680 direntry->props.time_modified = gate_win32_to_timestamp(&filedata->ftLastWriteTime);
2681
2682 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_DIRECTORY)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_DIRECTORY;
2683 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_READONLY)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_READONLY;
2684 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_HIDDEN)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
2685 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_SYSTEM)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_SYSTEM;
2686 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_ARCHIVE)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_ARCHIVE;
2687
2688 /* windows special types: */
2689 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_TEMPORARY)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_TEMP;
2690 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_COMPRESSED)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_COMPRESSED;
2691 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_ENCRYPTED)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_ENCRYPTED;
2692 #if defined(FILE_ATTRIBUTE_DEVICE)
2693 if (GATE_FLAG_ENABLED(fileAttribs, FILE_ATTRIBUTE_DEVICE)) direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_DEVICE;
2694 #endif
2695
2696 if (0 == (fileAttribs & (FILE_ATTRIBUTE_DIRECTORY
2697 #if defined(FILE_ATTRIBUTE_DEVICE)
2698 | FILE_ATTRIBUTE_DEVICE
2699 #endif
2700 )))
2701 {
2702 /* neither a directory nor a device -> file */
2703 direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_FILE;
2704 }
2705 gate_string_create_static_len(&filepathstr, filepath, filepathlen);
2706 if (gate_file_is_hidden_entry(&filepathstr))
2707 {
2708 direntry->props.attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
2709 }
2710
2711 if (gate_str_ends_with_ic(filepath, filepathlen, ".exe", 4))
2712 {
2713 direntry->props.access |= (GATE_FILEENTRY_ACCESS_ALLEXECUTE | GATE_FILEENTRY_ACCESS_OWNEREXECUTE | GATE_FILEENTRY_ACCESS_GROUPEXECUTE);
2714 }
2715 }
2716
2717 gate_result_t gate_file_get_entry(gate_string_t const* srcpath, gate_file_entry_t* ptr_entry)
2718 {
2719 gate_result_t ret;
2720 TCHAR path[GATE_MAX_FILEPATH_LENGTH + 5];
2721 gate_size_t pathlen = gate_win32_string_2_winstr(srcpath, path, sizeof(path) / sizeof(path[0]));
2722 gate_size_t filenamelen;
2723 gate_size_t filepathlen;
2724
2725 HANDLE handle;
2726 WIN32_FIND_DATA filedata;
2727 do
2728 {
2729 gate_mem_clear(ptr_entry, sizeof(gate_file_entry_t));
2730 if (pathlen == 0)
2731 {
2732 ret = GATE_RESULT_INVALIDARG;
2733 break;
2734 }
2735
2736 if (gate_win32_winstr_ends_with(path, pathlen, GATE_WIN32_WINSTR("\\"), 1))
2737 {
2738 --pathlen;
2739 path[pathlen] = 0;
2740 }
2741
2742 filepathlen = gate_win32_winstr_2_utf8(path, pathlen, ptr_entry->path, sizeof(ptr_entry->path));
2743
2744 handle = gate_win32_findfirstfile(path, &filedata);
2745
2746 if (handle == (HANDLE)INVALID_HANDLE_VALUE)
2747 {
2748 gate_win32_print_lasterror(&ret, NULL, 0);
2749 break;
2750 }
2751 gate_win32_findclose(handle);
2752
2753 filenamelen = gate_win32_winstr_2_utf8(filedata.cFileName, gate_win32_winstr_length(filedata.cFileName),
2754 ptr_entry->name, sizeof(ptr_entry->name));
2755 if (filenamelen == 0)
2756 {
2757 ret = GATE_RESULT_FAILED;
2758 break;
2759 }
2760
2761
2762 gate_win32_load_direntry(&filedata, ptr_entry, ptr_entry->path, filepathlen);
2763
2764 ret = GATE_RESULT_OK;
2765 } while (0);
2766
2767 return ret;
2768 }
2769
2770 gate_result_t gate_file_root_list(gate_file_list_callback_t callback, void* userparam)
2771 {
2772 gate_result_t ret = GATE_RESULT_OK;
2773 gate_file_entry_t direntry;
2774
2775 #if !defined(GATE_SYS_WINCE)
2776 DWORD drives;
2777 DWORD ndx;
2778 char name[] = "A:";
2779 char path[] = "A:\\";
2780 #endif
2781
2782 #if defined(GATE_SYS_WINCE)
2783
2784 gate_mem_clear(&direntry, sizeof(direntry));
2785 direntry.props.attribs = GATE_FILEENTRY_ATTRIB_DIRECTORY;
2786
2787 gate_str_print_text(direntry.name, sizeof(direntry.name), "\\", 1);
2788 gate_str_print_text(direntry.path, sizeof(direntry.path), "\\", 1);
2789
2790 if (callback != NULL)
2791 {
2792 callback(&direntry, userparam);
2793 }
2794 #else
2795 drives = GetLogicalDrives();
2796
2797 for (ndx = 0; ndx < 26; ++ndx)
2798 {
2799 if ((drives & (1 << ndx)) != 0)
2800 {
2801 if (callback != NULL)
2802 {
2803 gate_mem_clear(&direntry, sizeof(direntry));
2804
2805 gate_str_print_text(direntry.name, sizeof(direntry.name), name, 2);
2806 gate_str_print_text(direntry.path, sizeof(direntry.path), path, 3);
2807
2808 direntry.props.attribs = GATE_FILEENTRY_ATTRIB_DIRECTORY | GATE_FILEENTRY_ATTRIB_VOLUME;
2809
2810 if (!callback(&direntry, userparam))
2811 {
2812 break;
2813 }
2814 }
2815 }
2816 ++name[0];
2817 ++path[0];
2818 }
2819 #endif
2820
2821 return ret;
2822 }
2823
2824 gate_result_t gate_file_dir_open(gate_string_t const* dirpath, gate_file_dirreader_t* dirhandle)
2825 {
2826 gate_result_t ret = GATE_RESULT_FAILED;
2827 TCHAR searchpath[GATE_MAX_FILEPATH_LENGTH + 5];
2828 gate_size_t searchpath_len;
2829 WIN32_FIND_DATA filedata;
2830 gate_size_t filename_len;
2831
2832 do
2833 {
2834 gate_mem_clear(dirhandle, sizeof(gate_file_dirreader_t));
2835
2836 dirhandle->bufferlen = gate_string_to_buffer(dirpath, dirhandle->buffer, sizeof(dirhandle->buffer));
2837 if (dirhandle->buffer[dirhandle->bufferlen - 1] != '\\')
2838 {
2839 dirhandle->buffer[dirhandle->bufferlen] = '\\';
2840 ++dirhandle->bufferlen;
2841 dirhandle->buffer[dirhandle->bufferlen] = '\0';
2842 }
2843
2844 searchpath_len = gate_win32_utf8_2_winstr(dirhandle->buffer, dirhandle->bufferlen, searchpath, sizeof(searchpath) / sizeof(searchpath[0]));
2845 searchpath[searchpath_len++] = (TCHAR)'*';
2846 searchpath[searchpath_len++] = (TCHAR)'.';
2847 searchpath[searchpath_len++] = (TCHAR)'*';
2848 searchpath[searchpath_len] = (TCHAR)'\0';
2849
2850 dirhandle->handle = (void*)gate_win32_findfirstfile(searchpath, &filedata);
2851 if ((HANDLE)dirhandle->handle == (HANDLE)INVALID_HANDLE_VALUE)
2852 {
2853 gate_win32_print_lasterror(&ret, NULL, 0);
2854 break;
2855 }
2856 filename_len = gate_win32_winstr_length(filedata.cFileName);
2857
2858 for (;;)
2859 {
2860 if ((0 != gate_win32_winstr_compare(filedata.cFileName, filename_len, _T("."), 1))
2861 && (0 != gate_win32_winstr_compare(filedata.cFileName, filename_len, _T(".."), 2)))
2862 {
2863 break;
2864 }
2865 if (gate_win32_findnext((HANDLE)dirhandle->handle, &filedata))
2866 {
2867 filename_len = gate_win32_winstr_length(filedata.cFileName);
2868 }
2869 else
2870 {
2871 gate_mem_clear(dirhandle->buffer, sizeof(dirhandle->buffer));
2872 dirhandle->bufferlen = 0;
2873 return GATE_RESULT_OK;
2874 }
2875 }
2876
2877 gate_win32_winstr_2_utf8(filedata.cFileName, gate_win32_winstr_length(filedata.cFileName),
2878 &dirhandle->buffer[dirhandle->bufferlen], sizeof(dirhandle->buffer) - dirhandle->bufferlen);
2879
2880 ret = GATE_RESULT_OK;
2881 } while (0);
2882
2883 return ret;
2884 }
2885 gate_size_t gate_file_dir_read(gate_file_dirreader_t* dirhandle, char* path, gate_size_t pathlen, gate_bool_t filename_only)
2886 {
2887 gate_size_t ret = 0;
2888 WIN32_FIND_DATA filedata;
2889
2890 if (filename_only)
2891 {
2892 /* return previously retrieved file name */
2893 ret = gate_str_print_text(path, pathlen,
2894 &dirhandle->buffer[dirhandle->bufferlen],
2895 gate_str_length(&dirhandle->buffer[dirhandle->bufferlen]));
2896 }
2897 else
2898 {
2899 /* return previously retrieved file path */
2900 ret = gate_str_print_text(path, pathlen,
2901 &dirhandle->buffer[0],
2902 gate_str_length(&dirhandle->buffer[0]));
2903 }
2904
2905 if (ret > 0)
2906 {
2907 if (gate_win32_findnext((HANDLE)dirhandle->handle, &filedata))
2908 {
2909 gate_win32_winstr_2_utf8(filedata.cFileName, gate_win32_winstr_length(filedata.cFileName),
2910 &dirhandle->buffer[dirhandle->bufferlen], sizeof(dirhandle->buffer) - dirhandle->bufferlen
2911 );
2912 }
2913 else
2914 {
2915 /* no more files can be retrieved -> set path buffer to zero*/
2916 gate_mem_clear(dirhandle->buffer, sizeof(dirhandle->buffer));
2917 dirhandle->bufferlen = 0;
2918 }
2919 /* find next */
2920 }
2921
2922 return ret;
2923 }
2924 gate_result_t gate_file_dir_close(gate_file_dirreader_t* dirhandle)
2925 {
2926 gate_result_t ret = GATE_RESULT_FAILED;
2927
2928 if (gate_win32_findclose((HANDLE)dirhandle->handle))
2929 {
2930 ret = GATE_RESULT_OK;
2931 }
2932 gate_mem_clear(dirhandle, sizeof(gate_file_dirreader_t));
2933
2934 return ret;
2935 }
2936
2937 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WINSTORE) && !defined(GATE_SYS_WIN16)
2938 # define GATE_FILES_MPR_SUPPORTED 1
2939 #endif
2940
2941
2942 #if defined(GATE_FILES_MPR_SUPPORTED)
2943
2944 typedef struct win32_mpr_functions_class
2945 {
2946 DWORD(WINAPI* MprWNetOpenEnum)(DWORD dwScope, DWORD dwType, DWORD dwUsage, LPNETRESOURCE lpNetResource, LPHANDLE lphEnum);
2947 DWORD(WINAPI* MprWNetEnumResource)(HANDLE hEnum, LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
2948 DWORD(WINAPI* MprWNetCloseEnum)(HANDLE hEnum);
2949 } win32_mpr_functions_t;
2950
2951 static win32_mpr_functions_t* win32_mpr()
2952 {
2953 static win32_mpr_functions_t mpr;
2954 static HMODULE hmpr = NULL;
2955 static gate_atomic_int_t mpr_load_state = 0;
2956 gate_int32_t state = 1;
2957
2958 do
2959 {
2960 state = gate_atomic_int_xchg_if(&mpr_load_state, 0, 1);
2961 if (state >= 2)
2962 {
2963 /* functions are loaded */
2964 break;
2965 }
2966 else if (state == 0)
2967 {
2968 hmpr = gate_win32_load_library(_T("mpr"), 0);
2969
2970 if (hmpr != NULL)
2971 {
2972 gate_win32_get_proc_address(hmpr, GATE_WIN32_DUAL_NAME("WNetOpenEnum"), &mpr.MprWNetOpenEnum);
2973 gate_win32_get_proc_address(hmpr, GATE_WIN32_DUAL_NAME("WNetEnumResource"), &mpr.MprWNetEnumResource);
2974 gate_win32_get_proc_address(hmpr, "WNetCloseEnum", &mpr.MprWNetCloseEnum);
2975 }
2976 gate_atomic_int_set(&mpr_load_state, 2);
2977 break;
2978 }
2979 else if (state < 0)
2980 {
2981 /* error, invalid state */
2982 break;
2983 }
2984 /* another thread is loading functions, -> wait/retry*/
2985 Sleep(0);
2986 } while (state == 1);
2987
2988 return &mpr;
2989 }
2990
2991 static gate_result_t gate_file_list_server_shares(LPTSTR path, gate_file_list_callback_t callback, void* userparam)
2992 {
2993 gate_result_t ret = GATE_RESULT_FAILED;
2994 gate_file_entry_t direntry;
2995 DWORD result;
2996 DWORD count;
2997 DWORD size;
2998 NETRESOURCE netres;
2999 HANDLE handle = NULL;
3000 gate_size_t filenamelen;
3001 gate_size_t filepathlen;
3002 win32_mpr_functions_t* mpr = win32_mpr();
3003 union
3004 {
3005 NETRESOURCE net;
3006 char buffer[8192];
3007 } netbuffer;
3008
3009 do
3010 {
3011 /* enumerate shares of an smb file service host */
3012 gate_mem_clear(&netres, sizeof(netres));
3013 netres.dwScope = RESOURCE_GLOBALNET;
3014 netres.dwType = RESOURCETYPE_DISK;
3015 netres.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
3016 netres.dwUsage = RESOURCEUSAGE_CONTAINER;
3017 netres.lpComment = NULL;
3018 netres.lpProvider = NULL;
3019 netres.lpLocalName = NULL;
3020 netres.lpRemoteName = path;
3021
3022 if (!mpr->MprWNetOpenEnum || !mpr->MprWNetEnumResource || !mpr->MprWNetCloseEnum)
3023 {
3024 ret = GATE_RESULT_NOTSUPPORTED;
3025 break;
3026 }
3027
3028 result = mpr->MprWNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, RESOURCEUSAGE_ALL, &netres, &handle);
3029 if (NO_ERROR != result)
3030 {
3031 gate_win32_setlasterror(result);
3032 ret = GATE_RESULT_FAILED;
3033 break;
3034 }
3035 count = 1;
3036 size = sizeof(netres);
3037 result = mpr->MprWNetEnumResource(handle, &count, &netbuffer, &size);
3038 while ((ERROR_MORE_DATA == result) || (NO_ERROR == result))
3039 {
3040 gate_mem_clear(&direntry, sizeof(direntry));
3041
3042 filenamelen = gate_win32_winstr_2_utf8(netbuffer.net.lpRemoteName, gate_win32_winstr_length(netbuffer.net.lpRemoteName),
3043 direntry.name, sizeof(direntry.name));
3044 filepathlen = gate_win32_winstr_2_utf8(path, gate_win32_winstr_length(path),
3045 direntry.path, sizeof(direntry.path));
3046 direntry.props.size = 0;
3047 direntry.props.attribs = GATE_FILEENTRY_ATTRIB_DIRECTORY;
3048 direntry.props.time_created = 0;
3049 direntry.props.time_modified = 0;
3050 direntry.props.time_accessed = 0;
3051
3052 if (callback != NULL)
3053 {
3054 if (false == callback(&direntry, userparam))
3055 {
3056 /* cancelled by user */
3057 break;
3058 }
3059 }
3060
3061 size = sizeof(netres);
3062 result = mpr->MprWNetEnumResource(handle, &count, &netbuffer, &size);
3063 }
3064 mpr->MprWNetCloseEnum(handle);
3065 } while (0);
3066
3067 return ret;
3068 }
3069 #endif /* defined(GATE_FILES_MPR_SUPPORTED) */
3070
3071
3072 gate_result_t gate_file_list(gate_string_t const* dirpath, gate_file_list_callback_t callback, void* userparam)
3073 {
3074 gate_result_t ret;
3075 TCHAR path[GATE_MAX_FILEPATH_LENGTH + 5];
3076 gate_size_t pathlen = gate_win32_string_2_winstr(dirpath, path, sizeof(path) / sizeof(path[0]));
3077 //char filename[GATE_MAX_FILENAME_LENGTH];
3078 gate_size_t filenamelen;
3079 char filepath[GATE_MAX_FILEPATH_LENGTH];
3080 gate_size_t filepathlen;
3081 gate_size_t filepathlen2;
3082 HANDLE hsearch = (HANDLE)NULL;
3083 WIN32_FIND_DATA filedata;
3084 gate_file_entry_t direntry;
3085
3086 do
3087 {
3088 if (pathlen == 0)
3089 {
3090 ret = GATE_RESULT_INVALIDARG;
3091 break;
3092 }
3093
3094 #if defined(GATE_FILES_MPR_SUPPORTED)
3095 if (!gate_file_is_server_share_path(path, false))
3096 {
3097 if (gate_file_is_server_path(path, true))
3098 {
3099 ret = gate_file_list_server_shares(path, callback, userparam);
3100 break;
3101 }
3102 }
3103 #endif /* defined(GATE_FILES_MPR_SUPPORTED) */
3104
3105 /* file search required '*.*' token at the end of the directory path */
3106 if (gate_win32_winstr_ends_with(path, pathlen, GATE_WIN32_WINSTR("\\"), 1))
3107 {
3108 gate_win32_winstr_print_text(&path[pathlen], sizeof(path) / sizeof(path[0]) - pathlen, GATE_WIN32_WINSTR("*.*"), 3);
3109 pathlen += 3;
3110
3111 }
3112 else if (!gate_win32_winstr_ends_with(path, pathlen, GATE_WIN32_WINSTR("\\*.*"), 4))
3113 {
3114 gate_win32_winstr_print_text(&path[pathlen], sizeof(path) / sizeof(path[0]) - pathlen, GATE_WIN32_WINSTR("\\*.*"), 4);
3115 pathlen += 4;
3116 }
3117
3118 filepathlen = gate_win32_winstr_2_utf8(path, pathlen - 3, filepath, sizeof(filepath));
3119
3120 hsearch = gate_win32_findfirstfile(path, &filedata);
3121 if ((HANDLE)INVALID_HANDLE_VALUE == hsearch)
3122 {
3123 #if defined(GATE_SYS_WINCE)
3124 /* empty directories return *.*-error in wince */
3125 path[pathlen - 3] = '\0';
3126 pathlen -= 3;
3127 hsearch = gate_win32_findfirstfile(path, &filedata);
3128 if (INVALID_HANDLE_VALUE != hsearch)
3129 {
3130 /* directory exists -> so it's empty */
3131 ret = GATE_RESULT_OK;
3132 break;
3133 }
3134 #endif
3135 gate_win32_print_lasterror(&ret, NULL, 0);
3136 break;
3137 }
3138 do
3139 {
3140 gate_mem_clear(&direntry, sizeof(direntry));
3141 filenamelen = gate_win32_winstr_2_utf8(filedata.cFileName, gate_win32_winstr_length(filedata.cFileName),
3142 direntry.name, sizeof(direntry.name));
3143 if (filenamelen == 0)
3144 {
3145 /* failed to convert filename -> skip */
3146 continue;
3147 }
3148 if (0 == gate_str_compare(direntry.name, filenamelen, "..", 2))
3149 {
3150 /* skip parent-reference */
3151 continue;
3152 }
3153 if (0 == gate_str_compare(direntry.name, filenamelen, ".", 1))
3154 {
3155 /* skip self-reference */
3156 continue;
3157 }
3158
3159 filepathlen2 = gate_str_print_text(&filepath[filepathlen], sizeof(filepath) - filepathlen, direntry.name, filenamelen);
3160
3161 GATE_DEBUG_ASSERT(filenamelen == filepathlen2);
3162
3163 gate_str_print_text(direntry.path, sizeof(direntry.path), filepath, filepathlen + filepathlen2);
3164
3165 gate_win32_load_direntry(&filedata, &direntry, filepath, filepathlen + filepathlen2);
3166
3167 if (callback != NULL)
3168 {
3169 if (false == callback(&direntry, userparam))
3170 {
3171 /* canceled by user */
3172 break;
3173 }
3174 }
3175
3176 } while (gate_win32_findnext(hsearch, &filedata));
3177 ret = GATE_RESULT_OK;
3178 } while (0);
3179 gate_win32_findclose(hsearch);
3180 return ret;
3181 }
3182
3183 #if defined(GATE_SYS_WIN16)
3184 static BOOL CreateDirectory(LPCSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
3185 {
3186 GATE_UNUSED_ARG(lpSecurityAttributes);
3187 if (0 == _mkdir(lpPathName))
3188 {
3189 return TRUE;
3190 }
3191 else
3192 {
3193 return FALSE;
3194 }
3195 }
3196 #endif
3197
3198 gate_result_t gate_file_dir_create(gate_string_t const* dirpath, gate_enumint_t flags)
3199 {
3200 gate_result_t ret;
3201 TCHAR path[GATE_MAX_FILEPATH_LENGTH];
3202 gate_size_t pathlen = gate_win32_string_2_winstr(dirpath, path, sizeof(path) / sizeof(path[0]));
3203 if (pathlen == 0)
3204 {
3205 ret = GATE_RESULT_INVALIDARG;
3206 }
3207 else
3208 {
3209 if (path[pathlen - 1] == _T('\\'))
3210 {
3211 path[--pathlen] = 0;
3212 }
3213 if (CreateDirectory(path, NULL))
3214 {
3215 ret = GATE_RESULT_OK;
3216 }
3217 else
3218 {
3219 gate_win32_print_lasterror(&ret, NULL, 0);
3220 }
3221 }
3222 return ret;
3223 }
3224
3225 #if defined(GATE_SYS_WIN16)
3226 static BOOL RemoveDirectory(LPCSTR lpPathName)
3227 {
3228 if (0 == _rmdir(lpPathName))
3229 {
3230 return TRUE;
3231 }
3232 return FALSE;
3233 }
3234 #endif
3235
3236 gate_result_t gate_file_dir_delete(gate_string_t const* dirpath)
3237 {
3238 gate_result_t ret;
3239 DWORD dw_error;
3240 TCHAR path[GATE_MAX_FILEPATH_LENGTH];
3241 gate_size_t pathlen = gate_win32_string_2_winstr(dirpath, path, sizeof(path) / sizeof(path[0]) - 1);
3242 if (pathlen == 0)
3243 {
3244 ret = GATE_RESULT_INVALIDARG;
3245 }
3246 else
3247 {
3248 path[pathlen + 1] = 0; /* ensure double zero for shell-file-ops */
3249 if (RemoveDirectory(path))
3250 {
3251 ret = GATE_RESULT_OK;
3252 }
3253 else
3254 {
3255 dw_error = gate_win32_getlasterror();
3256 gate_win32_print_lasterror_code(dw_error, &ret, NULL, 0);
3257 /* try fallback */
3258 if (gate_win32_shfileop(GATE_WIN32_SHFILEOP_DELETE, path, NULL))
3259 {
3260 ret = GATE_RESULT_OK;
3261 }
3262 else
3263 {
3264 gate_win32_setlasterror(dw_error);
3265 }
3266 }
3267 }
3268 return ret;
3269 }
3270
3271 gate_result_t gate_file_dir_exists(gate_string_t const* dirpath)
3272 {
3273 WIN32_FIND_DATA data;
3274 DWORD attribs;
3275 HANDLE hfind;
3276 TCHAR path[GATE_MAX_FILEPATH_LENGTH];
3277 gate_size_t pathlen = gate_win32_utf8_2_winstr(dirpath->str, dirpath->length, path, sizeof(path) / sizeof(path[0]));
3278 if (path[pathlen - 1] == '\\')
3279 {
3280 --pathlen;
3281 path[pathlen] = 0;
3282 }
3283
3284 #if !defined(GATE_SYS_WIN16)
3285 if (gate_file_is_server_path(path, false))
3286 {
3287 return GATE_RESULT_OK;
3288 }
3289 if (gate_file_is_server_share_path(path, false))
3290 {
3291 return GATE_RESULT_OK;
3292 }
3293 #endif
3294
3295 attribs = GetFileAttributes(path);
3296 if (attribs != INVALID_FILE_ATTRIBUTES)
3297 {
3298 if (GATE_FLAG_ENABLED(attribs, FILE_ATTRIBUTE_DIRECTORY))
3299 {
3300 return GATE_RESULT_OK;
3301 }
3302 else
3303 {
3304 return GATE_RESULT_NOMATCH;
3305 }
3306 }
3307
3308 hfind = gate_win32_findfirstfile(path, &data);
3309 if (hfind != (HANDLE)INVALID_HANDLE_VALUE)
3310 {
3311 gate_win32_findclose(hfind);
3312 if (GATE_FLAG_ENABLED(data.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
3313 {
3314 return GATE_RESULT_OK;
3315 }
3316 else
3317 {
3318 return GATE_RESULT_NOMATCH;
3319 }
3320 }
3321 else
3322 {
3323 return GATE_RESULT_NOTAVAILABLE;
3324 }
3325 }
3326
3327
3328 #endif /* GATE_CORE_FILES_WINAPI_IMPL */
3329
3330
3331 #if defined(GATE_CORE_FILES_POSIX_IMPL)
3332
3333 #include "gate/platforms.h"
3334 #include <sys/stat.h>
3335 #include <sys/types.h>
3336 #include <stdio.h>
3337 #include <errno.h>
3338 #include <fcntl.h>
3339 #include <dirent.h>
3340 #include <utime.h>
3341 #include <stdlib.h>
3342
3343 char const gate_file_path_separator_char = '/';
3344 char const* const gate_file_path_separator = "/";
3345
3346
3347 315 gate_result_t gate_file_exists(gate_string_t const* filepath)
3348 {
3349 gate_result_t ret;
3350 char pathbuffer[GATE_MAX_FILEPATH_LENGTH];
3351 struct stat filestat;
3352 315 gate_string_to_buffer(filepath, pathbuffer, sizeof(pathbuffer));
3353
2/2
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 184 times.
315 if (0 == stat(pathbuffer, &filestat))
3354 {
3355 131 ret = GATE_RESULT_OK;
3356 }
3357 else
3358 {
3359 184 gate_posix_errno(&ret);
3360 }
3361 315 return ret;
3362 }
3363 58 gate_result_t gate_file_dir_exists(gate_string_t const* dirpath)
3364 {
3365 gate_result_t ret;
3366 char pathbuffer[GATE_MAX_FILEPATH_LENGTH];
3367 struct stat filestat;
3368 58 gate_size_t len = gate_string_to_buffer(dirpath, pathbuffer, sizeof(pathbuffer));
3369
3/4
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 44 times.
58 if ((len > 1) && (pathbuffer[len - 1] == '/'))
3370 {
3371 14 --len;
3372 14 pathbuffer[len] = 0;
3373 }
3374
3375
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 28 times.
58 if (0 == stat(pathbuffer, &filestat))
3376 {
3377
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 if (S_ISDIR(filestat.st_mode))
3378 {
3379 25 ret = GATE_RESULT_OK;
3380 }
3381 else
3382 {
3383 5 ret = GATE_RESULT_INVALIDSTATE;
3384 }
3385 }
3386 else
3387 {
3388 28 gate_posix_errno(&ret);
3389 }
3390 58 return ret;
3391 }
3392
3393 3 gate_result_t gate_file_copy(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
3394 {
3395 gate_size_t ret;
3396
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (GATE_FLAG_ENABLED(flags, GATE_FILE_COPY_SIMPLE))
3397 {
3398 1 ret = gate_file_copy_internal(srcfilepath, dstfilepath, flags);
3399 }
3400 else
3401 {
3402 2 gate_file_t srcfile = GATE_FILE_INVALID;
3403 2 gate_file_t dstfile = GATE_FILE_INVALID;
3404 gate_size_t bufferused;
3405 gate_size_t pos;
3406 gate_size_t written;
3407 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
3408 struct stat srcstat;
3409 struct utimbuf utm;
3410 2 gate_bool_t srcstatreceived = false;
3411
3412 do
3413 {
3414
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!GATE_FLAG_ENABLED(flags, GATE_FILE_COPY_OVERWRITE))
3415 {
3416
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (GATE_SUCCEEDED(gate_file_exists(dstfilepath)))
3417 {
3418 ret = GATE_RESULT_ALREADYEXISTS;
3419 break;
3420 }
3421 }
3422
3423 2 ret = gate_file_open(srcfilepath, GATE_STREAM_OPEN_READ, &srcfile);
3424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
3425 {
3426 break;
3427 }
3428
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (0 == fstat((int)(gate_intptr_t)srcfile, &srcstat))
3429 {
3430 2 utm.actime = srcstat.st_atime;
3431 2 utm.modtime = srcstat.st_mtime;
3432 2 srcstatreceived = true;
3433 }
3434 2 ret = gate_file_open(dstfilepath, GATE_STREAM_OPEN_WRITE, &dstfile);
3435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
3436 {
3437 break;
3438 }
3439 2 ret = gate_file_read(srcfile, buffer, sizeof(buffer), &bufferused);
3440
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 while (GATE_SUCCEEDED(ret))
3441 {
3442
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (bufferused == 0)
3443 {
3444 /* end of file */
3445 2 break;
3446 }
3447 2 pos = 0;
3448
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 while (pos < bufferused)
3449 {
3450 2 ret = gate_file_write(dstfile, &buffer[pos], bufferused - pos, &written);
3451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
3452 {
3453 break;
3454 }
3455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (written == 0)
3456 {
3457 ret = GATE_RESULT_INCORRECTSIZE;
3458 break;
3459 }
3460 2 pos += written;
3461 }
3462
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
3463 {
3464 2 ret = gate_file_read(srcfile, buffer, sizeof(buffer), &bufferused);
3465 }
3466 }
3467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
3468 {
3469 break;
3470 }
3471 } while (0);
3472
3473
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (srcfile != GATE_FILE_INVALID)
3474 {
3475 2 gate_file_close(srcfile);
3476 }
3477
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (dstfile != GATE_FILE_INVALID)
3478 {
3479 2 gate_file_close(dstfile);
3480 }
3481
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (GATE_SUCCEEDED(ret))
3482 {
3483
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (srcstatreceived)
3484 {
3485 2 gate_string_to_buffer(dstfilepath, buffer, sizeof(buffer));
3486 2 utime(buffer, &utm);
3487 }
3488 }
3489 }
3490 3 return ret;
3491 }
3492 1 gate_result_t gate_file_move(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
3493 {
3494 gate_result_t ret;
3495 char srcpath[GATE_MAX_FILEPATH_LENGTH];
3496 char dstpath[GATE_MAX_FILEPATH_LENGTH];
3497 1 gate_string_to_buffer(srcfilepath, srcpath, sizeof(srcpath));
3498 1 gate_string_to_buffer(dstfilepath, dstpath, sizeof(dstpath));
3499
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (rename(srcpath, dstpath) == 0)
3500 {
3501 1 ret = GATE_RESULT_OK;
3502 }
3503 else
3504 {
3505 gate_posix_errno(&ret);
3506 }
3507 1 return ret;
3508 }
3509 12 gate_result_t gate_file_delete(gate_string_t const* filepath)
3510 {
3511 gate_result_t ret;
3512 char pathbuffer[GATE_MAX_FILEPATH_LENGTH];
3513 12 gate_string_to_buffer(filepath, pathbuffer, sizeof(pathbuffer));
3514
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (0 == unlink(pathbuffer))
3515 {
3516 12 ret = GATE_RESULT_OK;
3517 }
3518 else
3519 {
3520 gate_posix_errno(&ret);
3521 }
3522 12 return ret;
3523 }
3524 1 gate_result_t gate_file_real_path(gate_string_t const* relativepath, gate_string_t* absolutepath)
3525 {
3526 gate_result_t ret;
3527 char relpath[GATE_MAX_FILEPATH_LENGTH];
3528 char abspath[PATH_MAX + 1];
3529 1 gate_string_to_buffer(relativepath, relpath, sizeof(relpath));
3530
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (realpath(relpath, abspath) != NULL)
3531 {
3532
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (NULL == gate_string_create(absolutepath, abspath, gate_str_length(abspath)))
3533 {
3534 ret = GATE_RESULT_OUTOFMEMORY;
3535 }
3536 else
3537 {
3538 1 ret = GATE_RESULT_OK;
3539 }
3540 }
3541 else
3542 {
3543 gate_posix_errno(&ret);
3544 }
3545 1 return ret;
3546 }
3547 1 gate_result_t gate_file_create_link(gate_string_t const* targetpath, gate_string_t const* linkfile)
3548 {
3549 gate_result_t ret;
3550 char target[PATH_MAX];
3551 char link[GATE_MAX_FILEPATH_LENGTH];
3552 1 gate_string_to_buffer(targetpath, link, sizeof(link));
3553
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (NULL == realpath(link, target))
3554 {
3555 gate_posix_errno(&ret);
3556 }
3557 else
3558 {
3559 1 gate_string_to_buffer(linkfile, link, sizeof(link));
3560
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (symlink(target, link) == 0)
3561 {
3562 1 ret = GATE_RESULT_OK;
3563 }
3564 else
3565 {
3566 gate_posix_errno(&ret);
3567 }
3568 }
3569 1 return ret;
3570 }
3571 1 gate_result_t gate_file_read_link(gate_string_t const* filepath, gate_string_t* realpath)
3572 {
3573 gate_result_t ret;
3574 char linkpath[GATE_MAX_FILEPATH_LENGTH];
3575
3576 1 gate_string_to_buffer(filepath, linkpath, sizeof(linkpath));
3577 for (;;)
3578 1 {
3579 char destpath[GATE_MAX_FILEPATH_LENGTH];
3580 2 ssize_t rlresult = readlink(linkpath, destpath, sizeof(destpath) / sizeof(destpath[0]) - 1);
3581
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (rlresult <= 0)
3582 {
3583 1 int err = gate_posix_errno(&ret);
3584
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (err == EINVAL)
3585 {
3586 /* real path found (not another link), return it */
3587
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (NULL == gate_string_create(realpath, destpath, gate_str_length(destpath)))
3588 {
3589 ret = GATE_RESULT_OUTOFMEMORY;
3590 }
3591 else
3592 {
3593 1 ret = GATE_RESULT_OK;
3594 }
3595 }
3596 else
3597 {
3598 /* all other cases are real errors during resolution */
3599 }
3600 1 break;
3601 }
3602 else
3603 {
3604 /* a destination path could be resolved.
3605 make it a new source to check
3606 */
3607 1 destpath[rlresult] = 0;
3608 1 gate_str_print_text(linkpath, sizeof(linkpath), destpath, gate_str_length(destpath));
3609 }
3610 }
3611 1 return ret;
3612 }
3613 1 gate_result_t gate_file_create_hardlink(gate_string_t const* targetfile, gate_string_t const* linkfile)
3614 {
3615 gate_result_t ret;
3616 char target[GATE_MAX_FILEPATH_LENGTH];
3617 char linkpath[GATE_MAX_FILEPATH_LENGTH];
3618 1 gate_string_to_buffer(targetfile, target, sizeof(target));
3619 1 gate_string_to_buffer(linkfile, linkpath, sizeof(linkpath));
3620
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (link(target, linkpath) == 0)
3621 {
3622 1 ret = GATE_RESULT_OK;
3623 }
3624 else
3625 {
3626 gate_posix_errno(&ret);
3627 }
3628 1 return ret;
3629 }
3630
3631 61 static gate_bool_t gate_file_parent_stat(gate_string_t const* filepath, mode_t* ptrmode, uid_t* ptruid, gid_t* ptrgid)
3632 {
3633 61 gate_size_t pos = gate_str_char_pos_last(filepath->str, filepath->length, gate_file_path_separator_char);
3634
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 22 times.
61 if (pos != GATE_STR_NPOS)
3635 {
3636 char parent[GATE_MAX_FILEPATH_LENGTH];
3637 struct stat dirstat;
3638 39 gate_str_print_text(parent, sizeof(parent), filepath->str, pos);
3639
2/2
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 2 times.
39 if (0 == lstat(parent, &dirstat))
3640 {
3641 37 mode_t mode = dirstat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
3642
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 if (ptrmode != NULL) *ptrmode = mode;
3643
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 if (ptruid != NULL) *ptruid = dirstat.st_uid;
3644
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 if (ptrgid != NULL) *ptrgid = dirstat.st_gid;
3645 37 return true;
3646 }
3647 }
3648 24 return false;
3649 }
3650
3651 172 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
3652 {
3653 gate_result_t ret;
3654
3655 do
3656 {
3657 char path[GATE_MAX_FILEPATH_LENGTH];
3658 int openflags;
3659 int fd;
3660 mode_t mode;
3661 172 uid_t open_as_uid = getuid();
3662 172 uid_t open_as_gid = getgid();
3663
3664
2/4
✓ Branch 1 taken 172 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 172 times.
172 if (gate_string_is_empty(filepath) || (filehandle == NULL))
3665 {
3666 ret = GATE_RESULT_INVALIDARG;
3667 38 break;
3668 }
3669 172 gate_string_to_buffer(filepath, path, sizeof(path));
3670
3671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 172 times.
172 if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_APPENDREADWRITE)) { openflags = (O_CREAT | O_RDWR | O_APPEND); }
3672
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 155 times.
172 else if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_APPENDWRITE)) { openflags = (O_CREAT | O_WRONLY | O_APPEND); }
3673
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 147 times.
155 else if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_READWRITE)) { openflags = (O_CREAT | O_RDWR); }
3674
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 116 times.
147 else if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_WRITE)) { openflags = (O_CREAT | O_WRONLY | O_TRUNC); }
3675
1/2
✓ Branch 0 taken 116 times.
✗ Branch 1 not taken.
116 else if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_READ)) { openflags = (O_RDONLY); }
3676 else
3677 {
3678 ret = GATE_RESULT_INVALIDARG;
3679 break;
3680 }
3681
3682 #ifdef O_CLOEXEC
3683 172 openflags |= O_CLOEXEC;
3684 #endif
3685
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 116 times.
172 if (GATE_FLAG_ENABLED(openflags, O_CREAT))
3686 {
3687 /* if a new file is created we have a chance to influence its permissions
3688 */
3689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEOWNERRESTRICTED))
3690 {
3691 /* only the owner has read/write access */
3692 mode = S_IRUSR | S_IWUSR;
3693 if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEEXECUTABLE))
3694 {
3695 mode |= S_IXUSR;
3696 }
3697 }
3698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 else if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEGROUPRESTRICTED))
3699 {
3700 /* owner and owner's primary group have read/write access */
3701 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
3702 if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEEXECUTABLE))
3703 {
3704 mode |= S_IXUSR | S_IXGRP;
3705 }
3706 }
3707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 else if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEUNRESTRICTED))
3708 {
3709 /* everyone has read/write access */
3710 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
3711 if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEEXECUTABLE))
3712 {
3713 mode |= S_IXUSR | S_IXGRP;
3714 }
3715 }
3716 else
3717 {
3718 /* in case of no specification, we try to apply
3719 the windows convention, where permissions are
3720 inherited from the parent directory
3721 */
3722 56 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
3723
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 22 times.
56 if (gate_file_parent_stat(filepath, &mode, &open_as_uid, &open_as_gid))
3724 {
3725
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 if (open_as_uid == 0)
3726 {
3727 34 open_as_uid = getuid();
3728 }
3729
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 if (open_as_gid == 0)
3730 {
3731 34 open_as_gid = getgid();
3732 }
3733 /* remove directory-X-bits */
3734 34 mode &= ~(mode_t)(S_IXUSR | S_IXGRP | S_IXOTH);
3735 }
3736
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 55 times.
56 if (GATE_FLAG_ENABLED(flags, GATE_FILE_OPEN_CREATEEXECUTABLE))
3737 {
3738
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_FLAG_ENABLED(mode, S_IRUSR)) mode |= S_IXUSR;
3739
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_FLAG_ENABLED(mode, S_IRGRP)) mode |= S_IXGRP;
3740
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_FLAG_ENABLED(mode, S_IROTH)) mode |= S_IXOTH;
3741 }
3742 }
3743
3744 /* try to open exclusive and fail, if file existed */
3745 56 fd = open(path, openflags | O_EXCL, mode);
3746
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 23 times.
56 if (fd != -1)
3747 {
3748 int result;
3749 /* open() succeeded */
3750 33 *filehandle = (gate_file_t)(intptr_t)fd;
3751
3752 /* We cannot trust the given mode,
3753 due to umask and multithreading issues,
3754 so let's try to patch permissions.
3755 If it fails, we just go on as this step is optional
3756 */
3757 33 result = fchmod(fd, mode);
3758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if(result != 0)
3759 {
3760 GATE_DEBUG_TRACE("fchmod() failed");
3761 }
3762
3763 /* In case of permission inheritance, we
3764 also need to change owner and group.
3765 Concept: If we are allowed to create a new file in the directory,
3766 then the directory's owner or group will allow the current process
3767 user to access its contents and we can safely change the ownership
3768 of our new created file.
3769 If this fails, we continue as this step is optional
3770 */
3771 33 result = fchown(fd, open_as_uid, open_as_gid);
3772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if(result != 0)
3773 {
3774 GATE_DEBUG_TRACE("fchown() failed");
3775 }
3776
3777 33 ret = GATE_RESULT_OK;
3778 33 break;
3779 }
3780 /* in case of an error, the file may exist,
3781 so continue with the default opening-procedure
3782 */
3783 }
3784
3785 139 mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
3786 139 fd = open(path, openflags, mode);
3787
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 134 times.
139 if (fd == -1)
3788 {
3789 /* open() failed */
3790 5 gate_posix_errno(&ret);
3791 5 break;
3792 }
3793
3794 134 *filehandle = (gate_file_t)(intptr_t)fd;
3795 134 ret = GATE_RESULT_OK;
3796 } while (0);
3797
3798 172 return ret;
3799 }
3800 45513 gate_result_t gate_file_read(gate_file_t filehandle, char* buffer, gate_size_t bufferlength, gate_size_t* bufferused)
3801 {
3802 gate_result_t ret;
3803 45513 int fd = (int)(gate_intptr_t)filehandle;
3804 45513 ssize_t returned = read(fd, buffer, bufferlength);
3805
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45513 times.
45513 if (returned < 0)
3806 {
3807 gate_posix_errno(&ret);
3808 }
3809 else
3810 {
3811
1/2
✓ Branch 0 taken 45513 times.
✗ Branch 1 not taken.
45513 if (bufferused != NULL)
3812 {
3813 45513 *bufferused = (gate_size_t)returned;
3814 }
3815 45513 ret = GATE_RESULT_OK;
3816 }
3817 45513 return ret;
3818 }
3819 6180 gate_result_t gate_file_write(gate_file_t filehandle, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
3820 {
3821 gate_result_t ret;
3822 6180 int fd = (int)(gate_intptr_t)filehandle;
3823 6180 ssize_t processed = write(fd, buffer, bufferlength);
3824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6180 times.
6180 if (processed < 0)
3825 {
3826 gate_posix_errno(&ret);
3827 }
3828 else
3829 {
3830
1/2
✓ Branch 0 taken 6180 times.
✗ Branch 1 not taken.
6180 if (written != NULL)
3831 {
3832 6180 *written = (gate_size_t)processed;
3833 }
3834 6180 ret = GATE_RESULT_OK;
3835 }
3836 6180 return ret;
3837
3838 }
3839 14 gate_result_t gate_file_flush(gate_file_t filehandle)
3840 {
3841 gate_result_t ret;
3842 14 int fd = (int)(gate_intptr_t)filehandle;
3843
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if (fsync(fd) == -1)
3844 {
3845 gate_posix_errno(&ret);
3846 }
3847 else
3848 {
3849 14 ret = GATE_RESULT_OK;
3850 }
3851 14 return ret;
3852 }
3853 169 gate_result_t gate_file_close(gate_file_t filehandle)
3854 {
3855 gate_result_t ret;
3856 169 int fd = (int)(gate_intptr_t)filehandle;
3857
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 167 times.
169 if (-1 == close(fd))
3858 {
3859 2 gate_posix_errno(&ret);
3860 }
3861 else
3862 {
3863 167 ret = GATE_RESULT_OK;
3864 }
3865 169 return ret;
3866 }
3867 24 gate_result_t gate_file_seek(gate_file_t filehandle, gate_int64_t position, gate_enumint_t origin, gate_int64_t* newposition)
3868 {
3869 gate_result_t ret;
3870 do
3871 {
3872 24 int fd = (int)(gate_intptr_t)filehandle;
3873 off_t offset;
3874 int whence;
3875
3876
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 14 times.
24 if (origin == GATE_FILE_SEEK_ORIGIN_BEGIN) { whence = SEEK_SET; }
3877
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
14 else if (origin == GATE_FILE_SEEK_ORIGIN_CURPOS) { whence = SEEK_CUR; }
3878
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 else if (origin == GATE_FILE_SEEK_ORIGIN_END) { whence = SEEK_END; }
3879 else
3880 {
3881 ret = GATE_RESULT_INVALIDARG;
3882 break;
3883 }
3884 24 offset = lseek(fd, (off_t)position, whence);
3885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (offset == (off_t)-1)
3886 {
3887 gate_posix_errno(&ret);
3888 break;
3889 }
3890
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 14 times.
24 if (newposition != NULL)
3891 {
3892 10 *newposition = (gate_int64_t)offset;
3893 }
3894 24 ret = GATE_RESULT_OK;
3895 } while (0);
3896
3897 24 return ret;
3898 }
3899 2 gate_result_t gate_file_pos(gate_file_t filehandle, gate_int64_t* position)
3900 {
3901 gate_result_t ret;
3902 2 int fd = (int)(gate_intptr_t)filehandle;
3903 2 off_t offset = lseek(fd, 0, SEEK_CUR);
3904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (offset == (off_t)-1)
3905 {
3906 gate_posix_errno(&ret);
3907 }
3908 else
3909 {
3910
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (position != NULL)
3911 {
3912 2 *position = (gate_int64_t)offset;
3913 }
3914 2 ret = GATE_RESULT_OK;
3915 }
3916 2 return ret;
3917 }
3918 4 gate_result_t gate_file_size(gate_file_t filehandle, gate_int64_t* size)
3919 {
3920 gate_result_t ret;
3921 4 int fd = (int)(gate_intptr_t)filehandle;
3922 struct stat filestat;
3923
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (fstat(fd, &filestat) == -1)
3924 {
3925 gate_posix_errno(&ret);
3926 }
3927 else
3928 {
3929
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (size != NULL)
3930 {
3931 4 *size = (gate_int64_t)filestat.st_size;
3932 }
3933 4 ret = GATE_RESULT_OK;
3934 }
3935 4 return ret;
3936 }
3937
3938 8 gate_result_t gate_file_truncate(gate_file_t filehandle)
3939 {
3940 gate_result_t ret;
3941 8 int fd = (int)(gate_intptr_t)filehandle;
3942 8 off_t offset = lseek(fd, 0, SEEK_CUR);
3943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (offset == (off_t)-1)
3944 {
3945 gate_posix_errno(&ret);
3946 }
3947 else
3948 {
3949
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (0 != ftruncate(fd, offset))
3950 {
3951 gate_posix_errno(&ret);
3952 }
3953 else
3954 {
3955 8 ret = GATE_RESULT_OK;
3956 }
3957 }
3958 8 return ret;
3959 }
3960
3961
3962 13 gate_result_t gate_file_lock(gate_file_t filehandle, gate_bool_t wait)
3963 {
3964 13 gate_result_t ret = GATE_RESULT_FAILED;
3965 13 int fd = (int)(gate_intptr_t)filehandle;
3966
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 gate_posix_flock_operation op = wait ? gate_posix_flock_exclusive : gate_posix_flock_exclusive_test;
3967 13 int result = gate_posix_flock(fd, op);
3968
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (result == 0)
3969 {
3970 13 ret = GATE_RESULT_OK;
3971 }
3972 13 return ret;
3973 }
3974 13 gate_result_t gate_file_unlock(gate_file_t filehandle)
3975 {
3976 13 gate_result_t ret = GATE_RESULT_FAILED;
3977 13 int fd = (int)(gate_intptr_t)filehandle;
3978 13 int result = gate_posix_flock(fd, gate_posix_flock_unlock);
3979
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (result == 0)
3980 {
3981 13 ret = GATE_RESULT_OK;
3982 }
3983 13 return ret;
3984 }
3985
3986
3987
3988 150 static void gate_unix_mode_to_attributes(mode_t mode, gate_enumint_t* ptr_attribs, gate_enumint_t* ptr_accessbits)
3989 {
3990
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 if (ptr_accessbits)
3991 {
3992 150 *ptr_accessbits = 0;
3993
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 if (GATE_FLAG_ENABLED(mode, S_IRUSR)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_OWNERREAD;
3994
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 if (GATE_FLAG_ENABLED(mode, S_IWUSR)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_OWNERWRITE;
3995
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 9 times.
150 if (GATE_FLAG_ENABLED(mode, S_IXUSR)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_OWNEREXECUTE;
3996
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 7 times.
150 if (GATE_FLAG_ENABLED(mode, S_IRGRP)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_GROUPREAD;
3997
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 46 times.
150 if (GATE_FLAG_ENABLED(mode, S_IWGRP)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_GROUPWRITE;
3998
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 10 times.
150 if (GATE_FLAG_ENABLED(mode, S_IXGRP)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_GROUPEXECUTE;
3999
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 7 times.
150 if (GATE_FLAG_ENABLED(mode, S_IROTH)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_ALLREAD;
4000
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 49 times.
150 if (GATE_FLAG_ENABLED(mode, S_IWOTH)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_ALLWRITE;
4001
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 10 times.
150 if (GATE_FLAG_ENABLED(mode, S_IXOTH)) *ptr_accessbits |= GATE_FILEENTRY_ACCESS_ALLEXECUTE;
4002 }
4003
4004
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 14 times.
150 if (ptr_attribs)
4005 {
4006 136 *ptr_attribs = 0;
4007 #if defined(S_IFLNK)
4008
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 35 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFLNK)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_LINK;
4009 #endif
4010
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 135 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFDIR)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_DIRECTORY;
4011
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 1 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFREG)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_FILE;
4012
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFBLK)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_DEVICE;
4013
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 35 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFCHR)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_DEVICE;
4014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFIFO)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_DEVICE;
4015
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
136 if (GATE_FLAG_ENABLED(mode, S_IFSOCK)) *ptr_attribs |= GATE_FILEENTRY_ATTRIB_DEVICE;
4016 }
4017 150 }
4018
4019 134 static gate_bool_t gate_fstat_to_direntry(char const* path, gate_file_entry_t* entry)
4020 {
4021 do
4022 {
4023 struct stat filestat;
4024 134 gate_string_t tmp = GATE_STRING_INIT_EMPTY;
4025
4026
1/2
✓ Branch 1 taken 134 times.
✗ Branch 2 not taken.
134 if (0 == lstat(path, &filestat))
4027 {
4028 134 entry->props.size = filestat.st_size;
4029 134 entry->props.time_created = 0;
4030 134 entry->props.time_modified = 0;
4031 134 entry->props.time_accessed = 0;
4032 134 gate_time_from_unix(filestat.st_ctime, &entry->props.time_created); /* this is not the creation time, but may be close to it */
4033 134 gate_time_from_unix(filestat.st_mtime, &entry->props.time_modified);
4034 134 gate_time_from_unix(filestat.st_atime, &entry->props.time_accessed);
4035
4036 134 gate_unix_mode_to_attributes(filestat.st_mode, &entry->props.attribs, &entry->props.access);
4037
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 33 times.
134 if (GATE_FLAG_ENABLED(entry->props.attribs, GATE_FILEENTRY_ATTRIB_LINK))
4038 {
4039
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 101 times.
101 if (0 != stat(path, &filestat))
4040 {
4041 break;
4042 }
4043 }
4044 134 gate_string_create_static(&tmp, path);
4045
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
134 if (gate_file_is_hidden_entry(&tmp))
4046 {
4047 entry->props.attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
4048 }
4049
4050
4051 134 return true;
4052 }
4053 } while (0);
4054 return false;
4055 }
4056
4057 #if 0
4058 static gate_bool_t gate_readdir(DIR* dirp, struct dirent* entry)
4059 {
4060 struct dirent* returned_entry = NULL;
4061 int result = readdir_r(dirp, entry, &returned_entry);
4062 if (result == 0)
4063 {
4064 return entry != NULL;
4065 }
4066 return false;
4067 }
4068 #else
4069 203 static gate_bool_t gate_readdir(DIR* dirp, struct dirent* entry)
4070 {
4071 203 struct dirent* ptr_entry = readdir(dirp);
4072
2/2
✓ Branch 0 taken 193 times.
✓ Branch 1 taken 10 times.
203 if (ptr_entry)
4073 {
4074 193 gate_mem_copy(entry, ptr_entry, sizeof(struct dirent));
4075 193 return true;
4076 }
4077 10 return false;
4078 }
4079 #endif
4080
4081 9 gate_result_t gate_file_list(gate_string_t const* dirpath, gate_file_list_callback_t callback, void* userparam)
4082 {
4083 gate_result_t ret;
4084 9 DIR* dir = NULL;
4085
4086 do
4087 {
4088 char path[GATE_MAX_FILEPATH_LENGTH];
4089 char file[GATE_MAX_FILEPATH_LENGTH];
4090 gate_size_t namepos;
4091 9 struct dirent entry = GATE_INIT_EMPTY;
4092
4093
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 if (gate_string_is_empty(dirpath) || callback == NULL)
4094 {
4095 ret = GATE_RESULT_INVALIDARG;
4096 break;
4097 }
4098
4099 9 gate_string_to_buffer(dirpath, path, sizeof(path));
4100 9 namepos = gate_string_to_buffer(dirpath, file, sizeof(file));
4101
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 if (file[namepos - 1] != gate_file_path_separator_char)
4102 {
4103 6 file[namepos] = gate_file_path_separator_char;
4104 6 ++namepos;
4105 }
4106
4107 9 dir = opendir(path);
4108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (NULL == dir)
4109 {
4110 ret = GATE_RESULT_FAILED;
4111 break;
4112 }
4113
4114 9 ret = GATE_RESULT_OK;
4115
2/2
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 6 times.
157 while (gate_readdir(dir, &entry))
4116 {
4117 gate_size_t namelen;
4118 gate_file_entry_t direntry;
4119
4120
4/4
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 9 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 133 times.
151 if ((gate_str_comp(entry.d_name, "..") == 0) || (gate_str_comp(entry.d_name, ".") == 0))
4121 {
4122 18 continue;
4123 }
4124
4125 133 namelen = gate_str_print_text(&file[namepos], sizeof(file) - namepos, entry.d_name, gate_str_length(entry.d_name));
4126 133 gate_str_print_text(direntry.name, sizeof(direntry.name), entry.d_name, gate_str_length(entry.d_name));
4127 133 gate_str_print_text(direntry.path, sizeof(direntry.path), file, namepos + namelen);
4128 133 direntry.props.size = 0;
4129 133 direntry.props.attribs = 0;
4130 133 direntry.props.time_created = 0;
4131 133 direntry.props.time_modified = 0;
4132 133 direntry.props.time_accessed = 0;
4133 133 gate_fstat_to_direntry(direntry.path, &direntry);
4134
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 130 times.
133 if (!callback(&direntry, userparam))
4135 {
4136 3 break;
4137 }
4138 }
4139 } while (0);
4140
4141
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (dir != NULL)
4142 {
4143 9 closedir(dir);
4144 }
4145 9 return ret;
4146 }
4147
4148 11 gate_result_t gate_file_dir_open(gate_string_t const* dirpath, gate_file_dirreader_t* dirhandle)
4149 {
4150 11 gate_result_t ret = GATE_RESULT_FAILED;
4151 do
4152 {
4153 11 gate_mem_clear(dirhandle, sizeof(gate_file_dirreader_t));
4154 11 dirhandle->bufferlen = gate_str_print_text(dirhandle->buffer, sizeof(dirhandle->buffer),
4155 gate_string_ptr(dirpath, 0), gate_string_length(dirpath));
4156
4157 11 dirhandle->handle = opendir(dirhandle->buffer);
4158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (dirhandle->handle == NULL)
4159 {
4160 gate_posix_errno(&ret);
4161 }
4162 else
4163 {
4164 11 ret = GATE_RESULT_OK;
4165 }
4166
4167 } while (0);
4168
4169 11 return ret;
4170 }
4171 24 gate_size_t gate_file_dir_read(gate_file_dirreader_t* dirhandle, char* path, gate_size_t pathlen, gate_bool_t filename_only)
4172 {
4173 24 struct dirent entry = GATE_INIT_EMPTY;
4174 24 gate_size_t ret = 0;
4175
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 4 times.
46 while (gate_readdir((DIR*)dirhandle->handle, &entry))
4176 {
4177 42 gate_size_t name_len = gate_str_length(entry.d_name);
4178
4/4
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 11 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 11 times.
42 if ((gate_str_compare(entry.d_name, name_len, ".", 1) != 0) && (gate_str_compare(entry.d_name, name_len, "..", 2) != 0))
4179 {
4180
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19 times.
20 if (filename_only)
4181 {
4182 1 ret = gate_str_print_text(path, pathlen, entry.d_name, name_len);
4183 }
4184 else
4185 {
4186 19 ret = gate_file_build_path(path, pathlen,
4187 19 dirhandle->buffer, dirhandle->bufferlen,
4188 entry.d_name, gate_str_length_max(entry.d_name, sizeof(entry.d_name)));
4189 }
4190
4191
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (ret > 0)
4192 {
4193 20 break;
4194 }
4195 }
4196 }
4197 24 return ret;
4198 }
4199 11 gate_result_t gate_file_dir_close(gate_file_dirreader_t* dirhandle)
4200 {
4201 11 gate_result_t ret = GATE_RESULT_OK;
4202 11 closedir((DIR*)dirhandle->handle);
4203 11 return ret;
4204 }
4205
4206 3 gate_result_t gate_file_root_list(gate_file_list_callback_t callback, void* userparam)
4207 {
4208 3 gate_result_t ret = GATE_RESULT_OK;
4209 gate_file_entry_t direntry;
4210 3 gate_mem_clear(&direntry, sizeof(direntry));
4211 3 gate_str_print_text(direntry.name, sizeof(direntry.name), "/", 1);
4212 3 gate_str_print_text(direntry.path, sizeof(direntry.path), "/", 1);
4213
4214 3 direntry.props.attribs = GATE_FILEENTRY_ATTRIB_DIRECTORY | GATE_FILEENTRY_ATTRIB_VOLUME;
4215
4216 3 callback(&direntry, userparam);
4217
4218 3 return ret;
4219 }
4220
4221 1 gate_result_t gate_file_get_entry(gate_string_t const* filepath, gate_file_entry_t* ptr_entry)
4222 {
4223 gate_result_t ret;
4224
4225 do
4226 {
4227 char path[GATE_MAX_FILEPATH_LENGTH];
4228 1 gate_size_t pathlength = gate_string_to_buffer(filepath, path, sizeof(path));
4229 gate_size_t pos;
4230
4231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (pathlength == 0)
4232 {
4233 ret = GATE_RESULT_INVALIDARG;
4234 break;
4235 }
4236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (path[pathlength - 1] == gate_file_path_separator_char)
4237 {
4238 path[--pathlength] = '\0';
4239 }
4240 1 pos = gate_str_char_pos_last(path, pathlength, gate_file_path_separator_char);
4241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (pos == GATE_STR_NPOS)
4242 {
4243 pos = 0;
4244 }
4245 else
4246 {
4247 1 ++pos;
4248 }
4249 1 gate_mem_clear(ptr_entry, sizeof(gate_file_entry_t));
4250
4251 1 gate_mem_copy(ptr_entry->path, path, pathlength);
4252 1 ptr_entry->path[pathlength] = 0;
4253 1 gate_str_print_text(ptr_entry->name, sizeof(ptr_entry->name), &ptr_entry->path[pos], pathlength - pos);
4254
4255
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!gate_fstat_to_direntry(path, ptr_entry))
4256 {
4257 ret = GATE_RESULT_FAILED;
4258 break;
4259 }
4260 1 ret = GATE_RESULT_OK;
4261 } while (0);
4262
4263 1 return ret;
4264 }
4265 5 gate_result_t gate_file_dir_create(gate_string_t const* dirpath, gate_enumint_t flags)
4266 {
4267 gate_result_t ret;
4268
4269 do
4270 {
4271 char path[GATE_MAX_FILEPATH_LENGTH];
4272 5 gate_size_t pathlen = gate_string_to_buffer(dirpath, path, sizeof(path));
4273 5 mode_t mode = 0;
4274 5 uid_t uid = 0;
4275 5 gid_t gid = 0;
4276 5 gate_bool_t parent_stat = false;
4277
4278
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
5 if ((pathlen != 0) && (path[pathlen - 1] == '/'))
4279 {
4280 2 path[--pathlen] = 0;
4281 }
4282
4283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (GATE_FLAG_ENABLED(flags, GATE_FILE_DIR_CREATE_OWNERRESTRICTED))
4284 {
4285 mode = (S_IRUSR | S_IWUSR | S_IXUSR);
4286 }
4287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 else if (GATE_FLAG_ENABLED(flags, GATE_FILE_DIR_CREATE_GROUPRESTRICTED))
4288 {
4289 mode = (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP);
4290 }
4291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 else if (GATE_FLAG_ENABLED(flags, GATE_FILE_DIR_CREATE_UNRESTRICTED))
4292 {
4293 mode = (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
4294 }
4295 else
4296 {
4297 /* default */
4298 5 parent_stat = gate_file_parent_stat(dirpath, &mode, &uid, &gid);
4299
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (!parent_stat)
4300 {
4301 2 mode = 0;
4302 }
4303 5 mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
4304 }
4305
4306
4307
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (0 != mkdir(path, mode))
4308 {
4309 gate_posix_errno(&ret);
4310 break;
4311 }
4312
4313 5 ret = GATE_RESULT_OK;
4314
4315
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (parent_stat)
4316 {
4317 int result;
4318 3 result = chmod(path, mode);
4319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (result != 0)
4320 {
4321 GATE_DEBUG_TRACE("chmod() failed");
4322 }
4323 3 result = chown(path, uid, gid);
4324
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (result != 0)
4325 {
4326 GATE_DEBUG_TRACE("chown() failed");
4327 }
4328 (void)result;
4329 }
4330 } while (0);
4331
4332 5 return ret;
4333 }
4334 3 gate_result_t gate_file_dir_delete(gate_string_t const* dirpath)
4335 {
4336 gate_result_t ret;
4337 char path[GATE_MAX_FILEPATH_LENGTH];
4338
4339 3 gate_string_to_buffer(dirpath, path, sizeof(path));
4340
4341
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (0 != rmdir(path))
4342 {
4343 gate_posix_errno(&ret);
4344 }
4345 else
4346 {
4347 3 ret = GATE_RESULT_OK;
4348 }
4349 3 return ret;
4350 }
4351
4352 16 gate_result_t gate_file_get_attributes(gate_string_t const* targetfile, gate_enumint_t* attribs, gate_enumint_t* access_bits)
4353 {
4354 gate_result_t ret;
4355 char path[GATE_MAX_FILEPATH_LENGTH];
4356 struct stat filestat;
4357 16 gate_string_to_buffer(targetfile, path, sizeof(path));
4358
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if (0 != lstat(path, &filestat))
4359 {
4360 ret = GATE_RESULT_FAILED;
4361 }
4362 else
4363 {
4364 16 ret = GATE_RESULT_OK;
4365 16 gate_unix_mode_to_attributes(filestat.st_mode, attribs, access_bits);
4366
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (attribs)
4367 {
4368
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (gate_file_is_hidden_entry(targetfile))
4369 {
4370 *attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
4371 }
4372 }
4373 }
4374 16 return ret;
4375 }
4376
4377 gate_result_t gate_file_get_size(gate_string_t const* targetfile, gate_int64_t* filesize)
4378 {
4379 gate_result_t ret;
4380 char path[GATE_MAX_FILEPATH_LENGTH];
4381 struct stat filestat;
4382 gate_string_to_buffer(targetfile, path, sizeof(path));
4383 if (0 != lstat(path, &filestat))
4384 {
4385 ret = GATE_RESULT_FAILED;
4386 }
4387 else
4388 {
4389 ret = GATE_RESULT_OK;
4390 if (filesize)
4391 {
4392 *filesize = (gate_int64_t)filestat.st_size;
4393 }
4394 }
4395 return ret;
4396 }
4397
4398 gate_result_t gate_file_get_owner(gate_string_t const* targetpath,
4399 gate_uint32_t* owner_id, gate_string_t* owner_name)
4400 {
4401 gate_result_t ret;
4402 char path[GATE_MAX_FILEPATH_LENGTH];
4403 struct stat filestat;
4404
4405 gate_string_to_buffer(targetpath, path, sizeof(path));
4406 if (0 != lstat(path, &filestat))
4407 {
4408 ret = GATE_RESULT_FAILED;
4409 }
4410 else
4411 {
4412 if (NULL != owner_id)
4413 {
4414 *owner_id = (gate_uint32_t)filestat.st_uid;
4415 }
4416 if (NULL != owner_name)
4417 {
4418 gate_posix_user_info_t user_info = GATE_INIT_EMPTY;
4419 ret = gate_posix_get_user_info(filestat.st_uid, &user_info);
4420 if (GATE_SUCCEEDED(ret))
4421 {
4422 gate_string_create(owner_name, user_info.name, gate_str_length(user_info.name));
4423 }
4424 else
4425 {
4426 gate_string_create_empty(owner_name);
4427 }
4428 }
4429 ret = GATE_RESULT_OK;
4430 }
4431 return ret;
4432 }
4433
4434
4435 #define GATE_FILE_MODE_SET(mode_var, mask, attribs, attrib, native_mode) \
4436 do { \
4437 if(GATE_FLAG_ENABLED(mask, attrib)) { \
4438 if(GATE_FLAG_ENABLED(attribs, attrib)) { \
4439 mode_var |= native_mode; \
4440 } \
4441 else { \
4442 mode_var &= ~native_mode; \
4443 } \
4444 } \
4445 } while(0)
4446
4447 gate_result_t gate_file_set_attributes(gate_string_t const* targetfile,
4448 gate_enumint_t attribs, gate_enumint_t attribs_mask,
4449 gate_enumint_t access_bits, gate_enumint_t access_mask)
4450 {
4451 gate_result_t ret;
4452 char path[GATE_MAX_FILEPATH_LENGTH];
4453 struct stat filestat;
4454
4455 gate_string_to_buffer(targetfile, path, sizeof(path));
4456 if (0 != lstat(path, &filestat))
4457 {
4458 ret = GATE_RESULT_FAILED;
4459 }
4460 else
4461 {
4462 mode_t mode = filestat.st_mode;
4463 if (access_mask != 0)
4464 {
4465 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_OWNERREAD, S_IRUSR);
4466 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_OWNERWRITE, S_IWUSR);
4467 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_OWNEREXECUTE, S_IXUSR);
4468 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_OWNERSETID, S_ISUID);
4469 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_GROUPREAD, S_IRGRP);
4470 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_GROUPWRITE, S_IWGRP);
4471 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_GROUPEXECUTE, S_IXGRP);
4472 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_GROUPSETID, S_ISGID);
4473 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_ALLREAD, S_IROTH);
4474 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_ALLWRITE, S_IWOTH);
4475 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_ALLEXECUTE, S_IXOTH);
4476 GATE_FILE_MODE_SET(mode, access_mask, access_bits, GATE_FILEENTRY_ACCESS_NODELETE, S_ISVTX);
4477 }
4478
4479 if (0 != chmod(path, mode))
4480 {
4481 ret = GATE_RESULT_FAILED;
4482 }
4483 else
4484 {
4485 ret = GATE_RESULT_OK;
4486 }
4487 }
4488 return ret;
4489 }
4490
4491 gate_result_t gate_file_get_times(gate_string_t const* targetfile, gate_timestamp_t* modified,
4492 gate_timestamp_t* accessed, gate_timestamp_t* created)
4493 {
4494 gate_result_t ret;
4495 char path[GATE_MAX_FILEPATH_LENGTH];
4496 struct stat filestat;
4497
4498 gate_string_to_buffer(targetfile, path, sizeof(path));
4499
4500 if (0 != lstat(path, &filestat))
4501 {
4502 ret = GATE_RESULT_FAILED;
4503 }
4504 else
4505 {
4506 ret = GATE_RESULT_OK;
4507 if (created) gate_time_from_unix(filestat.st_ctime, created);
4508 if (modified)gate_time_from_unix(filestat.st_mtime, modified);
4509 if (accessed)gate_time_from_unix(filestat.st_atime, accessed);
4510 }
4511 return ret;
4512 }
4513 gate_result_t gate_file_set_times(gate_string_t const* targetfile, gate_timestamp_t const* modified,
4514 gate_timestamp_t const* accessed, gate_timestamp_t const* created)
4515 {
4516 gate_result_t ret;
4517 char path[GATE_MAX_FILEPATH_LENGTH];
4518 struct utimbuf ft;
4519 gate_timestamp_t orig_modified = 0, orig_accessed = 0;
4520 gate_int64_t accesstime = 0;
4521 gate_int64_t modifiedtime = 0;
4522
4523 if (!modified || !accessed)
4524 {
4525 gate_file_get_times(targetfile, &orig_modified, &orig_accessed, NULL);
4526 if (!modified) modified = &orig_modified;
4527 if (!accessed) accessed = &orig_accessed;
4528 }
4529
4530 gate_time_to_unix(*modified, &modifiedtime);
4531 gate_time_to_unix(*accessed, &accesstime);
4532
4533 gate_string_to_buffer(targetfile, path, sizeof(path));
4534
4535 ft.actime = (time_t)accesstime;
4536 ft.modtime = (time_t)modifiedtime;
4537 if (0 != utime(path, &ft))
4538 {
4539 ret = GATE_RESULT_FAILED;
4540 }
4541 else
4542 {
4543 ret = GATE_RESULT_OK;
4544 }
4545 return ret;
4546 }
4547
4548 #endif /* GATE_CORE_FILES_POSIX_IMPL */
4549
4550
4551
4552 #if defined(GATE_CORE_FILES_DOS_IMPL)
4553
4554 #include "gate/platforms.h"
4555 #include <dos.h>
4556 #include <io.h>
4557 #include <direct.h>
4558
4559 char const gate_file_path_separator_char = '\\';
4560
4561 char const* const gate_file_path_separator = "\\";
4562
4563 gate_result_t gate_file_exists(gate_string_t const* filepath)
4564 {
4565 gate_result_t ret = GATE_RESULT_FAILED;
4566
4567 do
4568 {
4569 char path[GATE_MAX_FILEPATH_LENGTH];
4570 struct find_t f;
4571 unsigned result;
4572 gate_string_to_buffer(filepath, path, sizeof(path));
4573 result = _dos_findfirst(path, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM, &f);
4574 if (0 != result)
4575 {
4576 ret = GATE_RESULT_NOTAVAILABLE;
4577 break;
4578 }
4579 ret = GATE_RESULT_OK;
4580 } while (0);
4581 return ret;
4582 }
4583 gate_result_t gate_file_copy(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
4584 {
4585 return gate_file_copy_internal(srcfilepath, dstfilepath, flags);
4586 }
4587 gate_result_t gate_file_move(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
4588 {
4589 return gate_file_move_internal(srcfilepath, dstfilepath);
4590 }
4591 gate_result_t gate_file_delete(gate_string_t const* filepath)
4592 {
4593 union REGS regs;
4594 struct SREGS segregs;
4595 char path[GATE_MAX_FILEPATH_LENGTH];
4596 gate_string_to_buffer(filepath, path, sizeof(path));
4597
4598 segregs.ds = segregs.es = FP_SEG(&path[0]);
4599 regs.h.ah = 0x41;
4600 regs.w.bx = 0;
4601 regs.w.cx = 0;
4602 regs.w.dx = FP_OFF(&path[0]);
4603
4604 intdosx(&regs, &regs, &segregs);
4605 if (regs.w.cflag & INTR_CF)
4606 {
4607 return GATE_RESULT_FAILED;
4608 }
4609 return GATE_RESULT_OK;
4610
4611 /*
4612 if(0 == unlink(path))
4613 {
4614 return GATE_RESULT_OK;
4615 }
4616 return GATE_RESULT_FAILED;
4617 */
4618 }
4619 gate_result_t gate_file_real_path(gate_string_t const* relativepath, gate_string_t* absolutepath)
4620 {
4621 /* TODO */
4622 GATE_UNUSED_ARG(relativepath);
4623 GATE_UNUSED_ARG(absolutepath);
4624 return GATE_RESULT_NOTSUPPORTED;
4625 }
4626 gate_result_t gate_file_create_link(gate_string_t const* targetpath, gate_string_t const* linkfile)
4627 {
4628 GATE_UNUSED_ARG(targetpath);
4629 GATE_UNUSED_ARG(linkfile);
4630 return GATE_RESULT_NOTSUPPORTED;
4631 }
4632 gate_result_t gate_file_read_link(gate_string_t const* filepath, gate_string_t* realpath)
4633 {
4634 GATE_UNUSED_ARG(filepath);
4635 GATE_UNUSED_ARG(realpath);
4636 return GATE_RESULT_NOTSUPPORTED;
4637 }
4638 gate_result_t gate_file_create_hardlink(gate_string_t const* targetfile, gate_string_t const* linkfile)
4639 {
4640 GATE_UNUSED_ARG(targetfile);
4641 GATE_UNUSED_ARG(linkfile);
4642 return GATE_RESULT_NOTSUPPORTED;
4643 }
4644 gate_result_t gate_file_get_attributes(gate_string_t const* targetpath, gate_enumint_t* attribs, gate_enumint_t* access_bits)
4645 {
4646 gate_result_t ret = GATE_RESULT_FAILED;
4647
4648 do
4649 {
4650 struct find_t f;
4651 char path[GATE_MAX_FILEPATH_LENGTH];
4652 unsigned result;
4653
4654 gate_string_to_buffer(targetpath, path, sizeof(path));
4655
4656 result = _dos_findfirst(path, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH, &f);
4657 if (0 != result)
4658 {
4659 ret = GATE_RESULT_NOTAVAILABLE;
4660 break;
4661 }
4662 if (attribs)
4663 {
4664 *attribs = 0;
4665 if (GATE_FLAG_ENABLED(f.attrib, _A_SUBDIR)) *attribs |= GATE_FILEENTRY_ATTRIB_DIRECTORY;
4666 else *attribs |= GATE_FILEENTRY_ATTRIB_FILE;
4667 if (GATE_FLAG_ENABLED(f.attrib, _A_RDONLY)) *attribs |= GATE_FILEENTRY_ATTRIB_READONLY;
4668 if (GATE_FLAG_ENABLED(f.attrib, _A_HIDDEN)) *attribs |= GATE_FILEENTRY_ATTRIB_HIDDEN;
4669 if (GATE_FLAG_ENABLED(f.attrib, _A_SYSTEM)) *attribs |= GATE_FILEENTRY_ATTRIB_SYSTEM;
4670 if (GATE_FLAG_ENABLED(f.attrib, _A_ARCH)) *attribs |= GATE_FILEENTRY_ATTRIB_ARCHIVE;
4671
4672 }
4673 if (access_bits)
4674 {
4675 gate_bool_t is_readonly = GATE_FLAG_ENABLED(f.attrib, _A_RDONLY);
4676 gate_bool_t is_executable = gate_string_ends_with_str_ic(targetpath, ".exe")
4677 || gate_string_ends_with_str_ic(targetpath, ".com")
4678 || gate_string_ends_with_str_ic(targetpath, ".bat");
4679
4680 /* all access granted */
4681 *access_bits = GATE_FILEENTRY_ACCESS_OWNERREAD | GATE_FILEENTRY_ACCESS_GROUPREAD | GATE_FILEENTRY_ACCESS_ALLREAD;
4682 if (!is_readonly)
4683 {
4684 *access_bits |= GATE_FILEENTRY_ACCESS_OWNERWRITE | GATE_FILEENTRY_ACCESS_GROUPWRITE | GATE_FILEENTRY_ACCESS_ALLWRITE;
4685 }
4686 if (is_executable)
4687 {
4688 *access_bits |= GATE_FILEENTRY_ACCESS_OWNEREXECUTE | GATE_FILEENTRY_ACCESS_GROUPEXECUTE | GATE_FILEENTRY_ACCESS_ALLEXECUTE;
4689 }
4690 }
4691
4692 ret = GATE_RESULT_OK;
4693 } while (0);
4694 return ret;
4695 }
4696 gate_result_t gate_file_set_attributes(gate_string_t const* targetpath,
4697 gate_enumint_t attribs, gate_enumint_t attribs_mask,
4698 gate_enumint_t access_bits, gate_enumint_t access_mask)
4699 {
4700 char path[GATE_MAX_FILEPATH_LENGTH];
4701
4702 GATE_UNUSED_ARG(access_bits);
4703 GATE_UNUSED_ARG(access_mask);
4704
4705 gate_string_to_buffer(targetpath, path, sizeof(path));
4706
4707 if (attribs_mask)
4708 {
4709 unsigned dosattribs = 0;
4710 unsigned result = _dos_getfileattr(path, &dosattribs);
4711 if (result != 0)
4712 {
4713 return GATE_RESULT_NOTAVAILABLE;
4714 }
4715
4716 if (GATE_FLAG_ENABLED(attribs_mask, GATE_FILEENTRY_ATTRIB_READONLY)) GATE_FLAG_SET(dosattribs, _A_RDONLY, GATE_FLAG_ENABLED(attribs, GATE_FILEENTRY_ATTRIB_READONLY));
4717 if (GATE_FLAG_ENABLED(attribs_mask, GATE_FILEENTRY_ATTRIB_HIDDEN)) GATE_FLAG_SET(dosattribs, _A_HIDDEN, GATE_FLAG_ENABLED(attribs, GATE_FILEENTRY_ATTRIB_HIDDEN));
4718 if (GATE_FLAG_ENABLED(attribs_mask, GATE_FILEENTRY_ATTRIB_SYSTEM)) GATE_FLAG_SET(dosattribs, _A_SYSTEM, GATE_FLAG_ENABLED(attribs, GATE_FILEENTRY_ATTRIB_SYSTEM));
4719 if (GATE_FLAG_ENABLED(attribs_mask, GATE_FILEENTRY_ATTRIB_ARCHIVE)) GATE_FLAG_SET(dosattribs, _A_ARCH, GATE_FLAG_ENABLED(attribs, GATE_FILEENTRY_ATTRIB_ARCHIVE));
4720
4721 result = _dos_setfileattr(path, dosattribs);
4722 if (result != 0)
4723 {
4724 return GATE_RESULT_FAILED;
4725 }
4726 }
4727
4728 return GATE_RESULT_OK;
4729 }
4730
4731 typedef struct {
4732 unsigned short twosecs : 5; /* seconds / 2 */
4733 unsigned short minutes : 6; /* minutes (0,59) */
4734 unsigned short hours : 5; /* hours (0,23) */
4735 } ftime_t;
4736
4737 typedef struct {
4738 unsigned short day : 5; /* day (1,31) */
4739 unsigned short month : 4; /* month (1,12) */
4740 unsigned short year : 7; /* 0 is 1980 */
4741 } fdate_t;
4742
4743 void gate_file_convert_time(unsigned short fdate, unsigned short ftime, gate_timestamp_t* ts)
4744 {
4745 fdate_t* ptr_date = (fdate_t*)&fdate;
4746 ftime_t* ptr_time = (ftime_t*)&ftime;
4747 gate_datetime_t dt;
4748 gate_time_t tm;
4749
4750 dt.date.year = 1980 + ptr_date->year;
4751 dt.date.month = ptr_date->month;
4752 dt.date.day = ptr_date->day;
4753 dt.time.hour = ptr_time->hours;
4754 dt.time.minute = ptr_time->minutes;
4755 dt.time.second = ptr_time->twosecs * 2;
4756 dt.time.microsecond = 0;
4757 gate_date_to_time(&dt, &tm);
4758 if (ts)
4759 {
4760 *ts = tm.timestamp;
4761 }
4762 }
4763
4764 gate_result_t gate_file_get_times(gate_string_t const* targetpath, gate_timestamp_t* modified, gate_timestamp_t* accessed, gate_timestamp_t* created)
4765 {
4766 gate_result_t ret = GATE_RESULT_FAILED;
4767
4768 do
4769 {
4770 struct find_t f;
4771 char path[GATE_MAX_FILEPATH_LENGTH];
4772 unsigned result;
4773
4774 gate_string_to_buffer(targetpath, path, sizeof(path));
4775
4776 result = _dos_findfirst(path, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH, &f);
4777 if (0 != result)
4778 {
4779 ret = GATE_RESULT_NOTAVAILABLE;
4780 break;
4781 }
4782 if (modified)
4783 {
4784 gate_file_convert_time(f.wr_date, f.wr_time, modified);
4785 }
4786 if (accessed)
4787 {
4788 gate_file_convert_time(f.wr_date, f.wr_time, accessed);
4789 }
4790 if (created)
4791 {
4792 *created = 0;
4793 }
4794 ret = GATE_RESULT_OK;
4795 } while (0);
4796 return ret;
4797 }
4798 gate_result_t gate_file_set_times(gate_string_t const* targetpath, gate_timestamp_t const* modified, gate_timestamp_t const* accessed, gate_timestamp_t const* created)
4799 {
4800 GATE_UNUSED_ARG(targetpath);
4801 GATE_UNUSED_ARG(modified);
4802 GATE_UNUSED_ARG(accessed);
4803 GATE_UNUSED_ARG(created);
4804 /* TODO */
4805 return GATE_RESULT_NOTSUPPORTED;
4806 }
4807 gate_result_t gate_file_get_size(gate_string_t const* targetfile, gate_int64_t* filesize)
4808 {
4809 gate_result_t ret = GATE_RESULT_FAILED;
4810
4811 do
4812 {
4813 struct find_t f;
4814 char path[GATE_MAX_FILEPATH_LENGTH];
4815 unsigned result;
4816
4817 gate_string_to_buffer(targetfile, path, sizeof(path));
4818
4819 result = _dos_findfirst(path, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH, &f);
4820 if (0 != result)
4821 {
4822 ret = GATE_RESULT_NOTAVAILABLE;
4823 break;
4824 }
4825 if (filesize)
4826 {
4827 *filesize = (gate_int64_t)f.size;
4828 }
4829 ret = GATE_RESULT_OK;
4830 } while (0);
4831 return ret;
4832 }
4833 gate_result_t gate_file_get_owner(gate_string_t const* targetfile,
4834 gate_uint32_t* owner_id, gate_string_t* owner_name)
4835 {
4836 GATE_UNUSED_ARG(targetfile);
4837 GATE_UNUSED_ARG(owner_id);
4838 GATE_UNUSED_ARG(owner_name);
4839 return GATE_RESULT_NOTSUPPORTED;
4840 }
4841
4842 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
4843 {
4844 gate_result_t ret;
4845 int platform_flags;
4846 gate_bool_t seek_end = false;
4847 gate_platform_stream_t stream;
4848
4849 switch (flags)
4850 {
4851 case GATE_STREAM_OPEN_READ:
4852 platform_flags = GATE_PLATFORM_STREAM_OPEN_READ;
4853 break;
4854 case GATE_STREAM_OPEN_WRITE:
4855 platform_flags = GATE_PLATFORM_STREAM_OPEN_WRITE;
4856 break;
4857 case GATE_STREAM_OPEN_READWRITE:
4858 platform_flags = GATE_PLATFORM_STREAM_OPEN_READWRITE;
4859 break;
4860 case GATE_STREAM_OPEN_APPENDWRITE:
4861 case GATE_STREAM_OPEN_APPENDREADWRITE:
4862 platform_flags = GATE_PLATFORM_STREAM_OPEN_READWRITE;
4863 seek_end = true;
4864 break;
4865 default:
4866 return GATE_RESULT_INVALIDARG;
4867 }
4868
4869 do
4870 {
4871 char path[GATE_MAX_FILEPATH_LENGTH];
4872 gate_string_to_buffer(filepath, path, sizeof(path));
4873 ret = gate_platform_stream_open(path, platform_flags, 0, &stream);
4874 GATE_BREAK_IF_FAILED(ret);
4875
4876 *filehandle = (gate_file_t)stream;
4877 ret = GATE_RESULT_OK;
4878 } while (0);
4879 return ret;
4880 }
4881 gate_result_t gate_file_read(gate_file_t filehandle, char* buffer, gate_size_t bufferlength, gate_size_t* bufferused)
4882 {
4883 gate_platform_stream_t stream = (gate_platform_stream_t)filehandle;
4884 return gate_platform_stream_read(stream, buffer, bufferlength, bufferused);
4885 }
4886 gate_result_t gate_file_write(gate_file_t filehandle, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
4887 {
4888 gate_platform_stream_t stream = (gate_platform_stream_t)filehandle;
4889 return gate_platform_stream_write(stream, buffer, bufferlength, written);
4890 }
4891 gate_result_t gate_file_flush(gate_file_t filehandle)
4892 {
4893 int handle = (int)(gate_intptr_t)(gate_platform_stream_t)filehandle;
4894 unsigned result = _dos_commit(handle);
4895 if (result != 0)
4896 {
4897 return GATE_RESULT_FAILED;
4898 }
4899 else
4900 {
4901 return GATE_RESULT_OK;
4902 }
4903 }
4904 gate_result_t gate_file_close(gate_file_t filehandle)
4905 {
4906 gate_platform_stream_t stream = (gate_platform_stream_t)filehandle;
4907 return gate_platform_stream_close(&stream);
4908 }
4909 gate_result_t gate_file_seek(gate_file_t filehandle, gate_int64_t position, gate_enumint_t origin, gate_int64_t* newposition)
4910 {
4911 gate_platform_stream_t stream = (gate_platform_stream_t)filehandle;
4912 int native_origin = GATE_PLATFORM_STREAM_ORIGIN_BEGIN;
4913 switch (origin)
4914 {
4915 case GATE_FILE_SEEK_ORIGIN_BEGIN: native_origin = GATE_PLATFORM_STREAM_ORIGIN_BEGIN; break;
4916 case GATE_FILE_SEEK_ORIGIN_CURPOS: native_origin = GATE_PLATFORM_STREAM_ORIGIN_CURRENT; break;
4917 case GATE_FILE_SEEK_ORIGIN_END: native_origin = GATE_PLATFORM_STREAM_ORIGIN_END; break;
4918 default: return GATE_RESULT_INVALIDARG;
4919 }
4920 return gate_platform_stream_seek(stream, position, native_origin, newposition);
4921 }
4922 gate_result_t gate_file_pos(gate_file_t filehandle, gate_int64_t* position)
4923 {
4924 gate_platform_stream_t stream = (gate_platform_stream_t)filehandle;
4925 return gate_platform_stream_seek(stream, 0, GATE_PLATFORM_STREAM_ORIGIN_CURRENT, position);
4926 }
4927 gate_result_t gate_file_size(gate_file_t filehandle, gate_int64_t* size)
4928 {
4929 gate_result_t ret = GATE_RESULT_FAILED;
4930 gate_platform_stream_t stream = (gate_platform_stream_t)filehandle;
4931 gate_int64_t cur_pos = 0;
4932 do
4933 {
4934 ret = gate_platform_stream_seek(stream, 0, GATE_PLATFORM_STREAM_ORIGIN_CURRENT, &cur_pos);
4935 GATE_BREAK_IF_FAILED(ret);
4936
4937 ret = gate_platform_stream_seek(stream, 0, GATE_PLATFORM_STREAM_ORIGIN_END, size);
4938 gate_platform_stream_seek(stream, cur_pos, GATE_PLATFORM_STREAM_ORIGIN_BEGIN, NULL);
4939 } while (0);
4940 return ret;
4941 }
4942 gate_result_t gate_file_lock(gate_file_t filehandle, gate_bool_t wait)
4943 {
4944 GATE_UNUSED_ARG(filehandle);
4945 GATE_UNUSED_ARG(wait);
4946 return GATE_RESULT_NOTSUPPORTED;
4947 }
4948 gate_result_t gate_file_unlock(gate_file_t filehandle)
4949 {
4950 GATE_UNUSED_ARG(filehandle);
4951 return GATE_RESULT_NOTSUPPORTED;
4952 }
4953 gate_result_t gate_file_truncate(gate_file_t filehandle)
4954 {
4955 GATE_UNUSED_ARG(filehandle);
4956 return GATE_RESULT_NOTSUPPORTED;
4957 }
4958 gate_result_t gate_file_root_list(gate_file_list_callback_t callback, void* userparam)
4959 {
4960 gate_result_t ret = GATE_RESULT_OK;
4961 gate_size_t n;
4962 for (n = 0; n < 26; ++n)
4963 {
4964 gate_file_entry_t entry;
4965 gate_dos_gpregs_t regs = GATE_INIT_EMPTY;
4966 regs.a.h = 0x32;
4967 regs.d.x = (n + 1);
4968 gate_dos_intr(0x21, &regs, NULL);
4969 if (regs.a.l != 0)
4970 {
4971 continue;
4972 }
4973 gate_mem_clear(&entry, sizeof(entry));
4974 entry.path[0] = 'A' + n;
4975 entry.path[1] = ':';
4976 entry.path[2] = '\\';
4977 entry.path[3] = 0;
4978 entry.name[0] = 'A' + n;
4979 entry.name[1] = ':';
4980 entry.name[2] = 0;
4981 entry.props.attribs = GATE_FILEENTRY_ATTRIB_VOLUME;
4982 if (!callback(&entry, userparam))
4983 {
4984 break;
4985 }
4986 }
4987 return ret;
4988 }
4989
4990 static void dos_find_to_gate_file_entry(struct find_t* ptr_find, gate_file_entry_t* ptr_entry)
4991 {
4992 gate_size_t namelen = gate_str_length(ptr_find->name);
4993 gate_bool_t is_executable = gate_str_ends_with_ic(ptr_find->name, namelen, ".exe", 4)
4994 || gate_str_ends_with_ic(ptr_find->name, namelen, ".com", 4)
4995 || gate_str_ends_with_ic(ptr_find->name, namelen, ".bat", 4);
4996 gate_str_print_text(&ptr_entry->name[0], sizeof(ptr_entry->name), ptr_find->name, namelen);
4997 ptr_entry->props.size = ptr_find->size;
4998 ptr_entry->props.attribs = 0;
4999 ptr_entry->props.access = GATE_FILEENTRY_ACCESS_OWNERREAD | GATE_FILEENTRY_ACCESS_GROUPREAD | GATE_FILEENTRY_ACCESS_ALLREAD;
5000 GATE_FLAG_SET(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_DIRECTORY, (ptr_find->attrib & _A_SUBDIR));
5001 GATE_FLAG_SET(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_ARCHIVE, (ptr_find->attrib & _A_ARCH));
5002 GATE_FLAG_SET(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_HIDDEN, (ptr_find->attrib & _A_HIDDEN));
5003 GATE_FLAG_SET(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_READONLY, (ptr_find->attrib & _A_RDONLY));
5004 GATE_FLAG_SET(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_SYSTEM, (ptr_find->attrib & _A_SYSTEM));
5005 if (!GATE_FLAG_ENABLED(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_DIRECTORY))
5006 {
5007 ptr_entry->props.attribs |= GATE_FILEENTRY_ATTRIB_FILE;
5008 }
5009 if (!GATE_FLAG_ENABLED(ptr_entry->props.attribs, GATE_FILEENTRY_ATTRIB_READONLY))
5010 {
5011 ptr_entry->props.access |= GATE_FILEENTRY_ACCESS_OWNERWRITE | GATE_FILEENTRY_ACCESS_GROUPWRITE | GATE_FILEENTRY_ACCESS_ALLWRITE;
5012 }
5013 if (is_executable)
5014 {
5015 ptr_entry->props.access |= GATE_FILEENTRY_ACCESS_OWNEREXECUTE | GATE_FILEENTRY_ACCESS_GROUPEXECUTE | GATE_FILEENTRY_ACCESS_ALLEXECUTE;
5016 }
5017 gate_file_convert_time(ptr_find->wr_date, ptr_find->wr_time, &ptr_entry->props.time_modified);
5018 ptr_entry->props.time_accessed = ptr_entry->props.time_modified;
5019 ptr_entry->props.time_created = ptr_entry->props.time_modified;
5020 }
5021
5022 gate_result_t gate_file_list(gate_string_t const* dirpath, gate_file_list_callback_t callback, void* userparam)
5023 {
5024 gate_result_t ret = GATE_RESULT_OK;
5025 char path[GATE_MAX_FILEPATH_LENGTH];
5026 gate_size_t pathlen;
5027 gate_size_t namelen;
5028 struct find_t found_file;
5029 gate_file_entry_t file_entry;
5030 unsigned errorstatus;
5031
5032 pathlen = gate_string_to_buffer(dirpath, path, sizeof(path) - 5);
5033 if (pathlen != 0)
5034 {
5035 if (path[pathlen - 1] != '\\')
5036 {
5037 path[pathlen] = '\\';
5038 ++pathlen;
5039 }
5040 }
5041 path[pathlen + 0] = '*';
5042 path[pathlen + 1] = '.';
5043 path[pathlen + 2] = '*';
5044 path[pathlen + 3] = '\0';
5045
5046 errorstatus = _dos_findfirst(path, _A_SUBDIR | _A_ARCH | _A_HIDDEN | _A_NORMAL | _A_RDONLY | _A_SYSTEM, &found_file);
5047 if (errorstatus)
5048 {
5049 return GATE_RESULT_FAILED;
5050 }
5051 while (errorstatus == 0)
5052 {
5053 namelen = gate_str_length(found_file.name);
5054 if ((gate_str_compare(found_file.name, namelen, ".", 1) != 0)
5055 && (gate_str_compare(found_file.name, namelen, "..", 2) != 0)
5056 )
5057 {
5058 gate_str_print_text(&file_entry.path[0], sizeof(file_entry.path), path, pathlen);
5059 gate_str_print_text(&file_entry.path[pathlen], sizeof(file_entry.path) - pathlen, found_file.name, namelen);
5060
5061 dos_find_to_gate_file_entry(&found_file, &file_entry);
5062 if (callback)
5063 {
5064 if (!callback(&file_entry, userparam))
5065 {
5066 /* skip all other iterations */
5067 while (errorstatus == 0)
5068 {
5069 errorstatus = _dos_findnext(&found_file);
5070 }
5071 break;
5072 }
5073 }
5074 }
5075 errorstatus = _dos_findnext(&found_file);
5076 }
5077 return ret;
5078 }
5079 gate_result_t gate_file_get_entry(gate_string_t const* filepath, gate_file_entry_t* ptr_entry)
5080 {
5081 gate_result_t ret = GATE_RESULT_FAILED;
5082
5083 do
5084 {
5085 char path[GATE_MAX_FILEPATH_LENGTH];
5086 struct find_t found_file;
5087 gate_size_t pathlen;
5088 unsigned search_attribs = _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR | _A_ARCH;
5089 unsigned result;
5090
5091 gate_mem_clear(ptr_entry, sizeof(gate_file_entry_t));
5092 pathlen = gate_string_to_buffer(filepath, path, sizeof(path));
5093
5094 if (pathlen == 0)
5095 {
5096 ret = GATE_RESULT_INVALIDARG;
5097 break;
5098 }
5099
5100 if (pathlen == 3)
5101 {
5102 if (path[1] == ':' && path[2] == '\\')
5103 {
5104 /* path is a folder */
5105 path[3] = '*';
5106 path[4] = '.';
5107 path[5] = '*';
5108 path[6] = '\0';
5109 result = _dos_findfirst(path, _A_SUBDIR | _A_ARCH | _A_HIDDEN | _A_NORMAL | _A_VOLID | _A_RDONLY | _A_SYSTEM, &found_file);
5110 if (result == 0)
5111 {
5112 gate_string_to_buffer(filepath, ptr_entry->path, sizeof(ptr_entry->path));
5113 gate_string_to_buffer(filepath, ptr_entry->name, sizeof(ptr_entry->name));
5114 ptr_entry->props.attribs = GATE_FILEENTRY_ATTRIB_DIRECTORY | GATE_FILEENTRY_ATTRIB_VOLUME;
5115 ptr_entry->props.access = GATE_FILEENTRY_ACCESS_ALLREAD | GATE_FILEENTRY_ACCESS_ALLWRITE;
5116 ptr_entry->props.size = 0;
5117 ret = GATE_RESULT_OK;
5118 break;
5119 }
5120 }
5121 }
5122
5123 if (path[pathlen - 1] == '\\')
5124 {
5125 --pathlen;
5126 path[pathlen] = '\0';
5127 if (pathlen == 0)
5128 {
5129 ret = GATE_RESULT_INVALIDARG;
5130 break;
5131 }
5132 }
5133 gate_mem_clear(&found_file, sizeof(found_file));
5134
5135 result = _dos_findfirst(path, search_attribs, &found_file);
5136 if (0 != result)
5137 {
5138 ret = GATE_RESULT_NOTAVAILABLE;
5139 break;
5140 }
5141
5142 if (ptr_entry)
5143 {
5144 gate_string_to_buffer(filepath, ptr_entry->path, sizeof(ptr_entry->path));
5145 dos_find_to_gate_file_entry(&found_file, ptr_entry);
5146 }
5147 ret = GATE_RESULT_OK;
5148 } while (0);
5149
5150 return ret;
5151 }
5152 gate_result_t gate_file_dir_create(gate_string_t const* dirpath, gate_enumint_t flags)
5153 {
5154 char path[GATE_MAX_FILEPATH_LENGTH];
5155 GATE_UNUSED_ARG(flags);
5156 gate_string_to_buffer(dirpath, path, sizeof(path));
5157 if (0 != _mkdir(path))
5158 {
5159 return GATE_RESULT_FAILED;
5160 }
5161 return GATE_RESULT_OK;
5162 }
5163 gate_result_t gate_file_dir_delete(gate_string_t const* dirpath)
5164 {
5165 char path[GATE_MAX_FILEPATH_LENGTH];
5166 gate_string_to_buffer(dirpath, path, sizeof(path));
5167 if (0 != _rmdir(path))
5168 {
5169 return GATE_RESULT_FAILED;
5170 }
5171 return GATE_RESULT_OK;
5172 }
5173 gate_result_t gate_file_dir_exists(gate_string_t const* dirpath)
5174 {
5175 DIR* ptr_dir;
5176 char path[GATE_MAX_FILEPATH_LENGTH];
5177 gate_string_to_buffer(dirpath, path, sizeof(path));
5178 ptr_dir = opendir(path);
5179 if (ptr_dir == NULL)
5180 {
5181 return GATE_RESULT_NOTAVAILABLE;
5182 }
5183 closedir(ptr_dir);
5184 return GATE_RESULT_OK;
5185 }
5186 gate_result_t gate_file_dir_open(gate_string_t const* dirpath, gate_file_dirreader_t* dirhandle)
5187 {
5188 DIR* ptr_dir;
5189
5190 if (!dirpath || !dirhandle)
5191 {
5192 return GATE_RESULT_INVALIDARG;
5193 }
5194
5195 gate_mem_clear(dirhandle, sizeof(gate_file_dirreader_t));
5196
5197 dirhandle->bufferlen = gate_string_to_buffer(dirpath, dirhandle->buffer, sizeof(dirhandle->buffer) - 1);
5198 if (dirhandle->bufferlen == 0)
5199 {
5200 return GATE_RESULT_FAILED;
5201 }
5202 if (dirhandle->buffer[dirhandle->bufferlen - 1] != '\\')
5203 {
5204 dirhandle->buffer[dirhandle->bufferlen] = '\\';
5205 ++dirhandle->bufferlen;
5206 dirhandle->buffer[dirhandle->bufferlen] = 0;
5207 }
5208
5209 ptr_dir = opendir(dirhandle->buffer);
5210 if (ptr_dir == NULL)
5211 {
5212 return GATE_RESULT_NOTAVAILABLE;
5213 }
5214 dirhandle->handle = ptr_dir;
5215 return GATE_RESULT_OK;
5216 }
5217 gate_size_t gate_file_dir_read(gate_file_dirreader_t* dirhandle, char* path, gate_size_t pathlen, gate_bool_t filename_only)
5218 {
5219 gate_size_t ret = 0;
5220
5221 if (dirhandle && dirhandle->handle && path && pathlen)
5222 {
5223 DIR* ptr_dir = (DIR*)dirhandle->handle;
5224 struct dirent* ptr_dirent = readdir(ptr_dir);
5225 while (ptr_dirent)
5226 {
5227 if ((gate_str_comp(ptr_dirent->d_name, "..") == 0) || (gate_str_comp(ptr_dirent->d_name, ".") == 0))
5228 {
5229 ptr_dirent = readdir(ptr_dir);
5230 }
5231 else
5232 {
5233 if (filename_only)
5234 {
5235 ret = gate_str_print_text(path, pathlen, ptr_dirent->d_name, gate_str_length(ptr_dirent->d_name));
5236 }
5237 else
5238 {
5239 ret = gate_str_print_text(path, pathlen, dirhandle->buffer, dirhandle->bufferlen);
5240 path += ret;
5241 pathlen -= ret;
5242 ret += gate_str_print_text(path, pathlen, ptr_dirent->d_name, gate_str_length(ptr_dirent->d_name));
5243 }
5244 break;
5245 }
5246 }
5247 }
5248
5249 return ret;
5250 }
5251 gate_result_t gate_file_dir_close(gate_file_dirreader_t* dirhandle)
5252 {
5253 if (dirhandle && dirhandle->handle)
5254 {
5255 DIR* ptr_dir = (DIR*)dirhandle->handle;
5256 closedir(ptr_dir);
5257 dirhandle->handle = NULL;
5258 }
5259 return GATE_RESULT_OK;
5260 }
5261
5262 #endif /* GATE_CORE_FILES_DOS_IMPL */
5263
5264
5265
5266
5267 #if defined(GATE_CORE_FILES_EFI_IMPL)
5268
5269 #include "gate/platform/efi/efi_gate.h"
5270
5271 char const gate_file_path_separator_char = '\\';
5272
5273 char const* const gate_file_path_separator = "\\";
5274
5275 static void update_volumes(void** device_handles, gate_size_t device_handles_count)
5276 {
5277 gate_size_t ndx;
5278 int dummy = 0;
5279
5280 for (ndx = 0; ndx != device_handles_count; ++ndx)
5281 {
5282 gate_platform_efi_register_volume(device_handles[ndx], &dummy);
5283 }
5284 }
5285
5286 static gate_result_t update_all_volumes()
5287 {
5288 void* device_handles[256] = GATE_INIT_EMPTY;
5289 gate_size_t device_handles_count = sizeof(device_handles) / sizeof(device_handles[0]);
5290 gate_result_t ret;
5291 ret = gate_platform_efi_find_volume_device_handles(device_handles, &device_handles_count);
5292 if (GATE_SUCCEEDED(ret))
5293 {
5294 update_volumes(device_handles, device_handles_count);
5295 }
5296 return ret;
5297 }
5298
5299 static gate_result_t open_volume_root(gate_string_t const* dirpath, void** ptr_volume_root, gate_string_t* subpath)
5300 {
5301 gate_result_t ret;
5302 gate_string_t drive = GATE_STRING_INIT_EMPTY;
5303 do
5304 {
5305 static gate_bool_t is_initialized = false;
5306 if (!is_initialized)
5307 {
5308 is_initialized = true;
5309 update_all_volumes();
5310 }
5311
5312 if (gate_string_starts_with_str(dirpath, gate_file_path_separator))
5313 {
5314 /* open boot device */
5315 ret = gate_platform_efi_open_app_volume_root(ptr_volume_root);
5316 GATE_BREAK_IF_FAILED(ret);
5317 gate_string_substr(subpath, dirpath, 1, GATE_STR_NPOS);
5318 }
5319 else if (gate_string_starts_with_str(dirpath, "FS") || gate_string_starts_with_str(dirpath, "fs"))
5320 {
5321 /* check for UEFI shell paths FSx:\\ */
5322 wchar_t fspath[8];
5323 void* volume_handle = NULL;
5324
5325 gate_string_substr(&drive, dirpath, 0, 5);
5326 if (!gate_string_ends_with_str(&drive, ":\\"))
5327 {
5328 ret = GATE_RESULT_INVALIDARG;
5329 break;
5330 }
5331
5332 /* it is a shell path: */
5333 fspath[0] = 'f';
5334 fspath[1] = 's';
5335 fspath[2] = (wchar_t)dirpath->str[2];
5336 fspath[3] = ':';
5337 fspath[4] = 0;
5338
5339 ret = gate_platform_efi_shell_get_volume_from_path(fspath, &volume_handle);
5340 GATE_BREAK_IF_FAILED(ret);
5341
5342 ret = gate_platform_efi_resolve_volume(volume_handle, NULL);
5343 if (GATE_FAILED(ret))
5344 {
5345 ret = update_all_volumes();
5346 GATE_BREAK_IF_FAILED(ret);
5347 ret = gate_platform_efi_resolve_volume(volume_handle, NULL);
5348 GATE_BREAK_IF_FAILED(ret);
5349 }
5350
5351 ret = gate_platform_efi_open_volume_device(volume_handle, ptr_volume_root);
5352 GATE_BREAK_IF_FAILED(ret);
5353
5354 gate_string_substr(subpath, dirpath, 5, GATE_STR_NPOS);
5355 }
5356 else
5357 {
5358 /* check for GATE- or DOS- style drive letters: */
5359 char letter;
5360 int volume_id = 0;
5361 void* volume_handle = NULL;
5362
5363 gate_string_substr(&drive, dirpath, 0, 3);
5364 if (!gate_string_ends_with_str(&drive, ":\\"))
5365 {
5366 ret = GATE_RESULT_INVALIDARG;
5367 break;
5368 }
5369 letter = gate_string_char_at(&drive, 0);
5370 if ((letter >= 'A') && (letter <= 'Z'))
5371 {
5372 volume_id = letter - 'A' + 1;
5373 }
5374 else if ((letter >= 'a') && (letter <= 'z'))
5375 {
5376 volume_id = letter - 'a' + 1;
5377 }
5378 else
5379 {
5380 ret = GATE_RESULT_INVALIDARG;
5381 break;
5382 }
5383
5384 ret = gate_platform_efi_get_volume(volume_id, &volume_handle);
5385 if (GATE_FAILED(ret))
5386 {
5387 ret = update_all_volumes();
5388 GATE_BREAK_IF_FAILED(ret);
5389 ret = gate_platform_efi_get_volume(volume_id, &volume_handle);
5390 }
5391 if (GATE_FAILED(ret))
5392 {
5393 ret = GATE_RESULT_NOMATCH;
5394 break;
5395 }
5396
5397 ret = gate_platform_efi_open_volume_device(volume_handle, ptr_volume_root);
5398 GATE_BREAK_IF_FAILED(ret);
5399
5400 gate_string_substr(subpath, dirpath, 3, GATE_STR_NPOS);
5401 }
5402 /* code */
5403 } while (0);
5404
5405 gate_string_release(&drive);
5406
5407 return ret;
5408 }
5409
5410
5411 gate_result_t open_volume_file(gate_string_t const* filepath, gate_enumint_t efi_open_type, void** ptr_file_handle)
5412 {
5413 gate_result_t ret;
5414 void* volume_root = NULL;
5415 void* file_handle = NULL;
5416 gate_string_t subpath = GATE_STRING_INIT_EMPTY;
5417 do
5418 {
5419 ret = open_volume_root(filepath, &volume_root, &subpath);
5420 GATE_BREAK_IF_FAILED(ret);
5421
5422 if (gate_string_is_empty(&subpath))
5423 {
5424 /* open root path itself */
5425 if (ptr_file_handle)
5426 {
5427 *ptr_file_handle = volume_root;
5428 volume_root = NULL;
5429 }
5430 }
5431 else
5432 {
5433 wchar_t native_path[GATE_MAX_FILEPATH_LENGTH];
5434 gate_str_utf8_2_utf16(gate_string_ptr(&subpath, 0), gate_string_length(&subpath),
5435 native_path, sizeof(native_path) / sizeof(native_path[0]));
5436
5437 ret = gate_platform_efi_open_file(volume_root, native_path, GATE_PLATFORM_EFI_OPEN_READ, &file_handle);
5438 GATE_BREAK_IF_FAILED(ret);
5439
5440 if (ptr_file_handle)
5441 {
5442 *ptr_file_handle = file_handle;
5443 file_handle = NULL;
5444 }
5445 }
5446
5447 } while (0);
5448
5449 if (file_handle != NULL)
5450 {
5451 gate_platform_efi_close_file(file_handle);
5452 }
5453 if (volume_root != NULL)
5454 {
5455 gate_platform_efi_close_file(volume_root);
5456 }
5457 gate_string_release(&subpath);
5458
5459 return ret;
5460 }
5461
5462 gate_result_t gate_file_exists(gate_string_t const* filepath)
5463 {
5464 return open_volume_file(filepath, GATE_PLATFORM_EFI_OPEN_READ, NULL);
5465 }
5466 gate_result_t gate_file_copy(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
5467 {
5468 return gate_file_copy_internal(srcfilepath, dstfilepath, flags);
5469 }
5470 gate_result_t gate_file_move(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
5471 {
5472 return gate_file_move_internal(srcfilepath, dstfilepath);
5473 }
5474 gate_result_t gate_file_delete(gate_string_t const* filepath)
5475 {
5476 void* file_handle = NULL;
5477 gate_result_t ret = open_volume_file(filepath, GATE_PLATFORM_EFI_OPEN_READ, &file_handle);
5478 if (GATE_SUCCEEDED(ret))
5479 {
5480 ret = gate_platform_efi_delete_file(file_handle);
5481 gate_platform_efi_close_file(file_handle);
5482 }
5483 return ret;
5484 }
5485 gate_result_t gate_file_real_path(gate_string_t const* relativepath, gate_string_t* absolutepath)
5486 {
5487 return GATE_RESULT_NOTSUPPORTED;
5488 }
5489 gate_result_t gate_file_create_link(gate_string_t const* targetpath, gate_string_t const* linkfile)
5490 {
5491 return GATE_RESULT_NOTSUPPORTED;
5492 }
5493 gate_result_t gate_file_read_link(gate_string_t const* filepath, gate_string_t* realpath)
5494 {
5495 return GATE_RESULT_NOTSUPPORTED;
5496 }
5497 gate_result_t gate_file_create_hardlink(gate_string_t const* targetfile, gate_string_t const* linkfile)
5498 {
5499 return GATE_RESULT_NOTSUPPORTED;
5500 }
5501 gate_result_t gate_file_get_attributes(gate_string_t const* targetpath, gate_enumint_t* attribs, gate_enumint_t* access_bits)
5502 {
5503 return GATE_RESULT_NOTSUPPORTED;
5504 }
5505 gate_result_t gate_file_set_attributes(gate_string_t const* targetpath,
5506 gate_enumint_t attribs, gate_enumint_t attribs_mask,
5507 gate_enumint_t access, gate_enumint_t access_mask)
5508 {
5509 return GATE_RESULT_NOTSUPPORTED;
5510 }
5511
5512 gate_result_t gate_file_get_times(gate_string_t const* targetpath, gate_timestamp_t* modified, gate_timestamp_t* accessed, gate_timestamp_t* created)
5513 {
5514 return GATE_RESULT_NOTSUPPORTED;
5515 }
5516 gate_result_t gate_file_set_times(gate_string_t const* targetpath, gate_timestamp_t const* modified, gate_timestamp_t const* accessed, gate_timestamp_t const* created)
5517 {
5518 return GATE_RESULT_NOTSUPPORTED;
5519 }
5520 gate_result_t gate_file_get_size(gate_string_t const* targetfile, gate_int64_t* filesize)
5521 {
5522 return GATE_RESULT_NOTSUPPORTED;
5523 }
5524 gate_result_t gate_file_get_owner(gate_string_t const* targetfile,
5525 gate_uint32_t* owner_id, gate_string_t* owner_name)
5526 {
5527 return GATE_RESULT_NOTSUPPORTED;
5528 }
5529
5530 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
5531 {
5532 gate_result_t ret = GATE_RESULT_FAILED;
5533 int efi_open_flags = 0;
5534 void* efi_handle = NULL;
5535 gate_enumint_t attribs = 0;
5536
5537 do
5538 {
5539 if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_READ))
5540 {
5541 efi_open_flags |= GATE_PLATFORM_EFI_OPEN_READ;
5542 }
5543 if (GATE_FLAG_ENABLED(flags, GATE_STREAM_OPEN_WRITE))
5544 {
5545 efi_open_flags |= GATE_PLATFORM_EFI_OPEN_WRITE;
5546 }
5547
5548 ret = open_volume_file(filepath, efi_open_flags, &efi_handle);
5549 GATE_BREAK_IF_FAILED(ret);
5550
5551 ret = gate_platform_efi_get_file_info(efi_handle,
5552 NULL, NULL, NULL,
5553 &attribs,
5554 NULL, NULL, NULL);
5555
5556 GATE_BREAK_IF_FAILED(ret);
5557
5558 if (GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_DIRECTORY))
5559 {
5560 /* directories cannot be opened as a file! */
5561 ret = GATE_RESULT_INVALIDSTATE;
5562 break;
5563 }
5564
5565 /* success case */
5566 ret = GATE_RESULT_OK;
5567 if (filehandle)
5568 {
5569 *filehandle = efi_handle;
5570 efi_handle = NULL;
5571 }
5572 } while (0);
5573
5574 if (efi_handle != NULL)
5575 {
5576 gate_platform_efi_close_file(efi_handle);
5577 }
5578
5579 return ret;
5580 }
5581 gate_result_t gate_file_read(gate_file_t filehandle, char* buffer, gate_size_t bufferlength, gate_size_t* bufferused)
5582 {
5583 gate_result_t ret = GATE_RESULT_FAILED;
5584 do
5585 {
5586 if (!filehandle)
5587 {
5588 ret = GATE_RESULT_INVALIDARG;
5589 break;
5590 }
5591 if ((bufferlength != 0) && (buffer == NULL))
5592 {
5593 ret = GATE_RESULT_INVALIDARG;
5594 break;
5595 }
5596 ret = gate_platform_efi_read_file(filehandle, (char*)buffer, bufferlength, bufferused);
5597 } while (0);
5598 return ret;
5599 }
5600 gate_result_t gate_file_write(gate_file_t filehandle, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
5601 {
5602 gate_result_t ret = GATE_RESULT_FAILED;
5603 do
5604 {
5605 if (!filehandle)
5606 {
5607 ret = GATE_RESULT_INVALIDARG;
5608 break;
5609 }
5610 if ((bufferlength != 0) && (buffer == NULL))
5611 {
5612 ret = GATE_RESULT_INVALIDARG;
5613 break;
5614 }
5615 ret = gate_platform_efi_read_file(filehandle, (char*)buffer, bufferlength, written);
5616 } while (0);
5617 return ret;
5618 }
5619 gate_result_t gate_file_flush(gate_file_t filehandle)
5620 {
5621 return gate_platform_efi_flush_file(filehandle);
5622 }
5623 gate_result_t gate_file_close(gate_file_t filehandle)
5624 {
5625 if (filehandle)
5626 {
5627 gate_platform_efi_close_file(filehandle);
5628 return GATE_RESULT_OK;
5629 }
5630 else
5631 {
5632 return GATE_RESULT_INVALIDARG;
5633 }
5634 }
5635 gate_result_t gate_file_seek(gate_file_t filehandle, gate_int64_t position, gate_enumint_t origin, gate_int64_t* newposition)
5636 {
5637 gate_result_t result = GATE_RESULT_OK;
5638 gate_int64_t target_pos = 0;
5639
5640 switch (origin)
5641 {
5642 case GATE_FILE_SEEK_ORIGIN_BEGIN:
5643 {
5644 target_pos = position;
5645 break;
5646 }
5647 case GATE_FILE_SEEK_ORIGIN_CURPOS:
5648 {
5649 result = gate_platform_efi_get_file_position(filehandle, &target_pos);
5650 target_pos += position;
5651 break;
5652 }
5653 case GATE_FILE_SEEK_ORIGIN_END:
5654 {
5655 result = gate_file_size(filehandle, &target_pos);
5656 target_pos += position;
5657 break;
5658 }
5659 default:
5660 {
5661 result = GATE_RESULT_INVALIDARG;
5662 break;
5663 }
5664 }
5665
5666 if (GATE_SUCCEEDED(result))
5667 {
5668 result = gate_platform_efi_set_file_position(filehandle, target_pos);
5669 if (newposition)
5670 {
5671 result = gate_platform_efi_get_file_position(filehandle, newposition);
5672 }
5673 }
5674 return result;
5675 }
5676 gate_result_t gate_file_pos(gate_file_t filehandle, gate_int64_t* position)
5677 {
5678 return gate_platform_efi_get_file_position(filehandle, position);
5679 }
5680 gate_result_t gate_file_size(gate_file_t filehandle, gate_int64_t* size)
5681 {
5682 gate_uint64_t sz = 0;
5683 gate_uint64_t f_sz = 0;
5684 gate_result_t ret = gate_platform_efi_get_file_info(filehandle, &sz, &f_sz, NULL, NULL, NULL, NULL, NULL);
5685 if (size) *size = f_sz;
5686 return ret;
5687 }
5688
5689 gate_result_t gate_file_truncate(gate_file_t filehandle)
5690 {
5691 gate_result_t ret = GATE_RESULT_NOTSUPPORTED;
5692 return ret;
5693 }
5694
5695
5696 gate_result_t gate_file_lock(gate_file_t filehandle, gate_bool_t wait)
5697 {
5698 return GATE_RESULT_NOTSUPPORTED;
5699 }
5700 gate_result_t gate_file_unlock(gate_file_t filehandle)
5701 {
5702 return GATE_RESULT_NOTSUPPORTED;
5703 }
5704
5705 gate_result_t gate_file_root_list(gate_file_list_callback_t callback, void* userparam)
5706 {
5707 gate_result_t ret;
5708 gate_size_t ndx;
5709 int volume_ids[26];
5710 gate_size_t volumes_count;
5711 gate_file_entry_t file_entry;
5712
5713 do
5714 {
5715 ret = update_all_volumes();
5716 GATE_BREAK_IF_FAILED(ret);
5717
5718 if (!callback)
5719 {
5720 break;
5721 }
5722
5723 ret = GATE_RESULT_OK;
5724 volumes_count = gate_platform_efi_list_volumes(volume_ids, sizeof(volume_ids) / sizeof(volume_ids[0]));
5725 for (ndx = 0; ndx != volumes_count; ++ndx)
5726 {
5727 int vol_id = volume_ids[ndx];
5728 gate_mem_clear(&file_entry, sizeof(file_entry));
5729 file_entry.path[0] = (char)('@' + vol_id);
5730 file_entry.path[1] = ':';
5731 file_entry.path[2] = '\\';
5732 file_entry.path[3] = 0;
5733
5734 file_entry.name[0] = (char)('@' + vol_id);
5735 file_entry.name[1] = ':';
5736 file_entry.name[2] = 0;
5737
5738 file_entry.props.attribs = GATE_FILEENTRY_ATTRIB_DIRECTORY | GATE_FILEENTRY_ATTRIB_VOLUME;
5739 if (!callback(&file_entry, userparam))
5740 {
5741 break;
5742 }
5743 }
5744 } while (0);
5745 return ret;
5746 }
5747
5748 gate_result_t gate_file_list(gate_string_t const* dirpath, gate_file_list_callback_t callback, void* userparam)
5749 {
5750 gate_result_t ret = GATE_RESULT_FAILED;
5751 void* file_handle = NULL;
5752
5753 do
5754 {
5755 gate_file_entry_t entry;
5756 gate_size_t parent_length;
5757
5758 ret = open_volume_file(dirpath, GATE_PLATFORM_EFI_OPEN_READ, &file_handle);
5759 GATE_BREAK_IF_FAILED(ret);
5760
5761 gate_mem_clear(&entry, sizeof(entry));
5762
5763 parent_length = gate_str_print_text(entry.path, sizeof(entry.path) - 1, gate_string_ptr(dirpath, 0), gate_string_length(dirpath));
5764 if (parent_length == 0)
5765 {
5766 ret = GATE_RESULT_INVALIDDATA;
5767 break;
5768 }
5769 if (entry.path[parent_length - 1] != gate_file_path_separator_char)
5770 {
5771 entry.path[parent_length] = gate_file_path_separator_char;
5772 ++parent_length;
5773 }
5774
5775 while (GATE_SUCCEEDED(ret))
5776 {
5777 wchar_t filename[256];
5778 gate_size_t filename_len = sizeof(filename) / sizeof(filename[0]);
5779 gate_size_t filename_used;
5780 gate_uint64_t filesize = 0;
5781 gate_uint32_t attribs = 0;
5782 gate_int64_t times[3];
5783 gate_bool_t is_readonly;
5784 gate_bool_t is_executable;
5785
5786 ret = gate_platform_efi_read_dir(file_handle,
5787 filename, &filename_len,
5788 NULL, &filesize, NULL,
5789 &attribs,
5790 &times[0],
5791 &times[1],
5792 &times[2]
5793 );
5794 if (ret == GATE_RESULT_ENDOFSTREAM)
5795 {
5796 ret = GATE_RESULT_OK;
5797 break;
5798 }
5799 GATE_BREAK_IF_FAILED(ret);
5800
5801 /* print filename */
5802 filename_used = gate_str_utf16_2_utf8(filename, filename_len, &entry.name[0], sizeof(entry.name));
5803 /* print filename after parent path */
5804 gate_str_print_text(&entry.path[parent_length], sizeof(entry.path) - parent_length, entry.name, filename_used);
5805
5806 entry.props.size = filesize;
5807 entry.props.attribs = 0;
5808 GATE_FLAG_SET(entry.props.attribs, GATE_FILEENTRY_ATTRIB_READONLY, GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_READONLY));
5809 GATE_FLAG_SET(entry.props.attribs, GATE_FILEENTRY_ATTRIB_HIDDEN, GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_HIDDEN));
5810 GATE_FLAG_SET(entry.props.attribs, GATE_FILEENTRY_ATTRIB_SYSTEM, GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_SYSTEM));
5811 GATE_FLAG_SET(entry.props.attribs, GATE_FILEENTRY_ATTRIB_ARCHIVE, GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_ARCHIVE));
5812 GATE_FLAG_SET(entry.props.attribs, GATE_FILEENTRY_ATTRIB_DIRECTORY, GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_DIRECTORY));
5813
5814 is_readonly = GATE_FLAG_ENABLED(attribs, GATE_PLATFORM_EFI_FILEATTR_READONLY);
5815 is_executable = gate_str_ends_with_ic(entry.name, filename_used, ".efi", 4);
5816
5817 entry.props.access = GATE_FILEENTRY_ACCESS_OWNERREAD
5818 | GATE_FILEENTRY_ACCESS_GROUPREAD
5819 | GATE_FILEENTRY_ACCESS_ALLREAD
5820 ;
5821
5822 if (!is_readonly)
5823 {
5824 entry.props.access |= GATE_FILEENTRY_ACCESS_OWNERWRITE
5825 | GATE_FILEENTRY_ACCESS_GROUPWRITE
5826 | GATE_FILEENTRY_ACCESS_ALLWRITE
5827 ;
5828 }
5829
5830 if (is_executable)
5831 {
5832 entry.props.access |= GATE_FILEENTRY_ACCESS_OWNEREXECUTE
5833 | GATE_FILEENTRY_ACCESS_GROUPEXECUTE
5834 | GATE_FILEENTRY_ACCESS_ALLEXECUTE
5835 ;
5836 }
5837
5838 gate_time_from_unix(times[0] / 1000, &entry.props.time_created);
5839 gate_time_from_unix(times[1] / 1000, &entry.props.time_accessed);
5840 gate_time_from_unix(times[2] / 1000, &entry.props.time_modified);
5841
5842 if (callback)
5843 {
5844 const gate_bool_t continue_iteration = callback(&entry, userparam);
5845 if (!continue_iteration)
5846 {
5847 break;
5848 }
5849 }
5850 }
5851 } while (0);
5852
5853 if (file_handle != NULL)
5854 {
5855 gate_platform_efi_close_file(file_handle);
5856 }
5857
5858 return ret;
5859
5860 return GATE_RESULT_NOTSUPPORTED;
5861 }
5862 gate_result_t gate_file_get_entry(gate_string_t const* filepath, gate_file_entry_t* ptrtonewentry)
5863 {
5864 return GATE_RESULT_NOTSUPPORTED;
5865 }
5866 gate_result_t gate_file_dir_create(gate_string_t const* dirpath, gate_enumint_t flags)
5867 {
5868 return GATE_RESULT_NOTSUPPORTED;
5869 }
5870 gate_result_t gate_file_dir_delete(gate_string_t const* dirpath)
5871 {
5872 return GATE_RESULT_NOTSUPPORTED;
5873 }
5874 gate_result_t gate_file_dir_exists(gate_string_t const* dirpath)
5875 {
5876 return GATE_RESULT_NOTSUPPORTED;
5877 }
5878 gate_result_t gate_file_dir_open(gate_string_t const* dirpath, gate_file_dirreader_t* dirhandle)
5879 {
5880 return GATE_RESULT_NOTSUPPORTED;
5881 }
5882 gate_size_t gate_file_dir_read(gate_file_dirreader_t* dirhandle, char* path, gate_size_t pathlen, gate_bool_t filename_only)
5883 {
5884 return GATE_RESULT_NOTSUPPORTED;
5885 }
5886 gate_result_t gate_file_dir_close(gate_file_dirreader_t* dirhandle)
5887 {
5888 return GATE_RESULT_NOTSUPPORTED;
5889 }
5890
5891 #endif /* GATE_CORE_FILES_EFI_IMPL */
5892
5893
5894 #if defined(GATE_CORE_FILES_WASM_IMPL)
5895
5896 #include <emscripten.h>
5897 #include "gate/strings.h"
5898 #include "gate/platform/wasm/wasm_gate.h"
5899
5900
5901 char const gate_file_path_separator_char = '/';
5902
5903 char const* const gate_file_path_separator = "/";
5904
5905 gate_result_t gate_file_exists(gate_string_t const* filepath)
5906 {
5907 return GATE_RESULT_NOTSUPPORTED;
5908 }
5909 gate_result_t gate_file_copy(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
5910 {
5911 return gate_file_copy_internal(srcfilepath, dstfilepath, flags);
5912 }
5913 gate_result_t gate_file_move(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
5914 {
5915 return gate_file_move_internal(srcfilepath, dstfilepath);
5916 }
5917 gate_result_t gate_file_delete(gate_string_t const* filepath)
5918 {
5919 return GATE_RESULT_NOTSUPPORTED;
5920 }
5921 gate_result_t gate_file_real_path(gate_string_t const* relativepath, gate_string_t* absolutepath)
5922 {
5923 return GATE_RESULT_NOTSUPPORTED;
5924 }
5925 gate_result_t gate_file_create_link(gate_string_t const* targetpath, gate_string_t const* linkfile)
5926 {
5927 return GATE_RESULT_NOTSUPPORTED;
5928 }
5929 gate_result_t gate_file_read_link(gate_string_t const* filepath, gate_string_t* realpath)
5930 {
5931 return GATE_RESULT_NOTSUPPORTED;
5932 }
5933 gate_result_t gate_file_create_hardlink(gate_string_t const* targetfile, gate_string_t const* linkfile)
5934 {
5935 return GATE_RESULT_NOTSUPPORTED;
5936 }
5937 gate_result_t gate_file_get_attributes(gate_string_t const* targetpath, gate_enumint_t* attribs, gate_enumint_t* access_bits)
5938 {
5939 return GATE_RESULT_NOTSUPPORTED;
5940
5941 }
5942 gate_result_t gate_file_set_attributes(gate_string_t const* targetpath,
5943 gate_enumint_t attribs, gate_enumint_t attribs_mask,
5944 gate_enumint_t access_bits, gate_enumint_t access_mask)
5945 {
5946 return GATE_RESULT_NOTSUPPORTED;
5947 }
5948 gate_result_t gate_file_get_times(gate_string_t const* targetpath, gate_timestamp_t* modified, gate_timestamp_t* accessed, gate_timestamp_t* created)
5949 {
5950 return GATE_RESULT_NOTSUPPORTED;
5951 }
5952 gate_result_t gate_file_set_times(gate_string_t const* targetpath, gate_timestamp_t const* modified, gate_timestamp_t const* accessed, gate_timestamp_t const* created)
5953 {
5954 return GATE_RESULT_NOTSUPPORTED;
5955 }
5956 gate_result_t gate_file_get_size(gate_string_t const* targetfile, gate_int64_t* filesize)
5957 {
5958 return GATE_RESULT_NOTSUPPORTED;
5959 }
5960 gate_result_t gate_file_get_owner(gate_string_t const* targetfile,
5961 gate_uint32_t* owner_id, gate_string_t* owner_name)
5962 {
5963 return GATE_RESULT_NOTSUPPORTED;
5964 }
5965
5966 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
5967 {
5968 gate_result_t ret;
5969 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
5970
5971 gate_cstrbuffer_create_string(&buffer, filepath, false);
5972 do
5973 {
5974 int fd = gate_wasm_open(gate_cstrbuffer_get(&buffer), flags);
5975 if (fd < 0)
5976 {
5977 ret = GATE_RESULT_FAILED;
5978 break;
5979 }
5980 *filehandle = (gate_file_t)fd;
5981 ret = GATE_RESULT_OK;
5982 } while (0);
5983
5984 gate_cstrbuffer_destroy(&buffer);
5985 return ret;
5986 }
5987 gate_result_t gate_file_read(gate_file_t filehandle, char* buffer, gate_size_t bufferlength, gate_size_t* bufferused)
5988 {
5989 int fd = (int)filehandle;
5990 gate_intptr_t result = gate_wasm_read(fd, buffer, bufferlength);
5991 if (result < 0)
5992 {
5993 return GATE_RESULT_FAILED;
5994 }
5995 else
5996 {
5997 if (bufferused)
5998 {
5999 *bufferused = (gate_size_t)result;
6000 }
6001 return GATE_RESULT_OK;
6002 }
6003 }
6004 gate_result_t gate_file_write(gate_file_t filehandle, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
6005 {
6006 int fd = (int)filehandle;
6007 gate_intptr_t result = gate_wasm_write(fd, buffer, bufferlength);
6008 if (result < 0)
6009 {
6010 return GATE_RESULT_FAILED;
6011 }
6012 else
6013 {
6014 if (written)
6015 {
6016 *written = (gate_size_t)result;
6017 }
6018 return GATE_RESULT_OK;
6019 }
6020 }
6021 gate_result_t gate_file_flush(gate_file_t filehandle)
6022 {
6023 return GATE_RESULT_NOTSUPPORTED;
6024 }
6025 gate_result_t gate_file_close(gate_file_t filehandle)
6026 {
6027 int fd = (int)filehandle;
6028 return gate_wasm_close(fd);
6029 }
6030 gate_result_t gate_file_seek(gate_file_t filehandle, gate_int64_t position, gate_enumint_t origin, gate_int64_t* newposition)
6031 {
6032 int fd = (int)filehandle;
6033 return gate_wasm_seek(fd, position, origin, newposition);
6034 }
6035 gate_result_t gate_file_pos(gate_file_t filehandle, gate_int64_t* position)
6036 {
6037 return GATE_RESULT_NOTSUPPORTED;
6038 }
6039 gate_result_t gate_file_size(gate_file_t filehandle, gate_int64_t* size)
6040 {
6041 return GATE_RESULT_NOTSUPPORTED;
6042 }
6043 gate_result_t gate_file_lock(gate_file_t filehandle, gate_bool_t wait)
6044 {
6045 return GATE_RESULT_NOTSUPPORTED;
6046 }
6047 gate_result_t gate_file_unlock(gate_file_t filehandle)
6048 {
6049 return GATE_RESULT_NOTSUPPORTED;
6050 }
6051 gate_result_t gate_file_root_list(gate_file_list_callback_t callback, void* userparam)
6052 {
6053 return GATE_RESULT_NOTSUPPORTED;
6054 }
6055 gate_result_t gate_file_list(gate_string_t const* dirpath, gate_file_list_callback_t callback, void* userparam)
6056 {
6057 gate_result_t ret;
6058 gate_cstrbuffer8_t buffer;
6059
6060 do
6061 {
6062 gate_string_t filenames[1024];
6063 gate_size_t used, n;
6064 gate_file_entry_t entry;
6065 char const* path_ptr;
6066 gate_size_t path_len;
6067
6068 if (NULL == gate_cstrbuffer_create_string(&buffer, dirpath, false))
6069 {
6070 ret = GATE_RESULT_OUTOFMEMORY;
6071 break;
6072 }
6073
6074 path_ptr = gate_cstrbuffer_get(&buffer);
6075 path_len = gate_cstrbuffer_length(&buffer);
6076
6077 used = gate_wasm_fs_readdir(path_ptr, filenames, sizeof(filenames) / sizeof(filenames[0]));
6078
6079 gate_mem_clear(&entry, sizeof(entry));
6080
6081 path_len = gate_str_print_text(entry.path, sizeof(entry.path) - 2, path_ptr, path_len);
6082 if (entry.path[path_len - 1] != gate_file_path_separator_char)
6083 {
6084 entry.path[path_len] = gate_file_path_separator_char;
6085 ++path_len;
6086 }
6087
6088 for (n = 0; n != used; ++n)
6089 {
6090 char const* name = gate_string_ptr(&filenames[n], 0);
6091 gate_size_t namelen = gate_string_length(&filenames[n]);
6092 gate_str_print_text(entry.name, sizeof(entry.name), name, namelen);
6093 gate_str_print_text(&entry.path[path_len], sizeof(entry.path) - path_len, name, namelen);
6094 entry.props.attribs = GATE_FILEENTRY_ATTRIB_FILE;
6095 entry.props.size = 1;
6096 if (!callback(&entry, userparam))
6097 {
6098 break;
6099 }
6100 }
6101 ret = GATE_RESULT_OK;
6102 for (n = 0; n != used; ++n)
6103 {
6104 gate_string_release(&filenames[n]);
6105 }
6106 } while (0);
6107 return ret;
6108 }
6109 gate_result_t gate_file_get_entry(gate_string_t const* filepath, gate_file_entry_t* ptrtonewentry)
6110 {
6111 return GATE_RESULT_NOTSUPPORTED;
6112 }
6113 gate_result_t gate_file_dir_create(gate_string_t const* dirpath, gate_enumint_t flags)
6114 {
6115 return GATE_RESULT_NOTSUPPORTED;
6116 }
6117 gate_result_t gate_file_dir_delete(gate_string_t const* dirpath)
6118 {
6119 return GATE_RESULT_NOTSUPPORTED;
6120 }
6121 gate_result_t gate_file_dir_exists(gate_string_t const* dirpath)
6122 {
6123 return GATE_RESULT_NOTSUPPORTED;
6124 }
6125 gate_result_t gate_file_dir_open(gate_string_t const* dirpath, gate_file_dirreader_t* dirhandle)
6126 {
6127 return GATE_RESULT_NOTSUPPORTED;
6128 }
6129 gate_size_t gate_file_dir_read(gate_file_dirreader_t* dirhandle, char* path, gate_size_t pathlen, gate_bool_t filename_only)
6130 {
6131 return GATE_RESULT_NOTSUPPORTED;
6132 }
6133 gate_result_t gate_file_dir_close(gate_file_dirreader_t* dirhandle)
6134 {
6135 return GATE_RESULT_NOTSUPPORTED;
6136 }
6137 gate_result_t gate_file_truncate(gate_file_t filehandle)
6138 {
6139 return GATE_RESULT_NOTSUPPORTED;
6140 }
6141
6142
6143 #endif /* GATE_CORE_FILES_WASM_IMPL */
6144
6145
6146
6147
6148 #if defined(GATE_CORE_FILES_NO_IMPL)
6149
6150 char const gate_file_path_separator_char = '/';
6151
6152 char const* const gate_file_path_separator = "/";
6153
6154 gate_result_t gate_file_exists(gate_string_t const* filepath)
6155 {
6156 return GATE_RESULT_NOTSUPPORTED;
6157 }
6158 gate_result_t gate_file_copy(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath, gate_enumint_t flags)
6159 {
6160 return GATE_RESULT_NOTSUPPORTED;
6161 }
6162 gate_result_t gate_file_move(gate_string_t const* srcfilepath, gate_string_t const* dstfilepath)
6163 {
6164 return GATE_RESULT_NOTSUPPORTED;
6165 }
6166 gate_result_t gate_file_delete(gate_string_t const* filepath)
6167 {
6168 return GATE_RESULT_NOTSUPPORTED;
6169 }
6170 gate_result_t gate_file_real_path(gate_string_t const* relativepath, gate_string_t* absolutepath)
6171 {
6172 return GATE_RESULT_NOTSUPPORTED;
6173 }
6174 gate_result_t gate_file_create_link(gate_string_t const* targetpath, gate_string_t const* linkfile)
6175 {
6176 return GATE_RESULT_NOTSUPPORTED;
6177 }
6178 gate_result_t gate_file_read_link(gate_string_t const* filepath, gate_string_t* realpath)
6179 {
6180 return GATE_RESULT_NOTSUPPORTED;
6181 }
6182 gate_result_t gate_file_create_hardlink(gate_string_t const* targetfile, gate_string_t const* linkfile)
6183 {
6184 return GATE_RESULT_NOTSUPPORTED;
6185 }
6186 gate_result_t gate_file_get_attributes(gate_string_t const* targetpath, gate_enumint_t* attribs, gate_enumint_t* access_bits)
6187 {
6188 return GATE_RESULT_NOTSUPPORTED;
6189
6190 }
6191 gate_result_t gate_file_set_attributes(gate_string_t const* targetpath,
6192 gate_enumint_t attribs, gate_enumint_t attribs_mask,
6193 gate_enumint_t access_bits, gate_enumint_t access_mask)
6194 {
6195 return GATE_RESULT_NOTSUPPORTED;
6196 }
6197 gate_result_t gate_file_get_times(gate_string_t const* targetpath, gate_timestamp_t* modified, gate_timestamp_t* accessed, gate_timestamp_t* created)
6198 {
6199 return GATE_RESULT_NOTSUPPORTED;
6200 }
6201 gate_result_t gate_file_set_times(gate_string_t const* targetpath, gate_timestamp_t const* modified, gate_timestamp_t const* accessed, gate_timestamp_t const* created)
6202 {
6203 return GATE_RESULT_NOTSUPPORTED;
6204 }
6205 gate_result_t gate_file_get_size(gate_string_t const* targetfile, gate_int64_t* filesize)
6206 {
6207 return GATE_RESULT_NOTSUPPORTED;
6208 }
6209 gate_result_t gate_file_get_owner(gate_string_t const* targetfile,
6210 gate_uint32_t* owner_id, gate_string_t* owner_name)
6211 {
6212 return GATE_RESULT_NOTSUPPORTED;
6213 }
6214
6215 gate_result_t gate_file_open(gate_string_t const* filepath, gate_enumint_t flags, gate_file_t* filehandle)
6216 {
6217 return GATE_RESULT_NOTSUPPORTED;
6218 }
6219 gate_result_t gate_file_read(gate_file_t filehandle, char* buffer, gate_size_t bufferlength, gate_size_t* bufferused)
6220 {
6221 return GATE_RESULT_NOTSUPPORTED;
6222 }
6223 gate_result_t gate_file_write(gate_file_t filehandle, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
6224 {
6225 return GATE_RESULT_NOTSUPPORTED;
6226 }
6227 gate_result_t gate_file_flush(gate_file_t filehandle)
6228 {
6229 return GATE_RESULT_NOTSUPPORTED;
6230 }
6231 gate_result_t gate_file_close(gate_file_t filehandle)
6232 {
6233 return GATE_RESULT_NOTSUPPORTED;
6234 }
6235 gate_result_t gate_file_seek(gate_file_t filehandle, gate_int64_t position, gate_enumint_t origin, gate_int64_t* newposition)
6236 {
6237 return GATE_RESULT_NOTSUPPORTED;
6238 }
6239 gate_result_t gate_file_pos(gate_file_t filehandle, gate_int64_t* position)
6240 {
6241 return GATE_RESULT_NOTSUPPORTED;
6242 }
6243 gate_result_t gate_file_size(gate_file_t filehandle, gate_int64_t* size)
6244 {
6245 return GATE_RESULT_NOTSUPPORTED;
6246 }
6247 gate_result_t gate_file_lock(gate_file_t filehandle, gate_bool_t wait)
6248 {
6249 return GATE_RESULT_NOTSUPPORTED;
6250 }
6251 gate_result_t gate_file_unlock(gate_file_t filehandle)
6252 {
6253 return GATE_RESULT_NOTSUPPORTED;
6254 }
6255 gate_result_t gate_file_root_list(gate_file_list_callback_t callback, void* userparam)
6256 {
6257 return GATE_RESULT_NOTSUPPORTED;
6258 }
6259 gate_result_t gate_file_list(gate_string_t const* dirpath, gate_file_list_callback_t callback, void* userparam)
6260 {
6261 return GATE_RESULT_NOTSUPPORTED;
6262 }
6263 gate_result_t gate_file_get_entry(gate_string_t const* filepath, gate_file_entry_t* ptrtonewentry)
6264 {
6265 return GATE_RESULT_NOTSUPPORTED;
6266 }
6267 gate_result_t gate_file_dir_create(gate_string_t const* dirpath, gate_enumint_t flags)
6268 {
6269 return GATE_RESULT_NOTSUPPORTED;
6270 }
6271 gate_result_t gate_file_dir_delete(gate_string_t const* dirpath)
6272 {
6273 return GATE_RESULT_NOTSUPPORTED;
6274 }
6275 gate_result_t gate_file_dir_exists(gate_string_t const* dirpath)
6276 {
6277 return GATE_RESULT_NOTSUPPORTED;
6278 }
6279 gate_result_t gate_file_dir_open(gate_string_t const* dirpath, gate_file_dirreader_t* dirhandle)
6280 {
6281 return GATE_RESULT_NOTSUPPORTED;
6282 }
6283 gate_size_t gate_file_dir_read(gate_file_dirreader_t* dirhandle, char* path, gate_size_t pathlen, gate_bool_t filename_only)
6284 {
6285 return GATE_RESULT_NOTSUPPORTED;
6286 }
6287 gate_result_t gate_file_dir_close(gate_file_dirreader_t* dirhandle)
6288 {
6289 return GATE_RESULT_NOTSUPPORTED;
6290 }
6291 gate_result_t gate_file_truncate(gate_file_t filehandle)
6292 {
6293 return GATE_RESULT_NOTSUPPORTED;
6294 }
6295
6296 #endif /* GATE_CORE_FILES_NO_IMPL */
6297
6298