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 <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>
44 struct TempNameBase_Impl
45 : public rtl::Static
< ::rtl::OUString
, TempNameBase_Impl
> {};
56 sal_Bool bIsDirectory
;
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:///");
77 sal_Bool
ensuredir( const rtl::OUString
& rUnqPath
)
80 if ( rUnqPath
.isEmpty() )
83 // remove trailing slash
84 if ( rUnqPath
[ rUnqPath
.getLength() - 1 ] == sal_Unicode( '/' ) )
85 aPath
= rUnqPath
.copy( 0, rUnqPath
.getLength() - 1 );
89 // HACK: create directory on a mount point with nobrowse option
90 // returns ENOSYS in any case !!
91 osl::Directory
aDirectory( aPath
);
93 /* RW permission for the user only! */
94 mode_t old_mode
= umask(077);
96 osl::FileBase::RC nError
= aDirectory
.open();
101 if( nError
== osl::File::E_None
)
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
);
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
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
);
128 String
ConstructTempDir_Impl( const String
* pParent
)
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
143 ::osl::FileBase::getFileURLFromSystemPath(
144 ::ucbhelper::getSystemPathFromFileURL( pBroker
, aTmp
),
146 if ( !aRet
.isEmpty() )
148 ::osl::DirectoryItem aItem
;
149 sal_Int32 i
= aRet
.getLength();
150 if ( aRet
[i
-1] == '/' )
153 if ( DirectoryItem::get( aRet
.copy(0, i
), aItem
) == FileBase::E_None
)
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(
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
;
175 // Make sure that directory ends with a separator
176 xub_StrLen i
= aName
.Len();
177 if( i
>0 && aName
.GetChar(i
-1) != '/' )
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" );
193 static unsigned long u
= Time::GetSystemTicks() % nMax
;
194 for ( unsigned long nSeed
= u
; ++u
!= nSeed
; )
197 String
aTmp( aName
);
198 aTmp
+= rtl::OUString::valueOf(static_cast<sal_Int64
>(u
), nRadix
);
199 aTmp
+= rtl::OUString( ".tmp" );
203 #ifdef UNX /* RW permission for the user only! */
204 mode_t old_mode
= umask(077);
206 FileBase::RC err
= Directory::create( aTmp
);
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
)
217 else if ( err
!= FileBase::E_EXIST
)
219 // if f.e. name contains invalid chars stop trying to create dirs
225 DBG_ASSERT( bKeep
, "Too expensive, use directory for creating name!" );
227 #ifdef UNX /* RW permission for the user only! */
228 mode_t old_mode
= umask(077);
230 FileBase::RC err
= aFile
.open( osl_File_OpenFlag_Create
| osl_File_OpenFlag_NoLock
);
234 if ( err
== FileBase::E_None
)
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
)
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
);
270 aTmp
+= String::CreateFromInt32( i
);
271 bUseNumber
= sal_True
;
275 aTmp
+= rtl::OUString( ".tmp" );
278 FileBase::RC err
= Directory::create( aTmp
);
279 if ( err
== FileBase::E_None
)
284 else if ( err
!= FileBase::E_EXIST
)
285 // if f.e. name contains invalid chars stop trying to create dirs
292 /* RW permission for the user only! */
293 mode_t old_mode
= umask(077);
295 FileBase::RC err
= aFile
.open(osl_File_OpenFlag_Create
);
299 if ( err
== FileBase::E_None
|| err
== FileBase::E_NOLCK
)
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
)
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
335 FileBase::getSystemPathFromFileURL( aName
, 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
);
377 File::remove( pImp
->aName
);
384 sal_Bool
TempFile::IsValid() const
386 return pImp
->aName
.Len() != 0;
389 String
TempFile::GetFileName() const
392 FileBase::getSystemPathFromFileURL( pImp
->aName
, aTmp
);
396 String
TempFile::GetURL() const
398 if ( !pImp
->aURL
.Len() )
401 LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp
);
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 */ );
415 pImp
->pStream
= new SvMemoryStream( eMode
);
418 return pImp
->pStream
;
421 void TempFile::CloseStream()
425 delete pImp
->pStream
;
426 pImp
->pStream
= NULL
;
430 String
TempFile::SetTempNameBaseDirectory( const String
&rBaseName
)
432 if( !rBaseName
.Len() )
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
);
450 // failure to create base directory means returning an empty string
454 // append own internal directory
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
);
473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */