xref: /aoo41x/main/cppuhelper/source/shlib.cxx (revision 9d7e27ac)
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_cppuhelper.hxx"
26 
27 #include "osl/diagnose.h"
28 #include "osl/file.hxx"
29 #include "osl/mutex.hxx"
30 #include "osl/module.hxx"
31 #include "rtl/unload.h"
32 #include "rtl/ustrbuf.hxx"
33 #include "uno/environment.h"
34 #include "uno/mapping.hxx"
35 #include "cppuhelper/factory.hxx"
36 #include "cppuhelper/shlib.hxx"
37 
38 #include "com/sun/star/beans/XPropertySet.hpp"
39 
40 #if OSL_DEBUG_LEVEL > 1
41 #include <stdio.h>
42 #endif
43 #include <vector>
44 
45 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
46 
47 
48 using namespace ::rtl;
49 using namespace ::osl;
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 
53 namespace cppu
54 {
55 
56 #if OSL_DEBUG_LEVEL > 1
57 //------------------------------------------------------------------------------
out(const char * p)58 static inline void out( const char * p ) SAL_THROW( () )
59 {
60     printf( p );
61 }
out(const OUString & r)62 static inline void out( const OUString & r ) throw ()
63 {
64     OString s( OUStringToOString( r, RTL_TEXTENCODING_ASCII_US ) );
65     out( s.getStr() );
66 }
67 #endif
68 
69 //------------------------------------------------------------------------------
getAccessDPath()70 static const ::std::vector< OUString > * getAccessDPath() SAL_THROW( () )
71 {
72     static ::std::vector< OUString > * s_p = 0;
73     static bool s_bInit = false;
74 
75     if (! s_bInit)
76     {
77         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
78         if (! s_bInit)
79         {
80             const char * pEnv = ::getenv( "CPLD_ACCESSPATH" );
81             if (pEnv)
82             {
83                 static ::std::vector< OUString > s_v;
84 
85                 OString aEnv( pEnv );
86                 sal_Int32 nIndex = 0;
87                 do
88                 {
89                     OUString aStr( OStringToOUString(
90                         aEnv.getToken( 0, ';', nIndex ),
91                         RTL_TEXTENCODING_ASCII_US ) );
92                     OUString aFileUrl;
93                     if (FileBase::getFileURLFromSystemPath(aStr, aFileUrl)
94                         != FileBase::E_None)
95                     {
96                         OSL_ASSERT(false);
97                     }
98                     s_v.push_back( aFileUrl );
99                 } while( nIndex != -1 );
100 #if OSL_DEBUG_LEVEL > 1
101                 out( "> cpld: acknowledged following access path(s): \"" );
102                 ::std::vector< OUString >::const_iterator iPos( s_v.begin() );
103                 while (iPos != s_v.end())
104                 {
105                     out( *iPos );
106                     ++iPos;
107                     if (iPos != s_v.end())
108                         out( ";" );
109                 }
110                 out( "\"\n" );
111 #endif
112                 s_p = & s_v;
113             }
114             else
115             {
116                 // no access path env set
117 #if OSL_DEBUG_LEVEL > 1
118                 out( "=> no CPLD_ACCESSPATH set.\n" );
119 #endif
120             }
121             s_bInit = true;
122         }
123     }
124 
125     return s_p;
126 }
127 
128 //------------------------------------------------------------------------------
checkAccessPath(OUString * pComp)129 static bool checkAccessPath( OUString * pComp ) throw ()
130 {
131     const ::std::vector< OUString > * pPath = getAccessDPath();
132 
133     if (pPath)
134     {
135         sal_Bool bAbsolute = (pComp->compareToAscii( "file://" , 7 ) == 0);
136         for ( ::std::vector< OUString >::const_iterator iPos( pPath->begin() );
137               iPos != pPath->end(); ++iPos )
138         {
139             OUString aBaseDir( *iPos );
140             OUString aAbs;
141 
142             if ( bAbsolute )
143             {
144                 aAbs = *pComp;
145 #if OSL_DEBUG_LEVEL > 1
146                 out( "> taking path: \"" );
147                 out( aAbs );
148 #endif
149             }
150             else
151             {
152                 if (osl_File_E_None !=
153                     ::osl_getAbsoluteFileURL(
154                         aBaseDir.pData, pComp->pData, &aAbs.pData ))
155                 {
156                     continue;
157                 }
158 #if OSL_DEBUG_LEVEL > 1
159                 out( "> found path: \"" );
160                 out( aBaseDir );
161                 out( "\" + \"" );
162                 out( *pComp );
163                 out( "\" => \"" );
164                 out( aAbs );
165 #endif
166             }
167 
168             if (0 == aAbs.indexOf( aBaseDir ) && // still part of it?
169                 aBaseDir.getLength() < aAbs.getLength() &&
170                 (aBaseDir[ aBaseDir.getLength() -1 ] == (sal_Unicode)'/' ||
171                  // dir boundary
172                  aAbs[ aBaseDir.getLength() ] == (sal_Unicode)'/'))
173             {
174 #if OSL_DEBUG_LEVEL > 1
175                 out( ": ok.\n" );
176 #endif
177                 // load from absolute path
178                 *pComp = aAbs;
179                 return true;
180             }
181 #if OSL_DEBUG_LEVEL > 1
182             else
183             {
184                 out( "\" ...does not match given path \"" );
185                 out( aBaseDir );
186                 out( "\".\n" );
187             }
188 #endif
189         }
190         return false;
191     }
192     else
193     {
194         // no access path env set
195         return true;
196     }
197 }
198 
199 //------------------------------------------------------------------------------
endsWith(const OUString & rText,const OUString & rEnd)200 static inline sal_Int32 endsWith(
201     const OUString & rText, const OUString & rEnd ) SAL_THROW( () )
202 {
203     if (rText.getLength() >= rEnd.getLength() &&
204         rEnd.equalsIgnoreAsciiCase(
205             rText.copy( rText.getLength() - rEnd.getLength() ) ))
206     {
207         return rText.getLength() - rEnd.getLength();
208     }
209     return -1;
210 }
211 
212 //------------------------------------------------------------------------------
makeComponentPath(const OUString & rLibName,const OUString & rPath)213 static OUString makeComponentPath(
214     const OUString & rLibName, const OUString & rPath )
215 {
216 #if OSL_DEBUG_LEVEL > 0
217     // No system path allowed here !
218     {
219         OUString aComp;
220         OSL_ASSERT( FileBase::E_None ==
221                     FileBase::getSystemPathFromFileURL( rLibName, aComp ) );
222         OSL_ASSERT(
223             ! rPath.getLength() ||
224             FileBase::E_None ==
225               FileBase::getSystemPathFromFileURL( rPath, aComp ) );
226     }
227 #endif
228 
229     OUStringBuffer buf( rPath.getLength() + rLibName.getLength() + 12 );
230 
231     if (0 != rPath.getLength())
232     {
233         buf.append( rPath );
234         if (rPath[ rPath.getLength() -1 ] != '/')
235             buf.append( (sal_Unicode) '/' );
236     }
237     sal_Int32 nEnd = endsWith( rLibName, OUSTR(SAL_DLLEXTENSION) );
238     if (nEnd < 0) // !endsWith
239     {
240 #ifndef OS2
241 //this is always triggered with .uno components
242 #if (OSL_DEBUG_LEVEL >= 2)
243         OSL_ENSURE(
244             !"### library name has no proper extension!",
245             OUStringToOString( rLibName, RTL_TEXTENCODING_ASCII_US ).getStr() );
246 #endif
247 #endif // OS2
248 
249 #if defined SAL_DLLPREFIX
250         nEnd = endsWith( rLibName, OUSTR(".uno") );
251         if (nEnd < 0) // !endsWith
252             buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLPREFIX) );
253 #endif
254         buf.append( rLibName );
255         buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLEXTENSION) );
256     }
257     else // name is completely pre/postfixed
258     {
259         buf.append( rLibName );
260     }
261 
262     OUString out( buf.makeStringAndClear() );
263 #if OSL_DEBUG_LEVEL > 1
264     OString str( OUStringToOString( out, RTL_TEXTENCODING_ASCII_US ) );
265     OSL_TRACE( "component path=%s\n", str.getStr() );
266 #endif
267 
268     return out;
269 }
270 
271 //==============================================================================
getLibEnv(OUString const & aModulePath,oslModule lib,uno::Environment * pEnv,OUString * pSourceEnv_name,uno::Environment const & cTargetEnv,OUString const & cImplName=OUString ())272 static OUString getLibEnv(OUString         const & aModulePath,
273                           oslModule                lib,
274                           uno::Environment       * pEnv,
275                           OUString               * pSourceEnv_name,
276                           uno::Environment const & cTargetEnv,
277                           OUString         const & cImplName = OUString())
278 {
279     OUString aExcMsg;
280 
281 	sal_Char const * pEnvTypeName = NULL;
282 
283 	OUString aGetEnvNameExt = OUSTR(COMPONENT_GETENVEXT);
284 	component_getImplementationEnvironmentExtFunc pGetImplEnvExt =
285 		(component_getImplementationEnvironmentExtFunc)osl_getFunctionSymbol(lib, aGetEnvNameExt.pData);
286 
287 	if (pGetImplEnvExt)
288 	{
289 		OString implName(OUStringToOString(cImplName, RTL_TEXTENCODING_ASCII_US));
290 		pGetImplEnvExt(&pEnvTypeName, (uno_Environment **)pEnv, implName.getStr(), cTargetEnv.get());
291 	}
292 	else
293 	{
294 		OUString aGetEnvName = OUSTR(COMPONENT_GETENV);
295 		component_getImplementationEnvironmentFunc pGetImplEnv =
296 			(component_getImplementationEnvironmentFunc)osl_getFunctionSymbol(
297 				lib, aGetEnvName.pData );
298 		if (pGetImplEnv)
299             pGetImplEnv(&pEnvTypeName, (uno_Environment **)pEnv);
300 
301         else
302         {
303             aExcMsg = aModulePath;
304             aExcMsg += OUSTR(": cannot get symbol: ");
305             aExcMsg += aGetEnvName;
306             aExcMsg += OUSTR("- nor: ");
307         }
308 	}
309 
310 	if (!pEnv->is() && pEnvTypeName)
311     {
312         *pSourceEnv_name = OUString::createFromAscii(pEnvTypeName);
313         const char * pUNO_ENV_LOG = ::getenv( "UNO_ENV_LOG" );
314         if (pUNO_ENV_LOG && rtl_str_getLength(pUNO_ENV_LOG) )
315         {
316             OString implName(OUStringToOString(cImplName, RTL_TEXTENCODING_ASCII_US));
317             OString aEnv( pUNO_ENV_LOG );
318             sal_Int32 nIndex = 0;
319             do
320             {
321                 const OString aStr( aEnv.getToken( 0, ';', nIndex ) );
322                 if ( aStr.equals(implName) )
323                 {
324                     *pSourceEnv_name += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":log"));
325                     break;
326                 }
327             } while( nIndex != -1 );
328         }
329 
330     }
331 
332 	return aExcMsg;
333 }
334 
s_getFactory(va_list * pParam)335 extern "C" {static void s_getFactory(va_list * pParam)
336 {
337 	component_getFactoryFunc         pSym      = va_arg(*pParam, component_getFactoryFunc);
338 	OString                  const * pImplName = va_arg(*pParam, OString const *);
339 	void                           * pSMgr     = va_arg(*pParam, void *);
340 	void                           * pKey      = va_arg(*pParam, void *);
341 	void                          ** ppSSF     = va_arg(*pParam, void **);
342 
343 	*ppSSF = pSym(pImplName->getStr(), pSMgr, pKey);
344 }}
345 
loadSharedLibComponentFactory(OUString const & rLibName,OUString const & rPath,OUString const & rImplName,Reference<lang::XMultiServiceFactory> const & xMgr,Reference<registry::XRegistryKey> const & xKey)346 Reference< XInterface > SAL_CALL loadSharedLibComponentFactory(
347     OUString const & rLibName, OUString const & rPath,
348     OUString const & rImplName,
349     Reference< lang::XMultiServiceFactory > const & xMgr,
350     Reference< registry::XRegistryKey > const & xKey )
351     SAL_THROW( (loader::CannotActivateFactoryException) )
352 {
353     OUString aModulePath( makeComponentPath( rLibName, rPath ) );
354     if (! checkAccessPath( &aModulePath ))
355     {
356         throw loader::CannotActivateFactoryException(
357             OUSTR("permission denied to load component library: ") +
358             aModulePath,
359             Reference< XInterface >() );
360     }
361 
362     oslModule lib = osl_loadModule(
363         aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL );
364     if (! lib)
365     {
366         throw loader::CannotActivateFactoryException(
367             OUSTR("loading component library failed: ") + aModulePath,
368             Reference< XInterface >() );
369     }
370 
371     Reference< XInterface > xRet;
372 
373 	uno::Environment currentEnv(Environment::getCurrent());
374 	uno::Environment env;
375 
376     OUString aEnvTypeName;
377 
378     OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv, rImplName);
379 	if (!aExcMsg.getLength())
380 	{
381         OUString aGetFactoryName = OUSTR(COMPONENT_GETFACTORY);
382         oslGenericFunction pSym = osl_getFunctionSymbol( lib, aGetFactoryName.pData );
383         if (pSym != 0)
384         {
385             OString aImplName(
386                 OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) );
387 
388 			if (!env.is())
389 				env = uno::Environment(aEnvTypeName);
390 
391 			if (env.is() && currentEnv.is())
392 			{
393 #if OSL_DEBUG_LEVEL > 1
394                 {
395                     rtl::OString libName(rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US));
396                     rtl::OString implName(rtl::OUStringToOString(rImplName, RTL_TEXTENCODING_ASCII_US));
397                     rtl::OString envDcp(rtl::OUStringToOString(env.getTypeName(), RTL_TEXTENCODING_ASCII_US));
398 
399                     fprintf(stderr, "loadSharedLibComponentFactory envDcp: %-12.12s  implName: %30.30s  libName: %-15.15s\n", envDcp.getStr(), implName.getStr() + (implName.getLength() > 30 ? implName.getLength() - 30 : 0), libName.getStr());
400                 }
401 #endif
402 
403 				Mapping aCurrent2Env( currentEnv, env );
404 				Mapping aEnv2Current( env, currentEnv );
405 
406 				if (aCurrent2Env.is() && aEnv2Current.is())
407 				{
408 					void * pSMgr = aCurrent2Env.mapInterface(
409 						xMgr.get(), ::getCppuType( &xMgr ) );
410 					void * pKey = aCurrent2Env.mapInterface(
411 						xKey.get(), ::getCppuType( &xKey ) );
412 
413 					void * pSSF = NULL;
414 
415 					env.invoke(s_getFactory, pSym, &aImplName, pSMgr, pKey, &pSSF);
416 
417 					if (pKey)
418 					{
419 						(env.get()->pExtEnv->releaseInterface)(
420 							env.get()->pExtEnv, pKey );
421 					}
422 					if (pSMgr)
423 					{
424 						(*env.get()->pExtEnv->releaseInterface)(
425 							env.get()->pExtEnv, pSMgr );
426 					}
427 
428 					if (pSSF)
429 					{
430 						aEnv2Current.mapInterface(
431 							reinterpret_cast< void ** >( &xRet ),
432 							pSSF, ::getCppuType( &xRet ) );
433 						(env.get()->pExtEnv->releaseInterface)(
434 							env.get()->pExtEnv, pSSF );
435 					}
436 					else
437 					{
438 						aExcMsg = aModulePath;
439 						aExcMsg += OUSTR(": cannot get factory of "
440 										 "demanded implementation: ");
441 						aExcMsg += OStringToOUString(
442 								aImplName, RTL_TEXTENCODING_ASCII_US );
443 					}
444 				}
445 				else
446 				{
447 					aExcMsg =
448 						OUSTR("cannot get uno mappings: C++ <=> UNO!");
449 				}
450 			}
451 			else
452 			{
453 				aExcMsg = OUSTR("cannot get uno environments!");
454 			}
455         }
456         else
457         {
458             aExcMsg = aModulePath;
459             aExcMsg += OUSTR(": cannot get symbol: ");
460             aExcMsg += aGetFactoryName;
461         }
462     }
463 
464     if (! xRet.is())
465     {
466         osl_unloadModule( lib );
467 #if OSL_DEBUG_LEVEL > 1
468         out( "### cannot activate factory: " );
469         out( aExcMsg );
470         out( "\n" );
471 #endif
472         throw loader::CannotActivateFactoryException(
473             aExcMsg,
474             Reference< XInterface >() );
475     }
476 
477     rtl_registerModuleForUnloading( lib);
478     return xRet;
479 }
480 
481 //==============================================================================
s_writeInfo(va_list * pParam)482 extern "C" { static void s_writeInfo(va_list * pParam)
483 {
484 	component_writeInfoFunc         pSym      = va_arg(*pParam, component_writeInfoFunc);
485 	void                          * pSMgr     = va_arg(*pParam, void *);
486 	void                          * pKey      = va_arg(*pParam, void *);
487     sal_Bool                      * pbRet     = va_arg(*pParam, sal_Bool *);
488 
489 	*pbRet = pSym(pSMgr, pKey);
490 
491 }}
492 
writeSharedLibComponentInfo(OUString const & rLibName,OUString const & rPath,Reference<lang::XMultiServiceFactory> const & xMgr,Reference<registry::XRegistryKey> const & xKey)493 void SAL_CALL writeSharedLibComponentInfo(
494     OUString const & rLibName, OUString const & rPath,
495     Reference< lang::XMultiServiceFactory > const & xMgr,
496     Reference< registry::XRegistryKey > const & xKey )
497     SAL_THROW( (registry::CannotRegisterImplementationException) )
498 {
499     OUString aModulePath( makeComponentPath( rLibName, rPath ) );
500 
501     if (! checkAccessPath( &aModulePath ))
502     {
503         throw registry::CannotRegisterImplementationException(
504             OUSTR("permission denied to load component library: ") +
505             aModulePath,
506             Reference< XInterface >() );
507     }
508 
509     oslModule lib = osl_loadModule(
510         aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL );
511     if (! lib)
512     {
513         throw registry::CannotRegisterImplementationException(
514             OUSTR("loading component library failed: ") + aModulePath,
515             Reference< XInterface >() );
516     }
517 
518     sal_Bool bRet = sal_False;
519 
520 	uno::Environment currentEnv(Environment::getCurrent());
521 	uno::Environment env;
522 
523     OUString aEnvTypeName;
524     OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv);
525 	if (!aExcMsg.getLength())
526     {
527         OUString aWriteInfoName = OUSTR(COMPONENT_WRITEINFO);
528         oslGenericFunction pSym = osl_getFunctionSymbol( lib, aWriteInfoName.pData );
529         if (pSym != 0)
530         {
531 			if (!env.is())
532 				env = uno::Environment(aEnvTypeName);
533 
534 			if (env.is() && currentEnv.is())
535 			{
536 				Mapping aCurrent2Env( currentEnv, env );
537 				if (aCurrent2Env.is())
538 				{
539 					void * pSMgr = aCurrent2Env.mapInterface(
540 						xMgr.get(), ::getCppuType( &xMgr ) );
541 					void * pKey = aCurrent2Env.mapInterface(
542 						xKey.get(), ::getCppuType( &xKey ) );
543 					if (pKey)
544 					{
545 						env.invoke(s_writeInfo, pSym, pSMgr, pKey, &bRet);
546 
547 
548 						(*env.get()->pExtEnv->releaseInterface)(
549 							env.get()->pExtEnv, pKey );
550 						if (! bRet)
551 						{
552 							aExcMsg = aModulePath;
553 							aExcMsg += OUSTR(": component_writeInfo() "
554 											 "returned false!");
555 						}
556 					}
557 					else
558 					{
559 						// key is mandatory
560 						aExcMsg = aModulePath;
561 						aExcMsg += OUSTR(": registry is mandatory to invoke"
562 										 " component_writeInfo()!");
563 					}
564 
565 					if (pSMgr)
566 					{
567 						(*env.get()->pExtEnv->releaseInterface)(
568 							env.get()->pExtEnv, pSMgr );
569 					}
570 				}
571 				else
572 				{
573 					aExcMsg = OUSTR("cannot get uno mapping: C++ <=> UNO!");
574 				}
575 			}
576 			else
577 			{
578 				aExcMsg = OUSTR("cannot get uno environments!");
579 			}
580         }
581         else
582         {
583             aExcMsg = aModulePath;
584             aExcMsg += OUSTR(": cannot get symbol: ");
585             aExcMsg += aWriteInfoName;
586         }
587     }
588 
589 //!
590 //! OK: please look at #88219#
591 //!
592 //! ::osl_unloadModule( lib);
593     if (! bRet)
594     {
595 #if OSL_DEBUG_LEVEL > 1
596         out( "### cannot write component info: " );
597         out( aExcMsg );
598         out( "\n" );
599 #endif
600         throw registry::CannotRegisterImplementationException(
601             aExcMsg, Reference< XInterface >() );
602     }
603 }
604 
605 }
606