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