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