1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #include <tools/tempfile.hxx> 32 #include "comdep.hxx" 33 34 #include <rtl/ustring.hxx> 35 #include <osl/file.hxx> 36 #include <rtl/instance.hxx> 37 #include <tools/time.hxx> 38 #include <tools/debug.hxx> 39 #include <stdio.h> 40 41 #ifdef UNX 42 #define _MAX_PATH 260 43 #endif 44 45 using namespace osl; 46 47 namespace { struct TempNameBase_Impl : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {}; } 48 49 struct TempFile_Impl 50 { 51 String aName; 52 sal_Bool bIsDirectory; 53 }; 54 55 String GetSystemTempDir_Impl() 56 { 57 char sBuf[_MAX_PATH]; 58 const char *pDir = TempDirImpl(sBuf); 59 60 ::rtl::OString aTmpA( pDir ); 61 ::rtl::OUString aTmp = ::rtl::OStringToOUString( aTmpA, osl_getThreadTextEncoding() ); 62 rtl::OUString aRet; 63 FileBase::getFileURLFromSystemPath( aTmp, aRet ); 64 String aName = aRet; 65 if( aName.GetChar(aName.Len()-1) != '/' ) 66 aName += '/'; 67 return aName; 68 } 69 70 #define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 ) 71 String ConstructTempDir_Impl( const String* pParent ) 72 { 73 String aName; 74 if ( pParent && pParent->Len() ) 75 { 76 // if parent given try to use it 77 rtl::OUString aTmp( *pParent ); 78 rtl::OUString aRet; 79 80 // test for valid filename 81 { 82 ::osl::DirectoryItem aItem; 83 sal_Int32 i = aRet.getLength(); 84 if ( aRet[i-1] == '/' ) 85 i--; 86 87 if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None ) 88 aName = aRet; 89 } 90 } 91 92 if ( !aName.Len() ) 93 { 94 // if no parent or invalid parent : use system directory 95 ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get(); 96 if ( !rTempNameBase_Impl.getLength() ) 97 rTempNameBase_Impl = GetSystemTempDir_Impl(); 98 aName = rTempNameBase_Impl; 99 } 100 101 // Make sure that directory ends with a separator 102 xub_StrLen i = aName.Len(); 103 if( i>0 && aName.GetChar(i-1) != '/' ) 104 aName += '/'; 105 106 return aName; 107 } 108 109 void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True ) 110 { 111 // add a suitable tempname 112 // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576 113 // ER 13.07.00 why not radix 36 [0-9A-Z] ?!? 114 const unsigned nRadix = 26; 115 String aName( rName ); 116 aName += String::CreateFromAscii( "sv" ); 117 118 rName.Erase(); 119 static unsigned long u = Time::GetSystemTicks(); 120 for ( unsigned long nOld = u; ++u != nOld; ) 121 { 122 u %= (nRadix*nRadix*nRadix); 123 String aTmp( aName ); 124 aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix ); 125 aTmp += String::CreateFromAscii( ".tmp" ); 126 127 if ( bDir ) 128 { 129 FileBase::RC err = Directory::create( aTmp ); 130 if ( err == FileBase::E_None ) 131 { 132 // !bKeep: only for creating a name, not a file or directory 133 if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None ) 134 rName = aTmp; 135 break; 136 } 137 else if ( err != FileBase::E_EXIST ) 138 { 139 // if f.e. name contains invalid chars stop trying to create dirs 140 break; 141 } 142 } 143 else 144 { 145 DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" ); 146 File aFile( aTmp ); 147 FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); 148 if ( err == FileBase::E_None ) 149 { 150 rName = aTmp; 151 aFile.close(); 152 break; 153 } 154 else if ( err != FileBase::E_EXIST ) 155 { 156 // if f.e. name contains invalid chars stop trying to create files 157 break; 158 } 159 } 160 } 161 } 162 163 String TempFile::CreateTempName( const String* pParent ) 164 { 165 // get correct directory 166 String aName = ConstructTempDir_Impl( pParent ); 167 168 // get TempFile name with default naming scheme 169 CreateTempName_Impl( aName, sal_False ); 170 171 // convert to file URL 172 rtl::OUString aTmp; 173 if ( aName.Len() ) 174 aTmp = aName; 175 return aTmp; 176 } 177 178 TempFile::TempFile( const String* pParent, sal_Bool bDirectory ) 179 : pImp( new TempFile_Impl ) 180 , bKillingFileEnabled( sal_False ) 181 { 182 pImp->bIsDirectory = bDirectory; 183 184 // get correct directory 185 pImp->aName = ConstructTempDir_Impl( pParent ); 186 187 // get TempFile with default naming scheme 188 CreateTempName_Impl( pImp->aName, sal_True, bDirectory ); 189 } 190 191 TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory ) 192 : pImp( new TempFile_Impl ) 193 , bKillingFileEnabled( sal_False ) 194 { 195 pImp->bIsDirectory = bDirectory; 196 197 // get correct directory 198 String aName = ConstructTempDir_Impl( pParent ); 199 200 // now use special naming scheme ( name takes leading chars and an index counting up from zero 201 aName += rLeadingChars; 202 for ( sal_Int32 i=0;; i++ ) 203 { 204 String aTmp( aName ); 205 aTmp += String::CreateFromInt32( i ); 206 if ( pExtension ) 207 aTmp += *pExtension; 208 else 209 aTmp += String::CreateFromAscii( ".tmp" ); 210 if ( bDirectory ) 211 { 212 FileBase::RC err = Directory::create( aTmp ); 213 if ( err == FileBase::E_None ) 214 { 215 pImp->aName = aTmp; 216 break; 217 } 218 else if ( err != FileBase::E_EXIST ) 219 // if f.e. name contains invalid chars stop trying to create dirs 220 break; 221 } 222 else 223 { 224 File aFile( aTmp ); 225 FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); 226 if ( err == FileBase::E_None ) 227 { 228 pImp->aName = aTmp; 229 aFile.close(); 230 break; 231 } 232 else if ( err != FileBase::E_EXIST ) 233 // if f.e. name contains invalid chars stop trying to create dirs 234 break; 235 } 236 } 237 } 238 239 TempFile::~TempFile() 240 { 241 if ( bKillingFileEnabled ) 242 { 243 if ( pImp->bIsDirectory ) 244 { 245 // at the moment no recursiv algorithm present 246 Directory::remove( pImp->aName ); 247 } 248 else 249 { 250 File::remove( pImp->aName ); 251 } 252 } 253 254 delete pImp; 255 } 256 257 sal_Bool TempFile::IsValid() const 258 { 259 return pImp->aName.Len() != 0; 260 } 261 262 String TempFile::GetName() const 263 { 264 rtl::OUString aTmp; 265 aTmp = pImp->aName; 266 return aTmp; 267 } 268 269 String TempFile::SetTempNameBaseDirectory( const String &rBaseName ) 270 { 271 String aName( rBaseName ); 272 273 ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get(); 274 275 FileBase::RC err= Directory::create( aName ); 276 if ( err == FileBase::E_None || err == FileBase::E_EXIST ) 277 { 278 rTempNameBase_Impl = aName; 279 rTempNameBase_Impl += String( '/' ); 280 281 TempFile aBase( NULL, sal_True ); 282 if ( aBase.IsValid() ) 283 rTempNameBase_Impl = aBase.pImp->aName; 284 } 285 286 rtl::OUString aTmp; 287 aTmp = rTempNameBase_Impl; 288 return aTmp; 289 } 290 291 String TempFile::GetTempNameBaseDirectory() 292 { 293 ::rtl::OUString& rTempNameBase_Impl = TempNameBase_Impl::get(); 294 if ( !rTempNameBase_Impl.getLength() ) 295 rTempNameBase_Impl = GetSystemTempDir_Impl(); 296 297 rtl::OUString aTmp; 298 aTmp = rTempNameBase_Impl; 299 return aTmp; 300 } 301 302