diff options
author | Nicolas Hillegeer <nicolas@hillegeer.com> | 2014-07-14 21:17:39 +0200 |
---|---|---|
committer | Nicolas Hillegeer <nicolas@hillegeer.com> | 2014-07-14 21:17:39 +0200 |
commit | 2b62dcddf801e096bde7d4608e090018b5227e98 (patch) | |
tree | 728251b27edf7110565bc0c4c8cc5864f5b31bfe /src/nvim/tempfile.c | |
parent | 47084ea7657121837536d409b9137fd38426aeef (diff) | |
parent | 14239ae33128ae961a4ce9e68436ad3f0f557b90 (diff) | |
download | rneovim-2b62dcddf801e096bde7d4608e090018b5227e98.tar.gz rneovim-2b62dcddf801e096bde7d4608e090018b5227e98.tar.bz2 rneovim-2b62dcddf801e096bde7d4608e090018b5227e98.zip |
Merge #850 'impl mkdtemp for windows, refactor vim_tempname'
Diffstat (limited to 'src/nvim/tempfile.c')
-rw-r--r-- | src/nvim/tempfile.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/nvim/tempfile.c b/src/nvim/tempfile.c new file mode 100644 index 0000000000..41fc163936 --- /dev/null +++ b/src/nvim/tempfile.c @@ -0,0 +1,131 @@ +#include <inttypes.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> + +#include "nvim/ascii.h" +#include "nvim/memory.h" +#include "nvim/misc1.h" +#include "nvim/os/os.h" +#include "nvim/os/os_defs.h" +#include "nvim/path.h" +#include "nvim/strings.h" +#include "nvim/tempfile.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "tempfile.c.generated.h" +#endif + +/// Name of Vim's own temp dir. Ends in a slash. +static char_u *vim_tempdir = NULL; + +/// Create a directory for private use by this instance of Neovim. +/// This is done once, and the same directory is used for all temp files. +/// This method avoids security problems because of symlink attacks et al. +/// It's also a bit faster, because we only need to check for an existing +/// file when creating the directory and not for each temp file. +static void vim_maketempdir(void) +{ + static const char *temp_dirs[] = TEMP_DIR_NAMES; + // Try the entries in `TEMP_DIR_NAMES` to create the temp directory. + char_u itmp[TEMP_FILE_PATH_MAXLEN]; + for (size_t i = 0; i < sizeof(temp_dirs) / sizeof(char *); ++i) { + // Expand environment variables, leave room for "/nvimXXXXXX/999999999" + expand_env((char_u *)temp_dirs[i], itmp, TEMP_FILE_PATH_MAXLEN - 22); + if (!os_isdir(itmp)) { // directory doesn't exist + continue; + } + + add_pathsep(itmp); + // Concatenate with temporary directory name pattern + STRCAT(itmp, "nvimXXXXXX"); + if (!os_mkdtemp((char *)itmp)) { + continue; + } + if (vim_settempdir(itmp)) { + // Successfully created and set temporary directory so stop trying. + break; + } else { + // Couldn't set `vim_tempdir` to itmp so remove created directory. + os_rmdir((char *)itmp); + } + } +} + +/// Delete the temp directory and all files it contains. +void vim_deltempdir(void) +{ + if (vim_tempdir != NULL) { + snprintf((char *)NameBuff, MAXPATHL, "%s*", vim_tempdir); + + char_u **files; + int file_count; + if (gen_expand_wildcards(1, &NameBuff, &file_count, &files, + EW_DIR|EW_FILE|EW_SILENT) == OK) { + for (int i = 0; i < file_count; ++i) { + os_remove((char *)files[i]); + } + FreeWild(file_count, files); + } + path_tail(NameBuff)[-1] = NUL; + os_rmdir((char *)NameBuff); + + free(vim_tempdir); + vim_tempdir = NULL; + } +} + +/// Get the name of temp directory. This directory would be created on the first +/// call to this function. +char_u *vim_gettempdir(void) +{ + if (vim_tempdir == NULL) { + vim_maketempdir(); + } + + return vim_tempdir; +} + +/// Set Neovim own temporary directory name to `tempdir`. This directory should +/// be already created. Expand this name to a full path and put it in +/// `vim_tempdir`. This avoids that using `:cd` would confuse us. +/// +/// @param tempdir must be no longer than MAXPATHL. +/// +/// @return false if we run out of memory. +static bool vim_settempdir(char_u *tempdir) +{ + char_u *buf = verbose_try_malloc((size_t)MAXPATHL + 2); + if (!buf) { + return false; + } + vim_FullName(tempdir, buf, MAXPATHL, false); + add_pathsep(buf); + vim_tempdir = vim_strsave(buf); + free(buf); + return true; +} + +/// Return a unique name that can be used for a temp file. +/// +/// @note The temp file is NOT created. +/// +/// @return pointer to the temp file name or NULL if Neovim can't create +/// temporary directory for its own temporary files. +char_u *vim_tempname(void) +{ + // Temp filename counter. + static uint32_t temp_count; + + char_u *tempdir = vim_gettempdir(); + if (!tempdir) { + return NULL; + } + + // There is no need to check if the file exists, because we own the directory + // and nobody else creates a file in it. + char_u itmp[TEMP_FILE_PATH_MAXLEN]; + snprintf((char *)itmp, TEMP_FILE_PATH_MAXLEN, + "%s%" PRIu32, tempdir, temp_count++); + return vim_strsave(itmp); +} |