xref: /trunk/main/tools/source/fsys/tempfile.cxx (revision 24c56ab9)
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