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