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