merge the formfield patch from ooo-build
[ooovba.git] / unotools / source / ucbhelper / tempfile.cxx
blob90b92a73e7cfbea41b25543af884edeaa18202c0
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tempfile.cxx,v $
10 * $Revision: 1.28 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_unotools.hxx"
34 #include <unotools/tempfile.hxx>
35 #include <tools/tempfile.hxx>
36 #include <unotools/localfilehelper.hxx>
37 #include <unotools/ucbstreamhelper.hxx>
38 #include <ucbhelper/fileidentifierconverter.hxx>
39 #include <ucbhelper/contentbroker.hxx>
40 #include <rtl/ustring.hxx>
41 #include <rtl/instance.hxx>
42 #include <osl/file.hxx>
43 #include <tools/time.hxx>
44 #include <tools/debug.hxx>
45 #include <stdio.h>
47 #ifdef UNX
48 #include <sys/stat.h>
49 #endif
51 using namespace osl;
53 namespace
55 struct TempNameBase_Impl
56 : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {};
59 namespace utl
62 struct TempFile_Impl
64 String aName;
65 String aURL;
66 SvStream* pStream;
67 sal_Bool bIsDirectory;
69 TempFile_Impl()
70 : pStream(0)
74 rtl::OUString getParentName( const rtl::OUString& aFileName )
76 sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') );
77 rtl::OUString aParent = aFileName.copy( 0,lastIndex );
79 if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 )
80 aParent += rtl::OUString::createFromAscii( "/" );
82 if( 0 == aParent.compareToAscii( "file://" ) )
83 aParent = rtl::OUString::createFromAscii( "file:///" );
85 return aParent;
88 sal_Bool ensuredir( const rtl::OUString& rUnqPath )
90 rtl::OUString aPath;
91 if ( rUnqPath.getLength() < 1 )
92 return sal_False;
94 // remove trailing slash
95 if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) )
96 aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
97 else
98 aPath = rUnqPath;
100 // HACK: create directory on a mount point with nobrowse option
101 // returns ENOSYS in any case !!
102 osl::Directory aDirectory( aPath );
103 #ifdef UNX
104 /* RW permission for the user only! */
105 mode_t old_mode = umask(077);
106 #endif
107 osl::FileBase::RC nError = aDirectory.open();
108 #ifdef UNX
109 umask(old_mode);
110 #endif
111 aDirectory.close();
112 if( nError == osl::File::E_None )
113 return sal_True;
115 // try to create the directory
116 nError = osl::Directory::create( aPath );
117 sal_Bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
118 if( !bSuccess )
120 // perhaps parent(s) don't exist
121 rtl::OUString aParentDir = getParentName( aPath );
122 if ( aParentDir != aPath )
124 bSuccess = ensuredir( getParentName( aPath ) );
126 // After parent directory structure exists try it one's more
127 if ( bSuccess )
129 // Parent directory exists, retry creation of directory
130 nError = osl::Directory::create( aPath );
131 bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
136 return bSuccess;
139 #define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 )
140 String ConstructTempDir_Impl( const String* pParent )
142 String aName;
143 if ( pParent && pParent->Len() )
145 ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get();
146 if ( pBroker )
148 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager =
149 pBroker->getContentProviderManagerInterface();
151 // if parent given try to use it
152 rtl::OUString aTmp( *pParent );
154 // test for valid filename
155 rtl::OUString aRet;
156 ::osl::FileBase::getFileURLFromSystemPath(
157 ::ucbhelper::getSystemPathFromFileURL( xManager, aTmp ),
158 aRet );
159 if ( aRet.getLength() )
161 ::osl::DirectoryItem aItem;
162 sal_Int32 i = aRet.getLength();
163 if ( aRet[i-1] == '/' )
164 i--;
166 if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None )
167 aName = aRet;
170 else
172 DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" );
176 if ( !aName.Len() )
178 ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
179 if (rTempNameBase_Impl.getLength() == 0)
181 ::rtl::OUString ustrTempDirURL;
182 ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
183 ustrTempDirURL );
184 if (rc == ::osl::FileBase::E_None)
185 rTempNameBase_Impl = ustrTempDirURL;
187 // if no parent or invalid parent : use default directory
188 DBG_ASSERT( rTempNameBase_Impl.getLength(), "No TempDir!" );
189 aName = rTempNameBase_Impl;
190 ensuredir( aName );
193 // Make sure that directory ends with a separator
194 xub_StrLen i = aName.Len();
195 if( i>0 && aName.GetChar(i-1) != '/' )
196 aName += '/';
198 return aName;
201 void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True )
203 // add a suitable tempname
204 // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576
205 // ER 13.07.00 why not radix 36 [0-9A-Z] ?!?
206 const unsigned nRadix = 26;
207 String aName( rName );
208 aName += String::CreateFromAscii( "sv" );
210 rName.Erase();
211 static unsigned long u = Time::GetSystemTicks();
212 for ( unsigned long nOld = u; ++u != nOld; )
214 u %= (nRadix*nRadix*nRadix);
215 String aTmp( aName );
216 aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix );
217 aTmp += String::CreateFromAscii( ".tmp" );
219 if ( bDir )
221 FileBase::RC err = Directory::create( aTmp );
222 if ( err == FileBase::E_None )
224 // !bKeep: only for creating a name, not a file or directory
225 if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
226 rName = aTmp;
227 break;
229 else if ( err != FileBase::E_EXIST )
231 // if f.e. name contains invalid chars stop trying to create dirs
232 break;
235 else
237 DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
238 File aFile( aTmp );
239 #ifdef UNX
240 /* RW permission for the user only! */
241 mode_t old_mode = umask(077);
242 #endif
243 FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
244 #ifdef UNX
245 umask(old_mode);
246 #endif
247 if ( err == FileBase::E_None )
249 rName = aTmp;
250 aFile.close();
251 break;
253 else if ( err != FileBase::E_EXIST )
255 // if f.e. name contains invalid chars stop trying to create files
256 // but if there is a folder with such name proceed further
258 DirectoryItem aTmpItem;
259 FileStatus aTmpStatus( FileStatusMask_Type );
260 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
261 || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
262 || aTmpStatus.getFileType() != FileStatus::Directory )
263 break;
269 void lcl_createName(TempFile_Impl& _rImpl,const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
271 _rImpl.bIsDirectory = bDirectory;
273 // get correct directory
274 String aName = ConstructTempDir_Impl( pParent );
276 sal_Bool bUseNumber = _bStartWithZero;
277 // now use special naming scheme ( name takes leading chars and an index counting up from zero
278 aName += rLeadingChars;
279 for ( sal_Int32 i=0;; i++ )
281 String aTmp( aName );
282 if ( bUseNumber )
283 aTmp += String::CreateFromInt32( i );
284 bUseNumber = sal_True;
285 if ( pExtension )
286 aTmp += *pExtension;
287 else
288 aTmp += String::CreateFromAscii( ".tmp" );
289 if ( bDirectory )
291 FileBase::RC err = Directory::create( aTmp );
292 if ( err == FileBase::E_None )
294 _rImpl.aName = aTmp;
295 break;
297 else if ( err != FileBase::E_EXIST )
298 // if f.e. name contains invalid chars stop trying to create dirs
299 break;
301 else
303 File aFile( aTmp );
304 #ifdef UNX
305 /* RW permission for the user only! */
306 mode_t old_mode = umask(077);
307 #endif
308 FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
309 #ifdef UNX
310 umask(old_mode);
311 #endif
312 if ( err == FileBase::E_None )
314 _rImpl.aName = aTmp;
315 aFile.close();
316 break;
318 else if ( err != FileBase::E_EXIST )
320 // if f.e. name contains invalid chars stop trying to create dirs
321 // but if there is a folder with such name proceed further
323 DirectoryItem aTmpItem;
324 FileStatus aTmpStatus( FileStatusMask_Type );
325 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
326 || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
327 || aTmpStatus.getFileType() != FileStatus::Directory )
328 break;
331 if ( !_bStartWithZero )
332 aTmp += String::CreateFromInt32( i );
337 String TempFile::CreateTempName( const String* pParent )
339 // get correct directory
340 String aName = ConstructTempDir_Impl( pParent );
342 // get TempFile name with default naming scheme
343 CreateTempName_Impl( aName, sal_False );
345 // convert to file URL
346 rtl::OUString aTmp;
347 if ( aName.Len() )
348 FileBase::getSystemPathFromFileURL( aName, aTmp );
349 return aTmp;
352 TempFile::TempFile( const String* pParent, sal_Bool bDirectory )
353 : pImp( new TempFile_Impl )
354 , bKillingFileEnabled( sal_False )
356 pImp->bIsDirectory = bDirectory;
358 // get correct directory
359 pImp->aName = ConstructTempDir_Impl( pParent );
361 // get TempFile with default naming scheme
362 CreateTempName_Impl( pImp->aName, sal_True, bDirectory );
365 TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory)
366 : pImp( new TempFile_Impl )
367 , bKillingFileEnabled( sal_False )
369 lcl_createName(*pImp,rLeadingChars,sal_True, pExtension, pParent, bDirectory);
371 TempFile::TempFile( const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory)
372 : pImp( new TempFile_Impl )
373 , bKillingFileEnabled( sal_False )
375 lcl_createName(*pImp,rLeadingChars,_bStartWithZero, pExtension, pParent, bDirectory);
378 TempFile::~TempFile()
380 delete pImp->pStream;
381 if ( bKillingFileEnabled )
383 if ( pImp->bIsDirectory )
385 // at the moment no recursiv algorithm present
386 Directory::remove( pImp->aName );
388 else
390 File::remove( pImp->aName );
394 delete pImp;
397 sal_Bool TempFile::IsValid() const
399 return pImp->aName.Len() != 0;
402 String TempFile::GetFileName() const
404 rtl::OUString aTmp;
405 FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
406 return aTmp;
409 String TempFile::GetURL() const
411 if ( !pImp->aURL.Len() )
413 String aTmp;
414 LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
415 pImp->aURL = aTmp;
418 return pImp->aURL;
421 SvStream* TempFile::GetStream( StreamMode eMode )
423 if ( !pImp->pStream )
425 if ( GetURL().Len() )
426 pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ );
427 else
428 pImp->pStream = new SvMemoryStream( eMode );
431 return pImp->pStream;
434 void TempFile::CloseStream()
436 if ( pImp->pStream )
438 delete pImp->pStream;
439 pImp->pStream = NULL;
443 String TempFile::SetTempNameBaseDirectory( const String &rBaseName )
445 if( !rBaseName.Len() )
446 return String();
448 rtl::OUString aUnqPath( rBaseName );
450 // remove trailing slash
451 if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) )
452 aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 );
454 // try to create the directory
455 sal_Bool bRet = sal_False;
456 osl::FileBase::RC err = osl::Directory::create( aUnqPath );
457 if ( err != FileBase::E_None && err != FileBase::E_EXIST )
458 // perhaps parent(s) don't exist
459 bRet = ensuredir( aUnqPath );
460 else
461 bRet = sal_True;
463 // failure to create base directory means returning an empty string
464 rtl::OUString aTmp;
465 if ( bRet )
467 // append own internal directory
468 bRet = sal_True;
469 ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
470 rTempNameBase_Impl = rBaseName;
471 rTempNameBase_Impl += String( '/' );
473 TempFile aBase( NULL, sal_True );
474 if ( aBase.IsValid() )
475 // use it in case of success
476 rTempNameBase_Impl = aBase.pImp->aName;
478 // return system path of used directory
479 FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
482 return aTmp;
485 String TempFile::GetTempNameBaseDirectory()
487 const ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
488 if ( !rTempNameBase_Impl.getLength() )
489 return String();
491 rtl::OUString aTmp;
492 FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
493 return aTmp;