Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
file_location.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2014, 2016-2017 Tobias Ellinghaus.
4 Copyright (C) 2011 Henrik Andersson.
5 Copyright (C) 2011 johannes hanika.
6 Copyright (C) 2011 Kanstantsin Shautsou.
7 Copyright (C) 2011 Moritz Lipp.
8 Copyright (C) 2012 Christian Tellefsen.
9 Copyright (C) 2012 Jean-Sébastien Pédron.
10 Copyright (C) 2012 Jérémy Rosen.
11 Copyright (C) 2012 Richard Wonka.
12 Copyright (C) 2013 Simon Spannagel.
13 Copyright (C) 2014, 2016 Roman Lebedev.
14 Copyright (C) 2016 Pedro Côrte-Real.
15 Copyright (C) 2016-2017 Peter Budai.
16 Copyright (C) 2018 parafin.
17 Copyright (C) 2019 Philippe Weyland.
18 Copyright (C) 2020-2021 David-Tillmann Schaefer.
19 Copyright (C) 2020-2021 Pascal Obry.
20 Copyright (C) 2022, 2025-2026 Aurélien PIERRE.
21 Copyright (C) 2022 Martin Bařinka.
22 Copyright (C) 2023 Alynx Zhou.
23
24 darktable is free software: you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation, either version 3 of the License, or
27 (at your option) any later version.
28
29 darktable is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with darktable. If not, see <http://www.gnu.org/licenses/>.
36*/
37
38/* getpwnam_r availability check */
39#if defined __APPLE__ || defined _POSIX_C_SOURCE >= 1 || defined _XOPEN_SOURCE || defined _BSD_SOURCE \
40 || defined _SVID_SOURCE || defined _POSIX_SOURCE || defined __DragonFly__ || defined __FreeBSD__ \
41 || defined __NetBSD__ || defined __OpenBSD__
42#include "config.h"
43
44#include <pwd.h>
45#include <sys/types.h>
46#define HAVE_GETPWNAM_R 1
47#endif
48
49#ifdef HAVE_CONFIG_H
50#include <config.h>
51#endif
52
53#ifdef __APPLE__
54#include "osx/osx.h"
55#endif
56
57#include "common/grealpath.h"
58#include "darktable.h"
59#include "file_location.h"
60#include "whereami.h"
61
62void dt_loc_init(const char *datadir, const char *moduledir, const char *localedir, const char *configdir, const char *cachedir, const char *tmpdir, const char *kerneldir)
63{
64 // Assemble pathes
65 char* application_directory = NULL;
66 int dirname_length;
67 // calling wai_getExecutablePath twice as recommended in the docs:
68 // the first call retrieves the length of the path
69 int length = wai_getExecutablePath(NULL, 0, &dirname_length);
70 if (length > 0)
71 {
72 application_directory = (char*)malloc(length + 1);
73 // the second call retrieves the path including the executable
74 wai_getExecutablePath(application_directory, length, &dirname_length);
75 // strip of the executable name from the path to retrieve the path alone
76 application_directory[dirname_length] = '\0';
77 }
78 dt_print(DT_DEBUG_DEV, "application_directory: %s\n", application_directory);
79
80 // set up absolute pathes based on their relative value
81 dt_loc_init_datadir(application_directory, datadir);
82 dt_loc_init_moduledir(application_directory, moduledir);
83 dt_loc_init_localedir(application_directory, localedir);
84 dt_loc_init_kerneldir(application_directory, kerneldir);
87 dt_loc_init_sharedir(application_directory);
88 dt_loc_init_tmp_dir(tmpdir);
89 dt_free(application_directory);
90}
91
92gchar *dt_loc_get_home_dir(const gchar *user)
93{
94 if(IS_NULL_PTR(user) || g_strcmp0(user, g_get_user_name()) == 0)
95 {
96 const char *home_dir = g_getenv("HOME");
97 return g_strdup((!IS_NULL_PTR(home_dir)) ? home_dir : g_get_home_dir());
98 }
99
100#if defined HAVE_GETPWNAM_R
101 /* if the given username is not the same as the current one, we try
102 * to retrieve the pw dir from the password file entry */
103 struct passwd pwd;
104 struct passwd *result;
105#ifdef _SC_GETPW_R_SIZE_MAX
106 int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
107 if(bufsize < 0)
108 {
109 bufsize = 4096;
110 }
111#else
112 int bufsize = 4096;
113#endif
114
115 gchar *buffer = g_malloc0_n(bufsize, sizeof(gchar));
116 if(IS_NULL_PTR(buffer))
117 {
118 return NULL;
119 }
120
121 getpwnam_r(user, &pwd, buffer, bufsize, &result);
122 if(IS_NULL_PTR(result))
123 {
124 dt_free(buffer);
125 return NULL;
126 }
127
128 gchar *dir = g_strdup(pwd.pw_dir);
129 dt_free(buffer);
130
131 return dir;
132#else
133 return NULL;
134#endif
135}
136
137gchar *dt_loc_init_generic(const char *absolute_value, const char *application_directory, const char *default_value)
138{
139 gchar *result = NULL;
140 gchar *path = NULL;
141
142 if(absolute_value)
143 {
144 // the only adjustment the absolute path needs is transforming the possible tilde '~' to an absolute path
145 path = dt_util_fix_path(absolute_value);
146 }
147 else
148 {
149 // the default_value could be absolute or relative. we decide upon presence of the application_directory.
150 if(application_directory)
151 {
152 // default_value is relative.
153 // combine basename (application_directory) and relative path (default_value).
154 gchar complete_path[PATH_MAX] = { 0 };
155#if defined(__APPLE__)
156 char *bundle_path = dt_osx_get_bundle_res_path();
157 if(bundle_path)
158 {
160
161 // on a mac inside the bundle the executables are in <bundleroot>/Contents/MacOS/
162 // all other directories are a subdirectory of <bundleroot>/Contents/Resources:
163 // <bundleroot>/Contents/Resources/etc
164 // <bundleroot>/Contents/Resources/lib
165 // <bundleroot>/Contents/Resources/share
166 // so the relative path from the binary directory to the other directories differs to the non-bundle version by
167 // ../etc -> ../Resources/etc,
168 // ../lib -> ../Resources/lib,
169 // ../share -> ../Resources/share,
170 // So we have to modify the relative default value
171
172 // +2: removes the two dots '..'
173 g_snprintf(complete_path, sizeof(complete_path), "%s/../Resources%s", application_directory, default_value + 2);
174 }
175 else
176 {
178 g_snprintf(complete_path, sizeof(complete_path), "%s/%s", application_directory, default_value);
179 }
180#else
181 g_snprintf(complete_path, sizeof(complete_path), "%s/%s", application_directory, default_value);
182#endif
183 path = g_strdup(complete_path);
184 }
185 else
186 {
187 // default_value is absolute
188 path = g_strdup(default_value);
189 }
190 }
191
192 // create file if it does not exist
193 if(g_file_test(path, G_FILE_TEST_EXISTS) == FALSE) g_mkdir_with_parents(path, 0700);
194
195 // removes '.', '..', and extra '/' characters.
196 result = g_realpath(path);
197
198 dt_free(path);
199 return result;
200}
201
202void dt_loc_init_user_config_dir(const char *configdir)
203{
204 char *default_config_dir = g_build_filename(g_get_user_config_dir(), "ansel", NULL);
205 darktable.configdir = dt_loc_init_generic(configdir, NULL, default_config_dir);
206 dt_check_opendir("ansel.configdir", darktable.configdir);
207 dt_free(default_config_dir);
208}
209
210void dt_loc_init_tmp_dir(const char *tmpdir)
211{
212 darktable.tmpdir = dt_loc_init_generic(tmpdir, NULL, g_get_tmp_dir());
213 dt_check_opendir("ansel.tmpdir", darktable.tmpdir);
214}
215
216void dt_loc_init_user_cache_dir(const char *cachedir)
217{
218 char *default_cache_dir = g_build_filename(g_get_user_cache_dir(), "ansel", NULL);
219 darktable.cachedir = dt_loc_init_generic(cachedir, NULL, default_cache_dir);
220 dt_check_opendir("ansel.cachedir", darktable.cachedir);
221 dt_free(default_cache_dir);
222}
223
224void dt_loc_init_moduledir(const char* application_directory, const char *moduledir)
225{
226 darktable.moduledir = dt_loc_init_generic(moduledir, application_directory, DARKTABLE_MODULEDIR);
227 dt_check_opendir("ansel.moduledir", darktable.moduledir);
228}
229
230void dt_check_opendir(const char* context, const char* directory)
231{
232 if (IS_NULL_PTR(directory))
233 {
234 fprintf(stderr, "directory for %s has not been set.\n", context);
235 exit(EXIT_FAILURE);
236 }
237
238#if _WIN32
239 wchar_t *wdirectory = g_utf8_to_utf16 (directory, -1, NULL, NULL, NULL);
240 DWORD attribs = GetFileAttributesW(wdirectory);
241 dt_free(wdirectory);
242 if (attribs != INVALID_FILE_ATTRIBUTES &&
243 (attribs & FILE_ATTRIBUTE_DIRECTORY))
244 {
245 dt_print(DT_DEBUG_DEV, "%s: %s\n", context, directory);
246 }
247 else
248 {
249 fprintf(stderr, "%s: directory '%s' fails to open.'\n", context, directory);
250 exit(EXIT_FAILURE);
251 }
252#else
253 DIR* dir = opendir(directory);
254 if (dir)
255 {
256 dt_print(DT_DEBUG_DEV, "%s: %s\n", context, directory);
257 closedir(dir);
258 }
259 else
260 {
261 fprintf(stderr, "opendir '%s' fails with: '%s'\n", directory, strerror(errno));
262 exit(EXIT_FAILURE);
263 }
264#endif
265}
266
267void dt_loc_init_localedir(const char* application_directory, const char *localedir)
268{
269 darktable.localedir = dt_loc_init_generic(localedir, application_directory, DARKTABLE_LOCALEDIR);
270 dt_check_opendir("ansel.localedir", darktable.localedir);
271}
272
273void dt_loc_init_datadir(const char* application_directory, const char *datadir)
274{
275 darktable.datadir = dt_loc_init_generic(datadir, application_directory, DARKTABLE_DATADIR);
276 dt_check_opendir("ansel.datadir", darktable.datadir);
277}
278
279void dt_loc_init_sharedir(const char* application_directory)
280{
281 darktable.sharedir = dt_loc_init_generic(NULL, application_directory, DARKTABLE_SHAREDIR);
282 dt_check_opendir("ansel.sharedir", darktable.sharedir);
283}
284
285void dt_loc_init_kerneldir(const char* application_directory, const char *kerneldir)
286{
287#ifdef HAVE_OPENCL
288 darktable.kerneldir = dt_loc_init_generic(kerneldir, application_directory, DARKTABLE_KERNELSDIR);
289 dt_check_opendir("ansel.kerneldir", darktable.kerneldir);
290#else
291 darktable.kerneldir = NULL;
292#endif
293}
294
295void dt_loc_get_kerneldir(char *kerneldir, size_t bufsize)
296{
297 g_strlcpy(kerneldir, darktable.kerneldir, bufsize);
298}
299
300void dt_loc_get_moduledir(char *moduledir, size_t bufsize)
301{
302 g_strlcpy(moduledir, darktable.moduledir, bufsize);
303}
304
305void dt_loc_get_localedir(char *localedir, size_t bufsize)
306{
307 g_strlcpy(localedir, darktable.localedir, bufsize);
308}
309
310void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
311{
312 g_strlcpy(configdir, darktable.configdir, bufsize);
313}
314void dt_loc_get_user_cache_dir(char *cachedir, size_t bufsize)
315{
316 g_strlcpy(cachedir, darktable.cachedir, bufsize);
317}
318void dt_loc_get_tmp_dir(char *tmpdir, size_t bufsize)
319{
320 g_strlcpy(tmpdir, darktable.tmpdir, bufsize);
321}
322void dt_loc_get_datadir(char *datadir, size_t bufsize)
323{
324 g_strlcpy(datadir, darktable.datadir, bufsize);
325}
326void dt_loc_get_sharedir(char *sharedir, size_t bufsize)
327{
328 g_strlcpy(sharedir, darktable.sharedir, bufsize);
329}
330// clang-format off
331// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
332// vim: shiftwidth=2 expandtab tabstop=2 cindent
333// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
334// clang-format on
#define FALSE
Definition ashift_lsd.c:158
#define DARKTABLE_LOCALEDIR
#define DARKTABLE_KERNELSDIR
#define DARKTABLE_DATADIR
#define DARKTABLE_SHAREDIR
#define DARKTABLE_MODULEDIR
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_DEV
Definition darktable.h:717
#define dt_free(ptr)
Definition darktable.h:456
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
void dt_loc_get_sharedir(char *sharedir, size_t bufsize)
void dt_loc_init_tmp_dir(const char *tmpdir)
void dt_loc_init_moduledir(const char *application_directory, const char *moduledir)
void dt_loc_get_user_cache_dir(char *cachedir, size_t bufsize)
void dt_loc_get_tmp_dir(char *tmpdir, size_t bufsize)
void dt_loc_get_kerneldir(char *kerneldir, size_t bufsize)
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_localedir(char *localedir, size_t bufsize)
gchar * dt_loc_init_generic(const char *absolute_value, const char *application_directory, const char *default_value)
void dt_loc_init_datadir(const char *application_directory, const char *datadir)
void dt_loc_init_user_cache_dir(const char *cachedir)
void dt_loc_init(const char *datadir, const char *moduledir, const char *localedir, const char *configdir, const char *cachedir, const char *tmpdir, const char *kerneldir)
void dt_loc_get_moduledir(char *moduledir, size_t bufsize)
void dt_loc_init_kerneldir(const char *application_directory, const char *kerneldir)
void dt_loc_init_localedir(const char *application_directory, const char *localedir)
void dt_loc_init_sharedir(const char *application_directory)
void dt_loc_init_user_config_dir(const char *configdir)
gchar * dt_loc_get_home_dir(const gchar *user)
void dt_check_opendir(const char *context, const char *directory)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
static gchar * g_realpath(const char *path)
Definition grealpath.h:46
char * dt_osx_get_bundle_res_path()
Definition osx.mm:138
char * tmpdir
Definition darktable.h:823
char * cachedir
Definition darktable.h:825
char * sharedir
Definition darktable.h:820
char * moduledir
Definition darktable.h:821
char * configdir
Definition darktable.h:824
char * datadir
Definition darktable.h:819
char * localedir
Definition darktable.h:822
char * kerneldir
Definition darktable.h:826
gchar * dt_util_fix_path(const gchar *path)
Definition utility.c:222