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-1301 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 | |
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, 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 | { |
114 | char prefix_buff[30]; |
115 | uint pfx_len; |
116 | File org_file; |
117 | |
118 | pfx_len= (uint) (strmov(strnmov(prefix_buff, |
119 | prefix ? prefix : "tmp." , |
120 | sizeof(prefix_buff)-7),"XXXXXX" ) - |
121 | prefix_buff); |
122 | if (!dir && ! (dir =getenv("TMPDIR" ))) |
123 | dir= DEFAULT_TMPDIR; |
124 | if (strlen(dir)+ pfx_len > FN_REFLEN-2) |
125 | { |
126 | errno=my_errno= ENAMETOOLONG; |
127 | DBUG_RETURN(file); |
128 | } |
129 | strmov(convert_dirname(to,dir,NullS),prefix_buff); |
130 | org_file=mkstemp(to); |
131 | if (org_file >= 0 && (MyFlags & MY_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 | ME_NOINPUT)); |
141 | my_errno=tmp; |
142 | } |
143 | } |
144 | #else |
145 | #error No implementation found for create_temp_file |
146 | #endif |
147 | if (file >= 0) |
148 | statistic_increment(my_tmp_file_created,&THR_LOCK_open); |
149 | DBUG_RETURN(file); |
150 | } |
151 | |