VirtualBox

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

Last change on this file since 38276 was 38276, checked in by vboxsync, 13 years ago

nsNativeComponentLoader::RegisterComponentsInDir: Don't go looking for components in debug bundles on the mac.

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