1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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"
35 oslFileError SAL_CALL
osl_getTempDirURL( rtl_uString
** pustrTempDir
)
38 /* described in environ(7) */
39 const char *pValue
= getenv( "TMPDIR" );
40 rtl_uString
*ustrTempPath
= nullptr;
43 pValue
= getenv( "TEMP" );
46 pValue
= getenv( "TMP" );
51 auto nLen
= strlen(pValue
);
52 while (nLen
> 1 && pValue
[nLen
- 1] == '/') // Allow path consisting of single "/"
54 rtl_string2UString( &ustrTempPath
, pValue
, nLen
, osl_getThreadTextEncoding(), OSTRING_TO_OUSTRING_CVTFLAGS
);
56 error
= osl_getFileURLFromSystemPath( ustrTempPath
, pustrTempDir
);
57 rtl_uString_release( ustrTempPath
);
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
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
];
85 gettimeofday(&tv
, nullptr);
87 value
+= (static_cast<uint64_t>(tv
.tv_usec
) << 16) ^ tv
.tv_sec
^ getpid();
91 for (i
= 0; i
< RAND_NAME_LENGTH
; i
++)
93 buffer
[i
] = LETTERS
[v
% COUNT_OF_LETTERS
];
94 v
/= COUNT_OF_LETTERS
;
101 RTL_TEXTENCODING_ASCII_US
,
102 OSTRING_TO_OUSTRING_CVTFLAGS
);
107 /*****************************************************************
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
);
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
);
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
;
163 osl_error
= osl_setup_base_directory_impl_(
164 pustrDirectoryURL
, ppustr_base_dir
);
166 *b_delete_on_close
= (ppustrTempFileURL
== nullptr);
172 /*****************************************************************
173 * Create a unique file in the specified directory and return
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(
199 (len_base_dir
+ 1 + RAND_NAME_LENGTH
));
200 capacity
= len_base_dir
+ 1 + RAND_NAME_LENGTH
;
202 rtl_uStringbuffer_insert(
206 rtl_uString_getStr(const_cast<rtl_uString
*>(pustr_base_directory
)),
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(
227 while(true) /* try until success */
229 osl_gen_random_name_impl_(&rand_name
);
231 rtl_uStringbuffer_insert(
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(
246 osl_File_OpenFlag_Read
|
247 osl_File_OpenFlag_Write
|
248 osl_File_OpenFlag_Create
,
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
);
259 rtl_uString_release(tmp_file_url
);
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
);
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_(
290 if (osl_error
!= osl_File_E_None
)
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;
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
);
338 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */