bump product version to 4.1.6.2
[LibreOffice.git] / unotools / source / ucbhelper / tempfile.cxx
blob798f61be5816b70c04d9a48323a105116695c753
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 "sal/config.h"
22 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
23 #include <comphelper/processfactory.hxx>
24 #include <unotools/tempfile.hxx>
25 #include <unotools/localfilehelper.hxx>
26 #include <unotools/ucbstreamhelper.hxx>
27 #include <ucbhelper/fileidentifierconverter.hxx>
28 #include <rtl/ustring.hxx>
29 #include <rtl/instance.hxx>
30 #include <osl/file.hxx>
31 #include <tools/time.hxx>
32 #include <tools/debug.hxx>
33 #include <stdio.h>
35 #ifdef UNX
36 #include <sys/stat.h>
37 #endif
39 using namespace osl;
41 namespace
43 struct TempNameBase_Impl
44 : public rtl::Static< OUString, TempNameBase_Impl > {};
47 namespace utl
50 struct TempFile_Impl
52 String aName;
53 String aURL;
54 SvStream* pStream;
55 sal_Bool bIsDirectory;
57 TempFile_Impl()
58 : pStream(0)
62 OUString getParentName( const OUString& aFileName )
64 sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') );
65 OUString aParent = aFileName.copy( 0,lastIndex );
67 if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 )
68 aParent += OUString("/");
70 if( 0 == aParent.compareToAscii( "file://" ) )
71 aParent = OUString("file:///");
73 return aParent;
76 sal_Bool ensuredir( const OUString& rUnqPath )
78 OUString aPath;
79 if ( rUnqPath.isEmpty() )
80 return sal_False;
82 // remove trailing slash
83 if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) )
84 aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
85 else
86 aPath = rUnqPath;
88 // HACK: create directory on a mount point with nobrowse option
89 // returns ENOSYS in any case !!
90 osl::Directory aDirectory( aPath );
91 #ifdef UNX
92 /* RW permission for the user only! */
93 mode_t old_mode = umask(077);
94 #endif
95 osl::FileBase::RC nError = aDirectory.open();
96 #ifdef UNX
97 umask(old_mode);
98 #endif
99 aDirectory.close();
100 if( nError == osl::File::E_None )
101 return sal_True;
103 // try to create the directory
104 nError = osl::Directory::create( aPath );
105 sal_Bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
106 if( !bSuccess )
108 // perhaps parent(s) don't exist
109 OUString aParentDir = getParentName( aPath );
110 if ( aParentDir != aPath )
112 bSuccess = ensuredir( getParentName( aPath ) );
114 // After parent directory structure exists try it one's more
115 if ( bSuccess )
117 // Parent directory exists, retry creation of directory
118 nError = osl::Directory::create( aPath );
119 bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
124 return bSuccess;
127 String ConstructTempDir_Impl( const String* pParent )
129 String aName;
130 if ( pParent && pParent->Len() )
132 com::sun::star::uno::Reference<
133 com::sun::star::ucb::XUniversalContentBroker > pBroker(
134 com::sun::star::ucb::UniversalContentBroker::create(
135 comphelper::getProcessComponentContext() ) );
137 // if parent given try to use it
138 OUString aTmp( *pParent );
140 // test for valid filename
141 OUString aRet;
142 ::osl::FileBase::getFileURLFromSystemPath(
143 ::ucbhelper::getSystemPathFromFileURL( pBroker, aTmp ),
144 aRet );
145 if ( !aRet.isEmpty() )
147 ::osl::DirectoryItem aItem;
148 sal_Int32 i = aRet.getLength();
149 if ( aRet[i-1] == '/' )
150 i--;
152 if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None )
153 aName = aRet;
157 if ( !aName.Len() )
159 OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
160 if (rTempNameBase_Impl.isEmpty())
162 OUString ustrTempDirURL;
163 ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
164 ustrTempDirURL );
165 if (rc == ::osl::FileBase::E_None)
166 rTempNameBase_Impl = ustrTempDirURL;
168 // if no parent or invalid parent : use default directory
169 DBG_ASSERT( !rTempNameBase_Impl.isEmpty(), "No TempDir!" );
170 aName = rTempNameBase_Impl;
171 ensuredir( aName );
174 // Make sure that directory ends with a separator
175 xub_StrLen i = aName.Len();
176 if( i>0 && aName.GetChar(i-1) != '/' )
177 aName += '/';
179 return aName;
182 void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
184 // add a suitable tempname
185 // 36 ** 6 == 2176782336
186 unsigned const nRadix = 36;
187 unsigned long const nMax = (nRadix*nRadix*nRadix*nRadix*nRadix*nRadix);
188 String aName( rName );
189 aName += OUString( "lu" );
191 rName.Erase();
192 static unsigned long u = Time::GetSystemTicks() % nMax;
193 for ( unsigned long nSeed = u; ++u != nSeed; )
195 u %= nMax;
196 String aTmp( aName );
197 aTmp += OUString::valueOf(static_cast<sal_Int64>(u), nRadix);
198 aTmp += OUString( ".tmp" );
200 if ( bDir )
202 #ifdef UNX /* RW permission for the user only! */
203 mode_t old_mode = umask(077);
204 #endif
205 FileBase::RC err = Directory::create( aTmp );
206 #ifdef UNX
207 umask(old_mode);
208 #endif
209 if ( err == FileBase::E_None )
211 // !bKeep: only for creating a name, not a file or directory
212 if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
213 rName = aTmp;
214 break;
216 else if ( err != FileBase::E_EXIST )
218 // if f.e. name contains invalid chars stop trying to create dirs
219 break;
222 else
224 DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
225 File aFile( aTmp );
226 #ifdef UNX /* RW permission for the user only! */
227 mode_t old_mode = umask(077);
228 #endif
229 FileBase::RC err = aFile.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
230 #ifdef UNX
231 umask(old_mode);
232 #endif
233 if ( err == FileBase::E_None )
235 rName = aTmp;
236 aFile.close();
237 break;
239 else if ( err != FileBase::E_EXIST )
241 // if f.e. name contains invalid chars stop trying to create files
242 // but if there is a folder with such name proceed further
244 DirectoryItem aTmpItem;
245 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
246 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
247 || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
248 || aTmpStatus.getFileType() != FileStatus::Directory )
249 break;
255 void lcl_createName(TempFile_Impl& _rImpl,const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
257 _rImpl.bIsDirectory = bDirectory;
259 // get correct directory
260 String aName = ConstructTempDir_Impl( pParent );
262 sal_Bool bUseNumber = _bStartWithZero;
263 // now use special naming scheme ( name takes leading chars and an index counting up from zero
264 aName += rLeadingChars;
265 for ( sal_Int32 i=0;; i++ )
267 String aTmp( aName );
268 if ( bUseNumber )
269 aTmp += OUString::number( i );
270 bUseNumber = sal_True;
271 if ( pExtension )
272 aTmp += *pExtension;
273 else
274 aTmp += OUString( ".tmp" );
275 if ( bDirectory )
277 FileBase::RC err = Directory::create( aTmp );
278 if ( err == FileBase::E_None )
280 _rImpl.aName = aTmp;
281 break;
283 else if ( err != FileBase::E_EXIST )
284 // if f.e. name contains invalid chars stop trying to create dirs
285 break;
287 else
289 File aFile( aTmp );
290 #ifdef UNX
291 /* RW permission for the user only! */
292 mode_t old_mode = umask(077);
293 #endif
294 FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
295 #ifdef UNX
296 umask(old_mode);
297 #endif
298 if ( err == FileBase::E_None || err == FileBase::E_NOLCK )
300 _rImpl.aName = aTmp;
301 aFile.close();
302 break;
304 else if ( err != FileBase::E_EXIST )
306 // if f.e. name contains invalid chars stop trying to create dirs
307 // but if there is a folder with such name proceed further
309 DirectoryItem aTmpItem;
310 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
311 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
312 || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
313 || aTmpStatus.getFileType() != FileStatus::Directory )
314 break;
317 if ( !_bStartWithZero )
318 aTmp += OUString::number( i );
323 String TempFile::CreateTempName( const String* pParent )
325 // get correct directory
326 String aName = ConstructTempDir_Impl( pParent );
328 // get TempFile name with default naming scheme
329 CreateTempName_Impl( aName, sal_False );
331 // convert to file URL
332 OUString aTmp;
333 if ( aName.Len() )
334 FileBase::getSystemPathFromFileURL( aName, aTmp );
335 return aTmp;
338 TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
339 : pImp( new TempFile_Impl )
340 , bKillingFileEnabled( sal_False )
342 pImp->bIsDirectory = bDirectory;
344 // get correct directory
345 pImp->aName = ConstructTempDir_Impl( pParent );
347 // get TempFile with default naming scheme
348 CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
351 TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory)
352 : pImp( new TempFile_Impl )
353 , bKillingFileEnabled( sal_False )
355 lcl_createName(*pImp,rLeadingChars,sal_True, pExtension, pParent, bDirectory);
357 TempFile::TempFile( const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
358 : pImp( new TempFile_Impl )
359 , bKillingFileEnabled( sal_False )
361 lcl_createName(*pImp,rLeadingChars,_bStartWithZero, pExtension, pParent, bDirectory);
364 TempFile::~TempFile()
366 delete pImp->pStream;
367 if ( bKillingFileEnabled )
369 if ( pImp->bIsDirectory )
371 // at the moment no recursiv algorithm present
372 Directory::remove( pImp->aName );
374 else
376 File::remove( pImp->aName );
380 delete pImp;
383 sal_Bool TempFile::IsValid() const
385 return pImp->aName.Len() != 0;
388 String TempFile::GetFileName() const
390 OUString aTmp;
391 FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
392 return aTmp;
395 String TempFile::GetURL() const
397 if ( !pImp->aURL.Len() )
399 OUString aTmp;
400 LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
401 pImp->aURL = aTmp;
404 return pImp->aURL;
407 SvStream* TempFile::GetStream( StreamMode eMode )
409 if ( !pImp->pStream )
411 if ( GetURL().Len() )
412 pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ );
413 else
414 pImp->pStream = new SvMemoryStream( eMode );
417 return pImp->pStream;
420 void TempFile::CloseStream()
422 if ( pImp->pStream )
424 delete pImp->pStream;
425 pImp->pStream = NULL;
429 String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
431 if( !rBaseName.Len() )
432 return String();
434 OUString aUnqPath( rBaseName );
436 // remove trailing slash
437 if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) )
438 aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 );
440 // try to create the directory
441 sal_Bool bRet = sal_False;
442 osl::FileBase::RC err = osl::Directory::create( aUnqPath );
443 if ( err != FileBase::E_None && err != FileBase::E_EXIST )
444 // perhaps parent(s) don't exist
445 bRet = ensuredir( aUnqPath );
446 else
447 bRet = sal_True;
449 // failure to create base directory means returning an empty string
450 OUString aTmp;
451 if ( bRet )
453 // append own internal directory
454 bRet = sal_True;
455 OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
456 rTempNameBase_Impl = rBaseName;
457 rTempNameBase_Impl += OUString('/');
459 TempFile aBase( NULL, sal_True );
460 if ( aBase.IsValid() )
461 // use it in case of success
462 rTempNameBase_Impl = aBase.pImp->aName;
464 // return system path of used directory
465 FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
468 return aTmp;
472 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */