2008-07-22 23:28:28 +00:00
|
|
|
/*
|
2014-01-19 01:09:44 +00:00
|
|
|
* This file Copyright (C) 2009-2014 Mnemosyne LLC
|
2006-07-16 19:39:23 +00:00
|
|
|
*
|
2014-01-21 03:10:30 +00:00
|
|
|
* It may be used under the GNU GPL versions 2 or 3
|
2014-01-19 01:09:44 +00:00
|
|
|
* or any future license endorsed by Mnemosyne LLC.
|
2006-07-16 19:39:23 +00:00
|
|
|
*
|
2008-07-22 23:28:28 +00:00
|
|
|
*/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2021-09-24 23:31:02 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
2021-09-27 13:45:21 +00:00
|
|
|
#include <list>
|
|
|
|
#include <string>
|
2021-09-24 23:31:02 +00:00
|
|
|
|
|
|
|
#ifndef _XOPEN_SOURCE
|
2017-04-19 12:04:45 +00:00
|
|
|
#define _XOPEN_SOURCE 600 /* needed for recursive locks. */
|
2021-09-24 23:31:02 +00:00
|
|
|
#endif
|
2013-07-08 17:07:31 +00:00
|
|
|
#ifndef __USE_UNIX98
|
2017-04-19 12:04:45 +00:00
|
|
|
#define __USE_UNIX98 /* some older Linuxes need it spelt out for them */
|
2012-12-27 19:39:44 +00:00
|
|
|
#endif
|
|
|
|
|
2014-09-21 18:03:13 +00:00
|
|
|
#ifdef __HAIKU__
|
2017-04-19 12:04:45 +00:00
|
|
|
#include <limits.h> /* PATH_MAX */
|
2014-09-21 18:03:13 +00:00
|
|
|
#endif
|
2013-07-08 17:07:31 +00:00
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-21 07:40:57 +00:00
|
|
|
#include <process.h> /* _beginthreadex(), _endthreadex() */
|
2017-04-19 12:04:45 +00:00
|
|
|
#include <windows.h>
|
2017-04-21 07:40:57 +00:00
|
|
|
#include <shlobj.h> /* SHGetKnownFolderPath(), FOLDERID_... */
|
2007-07-30 15:27:52 +00:00
|
|
|
#else
|
2014-12-13 15:22:39 +00:00
|
|
|
#include <unistd.h> /* getuid() */
|
2017-04-19 12:04:45 +00:00
|
|
|
#ifdef BUILD_MAC_CLIENT
|
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#endif
|
|
|
|
#ifdef __HAIKU__
|
|
|
|
#include <FindDirectory.h>
|
|
|
|
#endif
|
|
|
|
#include <pthread.h>
|
2006-07-16 19:39:23 +00:00
|
|
|
#endif
|
2007-07-30 15:27:52 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#include "transmission.h"
|
2014-07-08 00:08:43 +00:00
|
|
|
#include "file.h"
|
2013-01-25 23:34:20 +00:00
|
|
|
#include "log.h"
|
2007-07-31 14:26:44 +00:00
|
|
|
#include "platform.h"
|
2014-07-08 00:08:43 +00:00
|
|
|
#include "session.h"
|
2017-06-08 07:24:12 +00:00
|
|
|
#include "tr-assert.h"
|
2014-09-21 18:03:13 +00:00
|
|
|
#include "utils.h"
|
2007-07-30 15:27:52 +00:00
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2007-07-30 15:27:52 +00:00
|
|
|
/***
|
|
|
|
**** THREADS
|
|
|
|
***/
|
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2021-10-06 14:26:07 +00:00
|
|
|
using tr_thread_id = DWORD;
|
2007-10-01 15:17:15 +00:00
|
|
|
#else
|
2021-10-06 14:26:07 +00:00
|
|
|
using tr_thread_id = pthread_t;
|
2007-10-01 15:17:15 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static tr_thread_id tr_getCurrentThread(void)
|
2007-10-01 15:17:15 +00:00
|
|
|
{
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
return GetCurrentThreadId();
|
2007-10-01 15:17:15 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
return pthread_self();
|
2007-10-01 15:17:15 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static bool tr_areThreadsEqual(tr_thread_id a, tr_thread_id b)
|
2007-10-01 15:17:15 +00:00
|
|
|
{
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
return a == b;
|
2007-10-01 15:17:15 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
return pthread_equal(a, b) != 0;
|
2007-10-01 15:17:15 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-01-19 19:37:00 +00:00
|
|
|
/** @brief portability wrapper around OS-dependent threads */
|
2007-09-20 16:32:01 +00:00
|
|
|
struct tr_thread
|
2007-07-30 15:27:52 +00:00
|
|
|
{
|
2021-08-15 09:41:48 +00:00
|
|
|
void (*func)(void*);
|
2017-04-19 12:04:45 +00:00
|
|
|
void* arg;
|
|
|
|
tr_thread_id thread;
|
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
HANDLE thread_handle;
|
2007-07-30 15:27:52 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
bool tr_amInThread(tr_thread const* t)
|
2007-10-01 15:17:15 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return tr_areThreadsEqual(tr_getCurrentThread(), t->thread);
|
2007-10-01 15:17:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
#define ThreadFuncReturnType unsigned WINAPI
|
2007-07-31 19:56:40 +00:00
|
|
|
#else
|
fix: gcc warnings in libtransmission/ and utils/ (#843)
* fix: __attribute__(__printf__) warnings
* fix: implicit fallthrough warning
* fixup! fix: implicit fallthrough warning
* fix: disable warnings for 3rd party code
Since we want to leave upstream code as-is
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: disable warnings for 3rd party code
* silence spurious alignment warning
Xrefs
Discussion: https://stackoverflow.com/a/35554349
Macro inspiration: https://pagure.io/SSSD/sssd/blob/90ac46f71068d131391492360a8553bdd005b5a7/f/src/util/util_safealign.h#_35
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: implicit fallthrough warning
* make uncrustify happy
* remove uncrustify-test.sh
that's probably off-topic for this PR
* fixup! fix: __attribute__(__printf__) warnings
* Update libtransmission/CMakeLists.txt
Co-Authored-By: ckerr <ckerr@github.com>
* fixup! silence spurious alignment warning
* use -w for DISABLE_WARNINGS in Clang
* refactor: fix libtransmission deprecation warnings
* fix: pthread_create's start_routine's return value
This was defined as `void` on non-Windows but should have been `void*`
* chore: uncrustify
* fix: add DISABLE_WARNINGS option for SunPro Studio
* fix "unused in lambda capture" warnings by clang++
* fix 'increases required alignment' warning
Caused from storing int16_t's in a char array.
* fix net.c 'increases required alignment' warning
The code passes in a `struct sockaddr_storage*` which is a padded struct
large enough for the necessary alignment. Unfortunately it was recast as
a `struct sockaddr*` which has less padding and a smaller alignment. The
warning occrred because of these differing alignments.
* make building quieter so warnings are more visible
* fixup! fix 'increases required alignment' warning
* Fix -Wcast-function-type warnings in GTK+ app code
https://gitlab.gnome.org/GNOME/gnome-terminal/issues/96 talks about both
the issue and its solution.
GCC 8's -Wcast-function-type, enabled by -Wextra, is problematic in glib
applications because it's idiomatic there to recast function signatures,
e.g. `g_slist_free(list, (GFunc)g_free, NULL);`.
Disabling the warning with pragmas causes "unrecognized pragma" warnings
on clang and older versions of gcc, and disabling the warning could miss
actual bugs. GCC defines `void (*)(void)` as a special case that matches
anything so we can silence warnings by double-casting through GCallback.
In the previous example, the warning is silenced by changing the code to
read `g_slist_free(list, (GFunc)(GCallback)g_free, NULL);`).
* fixup! fix "unused in lambda capture" warnings by clang++
* fixup! fix "unused in lambda capture" warnings by clang++
* fix two more libtransmission compiler warnings
* fix: in watchdir, use TR_ENABLE_ASSERTS not NDEBUG
2019-11-06 17:27:03 +00:00
|
|
|
#define ThreadFuncReturnType void*
|
2007-07-31 19:56:40 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static ThreadFuncReturnType ThreadFunc(void* _t)
|
2007-07-30 15:27:52 +00:00
|
|
|
{
|
2017-02-22 21:07:39 +00:00
|
|
|
#ifndef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
pthread_detach(pthread_self());
|
2017-02-22 21:07:39 +00:00
|
|
|
#endif
|
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* t = static_cast<tr_thread*>(_t);
|
2007-07-30 15:27:52 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
t->func(t->arg);
|
2007-07-31 19:56:40 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(t);
|
2017-02-22 21:07:39 +00:00
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
_endthreadex(0);
|
|
|
|
return 0;
|
fix: gcc warnings in libtransmission/ and utils/ (#843)
* fix: __attribute__(__printf__) warnings
* fix: implicit fallthrough warning
* fixup! fix: implicit fallthrough warning
* fix: disable warnings for 3rd party code
Since we want to leave upstream code as-is
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: disable warnings for 3rd party code
* silence spurious alignment warning
Xrefs
Discussion: https://stackoverflow.com/a/35554349
Macro inspiration: https://pagure.io/SSSD/sssd/blob/90ac46f71068d131391492360a8553bdd005b5a7/f/src/util/util_safealign.h#_35
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: implicit fallthrough warning
* make uncrustify happy
* remove uncrustify-test.sh
that's probably off-topic for this PR
* fixup! fix: __attribute__(__printf__) warnings
* Update libtransmission/CMakeLists.txt
Co-Authored-By: ckerr <ckerr@github.com>
* fixup! silence spurious alignment warning
* use -w for DISABLE_WARNINGS in Clang
* refactor: fix libtransmission deprecation warnings
* fix: pthread_create's start_routine's return value
This was defined as `void` on non-Windows but should have been `void*`
* chore: uncrustify
* fix: add DISABLE_WARNINGS option for SunPro Studio
* fix "unused in lambda capture" warnings by clang++
* fix 'increases required alignment' warning
Caused from storing int16_t's in a char array.
* fix net.c 'increases required alignment' warning
The code passes in a `struct sockaddr_storage*` which is a padded struct
large enough for the necessary alignment. Unfortunately it was recast as
a `struct sockaddr*` which has less padding and a smaller alignment. The
warning occrred because of these differing alignments.
* make building quieter so warnings are more visible
* fixup! fix 'increases required alignment' warning
* Fix -Wcast-function-type warnings in GTK+ app code
https://gitlab.gnome.org/GNOME/gnome-terminal/issues/96 talks about both
the issue and its solution.
GCC 8's -Wcast-function-type, enabled by -Wextra, is problematic in glib
applications because it's idiomatic there to recast function signatures,
e.g. `g_slist_free(list, (GFunc)g_free, NULL);`.
Disabling the warning with pragmas causes "unrecognized pragma" warnings
on clang and older versions of gcc, and disabling the warning could miss
actual bugs. GCC defines `void (*)(void)` as a special case that matches
anything so we can silence warnings by double-casting through GCallback.
In the previous example, the warning is silenced by changing the code to
read `g_slist_free(list, (GFunc)(GCallback)g_free, NULL);`).
* fixup! fix "unused in lambda capture" warnings by clang++
* fixup! fix "unused in lambda capture" warnings by clang++
* fix two more libtransmission compiler warnings
* fix: in watchdir, use TR_ENABLE_ASSERTS not NDEBUG
2019-11-06 17:27:03 +00:00
|
|
|
#else
|
2021-09-15 00:18:09 +00:00
|
|
|
return nullptr;
|
2007-07-31 19:56:40 +00:00
|
|
|
#endif
|
2007-07-30 15:27:52 +00:00
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
tr_thread* tr_threadNew(void (*func)(void*), void* arg)
|
2007-07-30 15:27:52 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* t = static_cast<tr_thread*>(tr_new0(tr_thread, 1));
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
t->func = func;
|
|
|
|
t->arg = arg;
|
2007-07-30 15:27:52 +00:00
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
unsigned int id;
|
2021-09-15 00:18:09 +00:00
|
|
|
t->thread_handle = (HANDLE)_beginthreadex(nullptr, 0, &ThreadFunc, t, 0, &id);
|
2017-04-19 12:04:45 +00:00
|
|
|
t->thread = (DWORD)id;
|
|
|
|
}
|
|
|
|
|
2007-07-30 15:27:52 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
pthread_create(&t->thread, nullptr, (void* (*)(void*))ThreadFunc, t);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2007-07-30 15:27:52 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return t;
|
2007-07-30 15:27:52 +00:00
|
|
|
}
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2007-07-30 15:27:52 +00:00
|
|
|
/***
|
|
|
|
**** PATHS
|
|
|
|
***/
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifndef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
#include <pwd.h>
|
2007-08-02 19:43:29 +00:00
|
|
|
#endif
|
2006-10-13 06:29:26 +00:00
|
|
|
|
2014-09-21 18:03:13 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static char* win32_get_known_folder_ex(REFKNOWNFOLDERID folder_id, DWORD flags)
|
2014-09-21 18:03:13 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
char* ret = nullptr;
|
2017-04-19 12:04:45 +00:00
|
|
|
PWSTR path;
|
2015-04-10 22:15:41 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (SHGetKnownFolderPath(folder_id, flags | KF_FLAG_DONT_UNEXPAND, nullptr, &path) == S_OK)
|
2015-04-10 22:15:41 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
ret = tr_win32_native_to_utf8(path, -1);
|
|
|
|
CoTaskMemFree(path);
|
2015-04-10 22:15:41 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2014-09-21 18:03:13 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static char* win32_get_known_folder(REFKNOWNFOLDERID folder_id)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return win32_get_known_folder_ex(folder_id, KF_FLAG_DONT_VERIFY);
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2014-09-21 18:03:13 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static char const* getHomeDir(void)
|
2006-10-13 06:29:26 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
static char const* home = nullptr;
|
2006-10-13 06:29:26 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (home == nullptr)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
home = tr_env_get_string("HOME", nullptr);
|
2006-10-13 06:29:26 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (home == nullptr)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2014-07-04 00:00:07 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
home = win32_get_known_folder(FOLDERID_Profile);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2007-08-02 19:43:29 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2020-11-05 22:46:21 +00:00
|
|
|
struct passwd pwent;
|
2021-09-15 00:18:09 +00:00
|
|
|
struct passwd* pw = nullptr;
|
2020-11-05 22:46:21 +00:00
|
|
|
char buf[4096];
|
|
|
|
getpwuid_r(getuid(), &pwent, buf, sizeof buf, &pw);
|
2021-09-15 00:18:09 +00:00
|
|
|
if (pw != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
home = tr_strdup(pw->pw_dir);
|
|
|
|
}
|
|
|
|
|
2007-08-02 19:43:29 +00:00
|
|
|
#endif
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (home == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
home = tr_strdup("");
|
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
2008-04-05 20:12:11 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return home;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
#if defined(__APPLE__) || defined(_WIN32)
|
|
|
|
#define RESUME_SUBDIR "Resume"
|
|
|
|
#define TORRENT_SUBDIR "Torrents"
|
2008-10-14 03:03:29 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
#define RESUME_SUBDIR "resume"
|
|
|
|
#define TORRENT_SUBDIR "torrents"
|
2008-10-14 03:03:29 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
void tr_setConfigDir(tr_session* session, char const* configDir)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
session->configDir = tr_strdup(configDir);
|
2008-04-05 20:12:11 +00:00
|
|
|
|
2021-10-23 15:43:15 +00:00
|
|
|
char* path = tr_buildPath(configDir, RESUME_SUBDIR, nullptr);
|
2021-09-15 00:18:09 +00:00
|
|
|
tr_sys_dir_create(path, TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
session->resumeDir = path;
|
2008-04-05 20:12:11 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
path = tr_buildPath(configDir, TORRENT_SUBDIR, nullptr);
|
|
|
|
tr_sys_dir_create(path, TR_SYS_DIR_CREATE_PARENTS, 0777, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
session->torrentDir = path;
|
2008-04-05 20:12:11 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* tr_sessionGetConfigDir(tr_session const* session)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return session->configDir;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* tr_getTorrentDir(tr_session const* session)
|
2006-07-16 19:39:23 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return session->torrentDir;
|
2008-04-05 20:12:11 +00:00
|
|
|
}
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* tr_getResumeDir(tr_session const* session)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
return session->resumeDir;
|
2008-04-05 20:12:11 +00:00
|
|
|
}
|
2007-06-18 19:39:52 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* tr_getDefaultConfigDir(char const* appname)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
static char const* s = nullptr;
|
2006-07-16 19:39:23 +00:00
|
|
|
|
2019-07-13 08:52:44 +00:00
|
|
|
if (tr_str_is_empty(appname))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
appname = "Transmission";
|
|
|
|
}
|
2008-12-13 23:17:36 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (s == nullptr)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_env_get_string("TRANSMISSION_HOME", nullptr);
|
2014-09-21 18:05:14 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (s == nullptr)
|
2008-04-05 20:12:11 +00:00
|
|
|
{
|
2014-07-03 19:20:12 +00:00
|
|
|
#ifdef __APPLE__
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(getHomeDir(), "Library", "Application Support", appname, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
char* appdata = win32_get_known_folder(FOLDERID_LocalAppData);
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(appdata, appname, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(appdata);
|
|
|
|
|
|
|
|
#elif defined(__HAIKU__)
|
|
|
|
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
find_directory(B_USER_SETTINGS_DIRECTORY, -1, true, buf, sizeof(buf));
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(buf, appname, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#else
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
char* const xdg_config_home = tr_env_get_string("XDG_CONFIG_HOME", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (xdg_config_home != nullptr)
|
2014-09-21 18:05:14 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(xdg_config_home, appname, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(xdg_config_home);
|
2014-09-21 18:05:14 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2014-09-21 18:05:14 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(getHomeDir(), ".config", appname, nullptr);
|
2014-09-21 18:05:14 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2006-07-16 19:39:23 +00:00
|
|
|
#endif
|
2008-04-05 20:12:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return s;
|
2006-07-16 19:39:23 +00:00
|
|
|
}
|
2008-02-28 19:06:23 +00:00
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* tr_getDefaultDownloadDir(void)
|
2008-11-15 17:39:54 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
static char const* user_dir = nullptr;
|
2009-04-05 13:33:32 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (user_dir == nullptr)
|
2009-04-05 13:41:38 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
/* figure out where to look for user-dirs.dirs */
|
2021-10-23 15:43:15 +00:00
|
|
|
char* const config_home = tr_env_get_string("XDG_CONFIG_HOME", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
auto const config_file = !tr_str_is_empty(config_home) ? tr_strvPath(config_home, "user-dirs.dirs") :
|
|
|
|
tr_strvPath(getHomeDir(), ".config", "user-dirs.dirs");
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
tr_free(config_home);
|
|
|
|
|
|
|
|
/* read in user-dirs.dirs and look for the download dir entry */
|
2021-10-23 15:43:15 +00:00
|
|
|
size_t content_len = 0;
|
2021-11-18 00:17:09 +00:00
|
|
|
auto* const content = (char*)tr_loadFile(config_file.c_str(), &content_len, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (content != nullptr && content_len > 0)
|
2009-04-05 13:33:32 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
char const* key = "XDG_DOWNLOAD_DIR=\"";
|
2017-04-19 12:04:45 +00:00
|
|
|
char* line = strstr(content, key);
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (line != nullptr)
|
2009-04-05 13:33:32 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
char* value = line + strlen(key);
|
|
|
|
char* end = strchr(value, '"');
|
2009-04-05 13:33:32 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (end != nullptr)
|
2009-04-05 13:33:32 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
if (strncmp(value, "$HOME/", 6) == 0)
|
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
user_dir = tr_buildPath(getHomeDir(), value + 6, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
else if (strcmp(value, "$HOME") == 0)
|
|
|
|
{
|
|
|
|
user_dir = tr_strdup(getHomeDir());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
user_dir = tr_strdup(value);
|
|
|
|
}
|
2009-04-05 13:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-10 22:15:41 +00:00
|
|
|
#ifdef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (user_dir == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
user_dir = win32_get_known_folder(FOLDERID_Downloads);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2015-04-10 22:15:41 +00:00
|
|
|
#endif
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (user_dir == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2009-07-09 18:18:14 +00:00
|
|
|
#ifdef __HAIKU__
|
2021-09-15 00:18:09 +00:00
|
|
|
user_dir = tr_buildPath(getHomeDir(), "Desktop", nullptr);
|
2009-07-09 18:18:14 +00:00
|
|
|
#else
|
2021-09-15 00:18:09 +00:00
|
|
|
user_dir = tr_buildPath(getHomeDir(), "Downloads", nullptr);
|
2009-07-09 18:18:14 +00:00
|
|
|
#endif
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2009-04-05 13:33:32 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(content);
|
2009-04-05 13:41:38 +00:00
|
|
|
}
|
2009-04-05 13:33:32 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return user_dir;
|
2008-11-15 17:39:54 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 04:07:14 +00:00
|
|
|
/***
|
|
|
|
****
|
|
|
|
***/
|
|
|
|
|
2021-12-16 05:16:40 +00:00
|
|
|
static bool isWebClientDir(std::string_view path)
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-11-13 00:10:04 +00:00
|
|
|
auto tmp = tr_strvPath(path, "index.html");
|
|
|
|
bool const ret = tr_sys_path_exists(tmp.c_str(), nullptr);
|
|
|
|
tr_logAddInfo(_("Searching for web interface file \"%s\""), tmp.c_str());
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return ret;
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
|
|
|
|
2021-10-10 16:52:26 +00:00
|
|
|
char const* tr_getWebClientDir([[maybe_unused]] tr_session const* session)
|
2008-07-11 04:07:14 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
static char const* s = nullptr;
|
2008-07-11 04:07:14 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (s == nullptr)
|
2008-07-11 04:07:14 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_env_get_string("CLUTCH_HOME", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (s == nullptr)
|
2008-07-11 04:07:14 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_env_get_string("TRANSMISSION_WEB_HOME", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (s == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2013-10-27 19:31:36 +00:00
|
|
|
#ifdef BUILD_MAC_CLIENT /* on Mac, look in the Application Support folder first, then in the app bundle. */
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* Look in the Application Support folder */
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(tr_sessionGetConfigDir(session), "public_html", nullptr);
|
2009-08-10 20:04:08 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (!isWebClientDir(s))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
tr_free(const_cast<char*>(s));
|
2009-08-10 20:04:08 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
CFURLRef appURL = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
|
|
|
CFStringRef appRef = CFURLCopyFileSystemPath(appURL, kCFURLPOSIXPathStyle);
|
2017-04-20 16:02:19 +00:00
|
|
|
CFIndex const appStringLength = CFStringGetMaximumSizeOfFileSystemRepresentation(appRef);
|
2011-08-15 00:10:06 +00:00
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
char* appString = static_cast<char*>(tr_malloc(appStringLength));
|
2017-04-20 16:02:19 +00:00
|
|
|
bool const success = CFStringGetFileSystemRepresentation(appRef, appString, appStringLength);
|
2017-06-08 07:24:12 +00:00
|
|
|
TR_ASSERT(success);
|
2010-03-24 23:41:08 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
CFRelease(appURL);
|
|
|
|
CFRelease(appRef);
|
2010-03-24 23:41:08 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* Fallback to the app bundle */
|
2021-09-15 00:18:09 +00:00
|
|
|
s = tr_buildPath(appString, "Contents", "Resources", "public_html", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
if (!isWebClientDir(s))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
tr_free(const_cast<char*>(s));
|
2021-09-15 00:18:09 +00:00
|
|
|
s = nullptr;
|
2009-02-28 21:45:16 +00:00
|
|
|
}
|
2010-03-24 23:41:08 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(appString);
|
2009-02-28 21:45:16 +00:00
|
|
|
}
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
#elif defined(_WIN32)
|
2008-09-23 19:11:04 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* Generally, Web interface should be stored in a Web subdir of
|
|
|
|
* calling executable dir. */
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
static KNOWNFOLDERID const* const known_folder_ids[] = {
|
2017-04-19 12:04:45 +00:00
|
|
|
&FOLDERID_LocalAppData,
|
|
|
|
&FOLDERID_RoamingAppData,
|
2021-08-15 09:41:48 +00:00
|
|
|
&FOLDERID_ProgramData,
|
2015-04-10 22:15:41 +00:00
|
|
|
};
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
for (size_t i = 0; s == nullptr && i < TR_N_ELEMENTS(known_folder_ids); ++i)
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
char* dir = win32_get_known_folder(*known_folder_ids[i]);
|
2021-09-15 00:18:09 +00:00
|
|
|
char* path = tr_buildPath(dir, "Transmission", "Web", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(dir);
|
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
if (isWebClientDir(path))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
s = path;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tr_free(path);
|
2008-10-19 17:43:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (s == nullptr) /* check calling module place */
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2014-09-21 18:03:13 +00:00
|
|
|
wchar_t wide_module_path[MAX_PATH];
|
2021-09-15 00:18:09 +00:00
|
|
|
GetModuleFileNameW(nullptr, wide_module_path, TR_N_ELEMENTS(wide_module_path));
|
2021-11-16 00:50:14 +00:00
|
|
|
char* module_path = tr_win32_native_to_utf8(wide_module_path, -1);
|
|
|
|
char* dir = tr_sys_path_dirname(module_path, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(module_path);
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (dir != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
char* path = tr_buildPath(dir, "Web", nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(dir);
|
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
if (isWebClientDir(path))
|
|
|
|
{
|
|
|
|
s = path;
|
|
|
|
}
|
|
|
|
else
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
tr_free(path);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
}
|
2008-10-19 17:43:04 +00:00
|
|
|
}
|
|
|
|
|
2009-03-01 14:01:49 +00:00
|
|
|
#else /* everyone else, follow the XDG spec */
|
2008-10-19 17:43:04 +00:00
|
|
|
|
2021-09-27 13:45:21 +00:00
|
|
|
auto candidates = std::list<std::string>{};
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
/* XDG_DATA_HOME should be the first in the list of candidates */
|
2021-09-27 13:45:21 +00:00
|
|
|
char* tmp = tr_env_get_string("XDG_DATA_HOME", nullptr);
|
2019-07-13 08:52:44 +00:00
|
|
|
if (!tr_str_is_empty(tmp))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-09-27 13:45:21 +00:00
|
|
|
candidates.emplace_back(tmp);
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2008-12-14 01:19:50 +00:00
|
|
|
{
|
2021-11-13 00:10:04 +00:00
|
|
|
candidates.emplace_back(tr_strvPath(getHomeDir(), ".local"sv, "share"sv));
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
2021-09-27 13:45:21 +00:00
|
|
|
tr_free(tmp);
|
2008-07-11 04:07:14 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* XDG_DATA_DIRS are the backup directories */
|
|
|
|
{
|
2020-09-10 23:50:46 +00:00
|
|
|
char const* const pkg = PACKAGE_DATA_DIR;
|
2021-12-16 05:16:40 +00:00
|
|
|
auto* xdg = tr_env_get_string("XDG_DATA_DIRS", "");
|
|
|
|
auto const buf = tr_strvJoin(pkg, ":", xdg, ":/usr/local/share:/usr/share");
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(xdg);
|
|
|
|
|
2021-12-16 05:16:40 +00:00
|
|
|
auto sv = std::string_view{ buf };
|
|
|
|
auto token = std::string_view{};
|
|
|
|
while (tr_strvSep(&sv, &token, ':'))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-12-16 05:16:40 +00:00
|
|
|
token = tr_strvStrip(token);
|
|
|
|
if (!std::empty(token))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-12-16 05:16:40 +00:00
|
|
|
candidates.emplace_back(token);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
/* walk through the candidates & look for a match */
|
2021-09-27 13:45:21 +00:00
|
|
|
for (auto const& dir : candidates)
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-12-16 05:16:40 +00:00
|
|
|
auto const path = tr_strvPath(dir, "transmission"sv, "public_html"sv);
|
|
|
|
if (isWebClientDir(path))
|
2012-12-05 17:29:46 +00:00
|
|
|
{
|
2021-12-16 05:16:40 +00:00
|
|
|
s = tr_strvDup(path);
|
2017-04-19 12:04:45 +00:00
|
|
|
break;
|
2008-10-14 03:03:29 +00:00
|
|
|
}
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
return s;
|
2008-07-11 04:07:14 +00:00
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
std::string tr_getSessionIdDir()
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
return std::string{ "/tmp"sv };
|
2016-09-21 20:56:03 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
2021-09-12 17:41:49 +00:00
|
|
|
char* program_data_dir = win32_get_known_folder_ex(FOLDERID_ProgramData, KF_FLAG_CREATE);
|
2021-11-13 00:10:04 +00:00
|
|
|
auto const result = tr_strvPath(program_data_dir, "Transmission");
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_free(program_data_dir);
|
2021-11-13 00:10:04 +00:00
|
|
|
tr_sys_dir_create(result.c_str(), 0, 0, nullptr);
|
2017-04-19 12:04:45 +00:00
|
|
|
return result;
|
2016-09-21 20:56:03 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|