Branch data 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 : : #include <unotools/tempfile.hxx>
22 : : #include <tools/tempfile.hxx>
23 : : #include <unotools/localfilehelper.hxx>
24 : : #include <unotools/ucbstreamhelper.hxx>
25 : : #include <ucbhelper/fileidentifierconverter.hxx>
26 : : #include <ucbhelper/contentbroker.hxx>
27 : : #include <rtl/ustring.hxx>
28 : : #include <rtl/instance.hxx>
29 : : #include <osl/file.hxx>
30 : : #include <tools/time.hxx>
31 : : #include <tools/debug.hxx>
32 : : #include <stdio.h>
33 : :
34 : : #ifdef UNX
35 : : #include <sys/stat.h>
36 : : #endif
37 : :
38 : : using namespace osl;
39 : :
40 : : namespace
41 : : {
42 : : struct TempNameBase_Impl
43 : : : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {};
44 : : }
45 : :
46 : : namespace utl
47 : : {
48 : :
49 [ + - ]: 9366 : struct TempFile_Impl
50 : : {
51 : : String aName;
52 : : String aURL;
53 : : SvStream* pStream;
54 : : sal_Bool bIsDirectory;
55 : :
56 : 9557 : TempFile_Impl()
57 [ + - ]: 9557 : : pStream(0)
58 : 9557 : {}
59 : : };
60 : :
61 : 0 : rtl::OUString getParentName( const rtl::OUString& aFileName )
62 : : {
63 : 0 : sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') );
64 : 0 : rtl::OUString aParent = aFileName.copy( 0,lastIndex );
65 : :
66 [ # # ][ # # ]: 0 : if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 )
[ # # ]
67 : 0 : aParent += rtl::OUString("/");
68 : :
69 [ # # ]: 0 : if( 0 == aParent.compareToAscii( "file://" ) )
70 : 0 : aParent = rtl::OUString("file:///");
71 : :
72 : 0 : return aParent;
73 : : }
74 : :
75 : 9397 : sal_Bool ensuredir( const rtl::OUString& rUnqPath )
76 : : {
77 : 9397 : rtl::OUString aPath;
78 [ - + ]: 9397 : if ( rUnqPath.isEmpty() )
79 : 0 : return sal_False;
80 : :
81 : : // remove trailing slash
82 [ + + ]: 9397 : if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) )
83 : 158 : aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
84 : : else
85 : 9239 : aPath = rUnqPath;
86 : :
87 : : // HACK: create directory on a mount point with nobrowse option
88 : : // returns ENOSYS in any case !!
89 : 9397 : osl::Directory aDirectory( aPath );
90 : : #ifdef UNX
91 : : /* RW permission for the user only! */
92 : 9397 : mode_t old_mode = umask(077);
93 : : #endif
94 [ + - ]: 9397 : osl::FileBase::RC nError = aDirectory.open();
95 : : #ifdef UNX
96 : 9397 : umask(old_mode);
97 : : #endif
98 [ + - ]: 9397 : aDirectory.close();
99 [ + - ]: 9397 : if( nError == osl::File::E_None )
100 : 9397 : return sal_True;
101 : :
102 : : // try to create the directory
103 [ # # ]: 0 : nError = osl::Directory::create( aPath );
104 [ # # ][ # # ]: 0 : sal_Bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
105 [ # # ]: 0 : if( !bSuccess )
106 : : {
107 : : // perhaps parent(s) don't exist
108 [ # # ]: 0 : rtl::OUString aParentDir = getParentName( aPath );
109 [ # # ]: 0 : if ( aParentDir != aPath )
110 : : {
111 [ # # ][ # # ]: 0 : bSuccess = ensuredir( getParentName( aPath ) );
112 : :
113 : : // After parent directory structure exists try it one's more
114 [ # # ]: 0 : if ( bSuccess )
115 : : {
116 : : // Parent directory exists, retry creation of directory
117 [ # # ]: 0 : nError = osl::Directory::create( aPath );
118 [ # # ][ # # ]: 0 : bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
119 : : }
120 : 0 : }
121 : : }
122 : :
123 [ + - ]: 9397 : return bSuccess;
124 : : }
125 : :
126 : 9557 : String ConstructTempDir_Impl( const String* pParent )
127 : : {
128 : 9557 : String aName;
129 [ + - ][ + + ]: 9557 : if ( pParent && pParent->Len() )
[ + + ]
130 : : {
131 [ + - ]: 1922 : ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get();
132 [ + - ]: 1922 : if ( pBroker )
133 : : {
134 : : ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager =
135 [ + - ]: 1922 : pBroker->getContentProviderManagerInterface();
136 : :
137 : : // if parent given try to use it
138 [ + - ]: 1922 : rtl::OUString aTmp( *pParent );
139 : :
140 : : // test for valid filename
141 : 1922 : rtl::OUString aRet;
142 : : ::osl::FileBase::getFileURLFromSystemPath(
143 : : ::ucbhelper::getSystemPathFromFileURL( xManager, aTmp ),
144 [ + - ][ + - ]: 1922 : aRet );
145 [ + + ]: 1922 : if ( !aRet.isEmpty() )
146 : : {
147 : 310 : ::osl::DirectoryItem aItem;
148 : 310 : sal_Int32 i = aRet.getLength();
149 [ + + ]: 310 : if ( aRet[i-1] == '/' )
150 : 150 : i--;
151 : :
152 [ + - ][ + + ]: 310 : if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None )
153 [ + - ][ + - ]: 310 : aName = aRet;
154 : 1922 : }
155 : : }
156 : : else
157 : : {
158 : : DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" );
159 : : }
160 : : }
161 : :
162 [ + + ]: 9557 : if ( !aName.Len() )
163 : : {
164 : 9397 : ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
165 [ + + ]: 9397 : if (rTempNameBase_Impl.isEmpty())
166 : : {
167 : 72 : ::rtl::OUString ustrTempDirURL;
168 : : ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
169 [ + - ]: 72 : ustrTempDirURL );
170 [ + - ]: 72 : if (rc == ::osl::FileBase::E_None)
171 : 72 : rTempNameBase_Impl = ustrTempDirURL;
172 : : }
173 : : // if no parent or invalid parent : use default directory
174 : : DBG_ASSERT( !rTempNameBase_Impl.isEmpty(), "No TempDir!" );
175 [ + - ]: 9397 : aName = rTempNameBase_Impl;
176 [ + - ][ + - ]: 9397 : ensuredir( aName );
177 : : }
178 : :
179 : : // Make sure that directory ends with a separator
180 : 9557 : xub_StrLen i = aName.Len();
181 [ + + ][ + + ]: 9557 : if( i>0 && aName.GetChar(i-1) != '/' )
[ + - ]
182 [ + - ]: 9249 : aName += '/';
183 : :
184 : 9557 : return aName;
185 : : }
186 : :
187 : 9250 : void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
188 : : {
189 : : // add a suitable tempname
190 : : // 36 ** 6 == 2176782336
191 : 9250 : unsigned const nRadix = 36;
192 : 9250 : unsigned long const nMax = (nRadix*nRadix*nRadix*nRadix*nRadix*nRadix);
193 [ + - ]: 9250 : String aName( rName );
194 [ + - ]: 9250 : aName += rtl::OUString( "lu" );
195 : :
196 [ + - ]: 9250 : rName.Erase();
197 [ + + ][ + - ]: 9250 : static unsigned long u = Time::GetSystemTicks() % nMax;
[ + - ][ # # ]
198 [ + - ]: 9251 : for ( unsigned long nSeed = u; ++u != nSeed; )
199 : : {
200 : 9251 : u %= nMax;
201 [ + - ]: 9251 : String aTmp( aName );
202 [ + - ]: 9251 : aTmp += rtl::OUString::valueOf(static_cast<sal_Int64>(u), nRadix);
203 [ + - ]: 9251 : aTmp += rtl::OUString( ".tmp" );
204 : :
205 [ + + ]: 9251 : if ( bDir )
206 : : {
207 : : #ifdef UNX /* RW permission for the user only! */
208 : 1771 : mode_t old_mode = umask(077);
209 : : #endif
210 [ + - ][ + - ]: 1771 : FileBase::RC err = Directory::create( aTmp );
211 : : #ifdef UNX
212 : 1771 : umask(old_mode);
213 : : #endif
214 [ + + ]: 1771 : if ( err == FileBase::E_None )
215 : : {
216 : : // !bKeep: only for creating a name, not a file or directory
217 [ - + ][ # # ]: 1770 : if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
[ # # ][ # # ]
[ - + ]
[ + - # # ]
218 [ + - ]: 1770 : rName = aTmp;
219 : : break;
220 : : }
221 [ - + ]: 1 : else if ( err != FileBase::E_EXIST )
222 : : {
223 : : // if f.e. name contains invalid chars stop trying to create dirs
224 : : break;
225 : : }
226 : : }
227 : : else
228 : : {
229 : : DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
230 [ + - ]: 7480 : File aFile( aTmp );
231 : : #ifdef UNX /* RW permission for the user only! */
232 : 7480 : mode_t old_mode = umask(077);
233 : : #endif
234 [ + - ]: 7480 : FileBase::RC err = aFile.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
235 : : #ifdef UNX
236 : 7480 : umask(old_mode);
237 : : #endif
238 [ + - ]: 7480 : if ( err == FileBase::E_None )
239 : : {
240 [ + - ]: 7480 : rName = aTmp;
241 [ + - ]: 7480 : aFile.close();
242 : : break;
243 : : }
244 [ # # ]: 0 : else if ( err != FileBase::E_EXIST )
245 : : {
246 : : // if f.e. name contains invalid chars stop trying to create files
247 : : // but if there is a folder with such name proceed further
248 : :
249 : 0 : DirectoryItem aTmpItem;
250 : 0 : FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
251 [ # # ][ # # ]: 0 : if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
252 [ # # ]: 0 : || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
253 [ # # ]: 0 : || aTmpStatus.getFileType() != FileStatus::Directory )
254 [ # # ][ # # ]: 0 : break;
[ # # ]
255 [ + - ][ - + ]: 7481 : }
256 : : }
257 [ + - ][ + + ]: 9251 : }
[ + - ]
258 : 9250 : }
259 : :
260 : 307 : void lcl_createName(TempFile_Impl& _rImpl,const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
261 : : {
262 : 307 : _rImpl.bIsDirectory = bDirectory;
263 : :
264 : : // get correct directory
265 [ + - ]: 307 : String aName = ConstructTempDir_Impl( pParent );
266 : :
267 : 307 : sal_Bool bUseNumber = _bStartWithZero;
268 : : // now use special naming scheme ( name takes leading chars and an index counting up from zero
269 [ + - ]: 307 : aName += rLeadingChars;
270 : 307 : for ( sal_Int32 i=0;; i++ )
271 : : {
272 [ + - ]: 307 : String aTmp( aName );
273 [ + - ]: 307 : if ( bUseNumber )
274 [ + - ][ + - ]: 307 : aTmp += String::CreateFromInt32( i );
[ + - ]
275 : 307 : bUseNumber = sal_True;
276 [ + + ]: 307 : if ( pExtension )
277 [ + - ]: 304 : aTmp += *pExtension;
278 : : else
279 [ + - ]: 3 : aTmp += rtl::OUString( ".tmp" );
280 [ - + ]: 307 : if ( bDirectory )
281 : : {
282 [ # # ][ # # ]: 0 : FileBase::RC err = Directory::create( aTmp );
283 [ # # ]: 0 : if ( err == FileBase::E_None )
284 : : {
285 [ # # ]: 0 : _rImpl.aName = aTmp;
286 : : break;
287 : : }
288 [ # # ]: 0 : else if ( err != FileBase::E_EXIST )
289 : : // if f.e. name contains invalid chars stop trying to create dirs
290 : : break;
291 : : }
292 : : else
293 : : {
294 [ + - ]: 307 : File aFile( aTmp );
295 : : #ifdef UNX
296 : : /* RW permission for the user only! */
297 : 307 : mode_t old_mode = umask(077);
298 : : #endif
299 [ + - ]: 307 : FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
300 : : #ifdef UNX
301 : 307 : umask(old_mode);
302 : : #endif
303 [ # # ][ - + ]: 307 : if ( err == FileBase::E_None || err == FileBase::E_NOLCK )
304 : : {
305 [ + - ]: 307 : _rImpl.aName = aTmp;
306 [ + - ]: 307 : aFile.close();
307 : : break;
308 : : }
309 [ # # ]: 0 : else if ( err != FileBase::E_EXIST )
310 : : {
311 : : // if f.e. name contains invalid chars stop trying to create dirs
312 : : // but if there is a folder with such name proceed further
313 : :
314 : 0 : DirectoryItem aTmpItem;
315 : 0 : FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
316 [ # # ][ # # ]: 0 : if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
317 [ # # ]: 0 : || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
318 [ # # ]: 0 : || aTmpStatus.getFileType() != FileStatus::Directory )
319 [ # # ][ # # ]: 0 : break;
[ # # ]
320 [ + - ][ - + ]: 307 : }
321 : : }
322 [ # # ]: 0 : if ( !_bStartWithZero )
323 [ # # ][ # # ]: 0 : aTmp += String::CreateFromInt32( i );
[ # # ]
324 [ + - ][ - + ]: 307 : }
[ + - ]
325 : 307 : }
326 : :
327 : :
328 : 0 : String TempFile::CreateTempName( const String* pParent )
329 : : {
330 : : // get correct directory
331 [ # # ]: 0 : String aName = ConstructTempDir_Impl( pParent );
332 : :
333 : : // get TempFile name with default naming scheme
334 [ # # ]: 0 : CreateTempName_Impl( aName, sal_False );
335 : :
336 : : // convert to file URL
337 : 0 : rtl::OUString aTmp;
338 [ # # ]: 0 : if ( aName.Len() )
339 [ # # ][ # # ]: 0 : FileBase::getSystemPathFromFileURL( aName, aTmp );
340 [ # # ][ # # ]: 0 : return aTmp;
341 : : }
342 : :
343 : 9250 : TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
344 [ + - ]: 9250 : : pImp( new TempFile_Impl )
345 : 9250 : , bKillingFileEnabled( sal_False )
346 : : {
347 : 9250 : pImp->bIsDirectory = bDirectory;
348 : :
349 : : // get correct directory
350 [ + - ]: 9250 : pImp->aName = ConstructTempDir_Impl( pParent );
351 : :
352 : : // get TempFile with default naming scheme
353 : 9250 : CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
354 : 9250 : }
355 : :
356 : 307 : TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory)
357 [ + - ]: 307 : : pImp( new TempFile_Impl )
358 : 307 : , bKillingFileEnabled( sal_False )
359 : : {
360 : 307 : lcl_createName(*pImp,rLeadingChars,sal_True, pExtension, pParent, bDirectory);
361 : 307 : }
362 : 0 : TempFile::TempFile( const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
363 [ # # ]: 0 : : pImp( new TempFile_Impl )
364 : 0 : , bKillingFileEnabled( sal_False )
365 : : {
366 : 0 : lcl_createName(*pImp,rLeadingChars,_bStartWithZero, pExtension, pParent, bDirectory);
367 : 0 : }
368 : :
369 : 9366 : TempFile::~TempFile()
370 : : {
371 [ + + ]: 9366 : delete pImp->pStream;
372 [ + + ]: 9366 : if ( bKillingFileEnabled )
373 : : {
374 [ - + ]: 5227 : if ( pImp->bIsDirectory )
375 : : {
376 : : // at the moment no recursiv algorithm present
377 [ # # ]: 0 : Directory::remove( pImp->aName );
378 : : }
379 : : else
380 : : {
381 [ + - ]: 5227 : File::remove( pImp->aName );
382 : : }
383 : : }
384 : :
385 [ + - ]: 9366 : delete pImp;
386 : 9366 : }
387 : :
388 : 167 : sal_Bool TempFile::IsValid() const
389 : : {
390 : 167 : return pImp->aName.Len() != 0;
391 : : }
392 : :
393 : 10303 : String TempFile::GetFileName() const
394 : : {
395 : 10303 : rtl::OUString aTmp;
396 [ + - ][ + - ]: 10303 : FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
397 [ + - ]: 10303 : return aTmp;
398 : : }
399 : :
400 : 11109 : String TempFile::GetURL() const
401 : : {
402 [ + + ]: 11109 : if ( !pImp->aURL.Len() )
403 : : {
404 : 9372 : rtl::OUString aTmp;
405 [ + - ][ + - ]: 9372 : LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
[ + - ][ + - ]
406 [ + - ]: 9372 : pImp->aURL = aTmp;
407 : : }
408 : :
409 : 11109 : return pImp->aURL;
410 : : }
411 : :
412 : 5521 : SvStream* TempFile::GetStream( StreamMode eMode )
413 : : {
414 [ + - ]: 5521 : if ( !pImp->pStream )
415 : : {
416 [ + - ]: 5521 : if ( GetURL().Len() )
417 : 5521 : pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ );
418 : : else
419 [ # # ]: 0 : pImp->pStream = new SvMemoryStream( eMode );
420 : : }
421 : :
422 : 5521 : return pImp->pStream;
423 : : }
424 : :
425 : 2600 : void TempFile::CloseStream()
426 : : {
427 [ + - ]: 2600 : if ( pImp->pStream )
428 : : {
429 [ + - ]: 2600 : delete pImp->pStream;
430 : 2600 : pImp->pStream = NULL;
431 : : }
432 : 2600 : }
433 : :
434 : 158 : String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
435 : : {
436 [ - + ]: 158 : if( !rBaseName.Len() )
437 [ # # ]: 0 : return String();
438 : :
439 [ + - ]: 158 : rtl::OUString aUnqPath( rBaseName );
440 : :
441 : : // remove trailing slash
442 [ - + ]: 158 : if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) )
443 [ # # ][ # # ]: 0 : aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 );
[ # # ]
444 : :
445 : : // try to create the directory
446 : 158 : sal_Bool bRet = sal_False;
447 [ + - ]: 158 : osl::FileBase::RC err = osl::Directory::create( aUnqPath );
448 [ + - ][ - + ]: 158 : if ( err != FileBase::E_None && err != FileBase::E_EXIST )
449 : : // perhaps parent(s) don't exist
450 [ # # ]: 0 : bRet = ensuredir( aUnqPath );
451 : : else
452 : 158 : bRet = sal_True;
453 : :
454 : : // failure to create base directory means returning an empty string
455 : 158 : rtl::OUString aTmp;
456 [ + - ]: 158 : if ( bRet )
457 : : {
458 : : // append own internal directory
459 : 158 : bRet = sal_True;
460 : 158 : ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
461 [ + - ]: 158 : rTempNameBase_Impl = rBaseName;
462 : 158 : rTempNameBase_Impl += rtl::OUString('/');
463 : :
464 [ + - ]: 158 : TempFile aBase( NULL, sal_True );
465 [ + - ][ + - ]: 158 : if ( aBase.IsValid() )
466 : : // use it in case of success
467 [ + - ]: 158 : rTempNameBase_Impl = aBase.pImp->aName;
468 : :
469 : : // return system path of used directory
470 [ + - ][ + - ]: 158 : FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
471 : : }
472 : :
473 [ + - ]: 158 : return aTmp;
474 : : }
475 : : }
476 : :
477 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|