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 : #include <stdio.h>
21 : #include <stdlib.h>
22 : #include <sys/types.h>
23 : #include <sys/stat.h>
24 : #include <sys/time.h>
25 : #include "system.hxx"
26 : #include <osl/file.h>
27 : #include <osl/thread.h>
28 : #include <rtl/ustrbuf.h>
29 : #include <osl/diagnose.h>
30 : #include <sal/macros.h>
31 :
32 : #include "file_url.hxx"
33 : #include "file_impl.hxx"
34 :
35 1627 : oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir )
36 : {
37 : oslFileError error;
38 : /* described in environ(7) */
39 1627 : const char *pValue = getenv( "TMPDIR" );
40 1627 : rtl_uString *ustrTempPath = NULL;
41 :
42 1627 : if ( !pValue )
43 0 : pValue = getenv( "TEMP" );
44 :
45 1627 : if ( !pValue )
46 0 : pValue = getenv( "TMP" );
47 :
48 1627 : if ( !pValue )
49 0 : pValue = "/tmp";
50 :
51 1627 : rtl_string2UString( &ustrTempPath, pValue, strlen( pValue ), osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
52 : OSL_ASSERT(ustrTempPath != NULL);
53 1627 : error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
54 1627 : rtl_uString_release( ustrTempPath );
55 :
56 1627 : return error;
57 : }
58 :
59 : /******************************************************************
60 : * Generates a random unique file name. We're using the scheme
61 : * from the standard c-lib function mkstemp to generate a more
62 : * or less random unique file name
63 : *
64 : * @param rand_name
65 : * receives the random name
66 : ******************************************************************/
67 :
68 : static const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
69 : static const int COUNT_OF_LETTERS = SAL_N_ELEMENTS(LETTERS) - 1;
70 :
71 : #define RAND_NAME_LENGTH 6
72 :
73 21599 : static void osl_gen_random_name_impl_(rtl_uString** rand_name)
74 : {
75 : static uint64_t value;
76 :
77 : char buffer[RAND_NAME_LENGTH];
78 : struct timeval tv;
79 : uint64_t v;
80 : int i;
81 :
82 21599 : gettimeofday(&tv, NULL);
83 :
84 21599 : value += ((uint64_t)tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
85 :
86 21599 : v = value;
87 :
88 151193 : for (i = 0; i < RAND_NAME_LENGTH; i++)
89 : {
90 129594 : buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
91 129594 : v /= COUNT_OF_LETTERS;
92 : }
93 :
94 : rtl_string2UString(
95 : rand_name,
96 : buffer,
97 : RAND_NAME_LENGTH,
98 : RTL_TEXTENCODING_ASCII_US,
99 21599 : OSTRING_TO_OUSTRING_CVTFLAGS);
100 : OSL_ASSERT(*rand_name != NULL);
101 21599 : }
102 :
103 : /*****************************************************************
104 : * Helper function
105 : * Either use the directory provided or the result of
106 : * osl_getTempDirUrl and return it as system path and file url
107 : ****************************************************************/
108 :
109 21599 : static oslFileError osl_setup_base_directory_impl_(
110 : rtl_uString* pustrDirectoryURL,
111 : rtl_uString** ppustr_base_dir)
112 : {
113 21599 : rtl_uString* dir_url = 0;
114 21599 : rtl_uString* dir = 0;
115 21599 : oslFileError error = osl_File_E_None;
116 :
117 21599 : if (pustrDirectoryURL)
118 20276 : rtl_uString_assign(&dir_url, pustrDirectoryURL);
119 : else
120 1323 : error = osl_getTempDirURL(&dir_url);
121 :
122 21599 : if (osl_File_E_None == error)
123 : {
124 21599 : error = osl_getSystemPathFromFileURL_Ex(dir_url, &dir);
125 21599 : rtl_uString_release(dir_url);
126 : }
127 :
128 21599 : if (osl_File_E_None == error)
129 : {
130 21599 : rtl_uString_assign(ppustr_base_dir, dir);
131 21599 : rtl_uString_release(dir);
132 : }
133 :
134 21599 : return error;
135 : }
136 :
137 : /*****************************************************************
138 : * osl_setup_createTempFile_impl
139 : * validate input parameter, setup variables
140 : ****************************************************************/
141 :
142 21599 : static oslFileError osl_setup_createTempFile_impl_(
143 : rtl_uString* pustrDirectoryURL,
144 : oslFileHandle* pHandle,
145 : rtl_uString** ppustrTempFileURL,
146 : rtl_uString** ppustr_base_dir,
147 : sal_Bool* b_delete_on_close)
148 : {
149 : oslFileError osl_error;
150 :
151 : OSL_PRECOND(((0 != pHandle) || (0 != ppustrTempFileURL)), "Invalid parameter!");
152 :
153 21599 : if ((0 == pHandle) && (0 == ppustrTempFileURL))
154 : {
155 0 : osl_error = osl_File_E_INVAL;
156 : }
157 : else
158 : {
159 : osl_error = osl_setup_base_directory_impl_(
160 21599 : pustrDirectoryURL, ppustr_base_dir);
161 :
162 21599 : *b_delete_on_close = (0 == ppustrTempFileURL);
163 : }
164 :
165 21599 : return osl_error;
166 : }
167 :
168 : /*****************************************************************
169 : * Create a unique file in the specified directory and return
170 : * its name
171 : ****************************************************************/
172 :
173 21599 : static oslFileError osl_create_temp_file_impl_(
174 : const rtl_uString* pustr_base_directory,
175 : oslFileHandle* file_handle,
176 : rtl_uString** ppustr_temp_file_name)
177 : {
178 21599 : rtl_uString* rand_name = 0;
179 21599 : sal_uInt32 len_base_dir = 0;
180 21599 : rtl_uString* tmp_file_path = 0;
181 21599 : rtl_uString* tmp_file_url = 0;
182 21599 : sal_Int32 capacity = 0;
183 21599 : oslFileError osl_error = osl_File_E_None;
184 : sal_Int32 offset_file_name;
185 : const sal_Unicode* puchr;
186 :
187 : OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
188 : OSL_PRECOND(file_handle, "Invalid Parameter");
189 : OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
190 :
191 21599 : len_base_dir = rtl_uString_getLength(pustr_base_directory);
192 :
193 : rtl_uStringbuffer_newFromStr_WithLength(
194 : &tmp_file_path,
195 21599 : rtl_uString_getStr(const_cast<rtl_uString*>(pustr_base_directory)),
196 43198 : len_base_dir);
197 :
198 : rtl_uStringbuffer_ensureCapacity(
199 : &tmp_file_path,
200 : &capacity,
201 21599 : (len_base_dir + 1 + RAND_NAME_LENGTH));
202 :
203 21599 : offset_file_name = len_base_dir;
204 :
205 21599 : puchr = rtl_uString_getStr(tmp_file_path);
206 :
207 : /* ensure that the last character is a '/' */
208 :
209 21599 : if ((sal_Unicode)'/' != puchr[len_base_dir - 1])
210 : {
211 : rtl_uStringbuffer_insert_ascii(
212 : &tmp_file_path,
213 : &capacity,
214 : len_base_dir,
215 : "/",
216 21543 : 1);
217 :
218 21543 : offset_file_name++;
219 : }
220 :
221 : while(true) /* try until success */
222 : {
223 21599 : osl_gen_random_name_impl_(&rand_name);
224 :
225 : rtl_uStringbuffer_insert(
226 : &tmp_file_path,
227 : &capacity,
228 : offset_file_name,
229 21599 : rtl_uString_getStr(rand_name),
230 43198 : rtl_uString_getLength(rand_name));
231 :
232 : osl_error = osl_getFileURLFromSystemPath(
233 21599 : tmp_file_path, &tmp_file_url);
234 :
235 21599 : if (osl_File_E_None == osl_error)
236 : {
237 : osl_error = openFile(
238 : tmp_file_url,
239 : file_handle,
240 : osl_File_OpenFlag_Read |
241 : osl_File_OpenFlag_Write |
242 : osl_File_OpenFlag_Create,
243 21599 : S_IRUSR | S_IWUSR);
244 : }
245 :
246 : /* in case of error osl_File_E_EXIST we simply try again else we give up */
247 :
248 21599 : if ((osl_File_E_None == osl_error) || (osl_error != osl_File_E_EXIST))
249 : {
250 21599 : rtl_uString_release(rand_name);
251 :
252 21599 : if (tmp_file_url)
253 21599 : rtl_uString_release(tmp_file_url);
254 :
255 21599 : break;
256 : }
257 : } /* while(1) */
258 :
259 21599 : if (osl_File_E_None == osl_error)
260 21599 : rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
261 :
262 21599 : rtl_uString_release(tmp_file_path);
263 :
264 21599 : return osl_error;
265 : }
266 :
267 21599 : oslFileError SAL_CALL osl_createTempFile(
268 : rtl_uString* pustrDirectoryURL,
269 : oslFileHandle* pHandle,
270 : rtl_uString** ppustrTempFileURL)
271 : {
272 21599 : rtl_uString* base_directory = 0;
273 21599 : rtl_uString* temp_file_name = 0;
274 : oslFileHandle temp_file_handle;
275 : sal_Bool b_delete_on_close;
276 : oslFileError osl_error;
277 :
278 : osl_error = osl_setup_createTempFile_impl_(
279 : pustrDirectoryURL,
280 : pHandle,
281 : ppustrTempFileURL,
282 : &base_directory,
283 21599 : &b_delete_on_close);
284 :
285 21599 : if (osl_File_E_None != osl_error)
286 0 : return osl_error;
287 :
288 : osl_error = osl_create_temp_file_impl_(
289 21599 : base_directory, &temp_file_handle, &temp_file_name);
290 :
291 21599 : if (osl_File_E_None == osl_error)
292 : {
293 21599 : rtl_uString* temp_file_url = 0;
294 :
295 : /* assuming this works */
296 21599 : osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
297 :
298 21599 : if (b_delete_on_close)
299 : {
300 0 : osl_error = osl_removeFile(temp_file_url);
301 :
302 0 : if (osl_File_E_None == osl_error)
303 0 : *pHandle = temp_file_handle;
304 : else
305 0 : osl_closeFile(temp_file_handle);
306 : }
307 : else
308 : {
309 21599 : if (pHandle)
310 20152 : *pHandle = temp_file_handle;
311 : else
312 1447 : osl_closeFile(temp_file_handle);
313 :
314 21599 : rtl_uString_assign(ppustrTempFileURL, temp_file_url);
315 : }
316 :
317 21599 : rtl_uString_release(temp_file_url);
318 :
319 21599 : rtl_uString_release(temp_file_name);
320 : }
321 :
322 21599 : rtl_uString_release(base_directory);
323 :
324 21599 : return osl_error;
325 : }
326 :
327 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|