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
GetSystemTempDir_Impl()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 )
ConstructTempDir_Impl(const String * pParent)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.getStr(), 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
CreateTempName_Impl(String & rName,sal_Bool bKeep,sal_Bool bDir=sal_True)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
CreateTempName(const String * pParent)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
TempFile(const String * pParent,sal_Bool bDirectory)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
TempFile(const String & rLeadingChars,const String * pExtension,const String * pParent,sal_Bool bDirectory)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
~TempFile()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
IsValid() const253 sal_Bool TempFile::IsValid() const
254 {
255 return pImp->aName.Len() != 0;
256 }
257
GetName() const258 String TempFile::GetName() const
259 {
260 rtl::OUString aTmp;
261 aTmp = pImp->aName;
262 return aTmp;
263 }
264
SetTempNameBaseDirectory(const String & rBaseName)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
GetTempNameBaseDirectory()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