Slightly more informative logging
[LibreOffice.git] / sal / osl / unx / tempfile.cxx
blob85259f1667f3d368a6577706f603981e75198d51
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <unistd.h>
24 #include <osl/file.h>
25 #include <osl/thread.h>
26 #include <rtl/ustrbuf.h>
27 #include <osl/diagnose.h>
28 #include <sal/macros.h>
30 #include "file_url.hxx"
31 #include "file_impl.hxx"
33 #include <cassert>
35 oslFileError SAL_CALL osl_getTempDirURL( rtl_uString** pustrTempDir )
37 oslFileError error;
38 /* described in environ(7) */
39 const char *pValue = getenv( "TMPDIR" );
40 rtl_uString *ustrTempPath = nullptr;
42 if ( !pValue )
43 pValue = getenv( "TEMP" );
45 if ( !pValue )
46 pValue = getenv( "TMP" );
48 if ( !pValue )
49 pValue = "/tmp";
51 auto nLen = strlen(pValue);
52 while (nLen > 1 && pValue[nLen - 1] == '/') // Allow path consisting of single "/"
53 --nLen;
54 rtl_string2UString( &ustrTempPath, pValue, nLen, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS );
55 assert(ustrTempPath);
56 error = osl_getFileURLFromSystemPath( ustrTempPath, pustrTempDir );
57 rtl_uString_release( ustrTempPath );
59 return error;
62 /******************************************************************
63 * Generates a random unique file name. We're using the scheme
64 * from the standard c-lib function mkstemp to generate a more
65 * or less random unique file name
67 * @param rand_name
68 * receives the random name
69 ******************************************************************/
71 const char LETTERS[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
72 const int COUNT_OF_LETTERS = SAL_N_ELEMENTS(LETTERS) - 1;
74 #define RAND_NAME_LENGTH 6
76 static void osl_gen_random_name_impl_(rtl_uString** rand_name)
78 static uint64_t value;
80 char buffer[RAND_NAME_LENGTH];
81 struct timeval tv;
82 uint64_t v;
83 int i;
85 gettimeofday(&tv, nullptr);
87 value += (static_cast<uint64_t>(tv.tv_usec) << 16) ^ tv.tv_sec ^ getpid();
89 v = value;
91 for (i = 0; i < RAND_NAME_LENGTH; i++)
93 buffer[i] = LETTERS[v % COUNT_OF_LETTERS];
94 v /= COUNT_OF_LETTERS;
97 rtl_string2UString(
98 rand_name,
99 buffer,
100 RAND_NAME_LENGTH,
101 RTL_TEXTENCODING_ASCII_US,
102 OSTRING_TO_OUSTRING_CVTFLAGS);
104 assert(*rand_name);
107 /*****************************************************************
108 * Helper function
109 * Either use the directory provided or the result of
110 * osl_getTempDirUrl and return it as system path and file url
111 ****************************************************************/
113 static oslFileError osl_setup_base_directory_impl_(
114 rtl_uString* pustrDirectoryURL,
115 rtl_uString** ppustr_base_dir)
117 rtl_uString* dir_url = nullptr;
118 rtl_uString* dir = nullptr;
119 oslFileError error = osl_File_E_None;
121 if (pustrDirectoryURL)
122 rtl_uString_assign(&dir_url, pustrDirectoryURL);
123 else
124 error = osl_getTempDirURL(&dir_url);
126 if (error == osl_File_E_None)
128 error = getSystemPathFromFileURL_Ex(dir_url, &dir);
129 rtl_uString_release(dir_url);
132 if (error == osl_File_E_None)
134 rtl_uString_assign(ppustr_base_dir, dir);
135 rtl_uString_release(dir);
138 return error;
141 /*****************************************************************
142 * osl_setup_createTempFile_impl
143 * validate input parameter, setup variables
144 ****************************************************************/
146 static oslFileError osl_setup_createTempFile_impl_(
147 rtl_uString* pustrDirectoryURL,
148 oslFileHandle* pHandle,
149 rtl_uString** ppustrTempFileURL,
150 rtl_uString** ppustr_base_dir,
151 bool* b_delete_on_close)
153 oslFileError osl_error;
155 OSL_PRECOND(((nullptr != pHandle) || (nullptr != ppustrTempFileURL)), "Invalid parameter!");
157 if ((pHandle == nullptr) && (ppustrTempFileURL == nullptr))
159 osl_error = osl_File_E_INVAL;
161 else
163 osl_error = osl_setup_base_directory_impl_(
164 pustrDirectoryURL, ppustr_base_dir);
166 *b_delete_on_close = (ppustrTempFileURL == nullptr);
169 return osl_error;
172 /*****************************************************************
173 * Create a unique file in the specified directory and return
174 * its name
175 ****************************************************************/
177 static oslFileError osl_create_temp_file_impl_(
178 const rtl_uString* pustr_base_directory,
179 oslFileHandle* file_handle,
180 rtl_uString** ppustr_temp_file_name)
182 rtl_uString* rand_name = nullptr;
183 sal_uInt32 len_base_dir = 0;
184 rtl_uString* tmp_file_path = nullptr;
185 rtl_uString* tmp_file_url = nullptr;
186 sal_Int32 capacity = 0;
187 oslFileError osl_error = osl_File_E_None;
188 sal_Int32 offset_file_name;
189 const sal_Unicode* puchr;
191 OSL_PRECOND(pustr_base_directory, "Invalid Parameter");
192 OSL_PRECOND(file_handle, "Invalid Parameter");
193 OSL_PRECOND(ppustr_temp_file_name, "Invalid Parameter");
195 len_base_dir = rtl_uString_getLength(pustr_base_directory);
197 rtl_uString_new_WithLength(
198 &tmp_file_path,
199 (len_base_dir + 1 + RAND_NAME_LENGTH));
200 capacity = len_base_dir + 1 + RAND_NAME_LENGTH;
202 rtl_uStringbuffer_insert(
203 &tmp_file_path,
204 &capacity,
206 rtl_uString_getStr(const_cast<rtl_uString*>(pustr_base_directory)),
207 len_base_dir);
209 offset_file_name = len_base_dir;
211 puchr = rtl_uString_getStr(tmp_file_path);
213 /* ensure that the last character is a '/' */
215 if (puchr[len_base_dir - 1] != '/')
217 rtl_uStringbuffer_insert_ascii(
218 &tmp_file_path,
219 &capacity,
220 len_base_dir,
221 "/",
224 offset_file_name++;
227 while(true) /* try until success */
229 osl_gen_random_name_impl_(&rand_name);
231 rtl_uStringbuffer_insert(
232 &tmp_file_path,
233 &capacity,
234 offset_file_name,
235 rtl_uString_getStr(rand_name),
236 rtl_uString_getLength(rand_name));
238 osl_error = osl_getFileURLFromSystemPath(
239 tmp_file_path, &tmp_file_url);
241 if (osl_error == osl_File_E_None)
243 osl_error = openFile(
244 tmp_file_url,
245 file_handle,
246 osl_File_OpenFlag_Read |
247 osl_File_OpenFlag_Write |
248 osl_File_OpenFlag_Create,
249 S_IRUSR | S_IWUSR);
252 /* in case of error osl_File_E_EXIST we simply try again else we give up */
254 if (osl_error != osl_File_E_EXIST)
256 rtl_uString_release(rand_name);
258 if (tmp_file_url)
259 rtl_uString_release(tmp_file_url);
261 break;
263 } /* while(1) */
265 if (osl_error == osl_File_E_None)
266 rtl_uString_assign(ppustr_temp_file_name, tmp_file_path);
268 rtl_uString_release(tmp_file_path);
270 return osl_error;
273 oslFileError SAL_CALL osl_createTempFile(
274 rtl_uString* pustrDirectoryURL,
275 oslFileHandle* pHandle,
276 rtl_uString** ppustrTempFileURL)
278 rtl_uString* base_directory = nullptr;
279 oslFileHandle temp_file_handle = nullptr;
280 bool b_delete_on_close;
281 oslFileError osl_error;
283 osl_error = osl_setup_createTempFile_impl_(
284 pustrDirectoryURL,
285 pHandle,
286 ppustrTempFileURL,
287 &base_directory,
288 &b_delete_on_close);
290 if (osl_error != osl_File_E_None)
291 return osl_error;
293 rtl_uString* temp_file_name = nullptr;
294 osl_error = osl_create_temp_file_impl_(
295 base_directory, &temp_file_handle, &temp_file_name);
297 rtl_uString* temp_file_url = nullptr;
298 if (osl_error == osl_File_E_None)
300 osl_error = osl_getFileURLFromSystemPath(temp_file_name, &temp_file_url);
301 rtl_uString_release(temp_file_name);
304 if (osl_error == osl_File_E_None)
306 if (b_delete_on_close)
308 osl_error = osl_removeFile(temp_file_url);
310 if (osl_error == osl_File_E_None)
312 *pHandle = temp_file_handle;
313 temp_file_handle = nullptr;
316 else
318 if (pHandle)
320 *pHandle = temp_file_handle;
321 temp_file_handle = nullptr;
324 rtl_uString_assign(ppustrTempFileURL, temp_file_url);
327 rtl_uString_release(temp_file_url);
330 if (temp_file_handle)
331 osl_closeFile(temp_file_handle);
333 rtl_uString_release(base_directory);
335 return osl_error;
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */