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