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