b1b32e75f5966874c2c0de204e2d2d144c0a0be7
[blender-staging.git] / source / blender / blenkernel / intern / appdir.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  */
19
20 /** \file blender/blenkernel/intern/appdir.c
21  *  \ingroup bke
22  *
23  * Access to application level directories.
24  */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #include "BLI_utildefines.h"
31 #include "BLI_string.h"
32 #include "BLI_fileops.h"
33 #include "BLI_path_util.h"
34
35 #include "BKE_appdir.h"  /* own include */
36
37 #include "GHOST_Path-api.h"
38
39 #include "../blenkernel/BKE_blender.h"  /* BLENDER_VERSION, bad level include (no function call) */
40
41 #include "MEM_guardedalloc.h"
42
43 #ifdef WIN32
44 #  include "utf_winfunc.h"
45 #  include "utfconv.h"
46 #  include <io.h>
47 #  ifdef _WIN32_IE
48 #    undef _WIN32_IE
49 #  endif
50 #  define _WIN32_IE 0x0501
51 #  include <windows.h>
52 #  include <shlobj.h>
53 #  include "BLI_winstuff.h"
54 #else /* non windows */
55 #  ifdef WITH_BINRELOC
56 #    include "binreloc.h"
57 #  endif
58 #  include <unistd.h>  /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
59 #endif /* WIN32 */
60
61 /* local */
62 static char bprogname[FILE_MAX];    /* full path to program executable */
63 static char bprogdir[FILE_MAX];     /* full path to directory in which executable is located */
64 static char btempdir_base[FILE_MAX];          /* persistent temporary directory */
65 static char btempdir_session[FILE_MAX] = "";  /* volatile temporary directory */
66
67 /* This is now only used to really get the user's default document folder */
68 /* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used
69  * as default location to save documents */
70 const char *BKE_appdir_folder_default(void)
71 {
72 #ifndef WIN32
73         const char * const xdg_documents_dir = getenv("XDG_DOCUMENTS_DIR");
74
75         if (xdg_documents_dir)
76                 return xdg_documents_dir;
77
78         return getenv("HOME");
79 #else /* Windows */
80         static char documentfolder[MAXPATHLEN];
81         HRESULT hResult;
82
83         /* Check for %HOME% env var */
84         if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) {
85                 if (BLI_is_dir(documentfolder)) return documentfolder;
86         }
87                                 
88         /* add user profile support for WIN 2K / NT.
89          * This is %APPDATA%, which translates to either
90          * %USERPROFILE%\Application Data or since Vista
91          * to %USERPROFILE%\AppData\Roaming
92          */
93         hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder);
94                 
95         if (hResult == S_OK) {
96                 if (BLI_is_dir(documentfolder)) return documentfolder;
97         }
98                 
99         return NULL;
100 #endif /* WIN32 */
101 }
102
103
104 // #define PATH_DEBUG
105
106 /* returns a formatted representation of the specified version number. Non-reentrant! */
107 static char *blender_version_decimal(const int ver)
108 {
109         static char version_str[5];
110         sprintf(version_str, "%d.%02d", ver / 100, ver % 100);
111         return version_str;
112 }
113
114 /**
115  * Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
116  * returning true if result points to a directory.
117  */
118 static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
119 {
120         char tmppath[FILE_MAX];
121         
122         if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
123         else BLI_strncpy(tmppath, path_base, sizeof(tmppath));
124
125         /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */
126         if (folder_name)
127                 BLI_make_file_string("/", targetpath, tmppath, folder_name);
128         else
129                 BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
130         /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
131          * if folder_name is specified but not otherwise? */
132
133         if (BLI_is_dir(targetpath)) {
134 #ifdef PATH_DEBUG
135                 printf("\t%s found: %s\n", __func__, targetpath);
136 #endif
137                 return true;
138         }
139         else {
140 #ifdef PATH_DEBUG
141                 printf("\t%s missing: %s\n", __func__, targetpath);
142 #endif
143                 //targetpath[0] = '\0';
144                 return false;
145         }
146 }
147
148 /**
149  * Puts the value of the specified environment variable into *path if it exists
150  * and points at a directory. Returns true if this was done.
151  */
152 static bool test_env_path(char *path, const char *envvar)
153 {
154         const char *env = envvar ? getenv(envvar) : NULL;
155         if (!env) return false;
156         
157         if (BLI_is_dir(env)) {
158                 BLI_strncpy(path, env, FILE_MAX);
159 #ifdef PATH_DEBUG
160                 printf("\t%s env %s found: %s\n", __func__, envvar, env);
161 #endif
162                 return true;
163         }
164         else {
165                 path[0] = '\0';
166 #ifdef PATH_DEBUG
167                 printf("\t%s env %s missing: %s\n", __func__, envvar, env);
168 #endif
169                 return false;
170         }
171 }
172
173 /**
174  * Constructs in \a targetpath the name of a directory relative to a version-specific
175  * subdirectory in the parent directory of the Blender executable.
176  *
177  * \param targetpath  String to return path
178  * \param folder_name  Optional folder name within version-specific directory
179  * \param subfolder_name  Optional subfolder name within folder_name
180  * \param ver  To construct name of version-specific directory within bprogdir
181  * \return true if such a directory exists.
182  */
183 static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
184 {
185         char relfolder[FILE_MAX];
186         
187 #ifdef PATH_DEBUG
188         printf("%s...\n", __func__);
189 #endif
190
191         if (folder_name) {
192                 if (subfolder_name) {
193                         BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
194                 }
195                 else {
196                         BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
197                 }
198         }
199         else {
200                 relfolder[0] = '\0';
201         }
202
203         /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
204 #ifdef __APPLE__
205         static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
206         sprintf(osx_resourses, "%s../Resources", bprogdir);
207         return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
208 #else
209         return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
210 #endif
211 }
212
213 /**
214  * Is this an install with user files kept together with the Blender executable and its
215  * installation files.
216  */
217 static bool is_portable_install(void)
218 {
219         /* detect portable install by the existence of config folder */
220         const int ver = BLENDER_VERSION;
221         char path[FILE_MAX];
222
223         return get_path_local(path, "config", NULL, ver);
224 }
225
226 /**
227  * Returns the path of a folder within the user-files area.
228  *
229  *
230  * \param targetpath  String to return path
231  * \param folder_name  default name of folder within user area
232  * \param subfolder_name  optional name of subfolder within folder
233  * \param envvar  name of environment variable which, if defined, overrides folder_name
234  * \param ver  Blender version, used to construct a subdirectory name
235  * \return true if it was able to construct such a path.
236  */
237 static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
238 {
239         char user_path[FILE_MAX];
240         const char *user_base_path;
241
242         /* for portable install, user path is always local */
243         if (is_portable_install())
244                 return get_path_local(targetpath, folder_name, subfolder_name, ver);
245         
246         user_path[0] = '\0';
247
248         if (test_env_path(user_path, envvar)) {
249                 if (subfolder_name) {
250                         return test_path(targetpath, user_path, NULL, subfolder_name);
251                 }
252                 else {
253                         BLI_strncpy(targetpath, user_path, FILE_MAX);
254                         return true;
255                 }
256         }
257
258         user_base_path = (const char *)GHOST_getUserDir(ver, blender_version_decimal(ver));
259         if (user_base_path)
260                 BLI_strncpy(user_path, user_base_path, FILE_MAX);
261
262         if (!user_path[0])
263                 return false;
264         
265 #ifdef PATH_DEBUG
266         printf("%s: %s\n", __func__, user_path);
267 #endif
268         
269         if (subfolder_name) {
270                 return test_path(targetpath, user_path, folder_name, subfolder_name);
271         }
272         else {
273                 return test_path(targetpath, user_path, NULL, folder_name);
274         }
275 }
276
277 /**
278  * Returns the path of a folder within the Blender installation directory.
279  *
280  * \param targetpath  String to return path
281  * \param folder_name  default name of folder within installation area
282  * \param subfolder_name  optional name of subfolder within folder
283  * \param envvar  name of environment variable which, if defined, overrides folder_name
284  * \param ver  Blender version, used to construct a subdirectory name
285  * \return  true if it was able to construct such a path.
286  */
287 static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
288 {
289         char system_path[FILE_MAX];
290         const char *system_base_path;
291         char cwd[FILE_MAX];
292         char relfolder[FILE_MAX];
293
294         if (folder_name) {
295                 if (subfolder_name) {
296                         BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
297                 }
298                 else {
299                         BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
300                 }
301         }
302         else {
303                 relfolder[0] = '\0';
304         }
305
306         /* first allow developer only overrides to the system path
307          * these are only used when running blender from source */
308
309         /* try CWD/release/folder_name */
310         if (BLI_current_working_dir(cwd, sizeof(cwd))) {
311                 if (test_path(targetpath, cwd, "release", relfolder)) {
312                         return true;
313                 }
314         }
315
316         /* try EXECUTABLE_DIR/release/folder_name */
317         if (test_path(targetpath, bprogdir, "release", relfolder))
318                 return true;
319
320         /* end developer overrides */
321
322
323
324         system_path[0] = '\0';
325
326         if (test_env_path(system_path, envvar)) {
327                 if (subfolder_name) {
328                         return test_path(targetpath, system_path, NULL, subfolder_name);
329                 }
330                 else {
331                         BLI_strncpy(targetpath, system_path, FILE_MAX);
332                         return true;
333                 }
334         }
335
336         system_base_path = (const char *)GHOST_getSystemDir(ver, blender_version_decimal(ver));
337         if (system_base_path)
338                 BLI_strncpy(system_path, system_base_path, FILE_MAX);
339         
340         if (!system_path[0])
341                 return false;
342         
343 #ifdef PATH_DEBUG
344         printf("%s: %s\n", __func__, system_path);
345 #endif
346         
347         if (subfolder_name) {
348                 /* try $BLENDERPATH/folder_name/subfolder_name */
349                 return test_path(targetpath, system_path, folder_name, subfolder_name);
350         }
351         else {
352                 /* try $BLENDERPATH/folder_name */
353                 return test_path(targetpath, system_path, NULL, folder_name);
354         }
355 }
356
357 /* get a folder out of the 'folder_id' presets for paths */
358 /* returns the path if found, NULL string if not */
359 const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
360 {
361         const int ver = BLENDER_VERSION;
362         static char path[FILE_MAX] = "";
363         
364         switch (folder_id) {
365                 case BLENDER_DATAFILES:     /* general case */
366                         if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
367                         if (get_path_local(path, "datafiles", subfolder, ver)) break;
368                         if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
369                         return NULL;
370                         
371                 case BLENDER_USER_DATAFILES:
372                         if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
373                         return NULL;
374                         
375                 case BLENDER_SYSTEM_DATAFILES:
376                         if (get_path_local(path, "datafiles", subfolder, ver)) break;
377                         if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
378                         return NULL;
379                         
380                 case BLENDER_USER_AUTOSAVE:
381                         if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
382                         return NULL;
383
384                 case BLENDER_USER_CONFIG:
385                         if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
386                         return NULL;
387                         
388                 case BLENDER_USER_SCRIPTS:
389                         if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
390                         return NULL;
391                         
392                 case BLENDER_SYSTEM_SCRIPTS:
393                         if (get_path_local(path, "scripts", subfolder, ver)) break;
394                         if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
395                         return NULL;
396                         
397                 case BLENDER_SYSTEM_PYTHON:
398                         if (get_path_local(path, "python", subfolder, ver)) break;
399                         if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
400                         return NULL;
401
402                 default:
403                         BLI_assert(0);
404                         break;
405         }
406         
407         return path;
408 }
409
410 /**
411  * Returns the path to a folder in the user area without checking that it actually exists first.
412  */
413 const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
414 {
415         const int ver = BLENDER_VERSION;
416         static char path[FILE_MAX] = "";
417
418         switch (folder_id) {
419                 case BLENDER_USER_DATAFILES:
420                         get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
421                         break;
422                 case BLENDER_USER_CONFIG:
423                         get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
424                         break;
425                 case BLENDER_USER_AUTOSAVE:
426                         get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
427                         break;
428                 case BLENDER_USER_SCRIPTS:
429                         get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
430                         break;
431                 default:
432                         BLI_assert(0);
433                         break;
434         }
435
436         if ('\0' == path[0]) {
437                 return NULL;
438         }
439         return path;
440 }
441
442 /**
443  * Returns the path to a folder in the user area, creating it if it doesn't exist.
444  */
445 const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
446 {
447         const char *path;
448
449         /* only for user folders */
450         if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
451                 return NULL;
452         
453         path = BKE_appdir_folder_id(folder_id, subfolder);
454         
455         if (!path) {
456                 path = BKE_appdir_folder_id_user_notest(folder_id, subfolder);
457                 if (path) BLI_dir_create_recursive(path);
458         }
459         
460         return path;
461 }
462
463 /**
464  * Returns the path of the top-level version-specific local, user or system directory.
465  * If do_check, then the result will be NULL if the directory doesn't exist.
466  */
467 const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check)
468 {
469         static char path[FILE_MAX] = "";
470         bool ok;
471         switch (folder_id) {
472                 case BLENDER_RESOURCE_PATH_USER:
473                         ok = get_path_user(path, NULL, NULL, NULL, ver);
474                         break;
475                 case BLENDER_RESOURCE_PATH_LOCAL:
476                         ok = get_path_local(path, NULL, NULL, ver);
477                         break;
478                 case BLENDER_RESOURCE_PATH_SYSTEM:
479                         ok = get_path_system(path, NULL, NULL, NULL, ver);
480                         break;
481                 default:
482                         path[0] = '\0'; /* in case do_check is false */
483                         ok = false;
484                         BLI_assert(!"incorrect ID");
485                         break;
486         }
487
488         if (!ok && do_check) {
489                 return NULL;
490         }
491
492         return path;
493 }
494
495 #ifdef PATH_DEBUG
496 #  undef PATH_DEBUG
497 #endif
498
499
500 /* -------------------------------------------------------------------- */
501 /* Preset paths */
502
503 /**
504  * Checks if name is a fully qualified filename to an executable.
505  * If not it searches $PATH for the file. On Windows it also
506  * adds the correct extension (.com .exe etc) from
507  * $PATHEXT if necessary. Also on Windows it translates
508  * the name to its 8.3 version to prevent problems with
509  * spaces and stuff. Final result is returned in fullname.
510  *
511  * \param fullname The full path and full name of the executable
512  * (must be FILE_MAX minimum)
513  * \param name The name of the executable (usually argv[0]) to be checked
514  */
515 static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
516 {
517 #ifdef WITH_BINRELOC
518         /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
519         {
520                 const char *path = NULL;
521                 path = br_find_exe(NULL);
522                 if (path) {
523                         BLI_strncpy(fullname, path, maxlen);
524                         free((void *)path);
525                         return;
526                 }
527         }
528 #endif
529
530 #ifdef _WIN32
531         {
532                 wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
533                 if (GetModuleFileNameW(0, fullname_16, maxlen)) {
534                         conv_utf_16_to_8(fullname_16, fullname, maxlen);
535                         if (!BLI_exists(fullname)) {
536                                 printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
537                                 MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
538                         }
539                         MEM_freeN(fullname_16);
540                         return;
541                 }
542
543                 MEM_freeN(fullname_16);
544         }
545 #endif
546
547         /* unix and non linux */
548         if (name && name[0]) {
549
550                 BLI_strncpy(fullname, name, maxlen);
551                 if (name[0] == '.') {
552                         char wdir[FILE_MAX] = "";
553                         BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
554
555                         // not needed but avoids annoying /./ in name
556                         if (name[1] == SEP)
557                                 BLI_join_dirfile(fullname, maxlen, wdir, name + 2);
558                         else
559                                 BLI_join_dirfile(fullname, maxlen, wdir, name);
560
561 #ifdef _WIN32
562                         BLI_path_program_extensions_add_win32(fullname, maxlen);
563 #endif
564                 }
565                 else if (BLI_last_slash(name)) {
566                         // full path
567                         BLI_strncpy(fullname, name, maxlen);
568 #ifdef _WIN32
569                         BLI_path_program_extensions_add_win32(fullname, maxlen);
570 #endif
571                 }
572                 else {
573                         BLI_path_program_search(fullname, maxlen, name);
574                 }
575 #if defined(DEBUG)
576                 if (!STREQ(name, fullname)) {
577                         printf("guessing '%s' == '%s'\n", name, fullname);
578                 }
579 #endif
580         }
581 }
582
583 void BKE_appdir_program_path_init(const char *argv0)
584 {
585         bli_where_am_i(bprogname, sizeof(bprogname), argv0);
586         BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
587 }
588
589 /**
590  * Path to executable
591  */
592 const char *BKE_appdir_program_path(void)
593 {
594         return bprogname;
595 }
596
597 /**
598  * Path to directory of executable
599  */
600 const char *BKE_appdir_program_dir(void)
601 {
602         return bprogdir;
603 }
604
605 bool BKE_appdir_program_python_search(
606         char *fullpath, const size_t fullpath_len,
607         const int version_major, const int version_minor)
608 {
609         const char *basename = "python";
610         char python_ver[16];
611         /* check both possible names */
612         const char *python_names[] = {basename, python_ver};
613         int i;
614
615         bool is_found = false;
616
617         BLI_snprintf(python_ver, sizeof(python_ver), "%s%d.%d", basename, version_major, version_minor);
618
619         {
620                 const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin");
621                 if (python_bin_dir) {
622
623                         for (i = 0; i < ARRAY_SIZE(python_names); i++) {
624                                 BLI_join_dirfile(fullpath, fullpath_len, python_bin_dir, python_names[i]);
625
626                                 if (
627 #ifdef _WIN32
628                                     BLI_path_program_extensions_add_win32(fullpath, fullpath_len)
629 #else
630                                     BLI_exists(fullpath)
631 #endif
632                                     )
633                                 {
634                                         is_found = true;
635                                         break;
636                                 }
637                         }
638                 }
639         }
640
641         if (is_found == false) {
642                 for (i = 0; i < ARRAY_SIZE(python_names); i++) {
643                         if (BLI_path_program_search(fullpath, fullpath_len, python_names[i])) {
644                                 is_found = true;
645                                 break;
646                         }
647                 }
648         }
649
650         if (is_found == false) {
651                 *fullpath = '\0';
652         }
653
654         return is_found;
655 }
656
657 /**
658  * Gets the temp directory when blender first runs.
659  * If the default path is not found, use try $TEMP
660  * 
661  * Also make sure the temp dir has a trailing slash
662  *
663  * \param fullname The full path to the temporary temp directory
664  * \param basename The full path to the persistent temp directory (may be NULL)
665  * \param maxlen The size of the fullname buffer
666  * \param userdir Directory specified in user preferences 
667  */
668 static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
669 {
670         /* Clear existing temp dir, if needed. */
671         BKE_tempdir_session_purge();
672
673         fullname[0] = '\0';
674         if (basename) {
675                 basename[0] = '\0';
676         }
677
678         if (userdir && BLI_is_dir(userdir)) {
679                 BLI_strncpy(fullname, userdir, maxlen);
680         }
681         
682         
683 #ifdef WIN32
684         if (fullname[0] == '\0') {
685                 const char *tmp = getenv("TEMP"); /* Windows */
686                 if (tmp && BLI_is_dir(tmp)) {
687                         BLI_strncpy(fullname, tmp, maxlen);
688                 }
689         }
690 #else
691         /* Other OS's - Try TMP and TMPDIR */
692         if (fullname[0] == '\0') {
693                 const char *tmp = getenv("TMP");
694                 if (tmp && BLI_is_dir(tmp)) {
695                         BLI_strncpy(fullname, tmp, maxlen);
696                 }
697         }
698         
699         if (fullname[0] == '\0') {
700                 const char *tmp = getenv("TMPDIR");
701                 if (tmp && BLI_is_dir(tmp)) {
702                         BLI_strncpy(fullname, tmp, maxlen);
703                 }
704         }
705 #endif
706         
707         if (fullname[0] == '\0') {
708                 BLI_strncpy(fullname, "/tmp/", maxlen);
709         }
710         else {
711                 /* add a trailing slash if needed */
712                 BLI_add_slash(fullname);
713 #ifdef WIN32
714                 if (userdir && userdir != fullname) {
715                         BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
716                 }
717 #endif
718         }
719
720         /* Now that we have a valid temp dir, add system-generated unique sub-dir. */
721         if (basename) {
722                 /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */
723                 char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX");
724                 const size_t ln = strlen(tmp_name) + 1;
725                 if (ln <= maxlen) {
726 #ifdef WIN32
727                         if (_mktemp_s(tmp_name, ln) == 0) {
728                                 BLI_dir_create_recursive(tmp_name);
729                         }
730 #else
731                         mkdtemp(tmp_name);
732 #endif
733                 }
734                 if (BLI_is_dir(tmp_name)) {
735                         BLI_strncpy(basename, fullname, maxlen);
736                         BLI_strncpy(fullname, tmp_name, maxlen);
737                         BLI_add_slash(fullname);
738                 }
739                 else {
740                         printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname);
741                 }
742
743                 MEM_freeN(tmp_name);
744         }
745 }
746
747 /**
748  * Sets btempdir_base to userdir if specified and is a valid directory, otherwise
749  * chooses a suitable OS-specific temporary directory.
750  * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base.
751  *
752  * \note On Window userdir will be set to the temporary directory!
753  */
754 void BKE_tempdir_init(char *userdir)
755 {
756         BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
757 ;
758 }
759
760 /**
761  * Path to temporary directory (with trailing slash)
762  */
763 const char *BKE_tempdir_session(void)
764 {
765         return btempdir_session[0] ? btempdir_session : BKE_tempdir_base();
766 }
767
768 /**
769  * Path to persistent temporary directory (with trailing slash)
770  */
771 const char *BKE_tempdir_base(void)
772 {
773         return btempdir_base;
774 }
775
776 /**
777  * Path to the system temporary directory (with trailing slash)
778  */
779 void BKE_tempdir_system_init(char *dir)
780 {
781         BLI_where_is_temp(dir, NULL, FILE_MAX, NULL);
782 }
783
784 /**
785  * Delete content of this instance's temp dir.
786  */
787 void BKE_tempdir_session_purge(void)
788 {
789         if (btempdir_session[0] && BLI_is_dir(btempdir_session)) {
790                 BLI_delete(btempdir_session, true, true);
791         }
792 }