1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 /*****************************************************************/
25 /* Includes */
26 /*****************************************************************/
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include "system.h"
34 #include <osl/file.h>
35 #include <osl/thread.h>
36 #include <rtl/ustrbuf.h>
37 #include <osl/diagnose.h>
38
39 #ifndef _FILE_URL_H_
40 #include "file_url.h"
41 #endif
42
43 /*****************************************************************/
44 /* osl_getTempFirURL */
45 /*****************************************************************/
46
osl_getTempDirURL(rtl_uString ** pustrTempDir)47 oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir )
48 {
49 const char *pValue = getenv( "TEMP" );
50
51 if ( !pValue )
52 {
53 pValue = getenv( "TMP" );
54 #if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD) || defined (MACOSX)
55 if ( !pValue )
56 pValue = P_tmpdir;
57 #endif
58 }
59
60 if ( pValue )
61 {
62 oslFileError error;
63 rtl_uString *ustrTempPath = NULL;
64
65 rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
66 OSL_ASSERT(ustrTempPath != NULL);
67 error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
68 rtl_uString_release( ustrTempPath );
69
70 return error;
71 }
72 else
73 return osl_File_E_NOENT;
74 }
75
76 /******************************************************************
77 * Generates a random unique file name. We're using the scheme
78 * from the standard c-lib function mkstemp to generate a more
79 * or less random unique file name
80 *
81 * @param rand_name
82 * receives the random name
83 ******************************************************************/
84
85 static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
86 static const int COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1;
87
88 #define RAND_NAME_LENGTH 6
89
osl_gen_random_name_impl_(rtl_uString ** rand_name)90 static void osl_gen_random_name_impl_(rtl_uString** rand_name)
91 {
92 static uint64_t value;
93
94 char buffer[RAND_NAME_LENGTH];
95 struct timeval tv;
96 uint64_t v;
97 int i;
98
99 gettimeofday(&tv, NULL);
100
101 value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
102
103 v = value;
104
105 for (i = 0; i < RAND_NAME_LENGTH; i++)
106 {
107 buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
108 v /= COUNT_OF_LETTERS;
109 }
110
111 rtl_string2UString(
112 rand_name,
113 buffer,
114 RAND_NAME_LENGTH,
115 RTL_TEXTENCODING_ASCII_US,
116 OSTRING_TO_OUSTRING_CVTFLAGS);
117 OSL_ASSERT(*rand_name != NULL);
118 }
119
120 /*****************************************************************
121 * Helper function
122 * Either use the directory provided or the result of
123 * osl_getTempDirUrl and return it as system path and file url
124 ****************************************************************/
125
osl_setup_base_directory_impl_(rtl_uString * pustrDirectoryURL,rtl_uString ** ppustr_base_dir)126 static oslFileError osl_setup_base_directory_impl_(
127 rtl_uString* pustrDirectoryURL,
128 rtl_uString** ppustr_base_dir)
129 {
130 rtl_uString* dir_url = NULL;
131 rtl_uString* dir = NULL;
132 oslFileError error = osl_File_E_None;
133
134 if (pustrDirectoryURL)
135 rtl_uString_assign(&dir_url, pustrDirectoryURL);
136 else
137 error = osl_getTempDirURL(&dir_url);
138
139 if (osl_File_E_None == error)
140 {
141 error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE);
142 rtl_uString_release(dir_url);
143 }
144
145 if (osl_File_E_None == error)
146 {
147 rtl_uString_assign(ppustr_base_dir, dir);
148 rtl_uString_release(dir);
149 }
150
151 return error;
152 }
153
154 /*****************************************************************
155 * osl_setup_createTempFile_impl
156 * validate input parameter, setup variables
157 ****************************************************************/
158
osl_setup_createTempFile_impl_(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL,rtl_uString ** ppustr_base_dir,sal_Bool * b_delete_on_close)159 static oslFileError osl_setup_createTempFile_impl_(
160 rtl_uString* pustrDirectoryURL,
161 oslFileHandle* pHandle,
162 rtl_uString** ppustrTempFileURL,
163 rtl_uString** ppustr_base_dir,
164 sal_Bool* b_delete_on_close)
165 {
166 oslFileError osl_error;
167
168 OSL_PRECOND(((NULL != pHandle) || (NULL != ppustrTempFileURL)),
169 "Invalid parameter!");
170
171 if ((NULL == pHandle) && (NULL == ppustrTempFileURL))
172 {
173 osl_error = osl_File_E_INVAL;
174 }
175 else
176 {
177 osl_error = osl_setup_base_directory_impl_(
178 pustrDirectoryURL, ppustr_base_dir);
179
180 *b_delete_on_close = (NULL == ppustrTempFileURL);
181 }
182
183 return osl_error;
184 }
185
186 /*****************************************************************
187 * Create a unique file in the specified directory and return
188 * it's name
189 ****************************************************************/
190
osl_create_temp_file_impl_(const rtl_uString * pustr_base_directory,oslFileHandle * file_handle,rtl_uString ** ppustr_temp_file_name)191 static oslFileError osl_create_temp_file_impl_(
192 const rtl_uString* pustr_base_directory,
193 oslFileHandle* file_handle,
194 rtl_uString** ppustr_temp_file_name)
195 {
196 rtl_uString* rand_name = NULL;
197 sal_uInt32 len_base_dir = 0;
198 rtl_uString* tmp_file_path = NULL;
199 rtl_uString* tmp_file_url = NULL;
200 sal_Int32 capacity = 0;
201 oslFileError osl_error = osl_File_E_None;
202 sal_Int32 offset_file_name;
203 const sal_Unicode* puchr;
204
205 OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
206 OSL_PRECOND(file_handle, "Invalid Parameter");
207 OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
208
209 len_base_dir = rtl_uString_getLength(pustr_base_directory);
210
211 rtl_uStringbuffer_newFromStr_WithLength(
212 &tmp_file_path,
213 rtl_uString_getStr((rtl_uString*)pustr_base_directory),
214 len_base_dir);
215
216 rtl_uStringbuffer_ensureCapacity(
217 &tmp_file_path,
218 &capacity,
219 (len_base_dir + 1 + RAND_NAME_LENGTH));
220
221 offset_file_name = len_base_dir;
222
223 puchr = rtl_uString_getStr(tmp_file_path);
224
225 /* ensure that the last character is a '\' */
226
227 if ((sal_Unicode)'\\' != puchr[len_base_dir - 1])
228 {
229 rtl_uStringbuffer_insert_ascii(
230 &tmp_file_path,
231 &capacity,
232 len_base_dir,
233 "\\",
234 1);
235
236 offset_file_name++;
237 }
238
239 while(1) /* try until success */
240 {
241 osl_gen_random_name_impl_(&rand_name);
242
243 rtl_uStringbuffer_insert(
244 &tmp_file_path,
245 &capacity,
246 offset_file_name,
247 rtl_uString_getStr(rand_name),
248 rtl_uString_getLength(rand_name));
249
250 osl_error = osl_getFileURLFromSystemPath(
251 tmp_file_path, &tmp_file_url);
252
253 if (osl_File_E_None == osl_error)
254 {
255 /* RW permission for the user only! */
256 mode_t old_mode = umask(077);
257
258 osl_error = osl_openFile(
259 tmp_file_url,
260 file_handle,
261 osl_File_OpenFlag_Read |
262 osl_File_OpenFlag_Write |
263 osl_File_OpenFlag_Create);
264
265 umask(old_mode);
266 }
267
268 /* in case of error osl_File_E_EXIST we simply try again else we give up */
269
270 if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
271 {
272 if (rand_name)
273 rtl_uString_release(rand_name);
274
275 if (tmp_file_url)
276 rtl_uString_release(tmp_file_url);
277
278 break;
279 }
280 } /* while(1) */
281
282 if (osl_File_E_None == osl_error)
283 rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
284
285 if (tmp_file_path)
286 rtl_uString_release(tmp_file_path);
287
288 return osl_error;
289 }
290
291 /*****************************************************************
292 * osl_createTempFile
293 *****************************************************************/
294
osl_createTempFile(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL)295 oslFileError SAL_CALL osl_createTempFile(
296 rtl_uString* pustrDirectoryURL,
297 oslFileHandle* pHandle,
298 rtl_uString** ppustrTempFileURL)
299 {
300 rtl_uString* base_directory = NULL;
301 rtl_uString* temp_file_name = NULL;
302 oslFileHandle temp_file_handle;
303 sal_Bool b_delete_on_close;
304 oslFileError osl_error;
305
306 osl_error = osl_setup_createTempFile_impl_(
307 pustrDirectoryURL,
308 pHandle,
309 ppustrTempFileURL,
310 &base_directory,
311 &b_delete_on_close);
312
313 if (osl_File_E_None != osl_error)
314 return osl_error;
315
316 osl_error = osl_create_temp_file_impl_(
317 base_directory, &temp_file_handle, &temp_file_name);
318
319 if (osl_File_E_None == osl_error)
320 {
321 rtl_uString* temp_file_url = NULL;
322
323 /* assuming this works */
324 osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
325
326 if (b_delete_on_close)
327 {
328 osl_error = osl_removeFile(temp_file_url);
329
330 if (osl_File_E_None == osl_error)
331 *pHandle = temp_file_handle;
332 else
333 osl_closeFile(temp_file_handle);
334 }
335 else
336 {
337 if (pHandle)
338 *pHandle = temp_file_handle;
339 else
340 osl_closeFile(temp_file_handle);
341
342 rtl_uString_assign(ppustrTempFileURL, temp_file_url);
343 }
344
345 if (temp_file_url)
346 rtl_uString_release(temp_file_url);
347
348 if (temp_file_name)
349 rtl_uString_release(temp_file_name);
350 }
351
352 if (base_directory)
353 rtl_uString_release(base_directory);
354
355 return osl_error;
356 }
357