Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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);
    }
}
Esempio n. 9
0
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);
	}		
}
Esempio n. 10
0
static void
set_system_error_if_file_found (tr_error ** error,
                                int         code)
{
  if (code != ENOENT)
    set_system_error (error, code);
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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);
}
Esempio n. 16
0
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);
        }
    }
Esempio n. 17
0
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;
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
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;
}
Esempio n. 22
0
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;
}
Esempio n. 23
0
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;
}
Esempio n. 24
0
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;
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
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;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
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);
}
Esempio n. 29
0
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;
}
Esempio n. 30
0
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;
}