Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : /*****************************************************************/
21 : /* Includes */
22 : /*****************************************************************/
23 :
24 : #include <stdio.h>
25 : #include <stdlib.h>
26 : #include <sys/types.h>
27 : #include <sys/stat.h>
28 : #include <sys/time.h>
29 : #include "system.h"
30 : #include <osl/file.h>
31 : #include <osl/thread.h>
32 : #include <rtl/ustrbuf.h>
33 : #include <osl/diagnose.h>
34 : #include <sal/macros.h>
35 :
36 : #ifndef _FILE_URL_H_
37 : #include "file_url.h"
38 : #endif
39 :
40 2111 : oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir )
41 : {
42 : oslFileError error;
43 : /* described in environ(7) */
44 2111 : const char *pValue = getenv( "TMPDIR" );
45 2111 : rtl_uString *ustrTempPath = NULL;
46 :
47 2111 : if ( !pValue )
48 0 : pValue = getenv( "TEMP" );
49 :
50 2111 : if ( !pValue )
51 0 : pValue = getenv( "TMP" );
52 :
53 2111 : if ( !pValue )
54 0 : pValue = "/tmp";
55 :
56 2111 : rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
57 : OSL_ASSERT(ustrTempPath != NULL);
58 2111 : error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
59 2111 : rtl_uString_release( ustrTempPath );
60 :
61 2111 : return error;
62 : }
63 :
64 : /******************************************************************
65 : * Generates a random unique file name. We're using the scheme
66 : * from the standard c-lib function mkstemp to generate a more
67 : * or less random unique file name
68 : *
69 : * @param rand_name
70 : * receives the random name
71 : ******************************************************************/
72 :
73 : static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
74 : static const int COUNT_OF_LETTERS = SAL_N_ELEMENTS(LETTERS) - 1;
75 :
76 : #define RAND_NAME_LENGTH 6
77 :
78 20324 : static void osl_gen_random_name_impl_(rtl_uString** rand_name)
79 : {
80 : static uint64_t value;
81 :
82 : char buffer[RAND_NAME_LENGTH];
83 : struct timeval tv;
84 : uint64_t v;
85 : int i;
86 :
87 20324 : gettimeofday(&tv, NULL);
88 :
89 20324 : value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
90 :
91 20324 : v = value;
92 :
93 142268 : for (i = 0; i < RAND_NAME_LENGTH; i++)
94 : {
95 121944 : buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
96 121944 : v /= COUNT_OF_LETTERS;
97 : }
98 :
99 20324 : rtl_string2UString(
100 : rand_name,
101 : buffer,
102 : RAND_NAME_LENGTH,
103 : RTL_TEXTENCODING_ASCII_US,
104 : OSTRING_TO_OUSTRING_CVTFLAGS);
105 : OSL_ASSERT(*rand_name != NULL);
106 20324 : }
107 :
108 : /*****************************************************************
109 : * Helper function
110 : * Either use the directory provided or the result of
111 : * osl_getTempDirUrl and return it as system path and file url
112 : ****************************************************************/
113 :
114 20324 : static oslFileError osl_setup_base_directory_impl_(
115 : rtl_uString* pustrDirectoryURL,
116 : rtl_uString** ppustr_base_dir)
117 : {
118 20324 : rtl_uString* dir_url = 0;
119 20324 : rtl_uString* dir = 0;
120 20324 : oslFileError error = osl_File_E_None;
121 :
122 20324 : if (pustrDirectoryURL)
123 18248 : rtl_uString_assign(&dir_url, pustrDirectoryURL);
124 : else
125 2076 : error = osl_getTempDirURL(&dir_url);
126 :
127 20324 : if (osl_File_E_None == error)
128 : {
129 20324 : error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir, FURL_DENY_RELATIVE);
130 20324 : rtl_uString_release(dir_url);
131 : }
132 :
133 20324 : if (osl_File_E_None == error)
134 : {
135 20324 : rtl_uString_assign(ppustr_base_dir, dir);
136 20324 : rtl_uString_release(dir);
137 : }
138 :
139 20324 : return error;
140 : }
141 :
142 : /*****************************************************************
143 : * osl_setup_createTempFile_impl
144 : * validate input parameter, setup variables
145 : ****************************************************************/
146 :
147 20324 : static oslFileError osl_setup_createTempFile_impl_(
148 : rtl_uString* pustrDirectoryURL,
149 : oslFileHandle* pHandle,
150 : rtl_uString** ppustrTempFileURL,
151 : rtl_uString** ppustr_base_dir,
152 : sal_Bool* b_delete_on_close)
153 : {
154 : oslFileError osl_error;
155 :
156 : OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!");
157 :
158 20324 : if ((0 == pHandle) && (0 == ppustrTempFileURL))
159 : {
160 0 : osl_error = osl_File_E_INVAL;
161 : }
162 : else
163 : {
164 20324 : osl_error = osl_setup_base_directory_impl_(
165 : pustrDirectoryURL, ppustr_base_dir);
166 :
167 20324 : *b_delete_on_close = (0 == ppustrTempFileURL);
168 : }
169 :
170 20324 : return osl_error;
171 : }
172 :
173 : /*****************************************************************
174 : * Create a unique file in the specified directory and return
175 : * it's name
176 : ****************************************************************/
177 :
178 20324 : static oslFileError osl_create_temp_file_impl_(
179 : const rtl_uString* pustr_base_directory,
180 : oslFileHandle* file_handle,
181 : rtl_uString** ppustr_temp_file_name)
182 : {
183 20324 : rtl_uString* rand_name = 0;
184 20324 : sal_uInt32 len_base_dir = 0;
185 20324 : rtl_uString* tmp_file_path = 0;
186 20324 : rtl_uString* tmp_file_url = 0;
187 20324 : sal_Int32 capacity = 0;
188 20324 : oslFileError osl_error = osl_File_E_None;
189 : sal_Int32 offset_file_name;
190 : const sal_Unicode* puchr;
191 :
192 : OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
193 : OSL_PRECOND(file_handle, "Invalid Parameter");
194 : OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
195 :
196 20324 : len_base_dir = rtl_uString_getLength(pustr_base_directory);
197 :
198 40648 : rtl_uStringbuffer_newFromStr_WithLength(
199 : &tmp_file_path,
200 20324 : rtl_uString_getStr((rtl_uString*)pustr_base_directory),
201 : len_base_dir);
202 :
203 20324 : rtl_uStringbuffer_ensureCapacity(
204 : &tmp_file_path,
205 : &capacity,
206 20324 : (len_base_dir + 1 + RAND_NAME_LENGTH));
207 :
208 20324 : offset_file_name = len_base_dir;
209 :
210 20324 : puchr = rtl_uString_getStr(tmp_file_path);
211 :
212 : /* ensure that the last character is a '/' */
213 :
214 20324 : if ((sal_Unicode)'/' != puchr[len_base_dir - 1])
215 : {
216 20263 : rtl_uStringbuffer_insert_ascii(
217 : &tmp_file_path,
218 : &capacity,
219 : len_base_dir,
220 : "/",
221 : 1);
222 :
223 20263 : offset_file_name++;
224 : }
225 :
226 : while(1) /* try until success */
227 : {
228 20324 : osl_gen_random_name_impl_(&rand_name);
229 :
230 40648 : rtl_uStringbuffer_insert(
231 : &tmp_file_path,
232 : &capacity,
233 : offset_file_name,
234 20324 : rtl_uString_getStr(rand_name),
235 : rtl_uString_getLength(rand_name));
236 :
237 20324 : osl_error = osl_getFileURLFromSystemPath(
238 : tmp_file_path, &tmp_file_url);
239 :
240 20324 : if (osl_File_E_None == osl_error)
241 : {
242 : /* RW permission for the user only! */
243 20324 : mode_t old_mode = umask(077);
244 :
245 20324 : osl_error = osl_openFile(
246 : tmp_file_url,
247 : file_handle,
248 : osl_File_OpenFlag_Read |
249 : osl_File_OpenFlag_Write |
250 : osl_File_OpenFlag_Create);
251 :
252 20324 : umask(old_mode);
253 : }
254 :
255 : /* in case of error osl_File_E_EXIST we simply try again else we give up */
256 :
257 20324 : if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
258 : {
259 20324 : if (rand_name)
260 20324 : rtl_uString_release(rand_name);
261 :
262 20324 : if (tmp_file_url)
263 20324 : rtl_uString_release(tmp_file_url);
264 :
265 20324 : break;
266 : }
267 0 : } /* while(1) */
268 :
269 20324 : if (osl_File_E_None == osl_error)
270 20324 : rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
271 :
272 20324 : if (tmp_file_path)
273 20324 : rtl_uString_release(tmp_file_path);
274 :
275 20324 : return osl_error;
276 : }
277 :
278 : /*****************************************************************
279 : * osl_createTempFile
280 : *****************************************************************/
281 :
282 20324 : oslFileError SAL_CALL osl_createTempFile(
283 : rtl_uString* pustrDirectoryURL,
284 : oslFileHandle* pHandle,
285 : rtl_uString** ppustrTempFileURL)
286 : {
287 20324 : rtl_uString* base_directory = 0;
288 20324 : rtl_uString* temp_file_name = 0;
289 : oslFileHandle temp_file_handle;
290 : sal_Bool b_delete_on_close;
291 : oslFileError osl_error;
292 :
293 20324 : osl_error = osl_setup_createTempFile_impl_(
294 : pustrDirectoryURL,
295 : pHandle,
296 : ppustrTempFileURL,
297 : &base_directory,
298 : &b_delete_on_close);
299 :
300 20324 : if (osl_File_E_None != osl_error)
301 0 : return osl_error;
302 :
303 20324 : osl_error = osl_create_temp_file_impl_(
304 : base_directory, &temp_file_handle, &temp_file_name);
305 :
306 20324 : if (osl_File_E_None == osl_error)
307 : {
308 20324 : rtl_uString* temp_file_url = 0;
309 :
310 : /* assuming this works */
311 20324 : osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
312 :
313 20324 : if (b_delete_on_close)
314 : {
315 0 : osl_error = osl_removeFile(temp_file_url);
316 :
317 0 : if (osl_File_E_None == osl_error)
318 0 : *pHandle = temp_file_handle;
319 : else
320 0 : osl_closeFile(temp_file_handle);
321 : }
322 : else
323 : {
324 20324 : if (pHandle)
325 18126 : *pHandle = temp_file_handle;
326 : else
327 2198 : osl_closeFile(temp_file_handle);
328 :
329 20324 : rtl_uString_assign(ppustrTempFileURL, temp_file_url);
330 : }
331 :
332 20324 : if (temp_file_url)
333 20324 : rtl_uString_release(temp_file_url);
334 :
335 20324 : if (temp_file_name)
336 20324 : rtl_uString_release(temp_file_name);
337 : }
338 :
339 20324 : if (base_directory)
340 20324 : rtl_uString_release(base_directory);
341 :
342 20324 : return osl_error;
343 : }
344 :
345 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|