tr_sys_file_t tr_sys_file_get_std (tr_std_sys_file_t std_file, tr_error ** error) { tr_sys_file_t ret = TR_BAD_SYS_FILE; switch (std_file) { case TR_STD_SYS_FILE_IN: ret = GetStdHandle (STD_INPUT_HANDLE); break; case TR_STD_SYS_FILE_OUT: ret = GetStdHandle (STD_OUTPUT_HANDLE); break; case TR_STD_SYS_FILE_ERR: ret = GetStdHandle (STD_ERROR_HANDLE); break; default: assert (0 && "Unknown standard file"); set_system_error (error, ERROR_INVALID_PARAMETER); return TR_BAD_SYS_FILE; } if (ret == TR_BAD_SYS_FILE) set_system_error (error, GetLastError ()); else if (ret == NULL) ret = TR_BAD_SYS_FILE; return ret; }
bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != NULL || size == 0); if (size > MAXDWORD) { set_system_error(error, ERROR_INVALID_PARAMETER); return false; } bool ret = false; DWORD my_bytes_read; if (ReadFile(handle, buffer, (DWORD)size, &my_bytes_read, NULL)) { if (bytes_read != NULL) { *bytes_read = my_bytes_read; } ret = true; } else { set_system_error(error, GetLastError()); } return ret; }
void* tr_sys_file_map_for_reading(tr_sys_file_t handle, uint64_t offset, uint64_t size, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(size > 0); if (size > MAXSIZE_T) { set_system_error(error, ERROR_INVALID_PARAMETER); return false; } void* ret = NULL; HANDLE mappingHandle = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL); if (mappingHandle != NULL) { ULARGE_INTEGER native_offset; native_offset.QuadPart = offset; ret = MapViewOfFile(mappingHandle, FILE_MAP_READ, native_offset.u.HighPart, native_offset.u.LowPart, (SIZE_T)size); } if (ret == NULL) { set_system_error(error, GetLastError()); } CloseHandle(mappingHandle); return ret; }
bool tr_sys_file_write (tr_sys_file_t handle, const void * buffer, uint64_t size, uint64_t * bytes_written, tr_error ** error) { bool ret = false; DWORD my_bytes_written; assert (handle != TR_BAD_SYS_FILE); assert (buffer != NULL || size == 0); if (size > MAXDWORD) { set_system_error (error, ERROR_INVALID_PARAMETER); return false; } if (WriteFile (handle, buffer, (DWORD)size, &my_bytes_written, NULL)) { if (bytes_written != NULL) *bytes_written = my_bytes_written; ret = true; } else { set_system_error (error, GetLastError ()); } return ret; }
tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, tr_error** error) { tr_sys_file_t ret = TR_BAD_SYS_FILE; switch (std_file) { case TR_STD_SYS_FILE_IN: ret = GetStdHandle(STD_INPUT_HANDLE); break; case TR_STD_SYS_FILE_OUT: ret = GetStdHandle(STD_OUTPUT_HANDLE); break; case TR_STD_SYS_FILE_ERR: ret = GetStdHandle(STD_ERROR_HANDLE); break; default: TR_ASSERT_MSG(false, "unknown standard file %d", (int)std_file); set_system_error(error, ERROR_INVALID_PARAMETER); return TR_BAD_SYS_FILE; } if (ret == TR_BAD_SYS_FILE) { set_system_error(error, GetLastError()); } else if (ret == NULL) { ret = TR_BAD_SYS_FILE; } return ret; }
bool tr_sys_path_get_info(char const* path, int flags, tr_sys_path_info* info, tr_error** error) { TR_ASSERT(path != NULL); TR_ASSERT(info != NULL); bool ret = false; wchar_t* wide_path = path_to_native_path(path); if ((flags & TR_SYS_PATH_NO_FOLLOW) == 0) { HANDLE handle = INVALID_HANDLE_VALUE; if (wide_path != NULL) { handle = CreateFileW(wide_path, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); } if (handle != INVALID_HANDLE_VALUE) { tr_error* my_error = NULL; ret = tr_sys_file_get_info(handle, info, &my_error); if (!ret) { tr_error_propagate(error, &my_error); } CloseHandle(handle); } else { set_system_error(error, GetLastError()); } } else { WIN32_FILE_ATTRIBUTE_DATA attributes; if (wide_path != NULL) { ret = GetFileAttributesExW(wide_path, GetFileExInfoStandard, &attributes); } if (ret) { stat_to_sys_path_info(attributes.dwFileAttributes, attributes.nFileSizeLow, attributes.nFileSizeHigh, &attributes.ftLastWriteTime, info); } else { set_system_error(error, GetLastError()); } } tr_free(wide_path); return ret; }
bool tr_sys_path_remove(char const* path, tr_error** error) { TR_ASSERT(path != NULL); bool ret = false; wchar_t* wide_path = path_to_native_path(path); if (wide_path != NULL) { DWORD const attributes = GetFileAttributesW(wide_path); if (attributes != INVALID_FILE_ATTRIBUTES) { if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { ret = RemoveDirectoryW(wide_path); } else { ret = DeleteFileW(wide_path); } } } if (!ret) { set_system_error(error, GetLastError()); } tr_free(wide_path); return ret; }
static void set_system_error_if_file_found(tr_error** error, DWORD code) { if (code != ERROR_FILE_NOT_FOUND && code != ERROR_PATH_NOT_FOUND && code != ERROR_NO_MORE_FILES) { set_system_error(error, code); } }
static void error_not_adc_channel(const uint8_t channel) { set_system_error(); if (LOG_LEVEL >= LOG_LEVEL_ERROR) { PGM_STR(ADC_NO_CHANNEL, failed_msg) LOG_ERROR(failed_msg, channel); } }
static void set_system_error_if_file_found (tr_error ** error, int code) { if (code != ENOENT) set_system_error (error, code); }
char * tr_sys_path_basename (const char * path, tr_error ** error) { if (path == NULL || path[0] == '\0') return tr_strdup ("."); if (!is_valid_path (path)) { set_system_error (error, ERROR_PATH_NOT_FOUND); return NULL; } const char * end = path + strlen (path); while (end > path && is_slash (*(end - 1))) --end; if (end == path) return tr_strdup ("/"); const char * name = end; while (name > path && *(name - 1) != ':' && !is_slash (*(name - 1))) --name; if (name == end) return tr_strdup ("/"); return tr_strndup (name, end - name); }
bool tr_sys_path_remove (const char * path, tr_error ** error) { bool ret = false; wchar_t * wide_path; assert (path != NULL); wide_path = tr_win32_utf8_to_native (path, -1); if (wide_path != NULL) { const DWORD attributes = GetFileAttributesW (wide_path); if (attributes != INVALID_FILE_ATTRIBUTES) { if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) ret = RemoveDirectoryW (wide_path); else ret = DeleteFileW (wide_path); } } if (!ret) set_system_error (error, GetLastError ()); tr_free (wide_path); return ret; }
static tr_sys_file_t open_file (const char * path, DWORD access, DWORD disposition, DWORD flags, tr_error ** error) { tr_sys_file_t ret = TR_BAD_SYS_FILE; wchar_t * wide_path; assert (path != NULL); wide_path = path_to_native_path (path); if (wide_path != NULL) ret = CreateFileW (wide_path, access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disposition, flags, NULL); if (ret == TR_BAD_SYS_FILE) set_system_error (error, GetLastError ()); tr_free (wide_path); return ret; }
bool tr_sys_file_seek (tr_sys_file_t handle, int64_t offset, tr_seek_origin_t origin, uint64_t * new_offset, tr_error ** error) { bool ret = false; LARGE_INTEGER native_offset, new_native_pointer; TR_STATIC_ASSERT (TR_SEEK_SET == FILE_BEGIN, "values should match"); TR_STATIC_ASSERT (TR_SEEK_CUR == FILE_CURRENT, "values should match"); TR_STATIC_ASSERT (TR_SEEK_END == FILE_END, "values should match"); assert (handle != TR_BAD_SYS_FILE); assert (origin == TR_SEEK_SET || origin == TR_SEEK_CUR || origin == TR_SEEK_END); native_offset.QuadPart = offset; if (SetFilePointerEx (handle, native_offset, &new_native_pointer, origin)) { if (new_offset != NULL) *new_offset = new_native_pointer.QuadPart; ret = true; } else { set_system_error (error, GetLastError ()); } return ret; }
char* tr_sys_path_dirname(char const* path, tr_error** error) { if (path == NULL || path[0] == '\0') { return tr_strdup("."); } if (!is_valid_path(path)) { set_system_error(error, ERROR_PATH_NOT_FOUND); return NULL; } bool const is_unc = is_unc_path(path); if (is_unc && path[2] == '\0') { return tr_strdup(path); } char const* end = path + strlen(path); while (end > path && is_slash(*(end - 1))) { --end; } if (end == path) { return tr_strdup("/"); } char const* name = end; while (name > path && *(name - 1) != ':' && !is_slash(*(name - 1))) { --name; } while (name > path && is_slash(*(name - 1))) { --name; } if (name == path) { return tr_strdup(is_unc ? "\\\\" : "."); } if (name > path && *(name - 1) == ':' && *name != '\0' && !is_slash(*name)) { return tr_strdup_printf("%c:.", path[0]); } return tr_strndup(path, name - path); }
bool tr_sys_file_lock(tr_sys_file_t handle, int operation, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT((operation & ~(TR_SYS_FILE_LOCK_SH | TR_SYS_FILE_LOCK_EX | TR_SYS_FILE_LOCK_NB | TR_SYS_FILE_LOCK_UN)) == 0); TR_ASSERT(!!(operation & TR_SYS_FILE_LOCK_SH) + !!(operation & TR_SYS_FILE_LOCK_EX) + !!(operation & TR_SYS_FILE_LOCK_UN) == 1); bool ret; OVERLAPPED overlapped = { .Pointer = 0, .hEvent = NULL }; if ((operation & TR_SYS_FILE_LOCK_UN) == 0) { DWORD native_flags = 0; if ((operation & TR_SYS_FILE_LOCK_EX) != 0) { native_flags |= LOCKFILE_EXCLUSIVE_LOCK; } if ((operation & TR_SYS_FILE_LOCK_NB) != 0) { native_flags |= LOCKFILE_FAIL_IMMEDIATELY; } ret = LockFileEx(handle, native_flags, 0, MAXDWORD, MAXDWORD, &overlapped) != FALSE; } else { ret = UnlockFileEx(handle, 0, MAXDWORD, MAXDWORD, &overlapped) != FALSE; } if (!ret) { set_system_error(error, GetLastError()); } return ret; } char* tr_sys_dir_get_current(tr_error** error) { char* ret = NULL; wchar_t* wide_ret = NULL; DWORD size; size = GetCurrentDirectoryW(0, NULL); if (size != 0) { wide_ret = tr_new(wchar_t, size); if (GetCurrentDirectoryW(size, wide_ret) != 0) { ret = tr_win32_native_to_utf8(wide_ret, size); } }
bool dtr_daemon (const dtr_callbacks * cb, void * cb_arg, bool foreground, int * exit_code, tr_error ** error) { callbacks = cb; callback_arg = cb_arg; *exit_code = 1; if (foreground) { if (!SetConsoleCtrlHandler (&handle_console_ctrl, TRUE)) { set_system_error (error, GetLastError (), "SetConsoleCtrlHandler() failed"); return false; } *exit_code = cb->on_start (cb_arg, true); } else { const SERVICE_TABLE_ENTRY service_table[] = { { (LPWSTR) service_name, &service_main }, { NULL, NULL } }; if (!StartServiceCtrlDispatcherW (service_table)) { set_system_error (error, GetLastError (), "StartServiceCtrlDispatcher() failed"); return false; } *exit_code = 0; } return true; }
bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); bool ret = CloseHandle(handle); if (!ret) { set_system_error(error, GetLastError()); } return ret; }
bool tr_sys_file_flush(tr_sys_file_t handle, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); bool ret = FlushFileBuffers(handle); if (!ret) { set_system_error(error, GetLastError()); } return ret; }
bool tr_sys_file_write_at (tr_sys_file_t handle, const void * buffer, uint64_t size, uint64_t offset, uint64_t * bytes_written, tr_error ** error) { bool ret = false; OVERLAPPED overlapped; DWORD my_bytes_written; assert (handle != TR_BAD_SYS_FILE); assert (buffer != NULL || size == 0); if (size > MAXDWORD) { set_system_error (error, ERROR_INVALID_PARAMETER); return false; } overlapped.Offset = (DWORD)offset; offset >>= 32; overlapped.OffsetHigh = (DWORD)offset; overlapped.hEvent = NULL; if (WriteFile (handle, buffer, (DWORD)size, &my_bytes_written, &overlapped)) { if (bytes_written != NULL) *bytes_written = my_bytes_written; ret = true; } else { set_system_error (error, GetLastError ()); } return ret; }
char * tr_sys_path_resolve (const char * path, tr_error ** error) { char * ret = NULL; wchar_t * wide_path; wchar_t * wide_ret = NULL; HANDLE handle; DWORD wide_ret_size; assert (path != NULL); wide_path = tr_win32_utf8_to_native (path, -1); if (wide_path == NULL) goto fail; handle = CreateFileW (wide_path, FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (handle == INVALID_HANDLE_VALUE) goto fail; wide_ret_size = GetFinalPathNameByHandleW (handle, NULL, 0, 0); if (wide_ret_size == 0) goto fail; wide_ret = tr_new (wchar_t, wide_ret_size); if (GetFinalPathNameByHandleW (handle, wide_ret, wide_ret_size, 0) != wide_ret_size - 1) goto fail; /* Resolved path always begins with "\\?\", so skip those first four chars. */ ret = tr_win32_native_to_utf8 (wide_ret + 4, -1); if (ret != NULL) goto cleanup; fail: set_system_error (error, GetLastError ()); tr_free (ret); ret = NULL; cleanup: tr_free (wide_ret); tr_free (wide_path); if (handle != INVALID_HANDLE_VALUE) CloseHandle (handle); return ret; }
tr_sys_file_t tr_sys_file_open (const char * path, int flags, int permissions, tr_error ** error) { tr_sys_file_t ret; DWORD native_access = 0; DWORD native_disposition = OPEN_EXISTING; DWORD native_flags = FILE_ATTRIBUTE_NORMAL; bool success; assert (path != NULL); assert ((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0); (void) permissions; if (flags & TR_SYS_FILE_READ) native_access |= GENERIC_READ; if (flags & TR_SYS_FILE_WRITE) native_access |= GENERIC_WRITE; if (flags & TR_SYS_FILE_CREATE_NEW) native_disposition = CREATE_NEW; else if (flags & TR_SYS_FILE_CREATE) native_disposition = flags & TR_SYS_FILE_TRUNCATE ? CREATE_ALWAYS : OPEN_ALWAYS; else if (flags & TR_SYS_FILE_TRUNCATE) native_disposition = TRUNCATE_EXISTING; if (flags & TR_SYS_FILE_SEQUENTIAL) native_flags |= FILE_FLAG_SEQUENTIAL_SCAN; ret = open_file (path, native_access, native_disposition, native_flags, error); success = ret != TR_BAD_SYS_FILE; if (success && (flags & TR_SYS_FILE_APPEND)) success = SetFilePointer (ret, 0, NULL, FILE_END) != INVALID_SET_FILE_POINTER; if (!success) { if (error == NULL) set_system_error (error, GetLastError ()); CloseHandle (ret); ret = TR_BAD_SYS_FILE; } return ret; }
bool tr_sys_file_read_at(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t offset, uint64_t* bytes_read, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); TR_ASSERT(buffer != NULL || size == 0); if (size > MAXDWORD) { set_system_error(error, ERROR_INVALID_PARAMETER); return false; } bool ret = false; OVERLAPPED overlapped; DWORD my_bytes_read; overlapped.Offset = (DWORD)offset; offset >>= 32; overlapped.OffsetHigh = (DWORD)offset; overlapped.hEvent = NULL; if (ReadFile(handle, buffer, (DWORD)size, &my_bytes_read, &overlapped)) { if (bytes_read != NULL) { *bytes_read = my_bytes_read; } ret = true; } else { set_system_error(error, GetLastError()); } return ret; }
bool tr_sys_file_flush (tr_sys_file_t handle, tr_error ** error) { bool ret; assert (handle != TR_BAD_SYS_FILE); ret = FlushFileBuffers (handle); if (!ret) set_system_error (error, GetLastError ()); return ret; }
bool tr_sys_file_close (tr_sys_file_t handle, tr_error ** error) { bool ret; assert (handle != TR_BAD_SYS_FILE); ret = CloseHandle (handle); if (!ret) set_system_error (error, GetLastError ()); return ret; }
bool tr_sys_file_unmap(void const* address, uint64_t size, tr_error** error) { TR_ASSERT(address != NULL); TR_ASSERT(size > 0); (void)size; bool ret = UnmapViewOfFile(address); if (!ret) { set_system_error(error, GetLastError()); } return ret; }
bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); FILE_END_OF_FILE_INFO info; info.EndOfFile.QuadPart = size; bool ret = SetFileInformationByHandle(handle, FileEndOfFileInfo, &info, sizeof(info)); if (!ret) { set_system_error(error, GetLastError()); } return ret; }
bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error** error) { TR_ASSERT(handle != TR_BAD_SYS_FILE); if ((flags & TR_SYS_FILE_PREALLOC_SPARSE) != 0) { DWORD tmp; if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &tmp, NULL)) { set_system_error(error, GetLastError()); return false; } } return tr_sys_file_truncate(handle, size, error); }
bool tr_sys_path_rename (const char * src_path, const char * dst_path, tr_error ** error) { bool ret = false; wchar_t * wide_src_path; wchar_t * wide_dst_path; assert (src_path != NULL); assert (dst_path != NULL); wide_src_path = tr_win32_utf8_to_native (src_path, -1); wide_dst_path = tr_win32_utf8_to_native (dst_path, -1); if (wide_src_path != NULL && wide_dst_path != NULL) { DWORD flags = MOVEFILE_REPLACE_EXISTING; DWORD attributes; attributes = GetFileAttributesW (wide_src_path); if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { flags = 0; } else { attributes = GetFileAttributesW (wide_dst_path); if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) flags = 0; } ret = MoveFileExW (wide_src_path, wide_dst_path, flags); } if (!ret) set_system_error (error, GetLastError ()); tr_free (wide_dst_path); tr_free (wide_src_path); return ret; }
static bool create_dir(char const* path, int flags, int permissions, bool okay_if_exists, tr_error** error) { TR_ASSERT(path != NULL); (void)permissions; bool ret; DWORD error_code = ERROR_SUCCESS; wchar_t* wide_path = path_to_native_path(path); if ((flags & TR_SYS_DIR_CREATE_PARENTS) != 0) { error_code = SHCreateDirectoryExW(NULL, wide_path, NULL); ret = error_code == ERROR_SUCCESS; } else { ret = CreateDirectoryW(wide_path, NULL); if (!ret) { error_code = GetLastError(); } } if (!ret && error_code == ERROR_ALREADY_EXISTS && okay_if_exists) { DWORD const attributes = GetFileAttributesW(wide_path); if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { ret = true; } } if (!ret) { set_system_error(error, error_code); } tr_free(wide_path); return ret; }