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 = 0;
142 rtl_uString* dir = 0;
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(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!");
180
181 if ((0 == pHandle) && (0 == ppustrTempFileURL))
182 {
183 osl_error = osl_File_E_INVAL;
184 }
185 else
186 {
187 osl_error = osl_setup_base_directory_impl_(
188 pustrDirectoryURL, ppustr_base_dir);
189
190 *b_delete_on_close = (0 == ppustrTempFileURL);
191 }
192
193 return osl_error;
194 }
195
196 /*****************************************************************
197 * Create a unique file in the specified directory and return
198 * it's name
199 ****************************************************************/
200
osl_create_temp_file_impl_(const rtl_uString * pustr_base_directory,oslFileHandle * file_handle,rtl_uString ** ppustr_temp_file_name)201 static oslFileError osl_create_temp_file_impl_(
202 const rtl_uString* pustr_base_directory,
203 oslFileHandle* file_handle,
204 rtl_uString** ppustr_temp_file_name)
205 {
206 rtl_uString* rand_name = 0;
207 sal_uInt32 len_base_dir = 0;
208 rtl_uString* tmp_file_path = 0;
209 rtl_uString* tmp_file_url = 0;
210 sal_Int32 capacity = 0;
211 oslFileError osl_error = osl_File_E_None;
212 sal_Int32 offset_file_name;
213 const sal_Unicode* puchr;
214
215 OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
216 OSL_PRECOND(file_handle, "Invalid Parameter");
217 OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
218
219 len_base_dir = rtl_uString_getLength(pustr_base_directory);
220
221 rtl_uStringbuffer_newFromStr_WithLength(
222 &tmp_file_path,
223 rtl_uString_getStr((rtl_uString*)pustr_base_directory),
224 len_base_dir);
225
226 rtl_uStringbuffer_ensureCapacity(
227 &tmp_file_path,
228 &capacity,
229 (len_base_dir + 1 + RAND_NAME_LENGTH));
230
231 offset_file_name = len_base_dir;
232
233 puchr = rtl_uString_getStr(tmp_file_path);
234
235 /* ensure that the last character is a '/' */
236
237 if ((sal_Unicode)'/' != puchr[len_base_dir - 1])
238 {
239 rtl_uStringbuffer_insert_ascii(
240 &tmp_file_path,
241 &capacity,
242 len_base_dir,
243 "/",
244 1);
245
246 offset_file_name++;
247 }
248
249 while(1) /* try until success */
250 {
251 osl_gen_random_name_impl_(&rand_name);
252
253 rtl_uStringbuffer_insert(
254 &tmp_file_path,
255 &capacity,
256 offset_file_name,
257 rtl_uString_getStr(rand_name),
258 rtl_uString_getLength(rand_name));
259
260 osl_error = osl_getFileURLFromSystemPath(
261 tmp_file_path, &tmp_file_url);
262
263 if (osl_File_E_None == osl_error)
264 {
265 /* RW permission for the user only! */
266 mode_t old_mode = umask(077);
267
268 osl_error = osl_openFile(
269 tmp_file_url,
270 file_handle,
271 osl_File_OpenFlag_Read |
272 osl_File_OpenFlag_Write |
273 osl_File_OpenFlag_Create);
274
275 umask(old_mode);
276 }
277
278 /* in case of error osl_File_E_EXIST we simply try again else we give up */
279
280 if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
281 {
282 if (rand_name)
283 rtl_uString_release(rand_name);
284
285 if (tmp_file_url)
286 rtl_uString_release(tmp_file_url);
287
288 break;
289 }
290 } /* while(1) */
291
292 if (osl_File_E_None == osl_error)
293 rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
294
295 if (tmp_file_path)
296 rtl_uString_release(tmp_file_path);
297
298 return osl_error;
299 }
300
301 /*****************************************************************
302 * osl_createTempFile
303 *****************************************************************/
304
osl_createTempFile(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL)305 oslFileError SAL_CALL osl_createTempFile(
306 rtl_uString* pustrDirectoryURL,
307 oslFileHandle* pHandle,
308 rtl_uString** ppustrTempFileURL)
309 {
310 rtl_uString* base_directory = 0;
311 rtl_uString* temp_file_name = 0;
312 oslFileHandle temp_file_handle;
313 sal_Bool b_delete_on_close;
314 oslFileError osl_error;
315
316 osl_error = osl_setup_createTempFile_impl_(
317 pustrDirectoryURL,
318 pHandle,
319 ppustrTempFileURL,
320 &base_directory,
321 &b_delete_on_close);
322
323 if (osl_File_E_None != osl_error)
324 return osl_error;
325
326 osl_error = osl_create_temp_file_impl_(
327 base_directory, &temp_file_handle, &temp_file_name);
328
329 if (osl_File_E_None == osl_error)
330 {
331 rtl_uString* temp_file_url = 0;
332
333 /* assuming this works */
334 osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
335
336 if (b_delete_on_close)
337 {
338 osl_error = osl_removeFile(temp_file_url);
339
340 if (osl_File_E_None == osl_error)
341 *pHandle = temp_file_handle;
342 else
343 osl_closeFile(temp_file_handle);
344 }
345 else
346 {
347 if (pHandle)
348 *pHandle = temp_file_handle;
349 else
350 osl_closeFile(temp_file_handle);
351
352 rtl_uString_assign(ppustrTempFileURL, temp_file_url);
353 }
354
355 if (temp_file_url)
356 rtl_uString_release(temp_file_url);
357
358 if (temp_file_name)
359 rtl_uString_release(temp_file_name);
360 }
361
362 if (base_directory)
363 rtl_uString_release(base_directory);
364
365 return osl_error;
366 }
367