xref: /trunk/main/sal/osl/os2/tempfile.c (revision cdf0e10c4e3984b49a9502b011690b615761d4a3) !
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     const char *pValue = getenv( "TEMP" );
54 
55     if ( !pValue )
56     {
57         pValue = getenv( "TMP" );
58 #if defined(SOLARIS) || defined (LINUX) || defined (FREEBSD) || defined (MACOSX)
59         if ( !pValue )
60             pValue = P_tmpdir;
61 #endif
62     }
63 
64     if ( pValue )
65     {
66         oslFileError error;
67         rtl_uString *ustrTempPath = NULL;
68 
69         rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
70         OSL_ASSERT(ustrTempPath != NULL);
71         error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
72         rtl_uString_release( ustrTempPath );
73 
74         return error;
75     }
76     else
77         return osl_File_E_NOENT;
78 }
79 
80 /******************************************************************
81  * Generates a random unique file name. We're using the scheme
82  * from the standard c-lib function mkstemp to generate a more
83  * or less random unique file name
84  *
85  * @param rand_name
86  *        receives the random name
87  ******************************************************************/
88 
89 static const char LETTERS[]        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
90 static const int  COUNT_OF_LETTERS = sizeof(LETTERS)/sizeof(LETTERS[0]) - 1;
91 
92 #define RAND_NAME_LENGTH 6
93 
94 static void osl_gen_random_name_impl_(rtl_uString** rand_name)
95 {
96     static uint64_t value;
97 
98     char     buffer[RAND_NAME_LENGTH];
99     struct   timeval tv;
100     uint64_t v;
101     int      i;
102 
103     gettimeofday(&tv, NULL);
104 
105     value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
106 
107     v = value;
108 
109     for (i = 0; i < RAND_NAME_LENGTH; i++)
110     {
111         buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
112         v        /= COUNT_OF_LETTERS;
113     }
114 
115     rtl_string2UString(
116             rand_name,
117             buffer,
118             RAND_NAME_LENGTH,
119             RTL_TEXTENCODING_ASCII_US,
120             OSTRING_TO_OUSTRING_CVTFLAGS);
121     OSL_ASSERT(*rand_name != NULL);
122 }
123 
124 /*****************************************************************
125  * Helper function
126  * Either use the directory provided or the result of
127  * osl_getTempDirUrl and return it as system path and file url
128  ****************************************************************/
129 
130 static oslFileError osl_setup_base_directory_impl_(
131     rtl_uString*  pustrDirectoryURL,
132     rtl_uString** ppustr_base_dir)
133 {
134     rtl_uString* dir_url = 0;
135     rtl_uString* dir     = 0;
136     oslFileError error   = osl_File_E_None;
137 
138     if (pustrDirectoryURL)
139         rtl_uString_assign(&dir_url, pustrDirectoryURL);
140     else
141         error = osl_getTempDirURL(&dir_url);
142 
143     if (osl_File_E_None == error)
144     {
145         error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE);
146         rtl_uString_release(dir_url);
147     }
148 
149     if (osl_File_E_None == error)
150     {
151         rtl_uString_assign(ppustr_base_dir, dir);
152         rtl_uString_release(dir);
153     }
154 
155     return error;
156 }
157 
158 /*****************************************************************
159  * osl_setup_createTempFile_impl
160  * validate input parameter, setup variables
161  ****************************************************************/
162 
163  static oslFileError osl_setup_createTempFile_impl_(
164     rtl_uString*   pustrDirectoryURL,
165     oslFileHandle* pHandle,
166     rtl_uString**  ppustrTempFileURL,
167     rtl_uString**  ppustr_base_dir,
168     sal_Bool*      b_delete_on_close)
169  {
170     oslFileError osl_error;
171 
172     OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!");
173 
174     if ((0 == pHandle) && (0 == ppustrTempFileURL))
175     {
176         osl_error = osl_File_E_INVAL;
177     }
178     else
179     {
180         osl_error = osl_setup_base_directory_impl_(
181             pustrDirectoryURL, ppustr_base_dir);
182 
183         *b_delete_on_close = (0 == ppustrTempFileURL);
184     }
185 
186     return osl_error;
187  }
188 
189 /*****************************************************************
190  * Create a unique file in the specified directory and return
191  * it's name
192  ****************************************************************/
193 
194 static oslFileError osl_create_temp_file_impl_(
195     const rtl_uString* pustr_base_directory,
196     oslFileHandle* file_handle,
197     rtl_uString** ppustr_temp_file_name)
198 {
199     rtl_uString*        rand_name        = 0;
200     sal_uInt32          len_base_dir     = 0;
201     rtl_uString*        tmp_file_path    = 0;
202     rtl_uString*        tmp_file_url     = 0;
203     sal_Int32           capacity         = 0;
204     oslFileError        osl_error        = osl_File_E_None;
205     sal_Int32           offset_file_name;
206     const sal_Unicode*  puchr;
207 
208     OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
209     OSL_PRECOND(file_handle, "Invalid Parameter");
210     OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
211 
212     len_base_dir = rtl_uString_getLength(pustr_base_directory);
213 
214     rtl_uStringbuffer_newFromStr_WithLength(
215         &tmp_file_path,
216         rtl_uString_getStr((rtl_uString*)pustr_base_directory),
217         len_base_dir);
218 
219     rtl_uStringbuffer_ensureCapacity(
220         &tmp_file_path,
221         &capacity,
222         (len_base_dir + 1 + RAND_NAME_LENGTH));
223 
224     offset_file_name = len_base_dir;
225 
226     puchr = rtl_uString_getStr(tmp_file_path);
227 
228     /* ensure that the last character is a '\' */
229 
230     if ((sal_Unicode)'\\' != puchr[len_base_dir - 1])
231     {
232         rtl_uStringbuffer_insert_ascii(
233             &tmp_file_path,
234             &capacity,
235             len_base_dir,
236             "\\",
237             1);
238 
239         offset_file_name++;
240     }
241 
242     while(1) /* try until success */
243     {
244         osl_gen_random_name_impl_(&rand_name);
245 
246         rtl_uStringbuffer_insert(
247             &tmp_file_path,
248             &capacity,
249             offset_file_name,
250             rtl_uString_getStr(rand_name),
251             rtl_uString_getLength(rand_name));
252 
253         osl_error = osl_getFileURLFromSystemPath(
254             tmp_file_path, &tmp_file_url);
255 
256         if (osl_File_E_None == osl_error)
257         {
258             /* RW permission for the user only! */
259             mode_t old_mode = umask(077);
260 
261             osl_error = osl_openFile(
262                 tmp_file_url,
263                 file_handle,
264                 osl_File_OpenFlag_Read |
265                 osl_File_OpenFlag_Write |
266                 osl_File_OpenFlag_Create);
267 
268             umask(old_mode);
269         }
270 
271         /* in case of error osl_File_E_EXIST we simply try again else we give up */
272 
273         if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
274         {
275             if (rand_name)
276                 rtl_uString_release(rand_name);
277 
278             if (tmp_file_url)
279                 rtl_uString_release(tmp_file_url);
280 
281             break;
282         }
283     } /* while(1) */
284 
285     if (osl_File_E_None == osl_error)
286         rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
287 
288     if (tmp_file_path)
289         rtl_uString_release(tmp_file_path);
290 
291     return osl_error;
292 }
293 
294 /*****************************************************************
295  * osl_createTempFile
296  *****************************************************************/
297 
298 oslFileError SAL_CALL osl_createTempFile(
299     rtl_uString*   pustrDirectoryURL,
300     oslFileHandle* pHandle,
301     rtl_uString**  ppustrTempFileURL)
302 {
303     rtl_uString*  base_directory     = 0;
304     rtl_uString*  temp_file_name     = 0;
305     oslFileHandle temp_file_handle;
306     sal_Bool      b_delete_on_close;
307     oslFileError  osl_error;
308 
309     osl_error = osl_setup_createTempFile_impl_(
310         pustrDirectoryURL,
311         pHandle,
312         ppustrTempFileURL,
313         &base_directory,
314         &b_delete_on_close);
315 
316     if (osl_File_E_None != osl_error)
317         return osl_error;
318 
319     osl_error = osl_create_temp_file_impl_(
320         base_directory, &temp_file_handle, &temp_file_name);
321 
322     if (osl_File_E_None == osl_error)
323     {
324         rtl_uString* temp_file_url = 0;
325 
326         /* assuming this works */
327         osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
328 
329         if (b_delete_on_close)
330         {
331             osl_error = osl_removeFile(temp_file_url);
332 
333             if (osl_File_E_None == osl_error)
334                 *pHandle = temp_file_handle;
335             else
336                 osl_closeFile(temp_file_handle);
337         }
338         else
339         {
340             if (pHandle)
341                 *pHandle = temp_file_handle;
342             else
343                 osl_closeFile(temp_file_handle);
344 
345             rtl_uString_assign(ppustrTempFileURL, temp_file_url);
346         }
347 
348         if (temp_file_url)
349             rtl_uString_release(temp_file_url);
350 
351         if (temp_file_name)
352             rtl_uString_release(temp_file_name);
353     }
354 
355     if (base_directory)
356         rtl_uString_release(base_directory);
357 
358     return osl_error;
359 }
360