xref: /trunk/main/sal/osl/unx/tempfile.c (revision d2992cc17a5536db9d9cad92e33116a6ace952cf)
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 
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 
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 
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 
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 
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 
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