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