VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp@ 101967

Last change on this file since 101967 was 101875, checked in by vboxsync, 15 months ago

libs/xpcom: Remove unused code from nsprpub, bugref:10545

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.6 KB
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org Code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK *****
37 * This Original Code has been modified by IBM Corporation.
38 * Modifications made by IBM described herein are
39 * Copyright (c) International Business Machines
40 * Corporation, 2000
41 *
42 * Modifications to Mozilla code or documentation
43 * identified per MPL Section 3.3
44 *
45 * Date Modified by Description of modification
46 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
47 */
48
49#include "prmem.h"
50#include "prerror.h"
51#include "nsNativeComponentLoader.h"
52#include "nsComponentManager.h"
53#include "nsCOMPtr.h"
54#include "nsIServiceManager.h"
55#include "nsIModule.h"
56#include "xcDll.h"
57#include "nsHashtable.h"
58#include "nsXPIDLString.h"
59#include "nsCRT.h"
60#include "nsIObserverService.h"
61
62#if defined(XP_MAC) // sdagley dougt fix
63#include <Files.h>
64#include <Errors.h>
65#include "nsILocalFileMac.h"
66#endif
67
68#include "prlog.h"
69extern PRLogModuleInfo *nsComponentManagerLog;
70
71static PRBool PR_CALLBACK
72DLLStore_Destroy(nsHashKey *aKey, void *aData, void* closure)
73{
74 nsDll* entry = NS_STATIC_CAST(nsDll*, aData);
75 delete entry;
76 return PR_TRUE;
77}
78
79nsNativeComponentLoader::nsNativeComponentLoader() :
80 mCompMgr(nsnull),
81 mLoadedDependentLibs(16, PR_TRUE),
82 mDllStore(nsnull, nsnull, DLLStore_Destroy,
83 nsnull, 256, PR_TRUE)
84{
85}
86
87NS_IMPL_THREADSAFE_ISUPPORTS2(nsNativeComponentLoader,
88 nsIComponentLoader,
89 nsINativeComponentLoader)
90
91NS_IMETHODIMP
92nsNativeComponentLoader::GetFactory(const nsIID & aCID,
93 const char *aLocation,
94 const char *aType,
95 nsIFactory **_retval)
96{
97 nsresult rv;
98
99 if (!_retval)
100 return NS_ERROR_NULL_POINTER;
101
102 /* use a hashtable of WeakRefs to store the factory object? */
103
104 /* Should this all live in xcDll? */
105 nsDll *dll;
106 rv = CreateDll(nsnull, aLocation, &dll);
107 if (NS_FAILED(rv))
108 return rv;
109
110 if (!dll)
111 return NS_ERROR_OUT_OF_MEMORY;
112
113 if (!dll->IsLoaded()) {
114#ifdef PR_LOGGING
115 nsXPIDLCString displayPath;
116 dll->GetDisplayPath(displayPath);
117
118 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
119 ("nsNativeComponentLoader: loading \"%s\"",
120 displayPath.get()));
121#endif
122 if (!dll->Load()) {
123
124 PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
125 ("nsNativeComponentLoader: load FAILED"));
126
127 char errorMsg[1024] = "<unknown; can't get error from NSPR>";
128
129 if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
130 PR_GetErrorText(errorMsg);
131
132 DumpLoadError(dll, "GetFactory", errorMsg);
133
134 return NS_ERROR_FAILURE;
135 }
136 }
137
138 /* Get service manager for factory */
139 nsCOMPtr<nsIServiceManager> serviceMgr;
140 rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
141 if (NS_FAILED(rv))
142 return rv; // XXX translate error code?
143
144 rv = GetFactoryFromModule(dll, aCID, _retval);
145
146 PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR,
147 ("nsNativeComponentLoader: Factory creation %s for %s",
148 (NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"),
149 aLocation));
150
151 // If the dll failed to get us a factory. But the dll registered that
152 // it would be able to create a factory for this CID. mmh!
153 // We cannot just delete the dll as the dll could be hosting
154 // other CID for which factory creation can pass.
155 // We will just let it be. The effect will be next time we try
156 // creating the object, we will query the dll again. Since the
157 // dll is loaded, this aint a big hit. So for optimized builds
158 // this is ok to limp along.
159 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Factory creation failed");
160
161 return rv;
162}
163
164NS_IMETHODIMP
165nsNativeComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aReg)
166{
167 mCompMgr = aCompMgr;
168 if (!mCompMgr)
169 return NS_ERROR_INVALID_ARG;
170
171 return NS_OK;
172}
173
174NS_IMETHODIMP
175nsNativeComponentLoader::AutoRegisterComponents(PRInt32 aWhen,
176 nsIFile *aDirectory)
177{
178#ifdef DEBUG
179 /* do we _really_ want to print this every time? */
180 fprintf(stderr, "nsNativeComponentLoader: autoregistering begins.\n");
181#endif
182
183 nsresult rv = RegisterComponentsInDir(aWhen, aDirectory);
184
185#ifdef DEBUG
186 fprintf(stderr, "nsNativeComponentLoader: autoregistering %s\n",
187 NS_FAILED(rv) ? "FAILED" : "succeeded");
188#endif
189
190 return rv;
191}
192
193nsresult
194nsNativeComponentLoader::RegisterComponentsInDir(PRInt32 when,
195 nsIFile *dir)
196{
197 nsresult rv = NS_ERROR_FAILURE;
198 PRBool isDir = PR_FALSE;
199
200#if 0
201 // Going to many of these checks is a performance hit on the mac.
202 // Since these routines are called relatively infrequently and
203 // we will fail anyway down the line if a directory aint there,
204 // we are commenting this check out.
205
206 // Make sure we are dealing with a directory
207 rv = dir->IsDirectory(&isDir);
208 if (NS_FAILED(rv)) return rv;
209
210 if (!isDir)
211 return NS_ERROR_INVALID_ARG;
212#endif /* 0 */
213
214 // Create a directory iterator
215 nsCOMPtr<nsISimpleEnumerator> dirIterator;
216 rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator));
217
218 if (NS_FAILED(rv)) return rv;
219
220 // whip through the directory to register every file
221 nsCOMPtr<nsIFile> dirEntry;
222 PRBool more = PR_FALSE;
223
224 rv = dirIterator->HasMoreElements(&more);
225 if (NS_FAILED(rv)) return rv;
226 while (more == PR_TRUE)
227 {
228 rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry));
229 if (NS_SUCCEEDED(rv))
230 {
231 rv = dirEntry->IsDirectory(&isDir);
232 if (NS_SUCCEEDED(rv))
233 {
234 if (isDir == PR_TRUE)
235 {
236 // This is a directory. Grovel for components into the directory.
237#ifdef RT_OS_DARWIN // But not if it's a debug bundle.
238 nsCAutoString leafName;
239 rv = dirEntry->GetNativeLeafName(leafName);
240 if ( NS_FAILED(rv)
241 || leafName.Length() < sizeof(".dSYM")
242 || PL_strcasecmp(leafName.get() + (leafName.Length() - sizeof(".dSYM") + 1), ".dSYM"))
243#endif
244 rv = RegisterComponentsInDir(when, dirEntry);
245 }
246 else
247 {
248 PRBool registered;
249 // This is a file. Try to register it.
250 rv = AutoRegisterComponent(when, dirEntry, &registered);
251 }
252 }
253 }
254 rv = dirIterator->HasMoreElements(&more);
255 if (NS_FAILED(rv)) return rv;
256 }
257
258 return rv;
259}
260
261static nsresult PR_CALLBACK
262nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when)
263{
264 nsresult rv = NS_ERROR_FAILURE;
265
266 if (!dll || dll->IsLoaded() == PR_FALSE)
267 {
268 return NS_ERROR_INVALID_ARG;
269 }
270
271 // Get if the dll was marked for unload in an earlier round
272 PRBool dllMarkedForUnload = dll->IsMarkedForUnload();
273
274 // Reset dll marking for unload just in case we return with
275 // an error.
276 dll->MarkForUnload(PR_FALSE);
277
278 PRBool canUnload = PR_FALSE;
279
280 // Get the module object
281 nsCOMPtr<nsIModule> mobj;
282 /* XXXshaver cheat and use the global component manager */
283 rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager),
284 getter_AddRefs(mobj));
285 if (NS_SUCCEEDED(rv))
286 {
287 rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload);
288 }
289
290 mobj = nsnull; // Release our reference to the module object
291 // When shutting down, whether we can unload the dll or not,
292 // we will shutdown the dll to release any memory it has got
293 if (when == nsIComponentManagerObsolete::NS_Shutdown)
294 {
295 dll->Shutdown();
296 }
297
298 // Check error status on CanUnload() call
299 if (NS_FAILED(rv))
300 {
301#ifdef PR_LOGGING
302 nsXPIDLCString displayPath;
303 dll->GetDisplayPath(displayPath);
304
305 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
306 ("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.",
307 displayPath.get()));
308#endif
309 return rv;
310 }
311
312 if (canUnload)
313 {
314 if (dllMarkedForUnload)
315 {
316#ifdef PR_LOGGING
317 nsXPIDLCString displayPath;
318 dll->GetDisplayPath(displayPath);
319
320 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
321 ("nsNativeComponentLoader: + Unloading \"%s\".", displayPath.get()));
322#endif
323
324#ifdef DEBUG_dougt
325 // XXX dlls aren't counting their outstanding instances correctly
326 // XXX hence, dont unload until this gets enforced.
327 rv = dll->Unload();
328#endif /* 0 */
329 }
330 else
331 {
332#ifdef PR_LOGGING
333 nsXPIDLCString displayPath;
334 dll->GetDisplayPath(displayPath);
335
336 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
337 ("nsNativeComponentLoader: Ready for unload \"%s\".", displayPath.get()));
338#endif
339 }
340 }
341 else
342 {
343#ifdef PR_LOGGING
344 nsXPIDLCString displayPath;
345 dll->GetDisplayPath(displayPath);
346
347 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
348 ("nsNativeComponentLoader: NOT ready for unload %s", displayPath.get()));
349#endif
350 rv = NS_ERROR_FAILURE;
351 }
352 return rv;
353}
354
355struct freeLibrariesClosure
356{
357 nsIServiceManager *serviceMgr;
358 PRInt32 when;
359};
360
361static PRBool PR_CALLBACK
362nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure)
363{
364 nsDll *dll = (nsDll *) aData;
365 struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure;
366 nsFreeLibrary(dll,
367 (callData ? callData->serviceMgr : NULL),
368 (callData ? callData->when : nsIComponentManagerObsolete::NS_Timer));
369 return PR_TRUE;
370}
371
372/*
373 * SelfRegisterDll
374 *
375 * Given a dll abstraction, this will load, selfregister the dll and
376 * unload the dll.
377 *
378 */
379nsresult
380nsNativeComponentLoader::SelfRegisterDll(nsDll *dll,
381 const char *registryLocation,
382 PRBool deferred)
383{
384 // Precondition: dll is not loaded already, unless we're deferred
385 PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE);
386
387 nsresult res;
388 nsCOMPtr<nsIServiceManager> serviceMgr;
389 res = NS_GetServiceManager(getter_AddRefs(serviceMgr));
390 if (NS_FAILED(res)) return res;
391
392 if (dll->Load() == PR_FALSE)
393 {
394 // Cannot load. Probably not a dll.
395 char errorMsg[1024] = "Cannot get error from nspr. Not enough memory.";
396 if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
397 PR_GetErrorText(errorMsg);
398
399 DumpLoadError(dll, "SelfRegisterDll", errorMsg);
400
401 return NS_ERROR_FAILURE;
402 }
403
404#ifdef PR_LOGGING
405 nsXPIDLCString displayPath;
406 dll->GetDisplayPath(displayPath);
407
408 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
409 ("nsNativeComponentLoader: Loaded \"%s\".", displayPath.get()));
410#endif
411
412 // Tell the module to self register
413 nsCOMPtr<nsIFile> fs;
414 nsCOMPtr<nsIModule> mobj;
415 res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
416 if (NS_SUCCEEDED(res))
417 {
418 /*************************************************************
419 * WARNING: Why are use introducing 'res2' here and then *
420 * later assigning it to 'res' rather than just using 'res'? *
421 * This is because this code turns up a code-generation bug *
422 * in VC6 on NT. Assigning to 'res' on the next line causes *
423 * the value of 'dll' to get nulled out! The two seem to be *
424 * getting aliased together during compilation. *
425 *************************************************************/
426 nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs)); // don't change 'res2' -- see warning, above
427 if (NS_SUCCEEDED(res2)) {
428 // in the case of re-registering a component, we want to remove
429 // any optional data that this file may have had.
430 AddDependentLibrary(fs, nsnull);
431
432 res = mobj->RegisterSelf(mCompMgr, fs, registryLocation,
433 nativeComponentType);
434 }
435 else
436 {
437 res = res2; // don't take this out -- see warning, above
438
439#ifdef PR_LOGGING
440 nsXPIDLCString displayPath;
441 dll->GetDisplayPath(displayPath);
442 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
443 ("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.",
444 displayPath.get()));
445#endif
446 }
447 mobj = NULL; // Force a release of the Module object before unload()
448 }
449
450 // Update the timestamp and size of the dll in registry
451 // Don't enter deferred modules in the registry, because it might only be
452 // able to register on some later autoreg, after another component has been
453 // installed.
454 if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) {
455 PRInt64 modTime;
456 if (!fs)
457 return res;
458
459 fs->GetLastModifiedTime(&modTime);
460 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
461 if (!manager)
462 return NS_ERROR_FAILURE;
463
464 nsCOMPtr<nsIFile> fs;
465 res = dll->GetDllSpec(getter_AddRefs(fs));
466 if (NS_FAILED(res)) return res;
467
468 manager->SaveFileInfo(fs, registryLocation, modTime);
469 }
470
471 return res;
472}
473
474//
475// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing.
476//
477
478#if defined(MOZ_DEMANGLE_SYMBOLS)
479#include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol()
480#endif
481
482nsresult
483nsNativeComponentLoader::DumpLoadError(nsDll *dll,
484 const char *aCallerName,
485 const char *aNsprErrorMsg)
486{
487 PR_ASSERT(aCallerName != NULL);
488
489 if (nsnull == dll || nsnull == aNsprErrorMsg)
490 return NS_OK;
491
492 nsCAutoString errorMsg(aNsprErrorMsg);
493
494#if defined(MOZ_DEMANGLE_SYMBOLS)
495 // Demangle undefined symbols
496 nsCAutoString undefinedMagicString("undefined symbol:");
497
498 PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE);
499
500 if (offset != kNotFound)
501 {
502 nsCAutoString symbol(errorMsg);
503 nsCAutoString demangledSymbol;
504
505 symbol.Cut(0,offset);
506
507 symbol.Cut(0,undefinedMagicString.Length());
508
509 symbol.StripWhitespace();
510
511 char demangled[4096] = "\0";
512
513 nsTraceRefcntImpl::DemangleSymbol(symbol.get(),demangled,sizeof(demangled));
514
515 if (demangled && *demangled != '\0')
516 demangledSymbol = demangled;
517
518 if (!demangledSymbol.IsEmpty())
519 {
520 nsCAutoString tmp(errorMsg);
521
522
523 tmp.Cut(offset + undefinedMagicString.Length(),
524 tmp.Length() - offset - undefinedMagicString.Length());
525
526 tmp += " \n";
527
528 tmp += demangledSymbol;
529
530 errorMsg = tmp;
531 }
532 }
533#endif // MOZ_DEMANGLE_SYMBOLS
534 nsXPIDLCString displayPath;
535 dll->GetDisplayPath(displayPath);
536
537#ifdef DEBUG
538 fprintf(stderr,
539 "nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n",
540 aCallerName,
541 displayPath.get(),
542 errorMsg.get());
543#endif
544
545 // Do NSPR log
546#ifdef PR_LOGGING
547 PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
548 ("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s",
549 aCallerName,
550 displayPath.get(),
551 errorMsg.get()));
552#endif
553 return NS_OK;
554}
555
556nsresult
557nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll)
558{
559 nsresult res;
560 nsCOMPtr<nsIServiceManager> serviceMgr;
561 res = NS_GetServiceManager(getter_AddRefs(serviceMgr));
562 if (NS_FAILED(res)) return res;
563
564 if (dll->Load() == PR_FALSE)
565 {
566 // Cannot load. Probably not a dll.
567 return(NS_ERROR_FAILURE);
568 }
569
570 // Tell the module to self register
571 nsCOMPtr<nsIModule> mobj;
572 res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
573 if (NS_SUCCEEDED(res))
574 {
575#ifdef PR_LOGGING
576 nsXPIDLCString displayPath;
577 dll->GetDisplayPath(displayPath);
578
579 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
580 ("nsNativeComponentLoader: %s using nsIModule to unregister self.", displayPath.get()));
581#endif
582 nsCOMPtr<nsIFile> fs;
583 res = dll->GetDllSpec(getter_AddRefs(fs));
584 if (NS_FAILED(res)) return res;
585 // Get registry location for spec
586 nsXPIDLCString registryName;
587
588 // what I want to do here is QI for a Component Registration Manager. Since this
589 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
590 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &res);
591 if (obsoleteManager)
592 res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName));
593
594 if (NS_FAILED(res)) return res;
595 mobj->UnregisterSelf(mCompMgr, fs, registryName);
596 }
597 return res;
598}
599
600nsresult
601nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when,
602 nsIFile *component,
603 PRBool *unregistered)
604{
605
606 nsresult rv = NS_ERROR_FAILURE;
607
608 *unregistered = PR_FALSE;
609
610 nsXPIDLCString persistentDescriptor;
611 // what I want to do here is QI for a Component Registration Manager. Since this
612 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
613 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
614 if (obsoleteManager)
615 rv = obsoleteManager->RegistryLocationForSpec(component,
616 getter_Copies(persistentDescriptor));
617 if (NS_FAILED(rv)) return rv;
618
619 // Notify observers, if any, of autoregistration work
620 nsCOMPtr<nsIObserverService> observerService =
621 do_GetService("@mozilla.org/observer-service;1", &rv);
622 if (NS_SUCCEEDED(rv))
623 {
624 nsCOMPtr<nsIServiceManager> mgr;
625 rv = NS_GetServiceManager(getter_AddRefs(mgr));
626 if (NS_SUCCEEDED(rv))
627 {
628 (void) observerService->NotifyObservers(mgr,
629 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
630 NS_LITERAL_STRING("Unregistering native component").get());
631 }
632 }
633
634 nsDll *dll = NULL;
635 rv = CreateDll(component, persistentDescriptor, &dll);
636 if (NS_FAILED(rv) || dll == NULL) return rv;
637
638 rv = SelfUnregisterDll(dll);
639
640#ifdef PR_LOGGING
641 nsXPIDLCString displayPath;
642 dll->GetDisplayPath(displayPath);
643
644 PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR,
645 ("nsNativeComponentLoader: AutoUnregistration for %s %s.",
646 (NS_FAILED(rv) ? "FAILED" : "succeeded"), displayPath.get()));
647#endif
648
649 if (NS_FAILED(rv))
650 return rv;
651
652 // Remove any autoreg info about this dll
653 nsCStringKey key(persistentDescriptor);
654 mDllStore.RemoveAndDelete(&key);
655
656 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
657 NS_ASSERTION(manager, "Something is terribly wrong");
658
659 manager->RemoveFileInfo(component, nsnull);
660
661 *unregistered = PR_TRUE;
662 return rv;
663}
664
665nsresult
666nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when,
667 nsIFile *component,
668 PRBool *registered)
669{
670 nsresult rv;
671 if (!registered)
672 return NS_ERROR_NULL_POINTER;
673
674 *registered = PR_FALSE;
675
676#ifndef VBOX
677 /* this should be a pref or registry entry, or something */
678 static const char *ValidDllExtensions[] = {
679 ".dll", /* Windows */
680 ".so", /* Unix */
681 ".shlb", /* Mac ? */
682 ".dso", /* Unix ? */
683 ".dylib", /* Unix: Mach */
684 ".so.1.0", /* Unix: BSD */
685 ".sl", /* Unix: HP-UX */
686#if defined(VMS)
687 ".exe", /* Open VMS */
688#endif
689 ".dlm", /* new for all platforms */
690 NULL
691 };
692
693 *registered = PR_FALSE;
694
695#if 0
696 // This is a performance hit on mac. Since we have already checked
697 // this; plus is we dont, load will fail anyway later on, this
698 // is being commented out.
699
700 // Ensure we are dealing with a file as opposed to a dir
701 PRBool b = PR_FALSE;
702
703 rv = component->IsFile(&b);
704 if (NS_FAILED(rv) || !b)
705 return rv;
706#endif /* 0 */
707
708 // deal only with files that have a valid extension
709 PRBool validExtension = PR_FALSE;
710
711#if defined(XP_MAC) // sdagley dougt fix
712 // rjc - on Mac, check the file's type code (skip checking the creator code)
713
714 nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(component);
715 if (localFileMac)
716 {
717 OSType type;
718 rv = localFileMac->GetFileType(&type);
719 if (NS_SUCCEEDED(rv))
720 {
721 // on Mac, Mozilla shared libraries are of type 'shlb'
722 // Note: we don't check the creator (which for Mozilla is 'MOZZ')
723 // so that 3rd party shared libraries will be noticed!
724 validExtension = ((type == 'shlb') || (type == 'NSPL'));
725 }
726 }
727
728#else
729 nsCAutoString leafName;
730 rv = component->GetNativeLeafName(leafName);
731 if (NS_FAILED(rv)) return rv;
732 int flen = leafName.Length();
733 for (int i=0; ValidDllExtensions[i] != NULL; i++)
734 {
735 int extlen = PL_strlen(ValidDllExtensions[i]);
736
737 // Does fullname end with this extension
738 if (flen >= extlen &&
739 !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i])
740 )
741 {
742 validExtension = PR_TRUE;
743 break;
744 }
745 }
746#endif
747
748 if (validExtension == PR_FALSE)
749 // Skip invalid extensions
750 return NS_OK;
751
752#else /* VBOX */
753 /* VBox: Only one valid suffix exist, so dispense with the the list. */
754# ifdef RT_OS_DARWIN
755# ifdef VBOX_IN_32_ON_64_MAIN_API
756 static const char s_szSuff[] = "-x86.dylib";
757# else
758 static const char s_szSuff[] = ".dylib";
759 static const char s_szSuffInvalid[] = "-x86.dylib";
760# endif
761# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
762# ifdef VBOX_IN_32_ON_64_MAIN_API
763 static const char s_szSuff[] = "-x86.dll";
764#else
765 static const char s_szSuff[] = ".dll";
766 static const char s_szSuffInvalid[] = "-x86.dll";
767# endif
768# else
769# ifdef VBOX_IN_32_ON_64_MAIN_API
770 static const char s_szSuff[] = "-x86.so";
771#else
772 static const char s_szSuff[] = ".so";
773 static const char s_szSuffInvalid[] = "-x86.so";
774# endif
775# endif
776
777 nsCAutoString strLeafName;
778 rv = component->GetNativeLeafName(strLeafName);
779 if (NS_FAILED(rv))
780 return rv;
781 size_t cchLeafName = strLeafName.Length();
782 if ( cchLeafName <= sizeof(s_szSuff)
783 || PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuff) + 1, s_szSuff))
784 {
785 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s'...", strLeafName.get()));
786 return NS_OK; /* skip */
787 }
788# ifndef VBOX_IN_32_ON_64_MAIN_API
789 if ( cchLeafName >= sizeof(s_szSuffInvalid)
790 && !PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuffInvalid) + 1, s_szSuffInvalid))
791 {
792 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s' (#2)...", strLeafName.get()));
793 return NS_OK; /* skip */
794 }
795# endif
796 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("... '%s'", strLeafName.get()));
797#endif /* VBOX */
798
799 nsXPIDLCString persistentDescriptor;
800 // what I want to do here is QI for a Component Registration Manager. Since this
801 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
802 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
803 if (obsoleteManager)
804 rv = obsoleteManager->RegistryLocationForSpec(component,
805 getter_Copies(persistentDescriptor));
806 if (NS_FAILED(rv))
807 return rv;
808
809 nsCStringKey key(persistentDescriptor);
810
811 // Get the registry representation of the dll, if any
812 nsDll *dll;
813 rv = CreateDll(component, persistentDescriptor, &dll);
814 if (NS_FAILED(rv))
815 return rv;
816
817 if (dll != NULL)
818 {
819 // We already have seen this dll. Check if this dll changed
820 if (!dll->HasChanged())
821 {
822#ifdef PR_LOGGING
823 nsXPIDLCString displayPath;
824 dll->GetDisplayPath(displayPath);
825
826 // Dll hasn't changed. Skip.
827 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
828 ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...",
829 displayPath.get()));
830#endif
831 *registered = PR_TRUE;
832 return NS_OK;
833 }
834
835 // Aagh! the dll has changed since the last time we saw it.
836 // re-register dll
837
838
839 // Notify observers, if any, of autoregistration work
840 nsCOMPtr<nsIObserverService> observerService =
841 do_GetService("@mozilla.org/observer-service;1", &rv);
842 if (NS_SUCCEEDED(rv))
843 {
844 nsCOMPtr<nsIServiceManager> mgr;
845 rv = NS_GetServiceManager(getter_AddRefs(mgr));
846 if (NS_SUCCEEDED(rv))
847 {
848 // this string can't come from a string bundle, because we
849 // don't have string bundles yet.
850 NS_ConvertASCIItoUCS2 fileName("(no name)");
851
852 // get the file name
853 nsCOMPtr<nsIFile> dllSpec;
854 if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec)
855 {
856 dllSpec->GetLeafName(fileName);
857 }
858
859 // this string can't come from a string bundle, because we
860 // don't have string bundles yet.
861 (void) observerService->
862 NotifyObservers(mgr,
863 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
864 PromiseFlatString(NS_LITERAL_STRING("Registering native component ") +
865 fileName).get());
866 }
867 }
868
869 if (dll->IsLoaded())
870 {
871 // We loaded the old version of the dll and now we find that the
872 // on-disk copy if newer. Try to unload the dll.
873 nsCOMPtr<nsIServiceManager> serviceMgr;
874 rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
875
876 rv = nsFreeLibrary(dll, serviceMgr, when);
877 if (NS_FAILED(rv))
878 {
879 // THIS IS THE WORST SITUATION TO BE IN.
880 // Dll doesn't want to be unloaded. Cannot re-register
881 // this dll.
882#ifdef PR_LOGGING
883 nsXPIDLCString displayPath;
884 dll->GetDisplayPath(displayPath);
885
886 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
887 ("nsNativeComponentLoader: *** Dll already loaded. "
888 "Cannot unload either. Hence cannot re-register "
889 "\"%s\". Skipping...", displayPath.get()));
890#endif
891 return rv;
892 }
893 else {
894 // dll doesn't have a CanUnload proc. Guess it is
895 // ok to unload it.
896 dll->Unload();
897#ifdef PR_LOGGING
898 nsXPIDLCString displayPath;
899 dll->GetDisplayPath(displayPath);
900 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
901 ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).",
902 displayPath.get()));
903#endif
904 }
905
906 } // dll isloaded
907
908 // Sanity.
909 if (dll->IsLoaded())
910 {
911 // We went through all the above to make sure the dll
912 // is unloaded. And here we are with the dll still
913 // loaded. Whoever taught dp programming...
914#ifdef PR_LOGGING
915 nsXPIDLCString displayPath;
916 dll->GetDisplayPath(displayPath);
917 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
918 ("nsNativeComponentLoader: Dll still loaded. Cannot re-register "
919 "\"%s\". Skipping...", displayPath.get()));
920#endif
921 return NS_ERROR_FAILURE;
922 }
923 } // dll != NULL
924 else
925 {
926 // Create and add the dll to the mDllStore
927 // It is ok to do this even if the creation of nsDll
928 // didnt succeed. That way we wont do this again
929 // when we encounter the same dll.
930 dll = new nsDll(component, this);
931 if (dll == NULL)
932 return NS_ERROR_OUT_OF_MEMORY;
933 mDllStore.Put(&key, (void *) dll);
934 } // dll == NULL
935
936 // Either we are seeing the dll for the first time or the dll has
937 // changed since we last saw it and it is unloaded successfully.
938 //
939 // Now we can try register the dll for sure.
940 nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE);
941 if (NS_FAILED(res))
942 {
943 if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) {
944 /* defer for later loading */
945 mDeferredComponents.AppendElement(dll);
946 *registered = PR_TRUE;
947 return NS_OK;
948 } else {
949#ifdef PR_LOGGING
950 nsXPIDLCString displayPath;
951 dll->GetDisplayPath(displayPath);
952
953 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
954 ("nsNativeComponentLoader: Autoregistration FAILED for "
955 "\"%s\". Skipping...", displayPath.get()));
956#endif
957 return NS_ERROR_FACTORY_NOT_REGISTERED;
958 }
959 }
960 else
961 {
962#ifdef PR_LOGGING
963 nsXPIDLCString displayPath;
964 dll->GetDisplayPath(displayPath);
965
966 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
967 ("nsNativeComponentLoader: Autoregistration Passed for "
968 "\"%s\".", displayPath.get()));
969#endif
970 // Marking dll along with modified time and size in the
971 // registry happens at PlatformRegister(). No need to do it
972 // here again.
973 *registered = PR_TRUE;
974 }
975 return NS_OK;
976}
977
978nsresult
979nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen,
980 PRBool *aRegistered)
981{
982#ifdef DEBUG
983 fprintf(stderr, "nNCL: registering deferred (%d)\n",
984 mDeferredComponents.Count());
985#endif
986 *aRegistered = PR_FALSE;
987 if (!mDeferredComponents.Count())
988 return NS_OK;
989
990 for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) {
991 nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]);
992 nsresult rv = SelfRegisterDll(dll,
993 nsnull,
994 PR_TRUE);
995 if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
996 if (NS_SUCCEEDED(rv))
997 *aRegistered = PR_TRUE;
998 mDeferredComponents.RemoveElementAt(i);
999 }
1000 }
1001#ifdef DEBUG
1002 if (*aRegistered)
1003 fprintf(stderr, "nNCL: registered deferred, %d left\n",
1004 mDeferredComponents.Count());
1005 else
1006 fprintf(stderr, "nNCL: didn't register any components, %d left\n",
1007 mDeferredComponents.Count());
1008#endif
1009 /* are there any fatal errors? */
1010 return NS_OK;
1011}
1012
1013nsresult
1014nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType,
1015 const char *aClassName,
1016 const char *aContractID,
1017 const char *aLocation,
1018 PRBool aReplace,
1019 PRBool aPersist)
1020{
1021 return NS_OK;
1022}
1023
1024nsresult
1025nsNativeComponentLoader::UnloadAll(PRInt32 aWhen)
1026{
1027 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading...."));
1028
1029 struct freeLibrariesClosure callData;
1030 callData.serviceMgr = NULL; // XXX need to get this as a parameter
1031 callData.when = aWhen;
1032
1033 // Cycle through the dlls checking to see if they want to be unloaded
1034 mDllStore.Enumerate(nsFreeLibraryEnum, &callData);
1035 return NS_OK;
1036}
1037
1038//
1039// CreateDll
1040// The only way to create a dll or get it from the dll cache. This will
1041// be called in multiple situations:
1042//
1043// 1. Autoregister will create one for each dll it is trying to register. This
1044// call will be passing a spec in.
1045// {spec, NULL, 0, 0}
1046//
1047// 2. GetFactory() This will call CreateDll() with a null spec but will give
1048// the registry represented name of the dll. If modtime and size are zero,
1049// we will go the registry to find the right modtime and size.
1050// {NULL, rel:libpref.so, 0, 0}
1051//
1052// 3. Prepopulation of dllCache A dll object created off a registry entry.
1053// Specifically dll name is stored in rel: or abs: or lib: formats in the
1054// registry along with its lastModTime and fileSize.
1055// {NULL, rel:libpref.so, 8985659, 20987}
1056nsresult
1057nsNativeComponentLoader::CreateDll(nsIFile *aSpec,
1058 const char *aLocation,
1059 nsDll **aDll)
1060{
1061 nsDll *dll;
1062 nsCOMPtr<nsIFile> dllSpec;
1063 nsCOMPtr<nsIFile> spec;
1064 nsresult rv;
1065
1066 nsCStringKey key(aLocation);
1067 dll = (nsDll *)mDllStore.Get(&key);
1068 if (dll)
1069 {
1070 *aDll = dll;
1071 return NS_OK;
1072 }
1073
1074 if (!aSpec)
1075 {
1076 // what I want to do here is QI for a Component Registration Manager. Since this
1077 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
1078 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
1079 if (obsoleteManager)
1080 rv = obsoleteManager->SpecForRegistryLocation(aLocation,
1081 getter_AddRefs(spec));
1082 if (NS_FAILED(rv))
1083 return rv;
1084 }
1085 else
1086 {
1087 spec = aSpec;
1088 }
1089
1090 if (!dll)
1091 {
1092 dll = new nsDll(spec, this);
1093 if (!dll)
1094 return NS_ERROR_OUT_OF_MEMORY;
1095 }
1096
1097 *aDll = dll;
1098 mDllStore.Put(&key, dll);
1099 return NS_OK;
1100}
1101
1102nsresult
1103nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID,
1104 nsIFactory **aFactory)
1105{
1106 nsresult rv;
1107
1108 nsCOMPtr<nsIModule> module;
1109 rv = aDll->GetModule(mCompMgr, getter_AddRefs(module));
1110
1111 if (NS_FAILED(rv))
1112 return rv;
1113
1114 return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory),
1115 (void **)aFactory);
1116}
1117
1118
1119NS_IMETHODIMP
1120nsNativeComponentLoader::AddDependentLibrary(nsIFile* aFile, const char* libName)
1121{
1122 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
1123 if (!manager)
1124 {
1125 NS_WARNING("Something is terribly wrong");
1126 return NS_ERROR_FAILURE;
1127 }
1128
1129 // the native component loader uses the optional data
1130 // to store a space delimited list of dependent library
1131 // names
1132
1133 if (!libName)
1134 {
1135 manager->SetOptionalData(aFile, nsnull, nsnull);
1136 return NS_OK;
1137 }
1138
1139 nsXPIDLCString data;
1140 manager->GetOptionalData(aFile, nsnull, getter_Copies(data));
1141
1142 if (!data.IsEmpty())
1143 data.AppendLiteral(" ");
1144
1145 data.Append(nsDependentCString(libName));
1146
1147 manager->SetOptionalData(aFile, nsnull, data);
1148 return NS_OK;
1149}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette