GCC Code Coverage Report


Directory: src/gate/
File: src/gate/files.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 591 888 66.6%
Functions: 48 62 77.4%
Branches: 264 604 43.7%

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