| 383 | } |
| 384 | |
| 385 | static int text_read_file(const char *path, char **data_out, size_t *len_out, |
| 386 | text_file_snapshot_t *snapshot_out) { |
| 387 | if (!path || !data_out || !len_out || !snapshot_out) { |
| 388 | return TEXT_ERROR; |
| 389 | } |
| 390 | *data_out = NULL; |
| 391 | *len_out = 0U; |
| 392 | memset(snapshot_out, 0, sizeof(*snapshot_out)); |
| 393 | |
| 394 | #ifdef _WIN32 |
| 395 | wchar_t *wide_path = cbm_utf8_to_wide(path); |
| 396 | if (!wide_path) { |
| 397 | return TEXT_ERROR; |
| 398 | } |
| 399 | HANDLE handle = CreateFileW( |
| 400 | wide_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, |
| 401 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT, NULL); |
| 402 | free(wide_path); |
| 403 | if (handle == INVALID_HANDLE_VALUE) { |
| 404 | DWORD error = GetLastError(); |
| 405 | if (error != ERROR_FILE_NOT_FOUND && error != ERROR_PATH_NOT_FOUND) { |
| 406 | return TEXT_ERROR; |
| 407 | } |
| 408 | char *empty = (char *)calloc(1U, 1U); |
| 409 | if (!empty) { |
| 410 | return TEXT_ERROR; |
| 411 | } |
| 412 | *data_out = empty; |
| 413 | return TEXT_OK; |
| 414 | } |
| 415 | text_file_snapshot_t before; |
| 416 | if (text_snapshot_from_handle(handle, &before) != TEXT_OK) { |
| 417 | CloseHandle(handle); |
| 418 | return TEXT_ERROR; |
| 419 | } |
| 420 | size_t len = (size_t)before.size; |
| 421 | char *data = (char *)malloc(len + 1U); |
| 422 | if (!data) { |
| 423 | CloseHandle(handle); |
| 424 | return TEXT_ERROR; |
| 425 | } |
| 426 | DWORD read_count = 0U; |
| 427 | BOOL read_ok = ReadFile(handle, data, (DWORD)len, &read_count, NULL); |
| 428 | text_file_snapshot_t after; |
| 429 | int after_result = text_snapshot_from_handle(handle, &after); |
| 430 | BOOL close_ok = CloseHandle(handle); |
| 431 | if (!read_ok || read_count != (DWORD)len || after_result != TEXT_OK || !close_ok || |
| 432 | !text_snapshot_equal(&before, &after)) { |
| 433 | free(data); |
| 434 | return TEXT_ERROR; |
| 435 | } |
| 436 | #else |
| 437 | #ifndef O_NOFOLLOW |
| 438 | (void)path; |
| 439 | return TEXT_ERROR; |
| 440 | #else |
| 441 | int flags = O_RDONLY | O_NOFOLLOW | O_NONBLOCK; |
| 442 | #ifdef O_CLOEXEC |
no test coverage detected