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 #ifdef MACOSX
50 const char *pValue = getenv( "TMPDIR" );
51
52 /* If TMPDIR environment variable is not set, use "/tmp" instead
53 of P_tmpdir because its value is "/var/tmp" and it is not
54 deleted on system start up */
55 if ( !pValue )
56 pValue = "/tmp";
57 #else
58
59 const char *pValue = getenv( "TEMP" );
60
61 if ( !pValue )
62 {
63 pValue = getenv( "TMP" );
64 #if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD)
65 if ( !pValue )
66 pValue = P_tmpdir;
67 #endif
68 }
69 #endif /* MACOSX */
70
71 if ( pValue )
72 {
73 oslFileError error;
74 rtl_uString *ustrTempPath = NULL;
75
76 rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
77 OSL_ASSERT(ustrTempPath != NULL);
78 error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
79 rtl_uString_release( ustrTempPath );
80
81 return error;
82 }
83 else
84 return osl_File_E_NOENT;
85 }
86
87 /******************************************************************
88 * Generates a random unique file name. We're using the scheme
89 * from the standard c-lib function mkstemp to generate a more
90 * or less random unique file name
91 *
92 * @param rand_name
93 * receives the random name
94 ******************************************************************/
95
96 static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
97 static const int COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1;
98
99 #define RAND_NAME_LENGTH 6
100
osl_gen_random_name_impl_(rtl_uString ** rand_name)101 static void osl_gen_random_name_impl_(rtl_uString** rand_name)
102 {
103 static uint64_t value;
104
105 char buffer[RAND_NAME_LENGTH];
106 struct timeval tv;
107 uint64_t v;
108 int i;
109
110 gettimeofday(&tv, NULL);
111
112 value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
113
114 v = value;
115
116 for (i = 0; i < RAND_NAME_LENGTH; i++)
117 {
118 buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
119 v /= COUNT_OF_LETTERS;
120 }
121
122 rtl_string2UString(
123 rand_name,
124 buffer,
125 RAND_NAME_LENGTH,
126 RTL_TEXTENCODING_ASCII_US,
127 OSTRING_TO_OUSTRING_CVTFLAGS);
128 OSL_ASSERT(*rand_name != NULL);
129 }
130
131 /*****************************************************************
132 * Helper function
133 * Either use the directory provided or the result of
134 * osl_getTempDirUrl and return it as system path and file url
135 ****************************************************************/
136
osl_setup_base_directory_impl_(rtl_uString * pustrDirectoryURL,rtl_uString ** ppustr_base_dir)137 static oslFileError osl_setup_base_directory_impl_(
138 rtl_uString* pustrDirectoryURL,
139 rtl_uString** ppustr_base_dir)
140 {
141 rtl_uString* dir_url = NULL;
142 rtl_uString* dir = NULL;
143 oslFileError error = osl_File_E_None;
144
145 if (pustrDirectoryURL)
146 rtl_uString_assign(&dir_url, pustrDirectoryURL);
147 else
148 error = osl_getTempDirURL(&dir_url);
149
150 if (osl_File_E_None == error)
151 {
152 error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE);
153 rtl_uString_release(dir_url);
154 }
155
156 if (osl_File_E_None == error)
157 {
158 rtl_uString_assign(ppustr_base_dir, dir);
159 rtl_uString_release(dir);
160 }
161
162 return error;
163 }
164
165 /*****************************************************************
166 * osl_setup_createTempFile_impl
167 * validate input parameter, setup variables
168 ****************************************************************/
169
osl_setup_createTempFile_impl_(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL,rtl_uString ** ppustr_base_dir,sal_Bool * b_delete_on_close)170 static oslFileError osl_setup_createTempFile_impl_(
171 rtl_uString* pustrDirectoryURL,
172 oslFileHandle* pHandle,
173 rtl_uString** ppustrTempFileURL,
174 rtl_uString** ppustr_base_dir,
175 sal_Bool* b_delete_on_close)
176 {
177 oslFileError osl_error;
178
179 OSL_PRECOND(((NULL != pHandle) || (NULL != ppustrTempFileURL)),
180 "Invalid parameter!");
181
182 if ((NULL == pHandle) && (NULL == ppustrTempFileURL))
183 {
184 osl_error = osl_File_E_INVAL;
185 }
186 else
187 {
188 osl_error = osl_setup_base_directory_impl_(
189 pustrDirectoryURL, ppustr_base_dir);
190
191 *b_delete_on_close = (NULL == ppustrTempFileURL);
192 }
193
194 return osl_error;
195 }
196
197 /*****************************************************************
198 * Create a unique file in the specified directory and return
199 * it's name
200 ****************************************************************/
201
osl_create_temp_file_impl_(const rtl_uString * pustr_base_directory,oslFileHandle * file_handle,rtl_uString ** ppustr_temp_file_name)202 static oslFileError osl_create_temp_file_impl_(
203 const rtl_uString* pustr_base_directory,
204 oslFileHandle* file_handle,
205 rtl_uString** ppustr_temp_file_name)
206 {
207 rtl_uString* rand_name = NULL;
208 sal_uInt32 len_base_dir = 0;
209 rtl_uString* tmp_file_path = NULL;
210 rtl_uString* tmp_file_url = NULL;
211 sal_Int32 capacity = 0;
212 oslFileError osl_error = osl_File_E_None;
213 sal_Int32 offset_file_name;
214 const sal_Unicode* puchr;
215
216 OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
217 OSL_PRECOND(file_handle, "Invalid Parameter");
218 OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
219
220 len_base_dir = rtl_uString_getLength(pustr_base_directory);
221
222 rtl_uStringbuffer_newFromStr_WithLength(
223 &tmp_file_path,
224 rtl_uString_getStr((rtl_uString*)pustr_base_directory),
225 len_base_dir);
226
227 rtl_uStringbuffer_ensureCapacity(
228 &tmp_file_path,
229 &capacity,
230 (len_base_dir + 1 + RAND_NAME_LENGTH));
231
232 offset_file_name = len_base_dir;
233
234 puchr = rtl_uString_getStr(tmp_file_path);
235
236 /* ensure that the last character is a '/' */
237
238 if ((sal_Unicode)'/' != puchr[len_base_dir - 1])
239 {
240 rtl_uStringbuffer_insert_ascii(
241 &tmp_file_path,
242 &capacity,
243 len_base_dir,
244 "/",
245 1);
246
247 offset_file_name++;
248 }
249
250 while(1) /* try until success */
251 {
252 osl_gen_random_name_impl_(&rand_name);
253
254 rtl_uStringbuffer_insert(
255 &tmp_file_path,
256 &capacity,
257 offset_file_name,
258 rtl_uString_getStr(rand_name),
259 rtl_uString_getLength(rand_name));
260
261 osl_error = osl_getFileURLFromSystemPath(
262 tmp_file_path, &tmp_file_url);
263
264 if (osl_File_E_None == osl_error)
265 {
266 /* RW permission for the user only! */
267 mode_t old_mode = umask(077);
268
269 osl_error = osl_openFile(
270 tmp_file_url,
271 file_handle,
272 osl_File_OpenFlag_Read |
273 osl_File_OpenFlag_Write |
274 osl_File_OpenFlag_Create);
275
276 umask(old_mode);
277 }
278
279 /* in case of error osl_File_E_EXIST we simply try again else we give up */
280
281 if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
282 {
283 if (rand_name)
284 rtl_uString_release(rand_name);
285
286 if (tmp_file_url)
287 rtl_uString_release(tmp_file_url);
288
289 break;
290 }
291 } /* while(1) */
292
293 if (osl_File_E_None == osl_error)
294 rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
295
296 if (tmp_file_path)
297 rtl_uString_release(tmp_file_path);
298
299 return osl_error;
300 }
301
302 /*****************************************************************
303 * osl_createTempFile
304 *****************************************************************/
305
osl_createTempFile(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL)306 oslFileError SAL_CALL osl_createTempFile(
307 rtl_uString* pustrDirectoryURL,
308 oslFileHandle* pHandle,
309 rtl_uString** ppustrTempFileURL)
310 {
311 rtl_uString* base_directory = NULL;
312 rtl_uString* temp_file_name = NULL;
313 oslFileHandle temp_file_handle;
314 sal_Bool b_delete_on_close;
315 oslFileError osl_error;
316
317 osl_error = osl_setup_createTempFile_impl_(
318 pustrDirectoryURL,
319 pHandle,
320 ppustrTempFileURL,
321 &base_directory,
322 &b_delete_on_close);
323
324 if (osl_File_E_None != osl_error)
325 return osl_error;
326
327 osl_error = osl_create_temp_file_impl_(
328 base_directory, &temp_file_handle, &temp_file_name);
329
330 if (osl_File_E_None == osl_error)
331 {
332 rtl_uString* temp_file_url = NULL;
333
334 /* assuming this works */
335 osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
336
337 if (b_delete_on_close)
338 {
339 osl_error = osl_removeFile(temp_file_url);
340
341 if (osl_File_E_None == osl_error)
342 *pHandle = temp_file_handle;
343 else
344 osl_closeFile(temp_file_handle);
345 }
346 else
347 {
348 if (pHandle)
349 *pHandle = temp_file_handle;
350 else
351 osl_closeFile(temp_file_handle);
352
353 rtl_uString_assign(ppustrTempFileURL, temp_file_url);
354 }
355
356 if (temp_file_url)
357 rtl_uString_release(temp_file_url);
358
359 if (temp_file_name)
360 rtl_uString_release(temp_file_name);
361 }
362
363 if (base_directory)
364 rtl_uString_release(base_directory);
365
366 return osl_error;
367 }
368