1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
43 struct TempNameBase_Impl
44 : public rtl::Static
< OUString
, TempNameBase_Impl
> {};
55 sal_Bool bIsDirectory
;
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:///");
76 sal_Bool
ensuredir( const OUString
& rUnqPath
)
79 if ( rUnqPath
.isEmpty() )
82 // remove trailing slash
83 if ( rUnqPath
[ rUnqPath
.getLength() - 1 ] == sal_Unicode( '/' ) )
84 aPath
= rUnqPath
.copy( 0, rUnqPath
.getLength() - 1 );
88 // HACK: create directory on a mount point with nobrowse option
89 // returns ENOSYS in any case !!
90 osl::Directory
aDirectory( aPath
);
92 /* RW permission for the user only! */
93 mode_t old_mode
= umask(077);
95 osl::FileBase::RC nError
= aDirectory
.open();
100 if( nError
== osl::File::E_None
)
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
);
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
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
);
127 String
ConstructTempDir_Impl( const String
* pParent
)
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
142 ::osl::FileBase::getFileURLFromSystemPath(
143 ::ucbhelper::getSystemPathFromFileURL( pBroker
, aTmp
),
145 if ( !aRet
.isEmpty() )
147 ::osl::DirectoryItem aItem
;
148 sal_Int32 i
= aRet
.getLength();
149 if ( aRet
[i
-1] == '/' )
152 if ( DirectoryItem::get( aRet
.copy(0, i
), aItem
) == FileBase::E_None
)
159 OUString
&rTempNameBase_Impl
= TempNameBase_Impl::get();
160 if (rTempNameBase_Impl
.isEmpty())
162 OUString ustrTempDirURL
;
163 ::osl::FileBase::RC rc
= ::osl::File::getTempDirURL(
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
;
174 // Make sure that directory ends with a separator
175 xub_StrLen i
= aName
.Len();
176 if( i
>0 && aName
.GetChar(i
-1) != '/' )
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" );
192 static unsigned long u
= Time::GetSystemTicks() % nMax
;
193 for ( unsigned long nSeed
= u
; ++u
!= nSeed
; )
196 String
aTmp( aName
);
197 aTmp
+= OUString::valueOf(static_cast<sal_Int64
>(u
), nRadix
);
198 aTmp
+= OUString( ".tmp" );
202 #ifdef UNX /* RW permission for the user only! */
203 mode_t old_mode
= umask(077);
205 FileBase::RC err
= Directory::create( aTmp
);
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
)
216 else if ( err
!= FileBase::E_EXIST
)
218 // if f.e. name contains invalid chars stop trying to create dirs
224 DBG_ASSERT( bKeep
, "Too expensive, use directory for creating name!" );
226 #ifdef UNX /* RW permission for the user only! */
227 mode_t old_mode
= umask(077);
229 FileBase::RC err
= aFile
.open( osl_File_OpenFlag_Create
| osl_File_OpenFlag_NoLock
);
233 if ( err
== FileBase::E_None
)
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
)
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
);
269 aTmp
+= OUString::number( i
);
270 bUseNumber
= sal_True
;
274 aTmp
+= OUString( ".tmp" );
277 FileBase::RC err
= Directory::create( aTmp
);
278 if ( err
== FileBase::E_None
)
283 else if ( err
!= FileBase::E_EXIST
)
284 // if f.e. name contains invalid chars stop trying to create dirs
291 /* RW permission for the user only! */
292 mode_t old_mode
= umask(077);
294 FileBase::RC err
= aFile
.open(osl_File_OpenFlag_Create
);
298 if ( err
== FileBase::E_None
|| err
== FileBase::E_NOLCK
)
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
)
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
334 FileBase::getSystemPathFromFileURL( aName
, 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
);
376 File::remove( pImp
->aName
);
383 sal_Bool
TempFile::IsValid() const
385 return pImp
->aName
.Len() != 0;
388 String
TempFile::GetFileName() const
391 FileBase::getSystemPathFromFileURL( pImp
->aName
, aTmp
);
395 String
TempFile::GetURL() const
397 if ( !pImp
->aURL
.Len() )
400 LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp
);
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 */ );
414 pImp
->pStream
= new SvMemoryStream( eMode
);
417 return pImp
->pStream
;
420 void TempFile::CloseStream()
424 delete pImp
->pStream
;
425 pImp
->pStream
= NULL
;
429 String
TempFile::SetTempNameBaseDirectory( const String
&rBaseName
)
431 if( !rBaseName
.Len() )
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
);
449 // failure to create base directory means returning an empty string
453 // append own internal directory
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
);
472 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */