GCC Code Coverage Report


Directory: src/gate/
File: src/gate/files.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 561 881 63.7%
Functions: 46 62 74.2%
Branches: 235 596 39.4%

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