LCOV - code coverage report
Current view: top level - unotools/source/ucbhelper - tempfile.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 165 222 74.3 %
Date: 2014-04-11 Functions: 16 18 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "sal/config.h"
      21             : 
      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>
      33             : #include <stdio.h>
      34             : 
      35             : #ifdef UNX
      36             : #include <sys/stat.h>
      37             : #endif
      38             : 
      39             : using namespace osl;
      40             : 
      41             : namespace
      42             : {
      43             :     struct TempNameBase_Impl
      44             :         : public rtl::Static< OUString, TempNameBase_Impl > {};
      45             : }
      46             : 
      47             : namespace utl
      48             : {
      49             : 
      50       18226 : struct TempFile_Impl
      51             : {
      52             :     OUString    aName;
      53             :     OUString    aURL;
      54             :     SvStream*   pStream;
      55             :     bool        bIsDirectory;
      56             : 
      57       18274 :     TempFile_Impl()
      58             :         : pStream(0)
      59       18274 :         , bIsDirectory(false)
      60             :     {
      61       18274 :     }
      62             : };
      63             : 
      64           0 : OUString getParentName( const OUString& aFileName )
      65             : {
      66           0 :     sal_Int32 lastIndex = aFileName.lastIndexOf( '/' );
      67           0 :     OUString aParent = aFileName.copy( 0, lastIndex );
      68             : 
      69           0 :     if( aParent.endsWith(":") && aParent.getLength() == 6 )
      70           0 :         aParent += "/";
      71             : 
      72           0 :     if( aParent.equalsAscii( "file://" ) )
      73           0 :         aParent = "file:///";
      74             : 
      75           0 :     return aParent;
      76             : }
      77             : 
      78       17875 : bool ensuredir( const OUString& rUnqPath )
      79             : {
      80       17875 :     OUString aPath;
      81       17875 :     if ( rUnqPath.isEmpty() )
      82           0 :         return false;
      83             : 
      84             :     // remove trailing slash
      85       17875 :     if ( rUnqPath.endsWith("/") )
      86          80 :         aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 );
      87             :     else
      88       17795 :         aPath = rUnqPath;
      89             : 
      90             :     // HACK: create directory on a mount point with nobrowse option
      91             :     // returns ENOSYS in any case !!
      92       35750 :     osl::Directory aDirectory( aPath );
      93             : #ifdef UNX
      94             : /* RW permission for the user only! */
      95       17875 :  mode_t old_mode = umask(077);
      96             : #endif
      97       17875 :     osl::FileBase::RC nError = aDirectory.open();
      98             : #ifdef UNX
      99       17875 : umask(old_mode);
     100             : #endif
     101       17875 :     aDirectory.close();
     102       17875 :     if( nError == osl::File::E_None )
     103       17875 :         return true;
     104             : 
     105             :     // try to create the directory
     106           0 :     nError = osl::Directory::create( aPath );
     107           0 :     bool  bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
     108           0 :     if( !bSuccess )
     109             :     {
     110             :         // perhaps parent(s) don't exist
     111           0 :         OUString aParentDir = getParentName( aPath );
     112           0 :         if ( aParentDir != aPath )
     113             :         {
     114           0 :             bSuccess = ensuredir( getParentName( aPath ) );
     115             : 
     116             :             // After parent directory structure exists try it one's more
     117           0 :             if ( bSuccess )
     118             :             {
     119             :                 // Parent directory exists, retry creation of directory
     120           0 :                 nError = osl::Directory::create( aPath );
     121           0 :                 bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST );
     122             :             }
     123           0 :         }
     124             :     }
     125             : 
     126       17875 :     return bSuccess;
     127             : }
     128             : 
     129       18283 : OUString ConstructTempDir_Impl( const OUString* pParent )
     130             : {
     131       18283 :     OUString aName;
     132       18283 :     if ( pParent && !pParent->isEmpty() )
     133             :     {
     134             :         com::sun::star::uno::Reference<
     135             :             com::sun::star::ucb::XUniversalContentBroker > pBroker(
     136             :                 com::sun::star::ucb::UniversalContentBroker::create(
     137         408 :                     comphelper::getProcessComponentContext() ) );
     138             : 
     139             :         // if parent given try to use it
     140         816 :         OUString aTmp( *pParent );
     141             : 
     142             :         // test for valid filename
     143         816 :         OUString aRet;
     144             :         ::osl::FileBase::getFileURLFromSystemPath(
     145             :             ::ucbhelper::getSystemPathFromFileURL( pBroker, aTmp ),
     146         408 :             aRet );
     147         408 :         if ( !aRet.isEmpty() )
     148             :         {
     149         408 :             ::osl::DirectoryItem aItem;
     150         408 :             sal_Int32 i = aRet.getLength();
     151         408 :             if ( aRet[i-1] == '/' )
     152           0 :                 i--;
     153             : 
     154         408 :             if ( DirectoryItem::get( aRet.copy(0, i), aItem ) == FileBase::E_None )
     155         408 :                 aName = aRet;
     156         408 :         }
     157             :     }
     158             : 
     159       18283 :     if ( aName.isEmpty() )
     160             :     {
     161       17875 :         OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
     162       17875 :         if (rTempNameBase_Impl.isEmpty())
     163             :         {
     164          59 :             OUString ustrTempDirURL;
     165             :             ::osl::FileBase::RC rc = ::osl::File::getTempDirURL(
     166          59 :                 ustrTempDirURL );
     167          59 :             if (rc == ::osl::FileBase::E_None)
     168          59 :                 rTempNameBase_Impl = ustrTempDirURL;
     169             :         }
     170             :         // if no parent or invalid parent : use default directory
     171             :         DBG_ASSERT( !rTempNameBase_Impl.isEmpty(), "No TempDir!" );
     172       17875 :         aName = rTempNameBase_Impl;
     173       17875 :         ensuredir( aName );
     174             :     }
     175             : 
     176             :     // Make sure that directory ends with a separator
     177       18283 :     if( !aName.isEmpty() && !aName.endsWith("/") )
     178       18203 :         aName += "/";
     179             : 
     180       18283 :     return aName;
     181             : }
     182             : 
     183       17871 : void CreateTempName_Impl( OUString& rName, bool bKeep, bool bDir = true )
     184             : {
     185             :     // add a suitable tempname
     186             :     // 36 ** 6 == 2176782336
     187       17871 :     unsigned const nRadix = 36;
     188       17871 :     unsigned long const nMax = (nRadix*nRadix*nRadix*nRadix*nRadix*nRadix);
     189       17871 :     OUString aName;
     190       35742 :     OUString aEyeCatcher = "lu";
     191             : #ifdef DBG_UTIL
     192             : #ifdef UNX
     193             :     const char* eye = getenv("LO_TESTNAME");
     194             :     if(eye)
     195             :     {
     196             :         aEyeCatcher = OUString(eye, strlen(eye), RTL_TEXTENCODING_ASCII_US);
     197             :     }
     198             : #endif
     199             : #endif
     200       17871 :     aName = rName + aEyeCatcher;
     201       17871 :     rName = "";
     202       17871 :     static unsigned long u = Time::GetSystemTicks() % nMax;
     203       35742 :     for ( unsigned long nSeed = u; ++u != nSeed; )
     204             :     {
     205       17871 :         u %= nMax;
     206       17871 :         OUString aTmp( aName );
     207       17871 :         aTmp += OUString::number(u, nRadix);
     208       17871 :         aTmp += ".tmp";
     209             : 
     210       17871 :         if ( bDir )
     211             :         {
     212             : #ifdef UNX /* RW permission for the user only! */
     213          95 :             mode_t old_mode = umask(077);
     214             : #endif
     215          95 :             FileBase::RC err = Directory::create( aTmp );
     216             : #ifdef UNX
     217          95 :             umask(old_mode);
     218             : #endif
     219          95 :             if ( err == FileBase::E_None )
     220             :             {
     221             :                 // !bKeep: only for creating a name, not a file or directory
     222          95 :                 if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None )
     223          95 :                     rName = aTmp;
     224          95 :                 break;
     225             :             }
     226           0 :             else if ( err != FileBase::E_EXIST )
     227             :             {
     228             :                 // if f.e. name contains invalid chars stop trying to create dirs
     229           0 :                 break;
     230             :             }
     231             :         }
     232             :         else
     233             :         {
     234             :             DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" );
     235       17776 :             File aFile( aTmp );
     236             : #ifdef UNX /* RW permission for the user only! */
     237       17776 :             mode_t old_mode = umask(077);
     238             : #endif
     239       17776 :             FileBase::RC err = aFile.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock );
     240             : #ifdef UNX
     241       17776 :             umask(old_mode);
     242             : #endif
     243       17776 :             if (  err == FileBase::E_None )
     244             :             {
     245       17776 :                 rName = aTmp;
     246       17776 :                 aFile.close();
     247       17776 :                 break;
     248             :             }
     249           0 :             else if ( err != FileBase::E_EXIST )
     250             :             {
     251             :                  // if f.e. name contains invalid chars stop trying to create files
     252             :                  // but if there is a folder with such name proceed further
     253             : 
     254           0 :                  DirectoryItem aTmpItem;
     255           0 :                  FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
     256           0 :                  if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
     257           0 :                    || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
     258           0 :                    || aTmpStatus.getFileType() != FileStatus::Directory )
     259           0 :                      break;
     260           0 :             }
     261             :         }
     262       17871 :     }
     263       17871 : }
     264             : 
     265         412 : void lcl_createName(TempFile_Impl& _rImpl,const OUString& rLeadingChars, bool _bStartWithZero,
     266             :                     const OUString* pExtension, const OUString* pParent, bool bDirectory)
     267             : {
     268         412 :     _rImpl.bIsDirectory = bDirectory;
     269             : 
     270             :     // get correct directory
     271         412 :     OUString aName = ConstructTempDir_Impl( pParent );
     272             : 
     273         412 :     bool bUseNumber = _bStartWithZero;
     274             :     // now use special naming scheme ( name takes leading chars and an index counting up from zero
     275         412 :     aName += rLeadingChars;
     276         412 :     for ( sal_Int32 i=0;; i++ )
     277             :     {
     278         412 :         OUString aTmp( aName );
     279         412 :         if ( bUseNumber )
     280         412 :             aTmp += OUString::number( i );
     281         412 :         bUseNumber = true;
     282         412 :         if ( pExtension )
     283         411 :             aTmp += *pExtension;
     284             :         else
     285           1 :             aTmp += ".tmp";
     286         412 :         if ( bDirectory )
     287             :         {
     288           0 :             FileBase::RC err = Directory::create( aTmp );
     289           0 :             if ( err == FileBase::E_None )
     290             :             {
     291           0 :                 _rImpl.aName = aTmp;
     292           0 :                 break;
     293             :             }
     294           0 :             else if ( err != FileBase::E_EXIST )
     295             :                 // if f.e. name contains invalid chars stop trying to create dirs
     296           0 :                 break;
     297             :         }
     298             :         else
     299             :         {
     300         412 :             File aFile( aTmp );
     301             : #ifdef UNX
     302             : /* RW permission for the user only! */
     303         412 :  mode_t old_mode = umask(077);
     304             : #endif
     305         412 :             FileBase::RC err = aFile.open(osl_File_OpenFlag_Create);
     306             : #ifdef UNX
     307         412 : umask(old_mode);
     308             : #endif
     309         412 :             if ( err == FileBase::E_None || err == FileBase::E_NOLCK )
     310             :             {
     311         412 :                 _rImpl.aName = aTmp;
     312         412 :                 aFile.close();
     313         412 :                 break;
     314             :             }
     315           0 :             else if ( err != FileBase::E_EXIST )
     316             :             {
     317             :                 // if f.e. name contains invalid chars stop trying to create dirs
     318             :                 // but if there is a folder with such name proceed further
     319             : 
     320           0 :                 DirectoryItem aTmpItem;
     321           0 :                 FileStatus aTmpStatus( osl_FileStatus_Mask_Type );
     322           0 :                 if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None
     323           0 :                   || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None
     324           0 :                   || aTmpStatus.getFileType() != FileStatus::Directory )
     325           0 :                     break;
     326           0 :             }
     327             :         }
     328           0 :         if ( !_bStartWithZero )
     329           0 :             aTmp += OUString::number( i );
     330           0 :     }
     331         412 : }
     332             : 
     333           9 : OUString TempFile::CreateTempName( const OUString* pParent )
     334             : {
     335             :     // get correct directory
     336           9 :     OUString aName = ConstructTempDir_Impl( pParent );
     337             : 
     338             :     // get TempFile name with default naming scheme
     339           9 :     CreateTempName_Impl( aName, false );
     340             : 
     341             :     // convert to file URL
     342           9 :     OUString aTmp;
     343           9 :     if ( !aName.isEmpty() )
     344           9 :         FileBase::getSystemPathFromFileURL( aName, aTmp );
     345           9 :     return aTmp;
     346             : }
     347             : 
     348       17862 : TempFile::TempFile( const OUString* pParent, bool bDirectory )
     349       17862 :     : pImp( new TempFile_Impl )
     350       35724 :     , bKillingFileEnabled( false )
     351             : {
     352       17862 :     pImp->bIsDirectory = bDirectory;
     353             : 
     354             :     // get correct directory
     355       17862 :     pImp->aName = ConstructTempDir_Impl( pParent );
     356             : 
     357             :     // get TempFile with default naming scheme
     358       17862 :     CreateTempName_Impl( pImp->aName, true, bDirectory );
     359       17862 : }
     360             : 
     361         412 : TempFile::TempFile( const OUString& rLeadingChars, const OUString* pExtension, const OUString* pParent, bool bDirectory)
     362         412 :     : pImp( new TempFile_Impl )
     363         824 :     , bKillingFileEnabled( false )
     364             : {
     365         412 :     lcl_createName(*pImp, rLeadingChars, true, pExtension, pParent, bDirectory);
     366         412 : }
     367           0 : TempFile::TempFile( const OUString& rLeadingChars, bool _bStartWithZero, const OUString* pExtension, const OUString* pParent, bool bDirectory)
     368           0 :     : pImp( new TempFile_Impl )
     369           0 :     , bKillingFileEnabled( false )
     370             : {
     371           0 :     lcl_createName(*pImp, rLeadingChars, _bStartWithZero, pExtension, pParent, bDirectory);
     372           0 : }
     373             : 
     374       18226 : TempFile::~TempFile()
     375             : {
     376       18226 :     delete pImp->pStream;
     377       18226 :     if ( bKillingFileEnabled )
     378             :     {
     379       10267 :         if ( pImp->bIsDirectory )
     380             :         {
     381             :             // at the moment no recursiv algorithm present
     382           0 :             Directory::remove( pImp->aName );
     383             :         }
     384             :         else
     385             :         {
     386       10267 :             File::remove( pImp->aName );
     387             :         }
     388             :     }
     389             : 
     390       18226 :     delete pImp;
     391       18226 : }
     392             : 
     393         110 : bool TempFile::IsValid() const
     394             : {
     395         110 :     return !(pImp->aName.isEmpty());
     396             : }
     397             : 
     398       19569 : OUString TempFile::GetFileName() const
     399             : {
     400       19569 :     OUString aTmp;
     401       19569 :     FileBase::getSystemPathFromFileURL( pImp->aName, aTmp );
     402       19569 :     return aTmp;
     403             : }
     404             : 
     405       21344 : OUString TempFile::GetURL() const
     406             : {
     407       21344 :     if ( pImp->aURL.isEmpty() )
     408             :     {
     409       17489 :         OUString aTmp;
     410       17489 :         LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp );
     411       17489 :         pImp->aURL = aTmp;
     412             :     }
     413             : 
     414       21344 :     return pImp->aURL;
     415             : }
     416             : 
     417        9265 : SvStream* TempFile::GetStream( StreamMode eMode )
     418             : {
     419        9265 :     if ( !pImp->pStream )
     420             :     {
     421        9265 :         if ( !GetURL().isEmpty() )
     422        9265 :             pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, true /* bFileExists */ );
     423             :         else
     424           0 :             pImp->pStream = new SvMemoryStream( eMode );
     425             :     }
     426             : 
     427        9265 :     return pImp->pStream;
     428             : }
     429             : 
     430        4712 : void TempFile::CloseStream()
     431             : {
     432        4712 :     if ( pImp->pStream )
     433             :     {
     434        4712 :         delete pImp->pStream;
     435        4712 :         pImp->pStream = NULL;
     436             :     }
     437        4712 : }
     438             : 
     439          80 : OUString TempFile::SetTempNameBaseDirectory( const OUString &rBaseName )
     440             : {
     441          80 :     if( rBaseName.isEmpty() )
     442           0 :         return OUString();
     443             : 
     444          80 :     OUString aUnqPath( rBaseName );
     445             : 
     446             :     // remove trailing slash
     447          80 :     if ( rBaseName.endsWith("/") )
     448           0 :         aUnqPath = rBaseName.copy( 0, rBaseName.getLength() - 1 );
     449             : 
     450             :     // try to create the directory
     451          80 :     bool bRet = false;
     452          80 :     osl::FileBase::RC err = osl::Directory::create( aUnqPath );
     453          80 :     if ( err != FileBase::E_None && err != FileBase::E_EXIST )
     454             :         // perhaps parent(s) don't exist
     455           0 :         bRet = ensuredir( aUnqPath );
     456             :     else
     457          80 :         bRet = true;
     458             : 
     459             :     // failure to create base directory means returning an empty string
     460         160 :     OUString aTmp;
     461          80 :     if ( bRet )
     462             :     {
     463             :         // append own internal directory
     464          80 :         bRet = true;
     465          80 :         OUString &rTempNameBase_Impl = TempNameBase_Impl::get();
     466          80 :         rTempNameBase_Impl = rBaseName;
     467          80 :         rTempNameBase_Impl += OUString('/');
     468             : 
     469          80 :         TempFile aBase( NULL, true );
     470          80 :         if ( aBase.IsValid() )
     471             :             // use it in case of success
     472          80 :             rTempNameBase_Impl = aBase.pImp->aName;
     473             : 
     474             :         // return system path of used directory
     475          80 :         FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp );
     476             :     }
     477             : 
     478         160 :     return aTmp;
     479             : }
     480             : }
     481             : 
     482             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10