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