xref: /aoo4110/main/sal/osl/unx/tempfile.c (revision b1cdbd2c)
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 
osl_getTempDirURL(rtl_uString ** pustrTempDir)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 
osl_gen_random_name_impl_(rtl_uString ** rand_name)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 
osl_setup_base_directory_impl_(rtl_uString * pustrDirectoryURL,rtl_uString ** ppustr_base_dir)137 static oslFileError osl_setup_base_directory_impl_(
138 	rtl_uString*  pustrDirectoryURL,
139 	rtl_uString** ppustr_base_dir)
140 {
141 	rtl_uString* dir_url = 0;
142 	rtl_uString* dir     = 0;
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 
osl_setup_createTempFile_impl_(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL,rtl_uString ** ppustr_base_dir,sal_Bool * b_delete_on_close)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(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!");
180 
181 	if ((0 == pHandle) && (0 == ppustrTempFileURL))
182 	{
183 		osl_error = osl_File_E_INVAL;
184 	}
185 	else
186 	{
187 		osl_error = osl_setup_base_directory_impl_(
188 			pustrDirectoryURL, ppustr_base_dir);
189 
190 		*b_delete_on_close = (0 == ppustrTempFileURL);
191 	}
192 
193 	return osl_error;
194  }
195 
196 /*****************************************************************
197  * Create a unique file in the specified directory and return
198  * it's name
199  ****************************************************************/
200 
osl_create_temp_file_impl_(const rtl_uString * pustr_base_directory,oslFileHandle * file_handle,rtl_uString ** ppustr_temp_file_name)201 static oslFileError osl_create_temp_file_impl_(
202 	const rtl_uString* pustr_base_directory,
203 	oslFileHandle* file_handle,
204 	rtl_uString** ppustr_temp_file_name)
205 {
206 	rtl_uString*        rand_name        = 0;
207 	sal_uInt32          len_base_dir     = 0;
208 	rtl_uString*        tmp_file_path    = 0;
209 	rtl_uString*        tmp_file_url     = 0;
210 	sal_Int32           capacity         = 0;
211 	oslFileError        osl_error        = osl_File_E_None;
212 	sal_Int32           offset_file_name;
213 	const sal_Unicode*  puchr;
214 
215 	OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
216 	OSL_PRECOND(file_handle, "Invalid Parameter");
217 	OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
218 
219 	len_base_dir = rtl_uString_getLength(pustr_base_directory);
220 
221 	rtl_uStringbuffer_newFromStr_WithLength(
222 		&tmp_file_path,
223 		rtl_uString_getStr((rtl_uString*)pustr_base_directory),
224 		len_base_dir);
225 
226 	rtl_uStringbuffer_ensureCapacity(
227 		&tmp_file_path,
228 		&capacity,
229 		(len_base_dir + 1 + RAND_NAME_LENGTH));
230 
231 	offset_file_name = len_base_dir;
232 
233 	puchr = rtl_uString_getStr(tmp_file_path);
234 
235 	/* ensure that the last character is a '/' */
236 
237 	if ((sal_Unicode)'/' != puchr[len_base_dir - 1])
238 	{
239 		rtl_uStringbuffer_insert_ascii(
240 			&tmp_file_path,
241 			&capacity,
242 			len_base_dir,
243 			"/",
244 			1);
245 
246 		offset_file_name++;
247 	}
248 
249 	while(1) /* try until success */
250 	{
251 		osl_gen_random_name_impl_(&rand_name);
252 
253 		rtl_uStringbuffer_insert(
254 			&tmp_file_path,
255 			&capacity,
256 			offset_file_name,
257 			rtl_uString_getStr(rand_name),
258 			rtl_uString_getLength(rand_name));
259 
260 		osl_error = osl_getFileURLFromSystemPath(
261 		    tmp_file_path, &tmp_file_url);
262 
263 		if (osl_File_E_None == osl_error)
264 		{
265 		    /* RW permission for the user only! */
266 		    mode_t old_mode = umask(077);
267 
268 		    osl_error = osl_openFile(
269 			    tmp_file_url,
270 			    file_handle,
271 			    osl_File_OpenFlag_Read |
272 			    osl_File_OpenFlag_Write |
273 			    osl_File_OpenFlag_Create);
274 
275 			umask(old_mode);
276 		}
277 
278 		/* in case of error osl_File_E_EXIST we simply try again else we give up */
279 
280 		if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
281 		{
282 			if (rand_name)
283 				rtl_uString_release(rand_name);
284 
285 			if (tmp_file_url)
286 				rtl_uString_release(tmp_file_url);
287 
288 			break;
289 		}
290 	} /* while(1) */
291 
292 	if (osl_File_E_None == osl_error)
293 		rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
294 
295 	if (tmp_file_path)
296 		rtl_uString_release(tmp_file_path);
297 
298 	return osl_error;
299 }
300 
301 /*****************************************************************
302  * osl_createTempFile
303  *****************************************************************/
304 
osl_createTempFile(rtl_uString * pustrDirectoryURL,oslFileHandle * pHandle,rtl_uString ** ppustrTempFileURL)305 oslFileError SAL_CALL osl_createTempFile(
306 	rtl_uString*   pustrDirectoryURL,
307 	oslFileHandle* pHandle,
308 	rtl_uString**  ppustrTempFileURL)
309 {
310 	rtl_uString*  base_directory     = 0;
311 	rtl_uString*  temp_file_name     = 0;
312 	oslFileHandle temp_file_handle;
313 	sal_Bool      b_delete_on_close;
314 	oslFileError  osl_error;
315 
316 	osl_error = osl_setup_createTempFile_impl_(
317 		pustrDirectoryURL,
318 		pHandle,
319 		ppustrTempFileURL,
320 		&base_directory,
321 		&b_delete_on_close);
322 
323 	if (osl_File_E_None != osl_error)
324 		return osl_error;
325 
326 	osl_error = osl_create_temp_file_impl_(
327 	    base_directory, &temp_file_handle, &temp_file_name);
328 
329 	if (osl_File_E_None == osl_error)
330 	{
331 		rtl_uString* temp_file_url = 0;
332 
333 		/* assuming this works */
334 		osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
335 
336 		if (b_delete_on_close)
337 		{
338 			osl_error = osl_removeFile(temp_file_url);
339 
340 			if (osl_File_E_None == osl_error)
341 				*pHandle = temp_file_handle;
342 			else
343 				osl_closeFile(temp_file_handle);
344 		}
345 		else
346 		{
347 			if (pHandle)
348 				*pHandle = temp_file_handle;
349 			else
350 				osl_closeFile(temp_file_handle);
351 
352 			rtl_uString_assign(ppustrTempFileURL, temp_file_url);
353         }
354 
355 		if (temp_file_url)
356 			rtl_uString_release(temp_file_url);
357 
358         if (temp_file_name)
359             rtl_uString_release(temp_file_name);
360 	}
361 
362     if (base_directory)
363     	rtl_uString_release(base_directory);
364 
365     return osl_error;
366 }
367