mf_tempfile.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License, version 2.0,
  4. as published by the Free Software Foundation.
  5. This program is also distributed with certain software (including
  6. but not limited to OpenSSL) that is licensed under separate terms,
  7. as designated in a particular file or component or in included license
  8. documentation. The authors of MySQL hereby grant you an additional
  9. permission to link the program and your derivative works with the
  10. separately licensed software that they have included with MySQL.
  11. Without limiting anything contained in the foregoing, this file,
  12. which is part of C Driver for MySQL (Connector/C), is also subject to the
  13. Universal FOSS Exception, version 1.0, a copy of which can be found at
  14. http://oss.oracle.com/licenses/universal-foss-exception.
  15. This program is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License, version 2.0, for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
  22. /**
  23. @file mysys/mf_tempfile.cc
  24. */
  25. #include "my_config.h"
  26. #include <errno.h>
  27. #ifdef HAVE_O_TMPFILE
  28. #include <fcntl.h>
  29. # ifndef O_TMPFILE
  30. # include <util/system/platform.h>
  31. # if defined(_arm_) || defined(_ppc_) || defined(_ppc64_)
  32. # define O_TMPFILE 020040000
  33. # else
  34. # define O_TMPFILE 020200000
  35. # endif
  36. # endif
  37. #endif
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <sys/types.h>
  41. #ifdef HAVE_UNISTD_H
  42. #include <unistd.h>
  43. #endif
  44. #include "m_string.h"
  45. #include "my_compiler.h"
  46. #include "my_dbug.h"
  47. #include "my_inttypes.h"
  48. #include "my_io.h"
  49. #include "my_sys.h"
  50. #include "my_thread_local.h"
  51. #include "mysql/psi/mysql_mutex.h"
  52. #include "mysys/mysys_priv.h"
  53. #include "mysys_err.h"
  54. #ifdef WIN32
  55. #include <fcntl.h> // O_EXCL
  56. #endif
  57. /*
  58. @brief
  59. Create a temporary file with unique name in a given directory
  60. @details
  61. create_temp_file
  62. to pointer to buffer where temporary filename will be stored
  63. dir directory where to create the file
  64. prefix prefix the filename with this
  65. mode Flags to use for my_create/my_open
  66. MyFlags Magic flags
  67. @return
  68. File descriptor of opened file if success
  69. -1 and sets errno if fails.
  70. @note
  71. The behaviour of this function differs a lot between
  72. implementation, it's main use is to generate a file with
  73. a name that does not already exist.
  74. The implementation using mkstemp should be considered the
  75. reference implementation when adding a new or modifying an
  76. existing one
  77. */
  78. File create_temp_file(char *to, const char *dir, const char *prefix,
  79. int mode MY_ATTRIBUTE((unused)),
  80. UnlinkOrKeepFile unlink_or_keep, myf MyFlags) {
  81. File file = -1;
  82. #ifdef _WIN32
  83. TCHAR path_buf[MAX_PATH - 14];
  84. #endif
  85. DBUG_ENTER("create_temp_file");
  86. DBUG_PRINT("enter", ("dir: %s, prefix: %s", dir, prefix));
  87. #if defined(_WIN32)
  88. /*
  89. Use GetTempPath to determine path for temporary files.
  90. This is because the documentation for GetTempFileName
  91. has the following to say about this parameter:
  92. "If this parameter is NULL, the function fails."
  93. */
  94. if (!dir) {
  95. if (GetTempPath(sizeof(path_buf), path_buf) > 0) dir = path_buf;
  96. }
  97. /*
  98. Use GetTempFileName to generate a unique filename, create
  99. the file and release it's handle
  100. - uses up to the first three letters from prefix
  101. */
  102. if (GetTempFileName(dir, prefix, 0, to) == 0) DBUG_RETURN(-1);
  103. DBUG_PRINT("info", ("name: %s", to));
  104. /*
  105. Open the file without the "open only if file doesn't already exist"
  106. since the file has already been created by GetTempFileName
  107. */
  108. if ((file = my_open(to, (mode & ~O_EXCL), MyFlags)) < 0) {
  109. /* Open failed, remove the file created by GetTempFileName */
  110. int tmp = my_errno();
  111. (void)my_delete(to, MYF(0));
  112. set_my_errno(tmp);
  113. DBUG_RETURN(file);
  114. }
  115. if (unlink_or_keep == UNLINK_FILE) {
  116. my_delete(to, MYF(0));
  117. }
  118. #else /* mkstemp() is available on all non-Windows supported platforms. */
  119. #ifdef HAVE_O_TMPFILE
  120. if (unlink_or_keep == UNLINK_FILE) {
  121. if (!dir && !(dir = getenv("TMPDIR"))) dir = DEFAULT_TMPDIR;
  122. char dirname_buf[FN_REFLEN];
  123. convert_dirname(dirname_buf, dir, nullptr);
  124. // Verify that the generated filename will fit in a FN_REFLEN size buffer.
  125. int max_filename_len = snprintf(to, FN_REFLEN, "%s%.20sfd=%d", dirname_buf,
  126. prefix ? prefix : "tmp.", 4 * 1024 * 1024);
  127. if (max_filename_len >= FN_REFLEN) {
  128. errno = ENAMETOOLONG;
  129. set_my_errno(ENAMETOOLONG);
  130. DBUG_RETURN(file);
  131. }
  132. /* Explicitly don't use O_EXCL here as it has a different
  133. meaning with O_TMPFILE.
  134. */
  135. file = open(dirname_buf, O_RDWR | O_TMPFILE | O_CLOEXEC, S_IRUSR | S_IWUSR);
  136. if (file >= 0) {
  137. sprintf(to, "%s%.20sfd=%d", dirname_buf, prefix ? prefix : "tmp.", file);
  138. file = my_register_filename(file, to, FILE_BY_O_TMPFILE,
  139. EE_CANTCREATEFILE, MyFlags);
  140. }
  141. }
  142. // Fall through, in case open() failed above (or we have KEEP_FILE).
  143. #endif /* HAVE_O_TMPFILE */
  144. if (file == -1) {
  145. char prefix_buff[30];
  146. uint pfx_len;
  147. File org_file;
  148. pfx_len = (uint)(my_stpcpy(my_stpnmov(prefix_buff, prefix ? prefix : "tmp.",
  149. sizeof(prefix_buff) - 7),
  150. "XXXXXX") -
  151. prefix_buff);
  152. if (!dir && !(dir = getenv("TMPDIR"))) dir = DEFAULT_TMPDIR;
  153. if (strlen(dir) + pfx_len > FN_REFLEN - 2) {
  154. errno = ENAMETOOLONG;
  155. set_my_errno(ENAMETOOLONG);
  156. DBUG_RETURN(file);
  157. }
  158. my_stpcpy(convert_dirname(to, dir, NullS), prefix_buff);
  159. org_file = mkstemp(to);
  160. file = my_register_filename(org_file, to, FILE_BY_MKSTEMP,
  161. EE_CANTCREATEFILE, MyFlags);
  162. /* If we didn't manage to register the name, remove the temp file */
  163. if (org_file >= 0 && file < 0) {
  164. int tmp = my_errno();
  165. close(org_file);
  166. (void)my_delete(to, MYF(MY_WME));
  167. set_my_errno(tmp);
  168. DBUG_RETURN(file);
  169. }
  170. if (unlink_or_keep == UNLINK_FILE) {
  171. unlink(to);
  172. }
  173. }
  174. #endif
  175. if (file >= 0) {
  176. mysql_mutex_lock(&THR_LOCK_open);
  177. my_tmp_file_created++;
  178. mysql_mutex_unlock(&THR_LOCK_open);
  179. }
  180. DBUG_RETURN(file);
  181. }