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

Generated by: LCOV version 1.10