1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
15
16 #include "mysys_priv.h"
17 #include <m_string.h>
18 #include "my_static.h"
19 #include "mysys_err.h"
20 #include <errno.h>
21 #ifdef HAVE_PATHS_H
22 #include <paths.h>
23 #endif
24
25 #ifdef HAVE_MKOSTEMP
26 #define mkstemp(A) mkostemp(A, O_CLOEXEC)
27 #endif
28
29 /*
30 @brief
31 Create a temporary file with unique name in a given directory
32
33 @details
34 create_temp_file
35 to pointer to buffer where temporary filename will be stored
36 dir directory where to create the file
37 prefix prefix the filename with this
38 mode Flags to use for my_create/my_open
39 MyFlags Magic flags
40
41 @return
42 File descriptor of opened file if success
43 -1 and sets errno if fails.
44
45 @note
46 The behaviour of this function differs a lot between
47 implementation, it's main use is to generate a file with
48 a name that does not already exist.
49
50 When passing MY_TEMPORARY flag in MyFlags the file is automatically deleted
51
52 "mode" bits that always must be used for newly created files with
53 unique file names (O_EXCL | O_TRUNC | O_CREAT | O_RDWR) are added
54 automatically, and shouldn't be specified by the caller.
55
56 The implementation using mkstemp should be considered the
57 reference implementation when adding a new or modifying an
58 existing one
59
60 */
61
create_temp_file(char * to,const char * dir,const char * prefix,int mode,myf MyFlags)62 File create_temp_file(char *to, const char *dir, const char *prefix,
63 int mode, myf MyFlags)
64 {
65 File file= -1;
66
67 DBUG_ENTER("create_temp_file");
68 DBUG_PRINT("enter", ("dir: %s, prefix: %s", dir ? dir : "(null)", prefix));
69 DBUG_ASSERT((mode & (O_EXCL | O_TRUNC | O_CREAT | O_RDWR)) == 0);
70
71 mode|= O_TRUNC | O_CREAT | O_RDWR; /* not O_EXCL, see Windows code below */
72
73 #ifdef _WIN32
74 {
75 TCHAR path_buf[MAX_PATH-14];
76 /*
77 Use GetTempPath to determine path for temporary files.
78 This is because the documentation for GetTempFileName
79 has the following to say about this parameter:
80 "If this parameter is NULL, the function fails."
81 */
82 if (!dir)
83 {
84 if(GetTempPath(sizeof(path_buf), path_buf) > 0)
85 dir = path_buf;
86 }
87 /*
88 Use GetTempFileName to generate a unique filename, create
89 the file and release it's handle
90 - uses up to the first three letters from prefix
91 */
92 if (GetTempFileName(dir, prefix, 0, to) == 0)
93 DBUG_RETURN(-1);
94
95 DBUG_PRINT("info", ("name: %s", to));
96
97 if (MyFlags & MY_TEMPORARY)
98 mode|= O_SHORT_LIVED | O_TEMPORARY;
99
100 /*
101 Open the file without O_EXCL flag
102 since the file has already been created by GetTempFileName
103 */
104 if ((file= my_open(to, mode, MyFlags)) < 0)
105 {
106 /* Open failed, remove the file created by GetTempFileName */
107 int tmp= my_errno;
108 (void) my_delete(to, MYF(0));
109 my_errno= tmp;
110 }
111 }
112 #elif defined(HAVE_MKSTEMP)
113 if (!dir && ! (dir =getenv("TMPDIR")))
114 dir= DEFAULT_TMPDIR;
115 #ifdef O_TMPFILE
116 {
117 static int O_TMPFILE_works= 1;
118
119 if ((MyFlags & MY_TEMPORARY) && O_TMPFILE_works)
120 {
121 /* explictly don't use O_EXCL here has it has a different
122 meaning with O_TMPFILE
123 */
124 if ((file= open(dir, (mode & ~O_CREAT) | O_TMPFILE | O_CLOEXEC,
125 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) >= 0)
126 {
127 my_snprintf(to, FN_REFLEN, "%s/#sql/fd=%d", dir, file);
128 file=my_register_filename(file, to, FILE_BY_O_TMPFILE,
129 EE_CANTCREATEFILE, MyFlags);
130 }
131 else if (errno == EOPNOTSUPP || errno == EINVAL)
132 {
133 my_printf_error(EE_CANTCREATEFILE, "O_TMPFILE is not supported on %s "
134 "(disabling future attempts)",
135 MYF(ME_NOTE | ME_ERROR_LOG_ONLY), dir);
136 O_TMPFILE_works= 0;
137 }
138 }
139 }
140 if (file == -1)
141 #endif /* O_TMPFILE */
142 {
143 char prefix_buff[30];
144 uint pfx_len;
145 File org_file;
146
147 pfx_len= (uint) (strmov(strnmov(prefix_buff,
148 prefix ? prefix : "tmp.",
149 sizeof(prefix_buff)-7),"XXXXXX") -
150 prefix_buff);
151 if (strlen(dir)+ pfx_len > FN_REFLEN-2)
152 {
153 errno=my_errno= ENAMETOOLONG;
154 DBUG_RETURN(file);
155 }
156 strmov(convert_dirname(to,dir,NullS),prefix_buff);
157 org_file=mkstemp(to);
158 if (org_file >= 0 && (MyFlags & MY_TEMPORARY))
159 (void) my_delete(to, MYF(MY_WME));
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 {
165 int tmp=my_errno;
166 close(org_file);
167 (void) my_delete(to, MYF(MY_WME));
168 my_errno=tmp;
169 }
170 }
171 #else
172 #error No implementation found for create_temp_file
173 #endif
174 if (file >= 0)
175 statistic_increment(my_tmp_file_created,&THR_LOCK_open);
176 DBUG_RETURN(file);
177 }
178