1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tempfile.cxx,v $
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>
55 struct TempNameBase_Impl
56 : public rtl::Static
< ::rtl::OUString
, TempNameBase_Impl
> {};
67 sal_Bool bIsDirectory
;
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:///" );
88 sal_Bool
ensuredir( const rtl::OUString
& rUnqPath
)
91 if ( rUnqPath
.getLength() < 1 )
94 // remove trailing slash
95 if ( rUnqPath
[ rUnqPath
.getLength() - 1 ] == sal_Unicode( '/' ) )
96 aPath
= rUnqPath
.copy( 0, rUnqPath
.getLength() - 1 );
100 // HACK: create directory on a mount point with nobrowse option
101 // returns ENOSYS in any case !!
102 osl::Directory
aDirectory( aPath
);
104 /* RW permission for the user only! */
105 mode_t old_mode
= umask(077);
107 osl::FileBase::RC nError
= aDirectory
.open();
112 if( nError
== osl::File::E_None
)
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
);
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
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
);
139 #define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 )
140 String
ConstructTempDir_Impl( const String
* pParent
)
143 if ( pParent
&& pParent
->Len() )
145 ::ucbhelper::ContentBroker
* pBroker
= ::ucbhelper::ContentBroker::get();
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
156 ::osl::FileBase::getFileURLFromSystemPath(
157 ::ucbhelper::getSystemPathFromFileURL( xManager
, aTmp
),
159 if ( aRet
.getLength() )
161 ::osl::DirectoryItem aItem
;
162 sal_Int32 i
= aRet
.getLength();
163 if ( aRet
[i
-1] == '/' )
166 if ( DirectoryItem::get( ::rtl::OUString( aRet
, i
), aItem
) == FileBase::E_None
)
172 DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" );
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(
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
;
193 // Make sure that directory ends with a separator
194 xub_StrLen i
= aName
.Len();
195 if( i
>0 && aName
.GetChar(i
-1) != '/' )
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" );
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" );
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
)
229 else if ( err
!= FileBase::E_EXIST
)
231 // if f.e. name contains invalid chars stop trying to create dirs
237 DBG_ASSERT( bKeep
, "Too expensive, use directory for creating name!" );
240 /* RW permission for the user only! */
241 mode_t old_mode
= umask(077);
243 FileBase::RC err
= aFile
.open(osl_File_OpenFlag_Create
);
247 if ( err
== FileBase::E_None
)
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
)
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
);
283 aTmp
+= String::CreateFromInt32( i
);
284 bUseNumber
= sal_True
;
288 aTmp
+= String::CreateFromAscii( ".tmp" );
291 FileBase::RC err
= Directory::create( aTmp
);
292 if ( err
== FileBase::E_None
)
297 else if ( err
!= FileBase::E_EXIST
)
298 // if f.e. name contains invalid chars stop trying to create dirs
305 /* RW permission for the user only! */
306 mode_t old_mode
= umask(077);
308 FileBase::RC err
= aFile
.open(osl_File_OpenFlag_Create
);
312 if ( err
== FileBase::E_None
)
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
)
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
348 FileBase::getSystemPathFromFileURL( aName
, 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
);
390 File::remove( pImp
->aName
);
397 sal_Bool
TempFile::IsValid() const
399 return pImp
->aName
.Len() != 0;
402 String
TempFile::GetFileName() const
405 FileBase::getSystemPathFromFileURL( pImp
->aName
, aTmp
);
409 String
TempFile::GetURL() const
411 if ( !pImp
->aURL
.Len() )
414 LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp
);
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 */ );
428 pImp
->pStream
= new SvMemoryStream( eMode
);
431 return pImp
->pStream
;
434 void TempFile::CloseStream()
438 delete pImp
->pStream
;
439 pImp
->pStream
= NULL
;
443 String
TempFile::SetTempNameBaseDirectory( const String
&rBaseName
)
445 if( !rBaseName
.Len() )
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
);
463 // failure to create base directory means returning an empty string
467 // append own internal directory
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
);
485 String
TempFile::GetTempNameBaseDirectory()
487 const ::rtl::OUString
&rTempNameBase_Impl
= TempNameBase_Impl::get();
488 if ( !rTempNameBase_Impl
.getLength() )
492 FileBase::getSystemPathFromFileURL( rTempNameBase_Impl
, aTmp
);