Bug 464146 - about:rights notification sometimes not shown with session restore....
[wine-gecko.git] / xpcom / glue / nsGREGlue.cpp
bloba0150875404d931cae997318ae7233df36403edf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
15 * The Original Code is Mozilla Communicator.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corp.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Sean Su <ssu@netscape.com>
24 * Benjamin Smedberg <benjamin@smedbergs.us>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsXPCOMGlue.h"
42 #include "nsINIParser.h"
43 #include "nsVersionComparator.h"
44 #include "nsXPCOMPrivate.h"
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
50 #ifdef XP_WIN32
51 # include <windows.h>
52 # include <mbstring.h>
53 # include <io.h>
54 # define snprintf _snprintf
55 # define R_OK 04
56 #elif defined(XP_OS2)
57 # define INCL_DOS
58 # include <os2.h>
59 #elif defined(XP_MACOSX)
60 # include <CFBundle.h>
61 # include <unistd.h>
62 # include <dirent.h>
63 #elif defined(XP_UNIX)
64 # include <unistd.h>
65 # include <sys/param.h>
66 # include <dirent.h>
67 #elif defined(XP_BEOS)
68 # include <FindDirectory.h>
69 # include <Path.h>
70 # include <unistd.h>
71 # include <sys/param.h>
72 # include <OS.h>
73 # include <image.h>
74 # include <dirent.h>
75 # include <FindDirectory.h>
76 #endif
78 #include <sys/stat.h>
80 /**
81 * Like strncat, appends a buffer to another buffer. This is where the
82 * similarity ends. Firstly, the "count" here is the total size of the buffer
83 * (not the number of chars to append. Secondly, the function returns PR_FALSE
84 * if the buffer is not long enough to hold the concatenated string.
86 static PRBool safe_strncat(char *dest, const char *append, PRUint32 count)
88 char *end = dest + count - 1;
90 // skip to the end of dest
91 while (*dest)
92 ++dest;
94 while (*append && dest < end) {
95 *dest = *append;
96 ++dest, ++append;
99 *dest = '\0';
101 return *append == '\0';
104 static PRBool
105 CheckVersion(const char* toCheck,
106 const GREVersionRange *versions,
107 PRUint32 versionsLength);
109 #if defined(XP_MACOSX)
111 static PRBool
112 GRE_FindGREFramework(const char* rootPath,
113 const GREVersionRange *versions,
114 PRUint32 versionsLength,
115 const GREProperty *properties,
116 PRUint32 propertiesLength,
117 char* buffer, PRUint32 buflen);
119 #elif defined(XP_UNIX) || defined(XP_BEOS)
121 static PRBool
122 GRE_GetPathFromConfigDir(const char* dirname,
123 const GREVersionRange *versions,
124 PRUint32 versionsLength,
125 const GREProperty *properties,
126 PRUint32 propertiesLength,
127 char* buffer, PRUint32 buflen);
129 static PRBool
130 GRE_GetPathFromConfigFile(const char* filename,
131 const GREVersionRange *versions,
132 PRUint32 versionsLength,
133 const GREProperty *properties,
134 PRUint32 propertiesLength,
135 char* buffer, PRUint32 buflen);
137 #elif defined(XP_WIN)
139 static PRBool
140 GRE_GetPathFromRegKey(HKEY aRegKey,
141 const GREVersionRange *versions,
142 PRUint32 versionsLength,
143 const GREProperty *properties,
144 PRUint32 propertiesLength,
145 char* buffer, PRUint32 buflen);
147 #endif
149 nsresult
150 GRE_GetGREPathWithProperties(const GREVersionRange *versions,
151 PRUint32 versionsLength,
152 const GREProperty *properties,
153 PRUint32 propertiesLength,
154 char *aBuffer, PRUint32 aBufLen)
156 #ifdef TARGET_XPCOM_ABI
157 // append the ABI to the properties to match only binary
158 // compatible GREs
159 static const GREProperty kExtraProperty =
160 { "abi", TARGET_XPCOM_ABI };
162 GREProperty *allProperties = new GREProperty[propertiesLength + 1];
163 if (!allProperties)
164 return NS_ERROR_OUT_OF_MEMORY;
166 for (PRUint32 i=0; i<propertiesLength; i++) {
167 allProperties[i].property = properties[i].property;
168 allProperties[i].value = properties[i].value;
170 allProperties[propertiesLength].property = kExtraProperty.property;
171 allProperties[propertiesLength].value = kExtraProperty.value;
172 PRUint32 allPropertiesLength = propertiesLength + 1;
173 #else
174 const GREProperty *allProperties = properties;
175 PRUint32 allPropertiesLength = propertiesLength;
176 #endif
178 // if GRE_HOME is in the environment, use that GRE
179 const char* env = getenv("GRE_HOME");
180 if (env && *env) {
181 char p[MAXPATHLEN];
182 snprintf(p, sizeof(p), "%s" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, env);
183 p[sizeof(p) - 1] = '\0';
185 #if XP_UNIX
186 if (realpath(p, aBuffer))
187 return NS_OK;
188 #elif XP_WIN
189 if (_fullpath(aBuffer, p, aBufLen))
190 return NS_OK;
191 #elif XP_OS2
192 // realpath on OS/2 returns a unix-ized path, so re-native-ize
193 if (realpath(p, aBuffer)) {
194 for (char* ptr = strchr(aBuffer, '/'); ptr; ptr = strchr(ptr, '/'))
195 *ptr = '\\';
196 return NS_OK;
198 #elif XP_BEOS
199 BPath path;
200 status_t result;
201 result = path.SetTo(p,0,true);
202 if (result == B_OK)
204 sprintf(aBuffer, path.Path());
205 return NS_OK;
207 #else
208 // hope for the best
209 // xxxbsmedberg: other platforms should have a "make absolute" function
210 #endif
212 if (strlen(p) >= aBufLen)
213 return NS_ERROR_FILE_NAME_TOO_LONG;
215 strcpy(aBuffer, p);
217 return NS_OK;
220 // the Gecko bits that sit next to the application or in the LD_LIBRARY_PATH
221 env = getenv("USE_LOCAL_GRE");
222 if (env && *env) {
223 *aBuffer = nsnull;
224 return NS_OK;
227 #ifdef XP_MACOSX
228 aBuffer[0] = '\0';
230 // Check the bundle first, for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib
231 CFBundleRef appBundle = CFBundleGetMainBundle();
232 if (appBundle) {
233 CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle);
234 CFURLRef absfwurl = nsnull;
235 if (fwurl) {
236 absfwurl = CFURLCopyAbsoluteURL(fwurl);
237 CFRelease(fwurl);
240 if (absfwurl) {
241 CFURLRef xulurl =
242 CFURLCreateCopyAppendingPathComponent(NULL, absfwurl,
243 CFSTR(GRE_FRAMEWORK_NAME),
244 PR_TRUE);
246 if (xulurl) {
247 CFURLRef xpcomurl =
248 CFURLCreateCopyAppendingPathComponent(NULL, xulurl,
249 CFSTR("libxpcom.dylib"),
250 PR_FALSE);
252 if (xpcomurl) {
253 char tbuffer[MAXPATHLEN];
255 if (CFURLGetFileSystemRepresentation(xpcomurl, PR_TRUE,
256 (UInt8*) tbuffer,
257 sizeof(tbuffer)) &&
258 access(tbuffer, R_OK | X_OK) == 0) {
259 if (!realpath(tbuffer, aBuffer)) {
260 aBuffer[0] = '\0';
264 CFRelease(xpcomurl);
267 CFRelease(xulurl);
270 CFRelease(absfwurl);
274 if (aBuffer[0])
275 return NS_OK;
277 // Check ~/Library/Frameworks/XUL.framework/Versions/<version>/libxpcom.dylib
278 const char *home = getenv("HOME");
279 if (home && *home && GRE_FindGREFramework(home,
280 versions, versionsLength,
281 allProperties, allPropertiesLength,
282 aBuffer, aBufLen)) {
283 return NS_OK;
286 // Check /Library/Frameworks/XUL.framework/Versions/<version>/libxpcom.dylib
287 if (GRE_FindGREFramework("",
288 versions, versionsLength,
289 allProperties, allPropertiesLength,
290 aBuffer, aBufLen)) {
291 return NS_OK;
294 #elif defined(XP_UNIX)
295 env = getenv("MOZ_GRE_CONF");
296 if (env && GRE_GetPathFromConfigFile(env,
297 versions, versionsLength,
298 allProperties, allPropertiesLength,
299 aBuffer, aBufLen)) {
300 return NS_OK;
303 env = getenv("HOME");
304 if (env && *env) {
305 char buffer[MAXPATHLEN];
307 // Look in ~/.gre.config
309 snprintf(buffer, sizeof(buffer),
310 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, env);
312 if (GRE_GetPathFromConfigFile(buffer,
313 versions, versionsLength,
314 allProperties, allPropertiesLength,
315 aBuffer, aBufLen)) {
316 return NS_OK;
319 // Look in ~/.gre.d/*.conf
321 snprintf(buffer, sizeof(buffer),
322 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_USER_CONF_DIR, env);
324 if (GRE_GetPathFromConfigDir(buffer,
325 versions, versionsLength,
326 allProperties, allPropertiesLength,
327 aBuffer, aBufLen)) {
328 return NS_OK;
332 // Look for a global /etc/gre.conf file
333 if (GRE_GetPathFromConfigFile(GRE_CONF_PATH,
334 versions, versionsLength,
335 allProperties, allPropertiesLength,
336 aBuffer, aBufLen)) {
337 return NS_OK;
340 // Look for a group of config files in /etc/gre.d/
341 if (GRE_GetPathFromConfigDir(GRE_CONF_DIR,
342 versions, versionsLength,
343 allProperties, allPropertiesLength,
344 aBuffer, aBufLen)) {
345 return NS_OK;
348 #elif defined(XP_BEOS)
349 env = getenv("MOZ_GRE_CONF");
350 if (env && GRE_GetPathFromConfigFile(env,
351 versions, versionsLength,
352 allProperties, allPropertiesLength,
353 aBuffer, aBufLen)) {
354 return NS_OK;
357 char p[MAXPATHLEN];
358 if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, 0, p, MAXPATHLEN)) {
359 char buffer[MAXPATHLEN];
361 // Look in B_USER_SETTINGS_DIRECTORY/gre.config
362 snprintf(buffer, sizeof(buffer),
363 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_NAME, p);
365 if (GRE_GetPathFromConfigFile(buffer,
366 versions, versionsLength,
367 allProperties, allPropertiesLength,
368 aBuffer, aBufLen)) {
369 return NS_OK;
372 // Look in B_USER_SETTINGS_DIRECTORY/gre.d/*.conf
373 snprintf(buffer, sizeof(buffer),
374 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_DIR, p);
376 if (GRE_GetPathFromConfigDir(buffer,
377 versions, versionsLength,
378 allProperties, allPropertiesLength,
379 aBuffer, aBufLen)) {
380 return NS_OK;
384 // Hope Zeta OS and Haiku OS multiuser versions will respect BeBook,
385 // for BeOS R5 COMMON and USER are equal
386 if (find_directory(B_COMMON_SETTINGS_DIRECTORY, 0, 0, p, MAXPATHLEN)) {
387 char buffer[MAXPATHLEN];
389 // Look for a B_COMMON_SETTINGS_DIRECTORY/gre.conf file
390 snprintf(buffer, sizeof(buffer),
391 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_PATH, p);
392 if (GRE_GetPathFromConfigFile(buffer,
393 versions, versionsLength,
394 allProperties, allPropertiesLength,
395 aBuffer, aBufLen)) {
396 return NS_OK;
399 // Look for a group of config files in B_COMMON_SETTINGS_DIRECTORY/gre.d/
400 snprintf(buffer, sizeof(buffer),
401 "%s" XPCOM_FILE_PATH_SEPARATOR GRE_CONF_DIR, p);
402 if (GRE_GetPathFromConfigDir(buffer,
403 versions, versionsLength,
404 allProperties, allPropertiesLength,
405 aBuffer, aBufLen)) {
406 return NS_OK;
410 #elif defined(XP_WIN)
411 HKEY hRegKey = NULL;
413 // A couple of key points here:
414 // 1. Note the usage of the "Software\\mozilla.org\\GRE" subkey - this allows
415 // us to have multiple versions of GREs on the same machine by having
416 // subkeys such as 1.0, 1.1, 2.0 etc. under it.
417 // 2. In this sample below we're looking for the location of GRE version 1.2
418 // i.e. we're compatible with GRE 1.2 and we're trying to find it's install
419 // location.
421 // Please see http://www.mozilla.org/projects/embedding/GRE.html for
422 // more info.
424 if (::RegOpenKeyEx(HKEY_CURRENT_USER, GRE_WIN_REG_LOC, 0,
425 KEY_READ, &hRegKey) == ERROR_SUCCESS) {
426 PRBool ok = GRE_GetPathFromRegKey(hRegKey,
427 versions, versionsLength,
428 allProperties, allPropertiesLength,
429 aBuffer, aBufLen);
430 ::RegCloseKey(hRegKey);
432 if (ok)
433 return NS_OK;
436 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, GRE_WIN_REG_LOC, 0,
437 KEY_ENUMERATE_SUB_KEYS, &hRegKey) == ERROR_SUCCESS) {
438 PRBool ok = GRE_GetPathFromRegKey(hRegKey,
439 versions, versionsLength,
440 allProperties, allPropertiesLength,
441 aBuffer, aBufLen);
442 ::RegCloseKey(hRegKey);
444 if (ok)
445 return NS_OK;
447 #endif
449 return NS_ERROR_FAILURE;
452 static PRBool
453 CheckVersion(const char* toCheck,
454 const GREVersionRange *versions,
455 PRUint32 versionsLength)
458 for (const GREVersionRange *versionsEnd = versions + versionsLength;
459 versions < versionsEnd;
460 ++versions) {
461 PRInt32 c = NS_CompareVersions(toCheck, versions->lower);
462 if (c < 0)
463 continue;
465 if (!c && !versions->lowerInclusive)
466 continue;
468 c = NS_CompareVersions(toCheck, versions->upper);
469 if (c > 0)
470 continue;
472 if (!c && !versions->upperInclusive)
473 continue;
475 return PR_TRUE;
478 return PR_FALSE;
481 #ifdef XP_MACOSX
482 PRBool
483 GRE_FindGREFramework(const char* rootPath,
484 const GREVersionRange *versions,
485 PRUint32 versionsLength,
486 const GREProperty *properties,
487 PRUint32 propertiesLength,
488 char* buffer, PRUint32 buflen)
490 PRBool found = PR_FALSE;
492 snprintf(buffer, buflen,
493 "%s/Library/Frameworks/" GRE_FRAMEWORK_NAME "/Versions", rootPath);
494 DIR *dir = opendir(buffer);
495 if (dir) {
496 struct dirent *entry;
497 while (!found && (entry = readdir(dir))) {
498 if (CheckVersion(entry->d_name, versions, versionsLength)) {
499 snprintf(buffer, buflen,
500 "%s/Library/Frameworks/" GRE_FRAMEWORK_NAME
501 "/Versions/%s/" XPCOM_DLL, rootPath, entry->d_name);
502 if (access(buffer, R_OK | X_OK) == 0)
503 found = PR_TRUE;
507 closedir(dir);
510 if (found)
511 return PR_TRUE;
513 buffer[0] = '\0';
514 return PR_FALSE;
517 #elif defined(XP_UNIX) || defined(XP_BEOS)
519 static PRBool IsConfFile(const char *filename)
521 const char *dot = strrchr(filename, '.');
523 return (dot && strcmp(dot, ".conf") == 0);
526 PRBool
527 GRE_GetPathFromConfigDir(const char* dirname,
528 const GREVersionRange *versions,
529 PRUint32 versionsLength,
530 const GREProperty *properties,
531 PRUint32 propertiesLength,
532 char* buffer, PRUint32 buflen)
534 // Open the directory provided and try to read any files in that
535 // directory that end with .conf. We look for an entry that might
536 // point to the GRE that we're interested in.
537 DIR *dir = opendir(dirname);
538 if (!dir)
539 return nsnull;
541 PRBool found = PR_FALSE;
542 struct dirent *entry;
544 while (!found && (entry = readdir(dir))) {
546 // Only look for files that end in .conf
547 // IsConfFile will skip "." and ".."
548 if (!IsConfFile(entry->d_name))
549 continue;
551 char fullPath[MAXPATHLEN];
552 snprintf(fullPath, sizeof(fullPath), "%s" XPCOM_FILE_PATH_SEPARATOR "%s",
553 dirname, entry->d_name);
555 found = GRE_GetPathFromConfigFile(fullPath,
556 versions, versionsLength,
557 properties, propertiesLength,
558 buffer, buflen);
561 closedir(dir);
563 return found;
566 #define READ_BUFFER_SIZE 1024
568 struct INIClosure
570 nsINIParser *parser;
571 const GREVersionRange *versions;
572 PRUint32 versionsLength;
573 const GREProperty *properties;
574 PRUint32 propertiesLength;
575 char *pathBuffer;
576 PRUint32 buflen;
577 PRBool found;
580 static PRBool
581 CheckINIHeader(const char *aHeader, void *aClosure)
583 nsresult rv;
585 INIClosure *c = reinterpret_cast<INIClosure *>(aClosure);
587 if (!CheckVersion(aHeader, c->versions, c->versionsLength))
588 return PR_TRUE;
590 const GREProperty *properties = c->properties;
591 const GREProperty *endProperties = properties + c->propertiesLength;
592 for (; properties < endProperties; ++properties) {
593 char buffer[MAXPATHLEN];
594 rv = c->parser->GetString(aHeader, properties->property,
595 buffer, sizeof(buffer));
596 if (NS_FAILED(rv))
597 return PR_TRUE;
599 if (strcmp(buffer, properties->value))
600 return PR_TRUE;
603 rv = c->parser->GetString(aHeader, "GRE_PATH", c->pathBuffer, c->buflen);
604 if (NS_FAILED(rv))
605 return PR_TRUE;
607 if (!safe_strncat(c->pathBuffer, "/" XPCOM_DLL, c->buflen) ||
608 access(c->pathBuffer, R_OK))
609 return PR_TRUE;
611 // We found a good GRE! Stop looking.
612 c->found = PR_TRUE;
613 return PR_FALSE;
616 PRBool
617 GRE_GetPathFromConfigFile(const char* filename,
618 const GREVersionRange *versions,
619 PRUint32 versionsLength,
620 const GREProperty *properties,
621 PRUint32 propertiesLength,
622 char* pathBuffer, PRUint32 buflen)
624 nsINIParser parser;
625 nsresult rv = parser.Init(filename);
626 if (NS_FAILED(rv))
627 return PR_FALSE;
629 INIClosure c = {
630 &parser,
631 versions, versionsLength,
632 properties, propertiesLength,
633 pathBuffer, buflen,
634 PR_FALSE
637 parser.GetSections(CheckINIHeader, &c);
638 return c.found;
641 #elif defined(XP_WIN)
643 static PRBool
644 CopyWithEnvExpansion(char* aDest, const char* aSource, PRUint32 aBufLen,
645 DWORD aType)
647 switch (aType) {
648 case REG_SZ:
649 if (strlen(aSource) >= aBufLen)
650 return PR_FALSE;
652 strcpy(aDest, aSource);
653 return PR_TRUE;
655 case REG_EXPAND_SZ:
656 if (ExpandEnvironmentStrings(aSource, aDest, aBufLen) > aBufLen)
657 return PR_FALSE;
659 return PR_TRUE;
662 // Whoops! We expected REG_SZ or REG_EXPAND_SZ, what happened here?
664 return PR_FALSE;
667 PRBool
668 GRE_GetPathFromRegKey(HKEY aRegKey,
669 const GREVersionRange *versions,
670 PRUint32 versionsLength,
671 const GREProperty *properties,
672 PRUint32 propertiesLength,
673 char* aBuffer, PRUint32 aBufLen)
675 // Formerly, GREs were registered at the registry key
676 // HKLM/Software/mozilla.org/GRE/<version> valuepair GreHome=Path.
677 // Nowadays, they are registered in any subkey of
678 // Software/mozilla.org/GRE, with the following valuepairs:
679 // Version=<version> (REG_SZ)
680 // GreHome=<path> (REG_SZ or REG_EXPAND_SZ)
681 // <Property>=<value> (REG_SZ)
683 // Additional meta-info may be available in the future, including
684 // localization info and other information which might be pertinent
685 // to selecting one GRE over another.
687 // When a GRE is being registered, it should try to register itself at
688 // HKLM/Software/mozilla.org/GRE/<Version> first, to preserve compatibility
689 // with older glue. If this key is already taken (i.e. there is more than
690 // one GRE of that version installed), it should append a unique number to
691 // the version, for example:
692 // 1.1 (already in use), 1.1_1, 1.1_2, etc...
694 DWORD i = 0;
696 while (PR_TRUE) {
697 char name[MAXPATHLEN + 1];
698 DWORD nameLen = MAXPATHLEN;
699 if (::RegEnumKeyEx(aRegKey, i, name, &nameLen, NULL, NULL, NULL, NULL) !=
700 ERROR_SUCCESS) {
701 break;
704 HKEY subKey = NULL;
705 if (::RegOpenKeyEx(aRegKey, name, 0, KEY_QUERY_VALUE, &subKey) !=
706 ERROR_SUCCESS) {
707 continue;
710 char version[40];
711 DWORD versionlen = 40;
712 char pathbuf[MAXPATHLEN];
713 DWORD pathlen;
714 DWORD pathtype;
716 PRBool ok = PR_FALSE;
718 if (::RegQueryValueEx(subKey, "Version", NULL, NULL,
719 (BYTE*) version, &versionlen) == ERROR_SUCCESS &&
720 CheckVersion(version, versions, versionsLength)) {
722 ok = PR_TRUE;
723 const GREProperty *props = properties;
724 const GREProperty *propsEnd = properties + propertiesLength;
725 for (; ok && props < propsEnd; ++props) {
726 pathlen = sizeof(pathbuf);
728 if (::RegQueryValueEx(subKey, props->property, NULL, &pathtype,
729 (BYTE*) pathbuf, &pathlen) != ERROR_SUCCESS ||
730 strcmp(pathbuf, props->value))
731 ok = PR_FALSE;
734 pathlen = sizeof(pathbuf);
735 if (ok &&
736 (!::RegQueryValueEx(subKey, "GreHome", NULL, &pathtype,
737 (BYTE*) pathbuf, &pathlen) == ERROR_SUCCESS ||
738 !*pathbuf ||
739 !CopyWithEnvExpansion(aBuffer, pathbuf, aBufLen, pathtype))) {
740 ok = PR_FALSE;
742 else if (!safe_strncat(aBuffer, "\\" XPCOM_DLL, aBufLen) ||
743 access(aBuffer, R_OK)) {
744 ok = PR_FALSE;
748 RegCloseKey(subKey);
750 if (ok)
751 return PR_TRUE;
753 ++i;
756 aBuffer[0] = '\0';
758 return PR_FALSE;
760 #endif // XP_WIN