From 414c70435dcd52eb67df59f56132837de0a63b64 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 23 Jun 2014 13:42:19 +0200 Subject: T39690: Modifications to Blender's 'temp dir' system. Current temporary data of Blender suffers one major issue - default 'temp' dir on Windows is never automatically cleaned up, and can end being quite big when used by Blender, especially when we have to store per-process data (using getpid() in file names). To address this, this patch: * Divides tempdir paths in two, one for 'base' temp dir (the same as previous unique tempdir path), the other is a mkdtemp-generated sub-dir, specific to each Blender instance. * Only uses base tempdir when we need some shallow persistance accross Blender sessions - and we always reuse the same filename (quit.blend...) or generate small file (crash reports...). * Uses temp sub-dir for heavy files like pointcache or renderEXRs (Save Buffer option). * Erases temp sub-dir on quit or crash. To get this working it also adds a working 'recursive delete' to BLI_delete() under Windows. Note that, as in current code, the 'recover render result' hack-feature that was possible with SaveBuffer option is still removed. A real renderresult cache feature will be added soon, though. Reviewers: campbellbarton, brecht, sergey Reviewed By: campbellbarton, sergey CC: sergey Differential Revision: https://developer.blender.org/D531 --- source/blender/blenlib/BLI_path_util.h | 6 ++- source/blender/blenlib/intern/fileops.c | 71 +++++++++++++++++++++++----- source/blender/blenlib/intern/path_util.c | 78 ++++++++++++++++++++++++++----- 3 files changed, 129 insertions(+), 26 deletions(-) (limited to 'source/blender/blenlib') diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index b33b26a2feb..244c308a05c 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -191,12 +191,14 @@ void BLI_char_switch(char *string, char from, char to) ATTR_NONNULL(); void BLI_init_program_path(const char *argv0); /* Initialize path to temporary directory. * NOTE: On Window userdir will be set to the temporary directory! */ -void BLI_init_temporary_dir(char *userdir); +void BLI_temp_dir_init(char *userdir); const char *BLI_program_path(void); const char *BLI_program_dir(void); -const char *BLI_temporary_dir(void); +const char *BLI_temp_dir_session(void); +const char *BLI_temp_dir_base(void); void BLI_system_temporary_dir(char *dir); +void BLI_temp_dir_session_purge(void); #ifdef WITH_ICONV void BLI_string_to_utf8(char *original, char *utf_8, const char *code); diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c index 5df46752e3b..c1a103b641e 100644 --- a/source/blender/blenlib/intern/fileops.c +++ b/source/blender/blenlib/intern/fileops.c @@ -48,6 +48,7 @@ # include # include "BLI_winstuff.h" # include "BLI_callbacks.h" +# include "BLI_fileops_types.h" # include "utf_winfunc.h" # include "utfconv.h" #else @@ -284,26 +285,72 @@ int BLI_access(const char *filename, int mode) return uaccess(filename, mode); } -int BLI_delete(const char *file, bool dir, bool recursive) +static bool delete_unique(const char *path, const bool dir) { - int err; - - UTF16_ENCODE(file); + bool err; - if (recursive) { - callLocalErrorCallBack("Recursive delete is unsupported on Windows"); - err = 1; - } - else if (dir) { - err = !RemoveDirectoryW(file_16); + UTF16_ENCODE(path); + + if (dir) { + err = !RemoveDirectoryW(path_16); if (err) printf("Unable to remove directory"); } else { - err = !DeleteFileW(file_16); + err = !DeleteFileW(path_16); if (err) callLocalErrorCallBack("Unable to delete file"); } - UTF16_UN_ENCODE(file); + UTF16_UN_ENCODE(path); + + return err; +} + +static bool delete_recursive(const char *dir) +{ + struct direntry *filelist, *fl; + bool err = false; + unsigned int nbr, i; + + i = nbr = BLI_dir_contents(dir, &filelist); + fl = filelist; + while(i--) { + char file[8]; + BLI_split_file_part(fl->path, file, sizeof(file)); + if (STREQ(file, ".") || STREQ(file, "..")) { + /* Skip! */ + } + else if (S_ISDIR(fl->type)) { + if (delete_recursive(fl->path) { + err = true; + } + } + else { + if (delete_unique(fl->path, false)) { + err = true; + } + } + ++fl; + } + + if (!err && delete_unique(dir, true)) { + err = true; + } + + BLI_free_filelist(filelist, nbr); + + return err; +} + +int BLI_delete(const char *file, bool dir, bool recursive) +{ + int err; + + if (recursive) { + err = delete_recursive(file); + } + else { + err = delete_unique(file, dir); + } return err; } diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index e00631fe996..d95cb5e5ee1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -49,9 +49,9 @@ #include "GHOST_Path-api.h" -#ifdef WIN32 -# include "MEM_guardedalloc.h" +#include "MEM_guardedalloc.h" +#ifdef WIN32 # include "utf_winfunc.h" # include "utfconv.h" # include @@ -73,7 +73,8 @@ static char bprogname[FILE_MAX]; /* full path to program executable */ static char bprogdir[FILE_MAX]; /* full path to directory in which executable is located */ -static char btempdir[FILE_MAX]; /* temporary directory */ +static char btempdir_base[FILE_MAX]; /* persistent temporary directory */ +static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */ /* implementation */ @@ -2319,14 +2320,21 @@ const char *BLI_program_dir(void) * * Also make sure the temp dir has a trailing slash * - * \param fullname The full path to the temp directory + * \param fullname The full path to the temporary temp directory + * \param basename The full path to the persistent temp directory (may be NULL) * \param maxlen The size of the fullname buffer * \param userdir Directory specified in user preferences */ -static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir) +static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir) { + /* Clear existing temp dir, if needed. */ + BLI_temp_dir_session_purge(); + fullname[0] = '\0'; - + if (basename) { + basename[0] = '\0'; + } + if (userdir && BLI_is_dir(userdir)) { BLI_strncpy(fullname, userdir, maxlen); } @@ -2368,23 +2376,59 @@ static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir } #endif } + + /* Now that we have a valid temp dir, add system-generated unique sub-dir. */ + if (basename) { + /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */ + char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX"); + const size_t ln = strlen(tmp_name) + 1; + if (ln <= maxlen) { +#ifdef WIN32 + if (_mktemp_s(tmp_name, ln) == 0) { + BLI_dir_create_recursive(tmp_name); + } +#else + mkdtemp(tmp_name); +#endif + } + if (BLI_is_dir(tmp_name)) { + BLI_strncpy(basename, fullname, maxlen); + BLI_strncpy(fullname, tmp_name, maxlen); + BLI_add_slash(fullname); + } + else { + printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname); + } + + MEM_freeN(tmp_name); + } } /** - * Sets btempdir to userdir if specified and is a valid directory, otherwise + * Sets btempdir_base to userdir if specified and is a valid directory, otherwise * chooses a suitable OS-specific temporary directory. + * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base. */ -void BLI_init_temporary_dir(char *userdir) +void BLI_temp_dir_init(char *userdir) { - BLI_where_is_temp(btempdir, FILE_MAX, userdir); + BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir); +; } /** * Path to temporary directory (with trailing slash) */ -const char *BLI_temporary_dir(void) +const char *BLI_temp_dir_session(void) +{ + return btempdir_session[0] ? btempdir_session : BLI_temp_dir_base(); +} + +/** + * Path to persistent temporary directory (with trailing slash) + */ +const char *BLI_temp_dir_base(void) { - return btempdir; + return btempdir_base; } /** @@ -2392,7 +2436,17 @@ const char *BLI_temporary_dir(void) */ void BLI_system_temporary_dir(char *dir) { - BLI_where_is_temp(dir, FILE_MAX, NULL); + BLI_where_is_temp(dir, NULL, FILE_MAX, NULL); +} + +/** + * Delete content of this instance's temp dir. + */ +void BLI_temp_dir_session_purge(void) +{ + if (btempdir_session[0] && BLI_is_dir(btempdir_session)) { + BLI_delete(btempdir_session, true, true); + } } #ifdef WITH_ICONV -- cgit v1.2.3