From c0fa2e7518a3a0e364c56f8223bdd0f549ddac66 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 4 Jan 2016 16:52:44 -0500 Subject: [PATCH] unix,win: add uv_os_tmpdir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/libuv/libuv/pull/672 Reviewed-By: Saúl Ibarra Corretgé --- Makefile.am | 1 + checksparse.sh | 1 + docs/src/misc.rst | 16 ++++++++++++++ include/uv.h | 1 + src/unix/core.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ src/win/util.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 3 +++ test/test-tmpdir.c | 50 +++++++++++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 9 files changed, 177 insertions(+) create mode 100644 test/test-tmpdir.c diff --git a/Makefile.am b/Makefile.am index 1fd09a5e..663b55ee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -243,6 +243,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-timer-again.c \ test/test-timer-from-check.c \ test/test-timer.c \ + test/test-tmpdir.c \ test/test-tty.c \ test/test-udp-bind.c \ test/test-udp-create-socket-early.c \ diff --git a/checksparse.sh b/checksparse.sh index 619cf6f8..dbaa4574 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -155,6 +155,7 @@ test/test-threadpool-cancel.c test/test-threadpool.c test/test-timer-again.c test/test-timer.c +test/test-tmpdir.c test/test-tty.c test/test-udp-dgram-too-big.c test/test-udp-ipv6.c diff --git a/docs/src/misc.rst b/docs/src/misc.rst index 2ce0887d..bf234dae 100644 --- a/docs/src/misc.rst +++ b/docs/src/misc.rst @@ -273,6 +273,22 @@ API .. versionadded:: 1.6.0 +.. c:function:: int uv_os_tmpdir(char* buffer, size_t* size) + + Gets the temp directory. On Windows, `uv_os_tmpdir()` uses `GetTempPathW()`. + On all other operating systems, `uv_os_tmpdir()` uses the first environment + variable found in the ordered list `TMPDIR`, `TMP`, `TEMP`, and `TEMPDIR`. + If none of these are found, the path `"/tmp"` is used, or, on Android, + `"/data/local/tmp"` is used. The temp directory is stored in `buffer`. When + `uv_os_tmpdir()` is called, `size` indicates the maximum size of `buffer`. + On success or `UV_ENOBUFS` failure, `size` is set to the string length of + `buffer` (which does not include the terminating null). + + .. warning:: + `uv_os_tmpdir()` is not thread safe. + + .. versionadded:: 1.9.0 + .. uint64_t uv_get_free_memory(void) .. c:function:: uint64_t uv_get_total_memory(void) diff --git a/include/uv.h b/include/uv.h index dd3111a9..8d56a45e 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1049,6 +1049,7 @@ typedef struct { UV_EXTERN int uv_getrusage(uv_rusage_t* rusage); UV_EXTERN int uv_os_homedir(char* buffer, size_t* size); +UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); diff --git a/src/unix/core.c b/src/unix/core.c index cedd86ed..8a7898e1 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -1102,3 +1102,54 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } + + +int uv_os_tmpdir(char* buffer, size_t* size) { + const char* buf; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return -EINVAL; + +#define CHECK_ENV_VAR(name) \ + do { \ + buf = getenv(name); \ + if (buf != NULL) \ + goto return_buffer; \ + } \ + while (0) + + /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */ + CHECK_ENV_VAR("TMPDIR"); + CHECK_ENV_VAR("TMP"); + CHECK_ENV_VAR("TEMP"); + CHECK_ENV_VAR("TEMPDIR"); + +#undef CHECK_ENV_VAR + + /* No temp environment variables defined */ + #if defined(__ANDROID__) + buf = "/data/local/tmp"; + #else + buf = "/tmp"; + #endif + +return_buffer: + len = strlen(buf); + + if (len >= *size) { + *size = len; + return -ENOBUFS; + } + + /* The returned directory should not have a trailing slash. */ + if (len > 1 && buf[len - 1] == '/') { + len--; + } + + memcpy(buffer, buf, len + 1); + buffer[len] = '\0'; + *size = len; + + return 0; +} diff --git a/src/win/util.c b/src/win/util.c index cb247513..dbad249b 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -1230,3 +1230,56 @@ convert_buffer: *size = bufsize - 1; return 0; } + + +int uv_os_tmpdir(char* buffer, size_t* size) { + wchar_t path[MAX_PATH + 1]; + DWORD bufsize; + size_t len; + + if (buffer == NULL || size == NULL || *size == 0) + return UV_EINVAL; + + len = GetTempPathW(MAX_PATH + 1, path); + + if (len == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (len > MAX_PATH + 1) { + /* This should not be possible */ + return UV_EIO; + } + + /* The returned directory should not have a trailing slash, unless it */ + /* points at a drive root, like c:\. Remove it if needed.*/ + if (path[len - 1] == L'\\' && + !(len == 3 && path[1] == L':')) { + len--; + path[len] = L'\0'; + } + + /* Check how much space we need */ + bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); + + if (bufsize == 0) { + return uv_translate_sys_error(GetLastError()); + } else if (bufsize > *size) { + *size = bufsize - 1; + return UV_ENOBUFS; + } + + /* Convert to UTF-8 */ + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + path, + -1, + buffer, + *size, + NULL, + NULL); + + if (bufsize == 0) + return uv_translate_sys_error(GetLastError()); + + *size = bufsize - 1; + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index dce5de32..3584df8a 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -199,6 +199,7 @@ TEST_DECLARE (cwd_and_chdir) TEST_DECLARE (get_memory) TEST_DECLARE (handle_fileno) TEST_DECLARE (homedir) +TEST_DECLARE (tmpdir) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail_sync) @@ -586,6 +587,8 @@ TASK_LIST_START TEST_ENTRY (homedir) + TEST_ENTRY (tmpdir) + TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) diff --git a/test/test-tmpdir.c b/test/test-tmpdir.c new file mode 100644 index 00000000..bbc8ba73 --- /dev/null +++ b/test/test-tmpdir.c @@ -0,0 +1,50 @@ +#include "uv.h" +#include "task.h" +#include + +#define PATHMAX 1024 +#define SMALLPATH 1 + +TEST_IMPL(tmpdir) { + char tmpdir[PATHMAX]; + size_t len; + char last; + int r; + + /* Test the normal case */ + len = sizeof tmpdir; + tmpdir[0] = '\0'; + + ASSERT(strlen(tmpdir) == 0); + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == 0); + ASSERT(strlen(tmpdir) == len); + ASSERT(len > 0); + ASSERT(tmpdir[len] == '\0'); + + if (len > 1) { + last = tmpdir[len - 1]; +#ifdef _WIN32 + ASSERT(last != '\\'); +#else + ASSERT(last != '/'); +#endif + } + + /* Test the case where the buffer is too small */ + len = SMALLPATH; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len > SMALLPATH); + + /* Test invalid inputs */ + r = uv_os_tmpdir(NULL, &len); + ASSERT(r == UV_EINVAL); + r = uv_os_tmpdir(tmpdir, NULL); + ASSERT(r == UV_EINVAL); + len = 0; + r = uv_os_tmpdir(tmpdir, &len); + ASSERT(r == UV_EINVAL); + + return 0; +} diff --git a/uv.gyp b/uv.gyp index 4a044b28..0e88f3fc 100644 --- a/uv.gyp +++ b/uv.gyp @@ -387,6 +387,7 @@ 'test/test-threadpool.c', 'test/test-threadpool-cancel.c', 'test/test-thread-equal.c', + 'test/test-tmpdir.c', 'test/test-mutexes.c', 'test/test-thread.c', 'test/test-barrier.c',