VirtualBox

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

Last change on this file since 4837 was 1, checked in by vboxsync, 54 years ago

import

  • 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 rv = RegisterComponentsInDir(when, dirEntry);
239 }
240 else
241 {
242 PRBool registered;
243 // This is a file. Try to register it.
244 rv = AutoRegisterComponent(when, dirEntry, &registered);
245 }
246 }
247 }
248 rv = dirIterator->HasMoreElements(&more);
249 if (NS_FAILED(rv)) return rv;
250 }
251
252 return rv;
253}
254
255static nsresult PR_CALLBACK
256nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when)
257{
258 nsresult rv = NS_ERROR_FAILURE;
259
260 if (!dll || dll->IsLoaded() == PR_FALSE)
261 {
262 return NS_ERROR_INVALID_ARG;
263 }
264
265 // Get if the dll was marked for unload in an earlier round
266 PRBool dllMarkedForUnload = dll->IsMarkedForUnload();
267
268 // Reset dll marking for unload just in case we return with
269 // an error.
270 dll->MarkForUnload(PR_FALSE);
271
272 PRBool canUnload = PR_FALSE;
273
274 // Get the module object
275 nsCOMPtr<nsIModule> mobj;
276 /* XXXshaver cheat and use the global component manager */
277 rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager),
278 getter_AddRefs(mobj));
279 if (NS_SUCCEEDED(rv))
280 {
281 rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload);
282 }
283
284 mobj = nsnull; // Release our reference to the module object
285 // When shutting down, whether we can unload the dll or not,
286 // we will shutdown the dll to release any memory it has got
287 if (when == nsIComponentManagerObsolete::NS_Shutdown)
288 {
289 dll->Shutdown();
290 }
291
292 // Check error status on CanUnload() call
293 if (NS_FAILED(rv))
294 {
295#ifdef PR_LOGGING
296 nsXPIDLCString displayPath;
297 dll->GetDisplayPath(displayPath);
298
299 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
300 ("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.",
301 displayPath.get()));
302#endif
303 return rv;
304 }
305
306 if (canUnload)
307 {
308 if (dllMarkedForUnload)
309 {
310#ifdef PR_LOGGING
311 nsXPIDLCString displayPath;
312 dll->GetDisplayPath(displayPath);
313
314 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
315 ("nsNativeComponentLoader: + Unloading \"%s\".", displayPath.get()));
316#endif
317
318#ifdef DEBUG_dougt
319 // XXX dlls aren't counting their outstanding instances correctly
320 // XXX hence, dont unload until this gets enforced.
321 rv = dll->Unload();
322#endif /* 0 */
323 }
324 else
325 {
326#ifdef PR_LOGGING
327 nsXPIDLCString displayPath;
328 dll->GetDisplayPath(displayPath);
329
330 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
331 ("nsNativeComponentLoader: Ready for unload \"%s\".", displayPath.get()));
332#endif
333 }
334 }
335 else
336 {
337#ifdef PR_LOGGING
338 nsXPIDLCString displayPath;
339 dll->GetDisplayPath(displayPath);
340
341 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
342 ("nsNativeComponentLoader: NOT ready for unload %s", displayPath.get()));
343#endif
344 rv = NS_ERROR_FAILURE;
345 }
346 return rv;
347}
348
349struct freeLibrariesClosure
350{
351 nsIServiceManager *serviceMgr;
352 PRInt32 when;
353};
354
355static PRBool PR_CALLBACK
356nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure)
357{
358 nsDll *dll = (nsDll *) aData;
359 struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure;
360 nsFreeLibrary(dll,
361 (callData ? callData->serviceMgr : NULL),
362 (callData ? callData->when : nsIComponentManagerObsolete::NS_Timer));
363 return PR_TRUE;
364}
365
366/*
367 * SelfRegisterDll
368 *
369 * Given a dll abstraction, this will load, selfregister the dll and
370 * unload the dll.
371 *
372 */
373nsresult
374nsNativeComponentLoader::SelfRegisterDll(nsDll *dll,
375 const char *registryLocation,
376 PRBool deferred)
377{
378 // Precondition: dll is not loaded already, unless we're deferred
379 PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE);
380
381 nsresult res;
382 nsCOMPtr<nsIServiceManager> serviceMgr;
383 res = NS_GetServiceManager(getter_AddRefs(serviceMgr));
384 if (NS_FAILED(res)) return res;
385
386 if (dll->Load() == PR_FALSE)
387 {
388 // Cannot load. Probably not a dll.
389 char errorMsg[1024] = "Cannot get error from nspr. Not enough memory.";
390 if (PR_GetErrorTextLength() < (int) sizeof(errorMsg))
391 PR_GetErrorText(errorMsg);
392
393 DumpLoadError(dll, "SelfRegisterDll", errorMsg);
394
395 return NS_ERROR_FAILURE;
396 }
397
398#ifdef PR_LOGGING
399 nsXPIDLCString displayPath;
400 dll->GetDisplayPath(displayPath);
401
402 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
403 ("nsNativeComponentLoader: Loaded \"%s\".", displayPath.get()));
404#endif
405
406 // Tell the module to self register
407 nsCOMPtr<nsIFile> fs;
408 nsCOMPtr<nsIModule> mobj;
409 res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
410 if (NS_SUCCEEDED(res))
411 {
412 /*************************************************************
413 * WARNING: Why are use introducing 'res2' here and then *
414 * later assigning it to 'res' rather than just using 'res'? *
415 * This is because this code turns up a code-generation bug *
416 * in VC6 on NT. Assigning to 'res' on the next line causes *
417 * the value of 'dll' to get nulled out! The two seem to be *
418 * getting aliased together during compilation. *
419 *************************************************************/
420 nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs)); // don't change 'res2' -- see warning, above
421 if (NS_SUCCEEDED(res2)) {
422 // in the case of re-registering a component, we want to remove
423 // any optional data that this file may have had.
424 AddDependentLibrary(fs, nsnull);
425
426 res = mobj->RegisterSelf(mCompMgr, fs, registryLocation,
427 nativeComponentType);
428 }
429 else
430 {
431 res = res2; // don't take this out -- see warning, above
432
433#ifdef PR_LOGGING
434 nsXPIDLCString displayPath;
435 dll->GetDisplayPath(displayPath);
436 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
437 ("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.",
438 displayPath.get()));
439#endif
440 }
441 mobj = NULL; // Force a release of the Module object before unload()
442 }
443
444 // Update the timestamp and size of the dll in registry
445 // Don't enter deferred modules in the registry, because it might only be
446 // able to register on some later autoreg, after another component has been
447 // installed.
448 if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) {
449 PRInt64 modTime;
450 if (!fs)
451 return res;
452
453 fs->GetLastModifiedTime(&modTime);
454 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
455 if (!manager)
456 return NS_ERROR_FAILURE;
457
458 nsCOMPtr<nsIFile> fs;
459 res = dll->GetDllSpec(getter_AddRefs(fs));
460 if (NS_FAILED(res)) return res;
461
462 manager->SaveFileInfo(fs, registryLocation, modTime);
463 }
464
465 return res;
466}
467
468//
469// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing.
470//
471
472#if defined(MOZ_DEMANGLE_SYMBOLS)
473#include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol()
474#endif
475
476nsresult
477nsNativeComponentLoader::DumpLoadError(nsDll *dll,
478 const char *aCallerName,
479 const char *aNsprErrorMsg)
480{
481 PR_ASSERT(aCallerName != NULL);
482
483 if (nsnull == dll || nsnull == aNsprErrorMsg)
484 return NS_OK;
485
486 nsCAutoString errorMsg(aNsprErrorMsg);
487
488#if defined(MOZ_DEMANGLE_SYMBOLS)
489 // Demangle undefined symbols
490 nsCAutoString undefinedMagicString("undefined symbol:");
491
492 PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE);
493
494 if (offset != kNotFound)
495 {
496 nsCAutoString symbol(errorMsg);
497 nsCAutoString demangledSymbol;
498
499 symbol.Cut(0,offset);
500
501 symbol.Cut(0,undefinedMagicString.Length());
502
503 symbol.StripWhitespace();
504
505 char demangled[4096] = "\0";
506
507 nsTraceRefcntImpl::DemangleSymbol(symbol.get(),demangled,sizeof(demangled));
508
509 if (demangled && *demangled != '\0')
510 demangledSymbol = demangled;
511
512 if (!demangledSymbol.IsEmpty())
513 {
514 nsCAutoString tmp(errorMsg);
515
516
517 tmp.Cut(offset + undefinedMagicString.Length(),
518 tmp.Length() - offset - undefinedMagicString.Length());
519
520 tmp += " \n";
521
522 tmp += demangledSymbol;
523
524 errorMsg = tmp;
525 }
526 }
527#endif // MOZ_DEMANGLE_SYMBOLS
528 nsXPIDLCString displayPath;
529 dll->GetDisplayPath(displayPath);
530
531#ifdef DEBUG
532 fprintf(stderr,
533 "nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n",
534 aCallerName,
535 displayPath.get(),
536 errorMsg.get());
537#endif
538
539 // Do NSPR log
540#ifdef PR_LOGGING
541 PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
542 ("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s",
543 aCallerName,
544 displayPath.get(),
545 errorMsg.get()));
546#endif
547 return NS_OK;
548}
549
550nsresult
551nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll)
552{
553 nsresult res;
554 nsCOMPtr<nsIServiceManager> serviceMgr;
555 res = NS_GetServiceManager(getter_AddRefs(serviceMgr));
556 if (NS_FAILED(res)) return res;
557
558 if (dll->Load() == PR_FALSE)
559 {
560 // Cannot load. Probably not a dll.
561 return(NS_ERROR_FAILURE);
562 }
563
564 // Tell the module to self register
565 nsCOMPtr<nsIModule> mobj;
566 res = dll->GetModule(mCompMgr, getter_AddRefs(mobj));
567 if (NS_SUCCEEDED(res))
568 {
569#ifdef PR_LOGGING
570 nsXPIDLCString displayPath;
571 dll->GetDisplayPath(displayPath);
572
573 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
574 ("nsNativeComponentLoader: %s using nsIModule to unregister self.", displayPath.get()));
575#endif
576 nsCOMPtr<nsIFile> fs;
577 res = dll->GetDllSpec(getter_AddRefs(fs));
578 if (NS_FAILED(res)) return res;
579 // Get registry location for spec
580 nsXPIDLCString registryName;
581
582 // what I want to do here is QI for a Component Registration Manager. Since this
583 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
584 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &res);
585 if (obsoleteManager)
586 res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName));
587
588 if (NS_FAILED(res)) return res;
589 mobj->UnregisterSelf(mCompMgr, fs, registryName);
590 }
591 return res;
592}
593
594nsresult
595nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when,
596 nsIFile *component,
597 PRBool *unregistered)
598{
599
600 nsresult rv = NS_ERROR_FAILURE;
601
602 *unregistered = PR_FALSE;
603
604 nsXPIDLCString persistentDescriptor;
605 // what I want to do here is QI for a Component Registration Manager. Since this
606 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
607 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
608 if (obsoleteManager)
609 rv = obsoleteManager->RegistryLocationForSpec(component,
610 getter_Copies(persistentDescriptor));
611 if (NS_FAILED(rv)) return rv;
612
613 // Notify observers, if any, of autoregistration work
614 nsCOMPtr<nsIObserverService> observerService =
615 do_GetService("@mozilla.org/observer-service;1", &rv);
616 if (NS_SUCCEEDED(rv))
617 {
618 nsCOMPtr<nsIServiceManager> mgr;
619 rv = NS_GetServiceManager(getter_AddRefs(mgr));
620 if (NS_SUCCEEDED(rv))
621 {
622 (void) observerService->NotifyObservers(mgr,
623 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
624 NS_LITERAL_STRING("Unregistering native component").get());
625 }
626 }
627
628 nsDll *dll = NULL;
629 rv = CreateDll(component, persistentDescriptor, &dll);
630 if (NS_FAILED(rv) || dll == NULL) return rv;
631
632 rv = SelfUnregisterDll(dll);
633
634#ifdef PR_LOGGING
635 nsXPIDLCString displayPath;
636 dll->GetDisplayPath(displayPath);
637
638 PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR,
639 ("nsNativeComponentLoader: AutoUnregistration for %s %s.",
640 (NS_FAILED(rv) ? "FAILED" : "succeeded"), displayPath.get()));
641#endif
642
643 if (NS_FAILED(rv))
644 return rv;
645
646 // Remove any autoreg info about this dll
647 nsCStringKey key(persistentDescriptor);
648 mDllStore.RemoveAndDelete(&key);
649
650 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
651 NS_ASSERTION(manager, "Something is terribly wrong");
652
653 manager->RemoveFileInfo(component, nsnull);
654
655 *unregistered = PR_TRUE;
656 return rv;
657}
658
659nsresult
660nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when,
661 nsIFile *component,
662 PRBool *registered)
663{
664 nsresult rv;
665 if (!registered)
666 return NS_ERROR_NULL_POINTER;
667
668 *registered = PR_FALSE;
669
670 /* this should be a pref or registry entry, or something */
671 static const char *ValidDllExtensions[] = {
672 ".dll", /* Windows */
673 ".so", /* Unix */
674 ".shlb", /* Mac ? */
675 ".dso", /* Unix ? */
676 ".dylib", /* Unix: Mach */
677 ".so.1.0", /* Unix: BSD */
678 ".sl", /* Unix: HP-UX */
679#if defined(VMS)
680 ".exe", /* Open VMS */
681#endif
682 ".dlm", /* new for all platforms */
683 NULL
684 };
685
686 *registered = PR_FALSE;
687
688#if 0
689 // This is a performance hit on mac. Since we have already checked
690 // this; plus is we dont, load will fail anyway later on, this
691 // is being commented out.
692
693 // Ensure we are dealing with a file as opposed to a dir
694 PRBool b = PR_FALSE;
695
696 rv = component->IsFile(&b);
697 if (NS_FAILED(rv) || !b)
698 return rv;
699#endif /* 0 */
700
701 // deal only with files that have a valid extension
702 PRBool validExtension = PR_FALSE;
703
704#if defined(XP_MAC) // sdagley dougt fix
705 // rjc - on Mac, check the file's type code (skip checking the creator code)
706
707 nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(component);
708 if (localFileMac)
709 {
710 OSType type;
711 rv = localFileMac->GetFileType(&type);
712 if (NS_SUCCEEDED(rv))
713 {
714 // on Mac, Mozilla shared libraries are of type 'shlb'
715 // Note: we don't check the creator (which for Mozilla is 'MOZZ')
716 // so that 3rd party shared libraries will be noticed!
717 validExtension = ((type == 'shlb') || (type == 'NSPL'));
718 }
719 }
720
721#else
722 nsCAutoString leafName;
723 rv = component->GetNativeLeafName(leafName);
724 if (NS_FAILED(rv)) return rv;
725 int flen = leafName.Length();
726 for (int i=0; ValidDllExtensions[i] != NULL; i++)
727 {
728 int extlen = PL_strlen(ValidDllExtensions[i]);
729
730 // Does fullname end with this extension
731 if (flen >= extlen &&
732 !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i])
733 )
734 {
735 validExtension = PR_TRUE;
736 break;
737 }
738 }
739#endif
740
741 if (validExtension == PR_FALSE)
742 // Skip invalid extensions
743 return NS_OK;
744
745 nsXPIDLCString persistentDescriptor;
746 // what I want to do here is QI for a Component Registration Manager. Since this
747 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
748 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
749 if (obsoleteManager)
750 rv = obsoleteManager->RegistryLocationForSpec(component,
751 getter_Copies(persistentDescriptor));
752 if (NS_FAILED(rv))
753 return rv;
754
755 nsCStringKey key(persistentDescriptor);
756
757 // Get the registry representation of the dll, if any
758 nsDll *dll;
759 rv = CreateDll(component, persistentDescriptor, &dll);
760 if (NS_FAILED(rv))
761 return rv;
762
763 if (dll != NULL)
764 {
765 // We already have seen this dll. Check if this dll changed
766 if (!dll->HasChanged())
767 {
768#ifdef PR_LOGGING
769 nsXPIDLCString displayPath;
770 dll->GetDisplayPath(displayPath);
771
772 // Dll hasn't changed. Skip.
773 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
774 ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...",
775 displayPath.get()));
776#endif
777 *registered = PR_TRUE;
778 return NS_OK;
779 }
780
781 // Aagh! the dll has changed since the last time we saw it.
782 // re-register dll
783
784
785 // Notify observers, if any, of autoregistration work
786 nsCOMPtr<nsIObserverService> observerService =
787 do_GetService("@mozilla.org/observer-service;1", &rv);
788 if (NS_SUCCEEDED(rv))
789 {
790 nsCOMPtr<nsIServiceManager> mgr;
791 rv = NS_GetServiceManager(getter_AddRefs(mgr));
792 if (NS_SUCCEEDED(rv))
793 {
794 // this string can't come from a string bundle, because we
795 // don't have string bundles yet.
796 NS_ConvertASCIItoUCS2 fileName("(no name)");
797
798 // get the file name
799 nsCOMPtr<nsIFile> dllSpec;
800 if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec)
801 {
802 dllSpec->GetLeafName(fileName);
803 }
804
805 // this string can't come from a string bundle, because we
806 // don't have string bundles yet.
807 (void) observerService->
808 NotifyObservers(mgr,
809 NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
810 PromiseFlatString(NS_LITERAL_STRING("Registering native component ") +
811 fileName).get());
812 }
813 }
814
815 if (dll->IsLoaded())
816 {
817 // We loaded the old version of the dll and now we find that the
818 // on-disk copy if newer. Try to unload the dll.
819 nsCOMPtr<nsIServiceManager> serviceMgr;
820 rv = NS_GetServiceManager(getter_AddRefs(serviceMgr));
821
822 rv = nsFreeLibrary(dll, serviceMgr, when);
823 if (NS_FAILED(rv))
824 {
825 // THIS IS THE WORST SITUATION TO BE IN.
826 // Dll doesn't want to be unloaded. Cannot re-register
827 // this dll.
828#ifdef PR_LOGGING
829 nsXPIDLCString displayPath;
830 dll->GetDisplayPath(displayPath);
831
832 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
833 ("nsNativeComponentLoader: *** Dll already loaded. "
834 "Cannot unload either. Hence cannot re-register "
835 "\"%s\". Skipping...", displayPath.get()));
836#endif
837 return rv;
838 }
839 else {
840 // dll doesn't have a CanUnload proc. Guess it is
841 // ok to unload it.
842 dll->Unload();
843#ifdef PR_LOGGING
844 nsXPIDLCString displayPath;
845 dll->GetDisplayPath(displayPath);
846 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
847 ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).",
848 displayPath.get()));
849#endif
850 }
851
852 } // dll isloaded
853
854 // Sanity.
855 if (dll->IsLoaded())
856 {
857 // We went through all the above to make sure the dll
858 // is unloaded. And here we are with the dll still
859 // loaded. Whoever taught dp programming...
860#ifdef PR_LOGGING
861 nsXPIDLCString displayPath;
862 dll->GetDisplayPath(displayPath);
863 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
864 ("nsNativeComponentLoader: Dll still loaded. Cannot re-register "
865 "\"%s\". Skipping...", displayPath.get()));
866#endif
867 return NS_ERROR_FAILURE;
868 }
869 } // dll != NULL
870 else
871 {
872 // Create and add the dll to the mDllStore
873 // It is ok to do this even if the creation of nsDll
874 // didnt succeed. That way we wont do this again
875 // when we encounter the same dll.
876 dll = new nsDll(component, this);
877 if (dll == NULL)
878 return NS_ERROR_OUT_OF_MEMORY;
879 mDllStore.Put(&key, (void *) dll);
880 } // dll == NULL
881
882 // Either we are seeing the dll for the first time or the dll has
883 // changed since we last saw it and it is unloaded successfully.
884 //
885 // Now we can try register the dll for sure.
886 nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE);
887 if (NS_FAILED(res))
888 {
889 if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) {
890 /* defer for later loading */
891 mDeferredComponents.AppendElement(dll);
892 *registered = PR_TRUE;
893 return NS_OK;
894 } else {
895#ifdef PR_LOGGING
896 nsXPIDLCString displayPath;
897 dll->GetDisplayPath(displayPath);
898
899 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
900 ("nsNativeComponentLoader: Autoregistration FAILED for "
901 "\"%s\". Skipping...", displayPath.get()));
902#endif
903 return NS_ERROR_FACTORY_NOT_REGISTERED;
904 }
905 }
906 else
907 {
908#ifdef PR_LOGGING
909 nsXPIDLCString displayPath;
910 dll->GetDisplayPath(displayPath);
911
912 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
913 ("nsNativeComponentLoader: Autoregistration Passed for "
914 "\"%s\".", displayPath.get()));
915#endif
916 // Marking dll along with modified time and size in the
917 // registry happens at PlatformRegister(). No need to do it
918 // here again.
919 *registered = PR_TRUE;
920 }
921 return NS_OK;
922}
923
924nsresult
925nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen,
926 PRBool *aRegistered)
927{
928#ifdef DEBUG
929 fprintf(stderr, "nNCL: registering deferred (%d)\n",
930 mDeferredComponents.Count());
931#endif
932 *aRegistered = PR_FALSE;
933 if (!mDeferredComponents.Count())
934 return NS_OK;
935
936 for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) {
937 nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]);
938 nsresult rv = SelfRegisterDll(dll,
939 nsnull,
940 PR_TRUE);
941 if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) {
942 if (NS_SUCCEEDED(rv))
943 *aRegistered = PR_TRUE;
944 mDeferredComponents.RemoveElementAt(i);
945 }
946 }
947#ifdef DEBUG
948 if (*aRegistered)
949 fprintf(stderr, "nNCL: registered deferred, %d left\n",
950 mDeferredComponents.Count());
951 else
952 fprintf(stderr, "nNCL: didn't register any components, %d left\n",
953 mDeferredComponents.Count());
954#endif
955 /* are there any fatal errors? */
956 return NS_OK;
957}
958
959nsresult
960nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType,
961 const char *aClassName,
962 const char *aContractID,
963 const char *aLocation,
964 PRBool aReplace,
965 PRBool aPersist)
966{
967 return NS_OK;
968}
969
970nsresult
971nsNativeComponentLoader::UnloadAll(PRInt32 aWhen)
972{
973 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading...."));
974
975 struct freeLibrariesClosure callData;
976 callData.serviceMgr = NULL; // XXX need to get this as a parameter
977 callData.when = aWhen;
978
979 // Cycle through the dlls checking to see if they want to be unloaded
980 mDllStore.Enumerate(nsFreeLibraryEnum, &callData);
981 return NS_OK;
982}
983
984//
985// CreateDll
986// The only way to create a dll or get it from the dll cache. This will
987// be called in multiple situations:
988//
989// 1. Autoregister will create one for each dll it is trying to register. This
990// call will be passing a spec in.
991// {spec, NULL, 0, 0}
992//
993// 2. GetFactory() This will call CreateDll() with a null spec but will give
994// the registry represented name of the dll. If modtime and size are zero,
995// we will go the registry to find the right modtime and size.
996// {NULL, rel:libpref.so, 0, 0}
997//
998// 3. Prepopulation of dllCache A dll object created off a registry entry.
999// Specifically dll name is stored in rel: or abs: or lib: formats in the
1000// registry along with its lastModTime and fileSize.
1001// {NULL, rel:libpref.so, 8985659, 20987}
1002nsresult
1003nsNativeComponentLoader::CreateDll(nsIFile *aSpec,
1004 const char *aLocation,
1005 nsDll **aDll)
1006{
1007 nsDll *dll;
1008 nsCOMPtr<nsIFile> dllSpec;
1009 nsCOMPtr<nsIFile> spec;
1010 nsresult rv;
1011
1012 nsCStringKey key(aLocation);
1013 dll = (nsDll *)mDllStore.Get(&key);
1014 if (dll)
1015 {
1016 *aDll = dll;
1017 return NS_OK;
1018 }
1019
1020 if (!aSpec)
1021 {
1022 // what I want to do here is QI for a Component Registration Manager. Since this
1023 // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
1024 nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(mCompMgr, &rv);
1025 if (obsoleteManager)
1026 rv = obsoleteManager->SpecForRegistryLocation(aLocation,
1027 getter_AddRefs(spec));
1028 if (NS_FAILED(rv))
1029 return rv;
1030 }
1031 else
1032 {
1033 spec = aSpec;
1034 }
1035
1036 if (!dll)
1037 {
1038 dll = new nsDll(spec, this);
1039 if (!dll)
1040 return NS_ERROR_OUT_OF_MEMORY;
1041 }
1042
1043 *aDll = dll;
1044 mDllStore.Put(&key, dll);
1045 return NS_OK;
1046}
1047
1048nsresult
1049nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID,
1050 nsIFactory **aFactory)
1051{
1052 nsresult rv;
1053
1054 nsCOMPtr<nsIModule> module;
1055 rv = aDll->GetModule(mCompMgr, getter_AddRefs(module));
1056
1057 if (NS_FAILED(rv))
1058 return rv;
1059
1060 return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory),
1061 (void **)aFactory);
1062}
1063
1064
1065NS_IMETHODIMP
1066nsNativeComponentLoader::AddDependentLibrary(nsIFile* aFile, const char* libName)
1067{
1068 nsCOMPtr<nsIComponentLoaderManager> manager = do_QueryInterface(mCompMgr);
1069 if (!manager)
1070 {
1071 NS_WARNING("Something is terribly wrong");
1072 return NS_ERROR_FAILURE;
1073 }
1074
1075 // the native component loader uses the optional data
1076 // to store a space delimited list of dependent library
1077 // names
1078
1079 if (!libName)
1080 {
1081 manager->SetOptionalData(aFile, nsnull, nsnull);
1082 return NS_OK;
1083 }
1084
1085 nsXPIDLCString data;
1086 manager->GetOptionalData(aFile, nsnull, getter_Copies(data));
1087
1088 if (!data.IsEmpty())
1089 data.AppendLiteral(" ");
1090
1091 data.Append(nsDependentCString(libName));
1092
1093 manager->SetOptionalData(aFile, nsnull, data);
1094 return NS_OK;
1095}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use