xref: /trunk/main/sal/osl/unx/tempfile.c (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 /*****************************************************************/
29 /* Includes                                                      */
30 /*****************************************************************/
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include "system.h"
38 #include <osl/file.h>
39 #include <osl/thread.h>
40 #include <rtl/ustrbuf.h>
41 #include <osl/diagnose.h>
42 
43 #ifndef _FILE_URL_H_
44 #include "file_url.h"
45 #endif
46 
47 /*****************************************************************/
48 /* osl_getTempFirURL                                             */
49 /*****************************************************************/
50 
51 oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir )
52 {
53 #ifdef MACOSX
54     const char *pValue = getenv( "TMPDIR" );
55 
56     /* If TMPDIR environment variable is not set, use "/tmp" instead
57        of P_tmpdir because its value is "/var/tmp" and it is not
58        deleted on system start up */
59     if ( !pValue )
60         pValue = "/tmp";
61 #else
62 
63     const char *pValue = getenv( "TEMP" );
64 
65     if ( !pValue )
66     {
67         pValue = getenv( "TMP" );
68 #if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD)
69         if ( !pValue )
70             pValue = P_tmpdir;
71 #endif
72     }
73 #endif /* MACOSX */
74 
75     if ( pValue )
76     {
77         oslFileError error;
78         rtl_uString *ustrTempPath = NULL;
79 
80         rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
81         OSL_ASSERT(ustrTempPath != NULL);
82         error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
83         rtl_uString_release( ustrTempPath );
84 
85         return error;
86     }
87     else
88         return osl_File_E_NOENT;
89 }
90 
91 /******************************************************************
92  * Generates a random unique file name. We're using the scheme
93  * from the standard c-lib function mkstemp to generate a more
94  * or less random unique file name
95  *
96  * @param rand_name
97  *        receives the random name
98  ******************************************************************/
99 
100 static const char LETTERS[]        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
101 static const int  COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1;
102 
103 #define RAND_NAME_LENGTH 6
104 
105 static void osl_gen_random_name_impl_(rtl_uString** rand_name)
106 {
107     static uint64_t value;
108 
109     char     buffer[RAND_NAME_LENGTH];
110     struct   timeval tv;
111     uint64_t v;
112     int      i;
113 
114     gettimeofday(&tv, NULL);
115 
116     value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
117 
118     v = value;
119 
120     for (i = 0; i < RAND_NAME_LENGTH; i++)
121     {
122         buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
123         v        /= COUNT_OF_LETTERS;
124     }
125 
126     rtl_string2UString(
127             rand_name,
128             buffer,
129             RAND_NAME_LENGTH,
130             RTL_TEXTENCODING_ASCII_US,
131             OSTRING_TO_OUSTRING_CVTFLAGS);
132     OSL_ASSERT(*rand_name != NULL);
133 }
134 
135 /*****************************************************************
136  * Helper function
137  * Either use the directory provided or the result of
138  * osl_getTempDirUrl and return it as system path and file url
139  ****************************************************************/
140 
141 static oslFileError osl_setup_base_directory_impl_(
142     rtl_uString*  pustrDirectoryURL,
143     rtl_uString** ppustr_base_dir)
144 {
145     rtl_uString* dir_url = 0;
146     rtl_uString* dir     = 0;
147     oslFileError error   = osl_File_E_None;
148 
149     if (pustrDirectoryURL)
150         rtl_uString_assign(&dir_url, pustrDirectoryURL);
151     else
152         error = osl_getTempDirURL(&dir_url);
153 
154     if (osl_File_E_None == error)
155     {
156         error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE);
157         rtl_uString_release(dir_url);
158     }
159 
160     if (osl_File_E_None == error)
161     {
162         rtl_uString_assign(ppustr_base_dir, dir);
163         rtl_uString_release(dir);
164     }
165 
166     return error;
167 }
168 
169 /*****************************************************************
170  * osl_setup_createTempFile_impl
171  * validate input parameter, setup variables
172  ****************************************************************/
173 
174  static oslFileError osl_setup_createTempFile_impl_(
175     rtl_uString*   pustrDirectoryURL,
176     oslFileHandle* pHandle,
177     rtl_uString**  ppustrTempFileURL,
178     rtl_uString**  ppustr_base_dir,
179     sal_Bool*      b_delete_on_close)
180  {
181     oslFileError osl_error;
182 
183     OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!");
184 
185     if ((0 == pHandle) && (0 == ppustrTempFileURL))
186     {
187         osl_error = osl_File_E_INVAL;
188     }
189     else
190     {
191         osl_error = osl_setup_base_directory_impl_(
192             pustrDirectoryURL, ppustr_base_dir);
193 
194         *b_delete_on_close = (0 == ppustrTempFileURL);
195     }
196 
197     return osl_error;
198  }
199 
200 /*****************************************************************
201  * Create a unique file in the specified directory and return
202  * it's name
203  ****************************************************************/
204 
205 static oslFileError osl_create_temp_file_impl_(
206     const rtl_uString* pustr_base_directory,
207     oslFileHandle* file_handle,
208     rtl_uString** ppustr_temp_file_name)
209 {
210     rtl_uString*        rand_name        = 0;
211     sal_uInt32          len_base_dir     = 0;
212     rtl_uString*        tmp_file_path    = 0;
213     rtl_uString*        tmp_file_url     = 0;
214     sal_Int32           capacity         = 0;
215     oslFileError        osl_error        = osl_File_E_None;
216     sal_Int32           offset_file_name;
217     const sal_Unicode*  puchr;
218 
219     OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
220     OSL_PRECOND(file_handle, "Invalid Parameter");
221     OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
222 
223     len_base_dir = rtl_uString_getLength(pustr_base_directory);
224 
225     rtl_uStringbuffer_newFromStr_WithLength(
226         &tmp_file_path,
227         rtl_uString_getStr((rtl_uString*)pustr_base_directory),
228         len_base_dir);
229 
230     rtl_uStringbuffer_ensureCapacity(
231         &tmp_file_path,
232         &capacity,
233         (len_base_dir + 1 + RAND_NAME_LENGTH));
234 
235     offset_file_name = len_base_dir;
236 
237     puchr = rtl_uString_getStr(tmp_file_path);
238 
239     /* ensure that the last character is a '/' */
240 
241     if ((sal_Unicode)'/' != puchr[len_base_dir - 1])
242     {
243         rtl_uStringbuffer_insert_ascii(
244             &tmp_file_path,
245             &capacity,
246             len_base_dir,
247             "/",
248             1);
249 
250         offset_file_name++;
251     }
252 
253     while(1) /* try until success */
254     {
255         osl_gen_random_name_impl_(&rand_name);
256 
257         rtl_uStringbuffer_insert(
258             &tmp_file_path,
259             &capacity,
260             offset_file_name,
261             rtl_uString_getStr(rand_name),
262             rtl_uString_getLength(rand_name));
263 
264         osl_error = osl_getFileURLFromSystemPath(
265             tmp_file_path, &tmp_file_url);
266 
267         if (osl_File_E_None == osl_error)
268         {
269             /* RW permission for the user only! */
270             mode_t old_mode = umask(077);
271 
272             osl_error = osl_openFile(
273                 tmp_file_url,
274                 file_handle,
275                 osl_File_OpenFlag_Read |
276                 osl_File_OpenFlag_Write |
277                 osl_File_OpenFlag_Create);
278 
279             umask(old_mode);
280         }
281 
282         /* in case of error osl_File_E_EXIST we simply try again else we give up */
283 
284         if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
285         {
286             if (rand_name)
287                 rtl_uString_release(rand_name);
288 
289             if (tmp_file_url)
290                 rtl_uString_release(tmp_file_url);
291 
292             break;
293         }
294     } /* while(1) */
295 
296     if (osl_File_E_None == osl_error)
297         rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
298 
299     if (tmp_file_path)
300         rtl_uString_release(tmp_file_path);
301 
302     return osl_error;
303 }
304 
305 /*****************************************************************
306  * osl_createTempFile
307  *****************************************************************/
308 
309 oslFileError SAL_CALL osl_createTempFile(
310     rtl_uString*   pustrDirectoryURL,
311     oslFileHandle* pHandle,
312     rtl_uString**  ppustrTempFileURL)
313 {
314     rtl_uString*  base_directory     = 0;
315     rtl_uString*  temp_file_name     = 0;
316     oslFileHandle temp_file_handle;
317     sal_Bool      b_delete_on_close;
318     oslFileError  osl_error;
319 
320     osl_error = osl_setup_createTempFile_impl_(
321         pustrDirectoryURL,
322         pHandle,
323         ppustrTempFileURL,
324         &base_directory,
325         &b_delete_on_close);
326 
327     if (osl_File_E_None != osl_error)
328         return osl_error;
329 
330     osl_error = osl_create_temp_file_impl_(
331         base_directory, &temp_file_handle, &temp_file_name);
332 
333     if (osl_File_E_None == osl_error)
334     {
335         rtl_uString* temp_file_url = 0;
336 
337         /* assuming this works */
338         osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
339 
340         if (b_delete_on_close)
341         {
342             osl_error = osl_removeFile(temp_file_url);
343 
344             if (osl_File_E_None == osl_error)
345                 *pHandle = temp_file_handle;
346             else
347                 osl_closeFile(temp_file_handle);
348         }
349         else
350         {
351             if (pHandle)
352                 *pHandle = temp_file_handle;
353             else
354                 osl_closeFile(temp_file_handle);
355 
356             rtl_uString_assign(ppustrTempFileURL, temp_file_url);
357         }
358 
359         if (temp_file_url)
360             rtl_uString_release(temp_file_url);
361 
362         if (temp_file_name)
363             rtl_uString_release(temp_file_name);
364     }
365 
366     if (base_directory)
367         rtl_uString_release(base_directory);
368 
369     return osl_error;
370 }
371