Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / unotools / source / ucbhelper / tempfile.cxx
blob1782dcf6a011f8099e9f09535fd3b5196df85a3e
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 <tools/tempfile.hxx>
26 #include <unotools/localfilehelper.hxx>
27 #include <unotools/ucbstreamhelper.hxx>
28 #include <ucbhelper/fileidentifierconverter.hxx>
29 #include <rtl/ustring.hxx>
30 #include <rtl/instance.hxx>
31 #include <osl/file.hxx>
32 #include <tools/time.hxx>
33 #include <tools/debug.hxx>
34 #include <stdio.h>
36 #ifdef UNX
37 #include <sys/stat.h>
38 #endif
40 using namespace osl;
42 namespace
44 struct TempNameBase_Impl
45 : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {};
48 namespace utl
51 struct TempFile_Impl
53 String aName;
54 String aURL;
55 SvStream* pStream;
56 sal_Bool bIsDirectory;
58 TempFile_Impl()
59 : pStream(0)
63 rtl::OUString getParentName( const rtl::OUString& aFileName )
65 sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') );
66 rtl::OUString aParent = aFileName.copy( 0,lastIndex );
68 if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 )
69 aParent += rtl::OUString("/");
71 if( 0 == aParent.compareToAscii( "file://" ) )
72 aParent = rtl::OUString("file:///");
74 return aParent;
77 sal_Bool ensuredir( const rtl::OUString& rUnqPath )
79 rtl::OUString aPath;
80 if ( rUnqPath.isEmpty() )
81 return sal_False;
83 // remove trailing slash
84 if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) )
85 aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
86 else
87 aPath = rUnqPath;
89 // HACK: create directory on a mount point with nobrowse option
90 // returns ENOSYS in any case !!
91 osl::Directory aDirectory( aPath );
92 #ifdef UNX
93 /* RW permission for the user only! */
94 mode_t old_mode = umask(077);
95 #endif
96 osl::FileBase::RC nError = aDirectory.open();
97 #ifdef UNX
98 umask(old_mode);
99 #endif
100 aDirectory.close();
101 if( nError == osl::File::E_None )
102 return sal_True;
104 // try to create the directory
105 nError = osl::Directory::create( aPath );
106 sal_Bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
107 if( !bSuccess )
109 // perhaps parent(s) don't exist
110 rtl::OUString aParentDir = getParentName( aPath );
111 if ( aParentDir != aPath )
113 bSuccess = ensuredir( getParentName( aPath ) );
115 // After parent directory structure exists try it one's more
116 if ( bSuccess )
118 // Parent directory exists, retry creation of directory
119 nError = osl::Directory::create( aPath );
120 bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
125 return bSuccess;
128 String ConstructTempDir_Impl( const String* pParent )
130 String aName;
131 if ( pParent && pParent->Len() )
133 com::sun::star::uno::Reference<
134 com::sun::star::ucb::XUniversalContentBroker > pBroker(
135 com::sun::star::ucb::UniversalContentBroker::create(
136 comphelper::getProcessComponentContext() ) );
138 // if parent given try to use it
139 rtl::OUString aTmp( *pParent );
141 // test for valid filename
142 rtl::OUString aRet;
143 ::osl::FileBase::getFileURLFromSystemPath(
144 ::ucbhelper::getSystemPathFromFileURL( pBroker, aTmp ),
145 aRet );
146 if ( !aRet.isEmpty() )
148 ::osl::DirectoryItem aItem;
149 sal_Int32 i = aRet.getLength();
150 if ( aRet[i-1] == '/' )
151 i--;
153 if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None )
154 aName = aRet;
158 if ( !aName.Len() )
160 ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
161 if (rTempNameBase_Impl.isEmpty())
163 ::rtl::OUString ustrTempDirURL;
164 ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
165 ustrTempDirURL );
166 if (rc == ::osl::FileBase::E_None)
167 rTempNameBase_Impl = ustrTempDirURL;
169 // if no parent or invalid parent : use default directory
170 DBG_ASSERT( !rTempNameBase_Impl.isEmpty(), "No TempDir!" );
171 aName = rTempNameBase_Impl;
172 ensuredir( aName );
175 // Make sure that directory ends with a separator
176 xub_StrLen i = aName.Len();
177 if( i>0 && aName.GetChar(i-1) != '/' )
178 aName += '/';
180 return aName;
183 void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
185 // add a suitable tempname
186 // 36 ** 6 == 2176782336
187 unsigned const nRadix = 36;
188 unsigned long const nMax = (nRadix*nRadix*nRadix*nRadix*nRadix*nRadix);
189 String aName( rName );
190 aName += rtl::OUString( "lu" );
192 rName.Erase();
193 static unsigned long u = Time::GetSystemTicks() % nMax;
194 for ( unsigned long nSeed = u; ++u != nSeed; )
196 u %= nMax;
197 String aTmp( aName );
198 aTmp += rtl::OUString::valueOf(static_cast<sal_Int64>(u), nRadix);
199 aTmp += rtl::OUString( ".tmp" );
201 if ( bDir )
203 #ifdef UNX /* RW permission for the user only! */
204 mode_t old_mode = umask(077);
205 #endif
206 FileBase::RC err = Directory::create( aTmp );
207 #ifdef UNX
208 umask(old_mode);
209 #endif
210 if ( err == FileBase::E_None )
212 // !bKeep: only for creating a name, not a file or directory
213 if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
214 rName = aTmp;
215 break;
217 else if ( err != FileBase::E_EXIST )
219 // if f.e. name contains invalid chars stop trying to create dirs
220 break;
223 else
225 DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
226 File aFile( aTmp );
227 #ifdef UNX /* RW permission for the user only! */
228 mode_t old_mode = umask(077);
229 #endif
230 FileBase::RC err = aFile.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
231 #ifdef UNX
232 umask(old_mode);
233 #endif
234 if ( err == FileBase::E_None )
236 rName = aTmp;
237 aFile.close();
238 break;
240 else if ( err != FileBase::E_EXIST )
242 // if f.e. name contains invalid chars stop trying to create files
243 // but if there is a folder with such name proceed further
245 DirectoryItem aTmpItem;
246 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
247 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
248 || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
249 || aTmpStatus.getFileType() != FileStatus::Directory )
250 break;
256 void lcl_createName(TempFile_Impl& _rImpl,const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
258 _rImpl.bIsDirectory = bDirectory;
260 // get correct directory
261 String aName = ConstructTempDir_Impl( pParent );
263 sal_Bool bUseNumber = _bStartWithZero;
264 // now use special naming scheme ( name takes leading chars and an index counting up from zero
265 aName += rLeadingChars;
266 for ( sal_Int32 i=0;; i++ )
268 String aTmp( aName );
269 if ( bUseNumber )
270 aTmp += String::CreateFromInt32( i );
271 bUseNumber = sal_True;
272 if ( pExtension )
273 aTmp += *pExtension;
274 else
275 aTmp += rtl::OUString( ".tmp" );
276 if ( bDirectory )
278 FileBase::RC err = Directory::create( aTmp );
279 if ( err == FileBase::E_None )
281 _rImpl.aName = aTmp;
282 break;
284 else if ( err != FileBase::E_EXIST )
285 // if f.e. name contains invalid chars stop trying to create dirs
286 break;
288 else
290 File aFile( aTmp );
291 #ifdef UNX
292 /* RW permission for the user only! */
293 mode_t old_mode = umask(077);
294 #endif
295 FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
296 #ifdef UNX
297 umask(old_mode);
298 #endif
299 if ( err == FileBase::E_None || err == FileBase::E_NOLCK )
301 _rImpl.aName = aTmp;
302 aFile.close();
303 break;
305 else if ( err != FileBase::E_EXIST )
307 // if f.e. name contains invalid chars stop trying to create dirs
308 // but if there is a folder with such name proceed further
310 DirectoryItem aTmpItem;
311 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
312 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
313 || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
314 || aTmpStatus.getFileType() != FileStatus::Directory )
315 break;
318 if ( !_bStartWithZero )
319 aTmp += String::CreateFromInt32( i );
324 String TempFile::CreateTempName( const String* pParent )
326 // get correct directory
327 String aName = ConstructTempDir_Impl( pParent );
329 // get TempFile name with default naming scheme
330 CreateTempName_Impl( aName, sal_False );
332 // convert to file URL
333 rtl::OUString aTmp;
334 if ( aName.Len() )
335 FileBase::getSystemPathFromFileURL( aName, aTmp );
336 return aTmp;
339 TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
340 : pImp( new TempFile_Impl )
341 , bKillingFileEnabled( sal_False )
343 pImp->bIsDirectory = bDirectory;
345 // get correct directory
346 pImp->aName = ConstructTempDir_Impl( pParent );
348 // get TempFile with default naming scheme
349 CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
352 TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory)
353 : pImp( new TempFile_Impl )
354 , bKillingFileEnabled( sal_False )
356 lcl_createName(*pImp,rLeadingChars,sal_True, pExtension, pParent, bDirectory);
358 TempFile::TempFile( const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
359 : pImp( new TempFile_Impl )
360 , bKillingFileEnabled( sal_False )
362 lcl_createName(*pImp,rLeadingChars,_bStartWithZero, pExtension, pParent, bDirectory);
365 TempFile::~TempFile()
367 delete pImp->pStream;
368 if ( bKillingFileEnabled )
370 if ( pImp->bIsDirectory )
372 // at the moment no recursiv algorithm present
373 Directory::remove( pImp->aName );
375 else
377 File::remove( pImp->aName );
381 delete pImp;
384 sal_Bool TempFile::IsValid() const
386 return pImp->aName.Len() != 0;
389 String TempFile::GetFileName() const
391 rtl::OUString aTmp;
392 FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
393 return aTmp;
396 String TempFile::GetURL() const
398 if ( !pImp->aURL.Len() )
400 rtl::OUString aTmp;
401 LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
402 pImp->aURL = aTmp;
405 return pImp->aURL;
408 SvStream* TempFile::GetStream( StreamMode eMode )
410 if ( !pImp->pStream )
412 if ( GetURL().Len() )
413 pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ );
414 else
415 pImp->pStream = new SvMemoryStream( eMode );
418 return pImp->pStream;
421 void TempFile::CloseStream()
423 if ( pImp->pStream )
425 delete pImp->pStream;
426 pImp->pStream = NULL;
430 String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
432 if( !rBaseName.Len() )
433 return String();
435 rtl::OUString aUnqPath( rBaseName );
437 // remove trailing slash
438 if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) )
439 aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 );
441 // try to create the directory
442 sal_Bool bRet = sal_False;
443 osl::FileBase::RC err = osl::Directory::create( aUnqPath );
444 if ( err != FileBase::E_None && err != FileBase::E_EXIST )
445 // perhaps parent(s) don't exist
446 bRet = ensuredir( aUnqPath );
447 else
448 bRet = sal_True;
450 // failure to create base directory means returning an empty string
451 rtl::OUString aTmp;
452 if ( bRet )
454 // append own internal directory
455 bRet = sal_True;
456 ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
457 rTempNameBase_Impl = rBaseName;
458 rTempNameBase_Impl += rtl::OUString('/');
460 TempFile aBase( NULL, sal_True );
461 if ( aBase.IsValid() )
462 // use it in case of success
463 rTempNameBase_Impl = aBase.pImp->aName;
465 // return system path of used directory
466 FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
469 return aTmp;
473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */