VirtualBox

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

Last change on this file since 95259 was 48282, checked in by vboxsync, 11 years ago

32-bit main API on 64-bit solaris.

  • 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 "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#ifndef VBOX
678 /* this should be a pref or registry entry, or something */
679 static const char *ValidDllExtensions[] = {
680 ".dll", /* Windows */
681 ".so", /* Unix */
682 ".shlb", /* Mac ? */
683 ".dso", /* Unix ? */
684 ".dylib", /* Unix: Mach */
685 ".so.1.0", /* Unix: BSD */
686 ".sl", /* Unix: HP-UX */
687#if defined(VMS)
688 ".exe", /* Open VMS */
689#endif
690 ".dlm", /* new for all platforms */
691 NULL
692 };
693
694 *registered = PR_FALSE;
695
696#if 0
697 // This is a performance hit on mac. Since we have already checked
698 // this; plus is we dont, load will fail anyway later on, this
699 // is being commented out.
700
701 // Ensure we are dealing with a file as opposed to a dir
702 PRBool b = PR_FALSE;
703
704 rv = component->IsFile(&b);
705 if (NS_FAILED(rv) || !b)
706 return rv;
707#endif /* 0 */
708
709 // deal only with files that have a valid extension
710 PRBool validExtension = PR_FALSE;
711
712#if defined(XP_MAC) // sdagley dougt fix
713 // rjc - on Mac, check the file's type code (skip checking the creator code)
714
715 nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(component);
716 if (localFileMac)
717 {
718 OSType type;
719 rv = localFileMac->GetFileType(&type);
720 if (NS_SUCCEEDED(rv))
721 {
722 // on Mac, Mozilla shared libraries are of type 'shlb'
723 // Note: we don't check the creator (which for Mozilla is 'MOZZ')
724 // so that 3rd party shared libraries will be noticed!
725 validExtension = ((type == 'shlb') || (type == 'NSPL'));
726 }
727 }
728
729#else
730 nsCAutoString leafName;
731 rv = component->GetNativeLeafName(leafName);
732 if (NS_FAILED(rv)) return rv;
733 int flen = leafName.Length();
734 for (int i=0; ValidDllExtensions[i] != NULL; i++)
735 {
736 int extlen = PL_strlen(ValidDllExtensions[i]);
737
738 // Does fullname end with this extension
739 if (flen >= extlen &&
740 !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i])
741 )
742 {
743 validExtension = PR_TRUE;
744 break;
745 }
746 }
747#endif
748
749 if (validExtension == PR_FALSE)
750 // Skip invalid extensions
751 return NS_OK;
752
753#else /* VBOX */
754 /* VBox: Only one valid suffix exist, so dispense with the the list. */
755# ifdef RT_OS_DARWIN
756# ifdef VBOX_IN_32_ON_64_MAIN_API
757 static const char s_szSuff[] = "-x86.dylib";
758# else
759 static const char s_szSuff[] = ".dylib";
760 static const char s_szSuffInvalid[] = "-x86.dylib";
761# endif
762# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
763# ifdef VBOX_IN_32_ON_64_MAIN_API
764 static const char s_szSuff[] = "-x86.dll";
765#else
766 static const char s_szSuff[] = ".dll";
767 static const char s_szSuffInvalid[] = "-x86.dll";
768# endif
769# else
770# ifdef VBOX_IN_32_ON_64_MAIN_API
771 static const char s_szSuff[] = "-x86.so";
772#else
773 static const char s_szSuff[] = ".so";
774 static const char s_szSuffInvalid[] = "-x86.so";
775# endif
776# endif
777
778 nsCAutoString strLeafName;
779 rv = component->GetNativeLeafName(strLeafName);
780 if (NS_FAILED(rv))
781 return rv;
782 size_t cchLeafName = strLeafName.Length();
783 if ( cchLeafName <= sizeof(s_szSuff)
784 || PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuff) + 1, s_szSuff))
785 {
786 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s'...", strLeafName.get()));
787 return NS_OK; /* skip */
788 }
789# ifndef VBOX_IN_32_ON_64_MAIN_API
790 if ( cchLeafName >= sizeof(s_szSuffInvalid)
791 && !PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuffInvalid) + 1, s_szSuffInvalid))
792 {
793 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s' (#2)...", strLeafName.get()));
794 return NS_OK; /* skip */
795 }
796# endif
797 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("... '%s'", strLeafName.get()));
798#endif /* VBOX */
799
800 nsXPIDLCString persistentDescriptor;
801 // what I want to do here is QI for a Component Registration Manager. Since this
802 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
803 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
804 if (obsoleteManager)
805 rv = obsoleteManager->RegistryLocationForSpec(component,
806 getter_Copies(persistentDescriptor));
807 if (NS_FAILED(rv))
808 return rv;
809
810 nsCStringKey key(persistentDescriptor);
811
812 // Get the registry representation of the dll, if any
813 nsDll *dll;
814 rv = CreateDll(component, persistentDescriptor, &dll);
815 if (NS_FAILED(rv))
816 return rv;
817
818 if (dll != NULL)
819 {
820 // We already have seen this dll. Check if this dll changed
821 if (!dll->HasChanged())
822 {
823#ifdef PR_LOGGING
824 nsXPIDLCString displayPath;
825 dll->GetDisplayPath(displayPath);
826
827 // Dll hasn't changed. Skip.
828 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
829 ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...",
830 displayPath.get()));
831#endif
832 *registered = PR_TRUE;
833 return NS_OK;
834 }
835
836 // Aagh! the dll has changed since the last time we saw it.
837 // re-register dll
838
839
840 // Notify observers, if any, of autoregistration work
841 nsCOMPtr<nsIObserverService> observerService =
842 do_GetService("@mozilla.org/observer-service;1", &rv);
843 if (NS_SUCCEEDED(rv))
844 {
845 nsCOMPtr<nsIServiceManager> mgr;
846 rv = NS_GetServiceManager(getter_AddRefs(mgr));
847 if (NS_SUCCEEDED(rv))
848 {
849 // this string can't come from a string bundle, because we
850 // don't have string bundles yet.
851 NS_ConvertASCIItoUCS2 fileName("(no name)");
852
853 // get the file name
854 nsCOMPtr<nsIFile> dllSpec;
855 if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec)
856 {
857 dllSpec->GetLeafName(fileName);
858 }
859
860 // this string can't come from a string bundle, because we
861 // don't have string bundles yet.
862 (void) observerService->
863 NotifyObservers(mgr,
864 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
865 PromiseFlatString(NS_LITERAL_STRING("Registering native component ") +
866 fileName).get());
867 }
868 }
869
870 if (dll->IsLoaded())
871 {
872 // We loaded the old version of the dll and now we find that the
873 // on-disk copy if newer. Try to unload the dll.
874 nsCOMPtr<nsIServiceManager> serviceMgr;
875 rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
876
877 rv = nsFreeLibrary(dll, serviceMgr, when);
878 if (NS_FAILED(rv))
879 {
880 // THIS IS THE WORST SITUATION TO BE IN.
881 // Dll doesn't want to be unloaded. Cannot re-register
882 // this dll.
883#ifdef PR_LOGGING
884 nsXPIDLCString displayPath;
885 dll->GetDisplayPath(displayPath);
886
887 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
888 ("nsNativeComponentLoader: *** Dll already loaded. "
889 "Cannot unload either. Hence cannot re-register "
890 "\"%s\". Skipping...", displayPath.get()));
891#endif
892 return rv;
893 }
894 else {
895 // dll doesn't have a CanUnload proc. Guess it is
896 // ok to unload it.
897 dll->Unload();
898#ifdef PR_LOGGING
899 nsXPIDLCString displayPath;
900 dll->GetDisplayPath(displayPath);
901 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
902 ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).",
903 displayPath.get()));
904#endif
905 }
906
907 } // dll isloaded
908
909 // Sanity.
910 if (dll->IsLoaded())
911 {
912 // We went through all the above to make sure the dll
913 // is unloaded. And here we are with the dll still
914 // loaded. Whoever taught dp programming...
915#ifdef PR_LOGGING
916 nsXPIDLCString displayPath;
917 dll->GetDisplayPath(displayPath);
918 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
919 ("nsNativeComponentLoader: Dll still loaded. Cannot re-register "
920 "\"%s\". Skipping...", displayPath.get()));
921#endif
922 return NS_ERROR_FAILURE;
923 }
924 } // dll != NULL
925 else
926 {
927 // Create and add the dll to the mDllStore
928 // It is ok to do this even if the creation of nsDll
929 // didnt succeed. That way we wont do this again
930 // when we encounter the same dll.
931 dll = new nsDll(component, this);
932 if (dll == NULL)
933 return NS_ERROR_OUT_OF_MEMORY;
934 mDllStore.Put(&key, (void *) dll);
935 } // dll == NULL
936
937 // Either we are seeing the dll for the first time or the dll has
938 // changed since we last saw it and it is unloaded successfully.
939 //
940 // Now we can try register the dll for sure.
941 nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE);
942 if (NS_FAILED(res))
943 {
944 if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) {
945 /* defer for later loading */
946 mDeferredComponents.AppendElement(dll);
947 *registered = PR_TRUE;
948 return NS_OK;
949 } else {
950#ifdef PR_LOGGING
951 nsXPIDLCString displayPath;
952 dll->GetDisplayPath(displayPath);
953
954 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
955 ("nsNativeComponentLoader: Autoregistration FAILED for "
956 "\"%s\". Skipping...", displayPath.get()));
957#endif
958 return NS_ERROR_FACTORY_NOT_REGISTERED;
959 }
960 }
961 else
962 {
963#ifdef PR_LOGGING
964 nsXPIDLCString displayPath;
965 dll->GetDisplayPath(displayPath);
966
967 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
968 ("nsNativeComponentLoader: Autoregistration Passed for "
969 "\"%s\".", displayPath.get()));
970#endif
971 // Marking dll along with modified time and size in the
972 // registry happens at PlatformRegister(). No need to do it
973 // here again.
974 *registered = PR_TRUE;
975 }
976 return NS_OK;
977}
978
979nsresult
980nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen,
981 PRBool *aRegistered)
982{
983#ifdef DEBUG
984 fprintf(stderr, "nNCL: registering deferred (%d)\n",
985 mDeferredComponents.Count());
986#endif
987 *aRegistered = PR_FALSE;
988 if (!mDeferredComponents.Count())
989 return NS_OK;
990
991 for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) {
992 nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]);
993 nsresult rv = SelfRegisterDll(dll,
994 nsnull,
995 PR_TRUE);
996 if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
997 if (NS_SUCCEEDED(rv))
998 *aRegistered = PR_TRUE;
999 mDeferredComponents.RemoveElementAt(i);
1000 }
1001 }
1002#ifdef DEBUG
1003 if (*aRegistered)
1004 fprintf(stderr, "nNCL: registered deferred, %d left\n",
1005 mDeferredComponents.Count());
1006 else
1007 fprintf(stderr, "nNCL: didn't register any components, %d left\n",
1008 mDeferredComponents.Count());
1009#endif
1010 /* are there any fatal errors? */
1011 return NS_OK;
1012}
1013
1014nsresult
1015nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType,
1016 const char *aClassName,
1017 const char *aContractID,
1018 const char *aLocation,
1019 PRBool aReplace,
1020 PRBool aPersist)
1021{
1022 return NS_OK;
1023}
1024
1025nsresult
1026nsNativeComponentLoader::UnloadAll(PRInt32 aWhen)
1027{
1028 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading...."));
1029
1030 struct freeLibrariesClosure callData;
1031 callData.serviceMgr = NULL; // XXX need to get this as a parameter
1032 callData.when = aWhen;
1033
1034 // Cycle through the dlls checking to see if they want to be unloaded
1035 mDllStore.Enumerate(nsFreeLibraryEnum, &callData);
1036 return NS_OK;
1037}
1038
1039//
1040// CreateDll
1041// The only way to create a dll or get it from the dll cache. This will
1042// be called in multiple situations:
1043//
1044// 1. Autoregister will create one for each dll it is trying to register. This
1045// call will be passing a spec in.
1046// {spec, NULL, 0, 0}
1047//
1048// 2. GetFactory() This will call CreateDll() with a null spec but will give
1049// the registry represented name of the dll. If modtime and size are zero,
1050// we will go the registry to find the right modtime and size.
1051// {NULL, rel:libpref.so, 0, 0}
1052//
1053// 3. Prepopulation of dllCache A dll object created off a registry entry.
1054// Specifically dll name is stored in rel: or abs: or lib: formats in the
1055// registry along with its lastModTime and fileSize.
1056// {NULL, rel:libpref.so, 8985659, 20987}
1057nsresult
1058nsNativeComponentLoader::CreateDll(nsIFile *aSpec,
1059 const char *aLocation,
1060 nsDll **aDll)
1061{
1062 nsDll *dll;
1063 nsCOMPtr<nsIFile> dllSpec;
1064 nsCOMPtr<nsIFile> spec;
1065 nsresult rv;
1066
1067 nsCStringKey key(aLocation);
1068 dll = (nsDll *)mDllStore.Get(&key);
1069 if (dll)
1070 {
1071 *aDll = dll;
1072 return NS_OK;
1073 }
1074
1075 if (!aSpec)
1076 {
1077 // what I want to do here is QI for a Component Registration Manager. Since this
1078 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
1079 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
1080 if (obsoleteManager)
1081 rv = obsoleteManager->SpecForRegistryLocation(aLocation,
1082 getter_AddRefs(spec));
1083 if (NS_FAILED(rv))
1084 return rv;
1085 }
1086 else
1087 {
1088 spec = aSpec;
1089 }
1090
1091 if (!dll)
1092 {
1093 dll = new nsDll(spec, this);
1094 if (!dll)
1095 return NS_ERROR_OUT_OF_MEMORY;
1096 }
1097
1098 *aDll = dll;
1099 mDllStore.Put(&key, dll);
1100 return NS_OK;
1101}
1102
1103nsresult
1104nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID,
1105 nsIFactory **aFactory)
1106{
1107 nsresult rv;
1108
1109 nsCOMPtr<nsIModule> module;
1110 rv = aDll->GetModule(mCompMgr, getter_AddRefs(module));
1111
1112 if (NS_FAILED(rv))
1113 return rv;
1114
1115 return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory),
1116 (void **)aFactory);
1117}
1118
1119
1120NS_IMETHODIMP
1121nsNativeComponentLoader::AddDependentLibrary(nsIFile* aFile, const char* libName)
1122{
1123 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
1124 if (!manager)
1125 {
1126 NS_WARNING("Something is terribly wrong");
1127 return NS_ERROR_FAILURE;
1128 }
1129
1130 // the native component loader uses the optional data
1131 // to store a space delimited list of dependent library
1132 // names
1133
1134 if (!libName)
1135 {
1136 manager->SetOptionalData(aFile, nsnull, nsnull);
1137 return NS_OK;
1138 }
1139
1140 nsXPIDLCString data;
1141 manager->GetOptionalData(aFile, nsnull, getter_Copies(data));
1142
1143 if (!data.IsEmpty())
1144 data.AppendLiteral(" ");
1145
1146 data.Append(nsDependentCString(libName));
1147
1148 manager->SetOptionalData(aFile, nsnull, data);
1149 return NS_OK;
1150}
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