ntdll: Implemented IOCTL for serial: SET_WAIT_MASK, GET_WAIT_MASK.
[wine] / dlls / ntdll / loadorder.c
1 /*
2  * Dlls load order support
3  *
4  * Copyright 1999 Bertho Stultiens
5  * Copyright 2003 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29
30 #include "windef.h"
31 #include "winternl.h"
32 #include "ntdll_misc.h"
33 #include "module.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(module);
39
40 #define LOADORDER_ALLOC_CLUSTER 32      /* Allocate with 32 entries at a time */
41
42 typedef struct module_loadorder
43 {
44     const WCHAR        *modulename;
45     enum loadorder_type loadorder[LOADORDER_NTYPES];
46 } module_loadorder_t;
47
48 struct loadorder_list
49 {
50     int                 count;
51     int                 alloc;
52     module_loadorder_t *order;
53 };
54
55 /* dll to load as builtins if not explicitly specified otherwise */
56 /* the list must remain sorted by dll name */
57 static const WCHAR default_builtins[][10] =
58 {
59     { 'g','d','i','3','2',0 },
60     { 'i','c','m','p',0 },
61     { 'k','e','r','n','e','l','3','2',0 },
62     { 'n','t','d','l','l',0 },
63     { 'o','d','b','c','3','2',0 },
64     { 't','t','y','d','r','v',0 },
65     { 'u','s','e','r','3','2',0 },
66     { 'w','3','2','s','k','r','n','l',0 },
67     { 'w','i','n','e','d','o','s',0 },
68     { 'w','i','n','e','p','s',0 },
69     { 'w','i','n','m','m',0 },
70     { 'w','n','a','s','p','i','3','2',0 },
71     { 'w','o','w','3','2',0 },
72     { 'w','s','2','_','3','2',0 },
73     { 'w','s','o','c','k','3','2',0 },
74     { 'x','1','1','d','r','v',0 }
75 };
76
77 /* default if nothing else specified */
78 static const enum loadorder_type default_loadorder[LOADORDER_NTYPES] =
79 {
80     LOADORDER_BI, LOADORDER_DLL, 0
81 };
82
83 static const WCHAR separatorsW[] = {',',' ','\t',0};
84
85 static int init_done;
86 static struct loadorder_list env_list;
87
88
89 /***************************************************************************
90  *      cmp_sort_func   (internal, static)
91  *
92  * Sorting and comparing function used in sort and search of loadorder
93  * entries.
94  */
95 static int cmp_sort_func(const void *s1, const void *s2)
96 {
97     return strcmpiW(((const module_loadorder_t *)s1)->modulename, ((const module_loadorder_t *)s2)->modulename);
98 }
99
100
101 /***************************************************************************
102  *      strcmp_func
103  */
104 static int strcmp_func(const void *s1, const void *s2)
105 {
106     return strcmpiW( (const WCHAR *)s1, (const WCHAR *)s2 );
107 }
108
109
110 /***************************************************************************
111  *      get_basename
112  *
113  * Return the base name of a file name (i.e. remove the path components).
114  */
115 static const WCHAR *get_basename( const WCHAR *name )
116 {
117     const WCHAR *ptr;
118
119     if (name[0] && name[1] == ':') name += 2;  /* strip drive specification */
120     if ((ptr = strrchrW( name, '\\' ))) name = ptr + 1;
121     if ((ptr = strrchrW( name, '/' ))) name = ptr + 1;
122     return name;
123 }
124
125 /***************************************************************************
126  *      remove_dll_ext
127  *
128  * Remove extension if it is ".dll".
129  */
130 static inline void remove_dll_ext( WCHAR *ext )
131 {
132     if (ext[0] == '.' &&
133         toupperW(ext[1]) == 'D' &&
134         toupperW(ext[2]) == 'L' &&
135         toupperW(ext[3]) == 'L' &&
136         !ext[4]) ext[0] = 0;
137 }
138
139
140 /***************************************************************************
141  *      debugstr_loadorder
142  *
143  * Return a loadorder in printable form.
144  */
145 static const char *debugstr_loadorder( enum loadorder_type lo[] )
146 {
147     int i;
148     char buffer[LOADORDER_NTYPES*3+1];
149
150     buffer[0] = 0;
151     for(i = 0; i < LOADORDER_NTYPES; i++)
152     {
153         if (lo[i] == LOADORDER_INVALID) break;
154         switch(lo[i])
155         {
156         case LOADORDER_DLL: strcat( buffer, "n," ); break;
157         case LOADORDER_BI:  strcat( buffer, "b," ); break;
158         default:            strcat( buffer, "?," ); break;
159         }
160     }
161     if (buffer[0]) buffer[strlen(buffer)-1] = 0;
162     return debugstr_a(buffer);
163 }
164
165
166 /***************************************************************************
167  *      append_load_order
168  *
169  * Append a load order to the list if necessary.
170  */
171 static void append_load_order(enum loadorder_type lo[], enum loadorder_type append)
172 {
173     int i;
174
175     for (i = 0; i < LOADORDER_NTYPES; i++)
176     {
177         if (lo[i] == LOADORDER_INVALID)  /* append it here */
178         {
179             lo[i++] = append;
180             lo[i] = LOADORDER_INVALID;
181             return;
182         }
183         if (lo[i] == append) return;  /* already in the list */
184     }
185     assert(0);  /* cannot get here */
186 }
187
188
189 /***************************************************************************
190  *      parse_load_order
191  *
192  * Parses the loadorder options from the configuration and puts it into
193  * a structure.
194  */
195 static void parse_load_order( const WCHAR *order, enum loadorder_type lo[] )
196 {
197     lo[0] = LOADORDER_INVALID;
198     while (*order)
199     {
200         order += strspnW( order, separatorsW );
201         switch(*order)
202         {
203         case 'N':       /* Native */
204         case 'n':
205             append_load_order( lo, LOADORDER_DLL );
206             break;
207         case 'B':       /* Builtin */
208         case 'b':
209             append_load_order( lo, LOADORDER_BI );
210             break;
211         }
212         order += strcspnW( order, separatorsW );
213     }
214 }
215
216
217 /***************************************************************************
218  *      add_load_order
219  *
220  * Adds an entry in the list of environment overrides.
221  */
222 static void add_load_order( const module_loadorder_t *plo )
223 {
224     int i;
225
226     for(i = 0; i < env_list.count; i++)
227     {
228         if(!cmp_sort_func(plo, &env_list.order[i] ))
229         {
230             /* replace existing option */
231             memcpy( env_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
232             return;
233         }
234     }
235
236     if (i >= env_list.alloc)
237     {
238         /* No space in current array, make it larger */
239         env_list.alloc += LOADORDER_ALLOC_CLUSTER;
240         if (env_list.order)
241             env_list.order = RtlReAllocateHeap(GetProcessHeap(), 0, env_list.order,
242                                                env_list.alloc * sizeof(module_loadorder_t));
243         else
244             env_list.order = RtlAllocateHeap(GetProcessHeap(), 0,
245                                              env_list.alloc * sizeof(module_loadorder_t));
246         if(!env_list.order)
247         {
248             MESSAGE("Virtual memory exhausted\n");
249             exit(1);
250         }
251     }
252     memcpy(env_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
253     env_list.order[i].modulename = plo->modulename;
254     env_list.count++;
255 }
256
257
258 /***************************************************************************
259  *      add_load_order_set
260  *
261  * Adds a set of entries in the list of command-line overrides from the key parameter.
262  */
263 static void add_load_order_set( WCHAR *entry )
264 {
265     module_loadorder_t ldo;
266     WCHAR *end = strchrW( entry, '=' );
267
268     if (!end) return;
269     *end++ = 0;
270     parse_load_order( end, ldo.loadorder );
271
272     while (*entry)
273     {
274         entry += strspnW( entry, separatorsW );
275         end = entry + strcspnW( entry, separatorsW );
276         if (*end) *end++ = 0;
277         if (*entry)
278         {
279             WCHAR *ext = strrchrW(entry, '.');
280             if (ext) remove_dll_ext( ext );
281             ldo.modulename = entry;
282             add_load_order( &ldo );
283             entry = end;
284         }
285     }
286 }
287
288
289 /***************************************************************************
290  *      init_load_order
291  */
292 static void init_load_order(void)
293 {
294     const char *order = getenv( "WINEDLLOVERRIDES" );
295     UNICODE_STRING strW;
296     WCHAR *entry, *next;
297
298     init_done = 1;
299     if (!order) return;
300
301     if (!strcmp( order, "help" ))
302     {
303         MESSAGE( "Syntax:\n"
304                  "  WINEDLLOVERRIDES=\"entry;entry;entry...\"\n"
305                  "    where each entry is of the form:\n"
306                  "        module[,module...]={native|builtin}[,{b|n}]\n"
307                  "\n"
308                  "    Only the first letter of the override (native or builtin)\n"
309                  "    is significant.\n\n"
310                  "Example:\n"
311                  "  WINEDLLOVERRIDES=\"comdlg32=n,b;shell32,shlwapi=b\"\n" );
312         exit(0);
313     }
314
315     RtlCreateUnicodeStringFromAsciiz( &strW, order );
316     entry = strW.Buffer;
317     while (*entry)
318     {
319         while (*entry && *entry == ';') entry++;
320         if (!*entry) break;
321         next = strchrW( entry, ';' );
322         if (next) *next++ = 0;
323         else next = entry + strlenW(entry);
324         add_load_order_set( entry );
325         entry = next;
326     }
327
328     /* sort the array for quick lookup */
329     if (env_list.count)
330         qsort(env_list.order, env_list.count, sizeof(env_list.order[0]), cmp_sort_func);
331
332     /* Note: we don't free the Unicode string because the
333      * stored module names point inside it */
334 }
335
336
337 /***************************************************************************
338  *      get_env_load_order
339  *
340  * Get the load order for a given module from the WINEDLLOVERRIDES environment variable.
341  */
342 static inline BOOL get_env_load_order( const WCHAR *module, enum loadorder_type lo[] )
343 {
344     module_loadorder_t tmp, *res = NULL;
345
346     tmp.modulename = module;
347     /* some bsearch implementations (Solaris) are buggy when the number of items is 0 */
348     if (env_list.count &&
349         (res = bsearch(&tmp, env_list.order, env_list.count, sizeof(env_list.order[0]), cmp_sort_func)))
350         memcpy( lo, res->loadorder, sizeof(res->loadorder) );
351     return (res != NULL);
352 }
353
354
355 /***************************************************************************
356  *      get_default_load_order
357  *
358  * Get the load order for a given module from the default list.
359  */
360 static inline BOOL get_default_load_order( const WCHAR *module, enum loadorder_type lo[] )
361 {
362     const int count = sizeof(default_builtins) / sizeof(default_builtins[0]);
363     if (!bsearch( module, default_builtins, count, sizeof(default_builtins[0]), strcmp_func ))
364         return FALSE;
365     lo[0] = LOADORDER_BI;
366     lo[1] = LOADORDER_INVALID;
367     TRACE( "got compiled-in default %s for %s\n", debugstr_loadorder(lo), debugstr_w(module) );
368     return TRUE;
369 }
370
371
372 /***************************************************************************
373  *      get_standard_key
374  *
375  * Return a handle to the standard DllOverrides registry section.
376  */
377 static HANDLE get_standard_key(void)
378 {
379     static const WCHAR DllOverridesW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
380                                           'D','l','l','O','v','e','r','r','i','d','e','s',0};
381     static HANDLE std_key = (HANDLE)-1;
382
383     if (std_key == (HANDLE)-1)
384     {
385         OBJECT_ATTRIBUTES attr;
386         UNICODE_STRING nameW;
387         HANDLE root;
388
389         RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
390         attr.Length = sizeof(attr);
391         attr.RootDirectory = root;
392         attr.ObjectName = &nameW;
393         attr.Attributes = 0;
394         attr.SecurityDescriptor = NULL;
395         attr.SecurityQualityOfService = NULL;
396         RtlInitUnicodeString( &nameW, DllOverridesW );
397
398         /* @@ Wine registry key: HKCU\Software\Wine\DllOverrides */
399         if (NtOpenKey( &std_key, KEY_ALL_ACCESS, &attr )) std_key = 0;
400         NtClose( root );
401     }
402     return std_key;
403 }
404
405
406 /***************************************************************************
407  *      get_app_key
408  *
409  * Get the registry key for the app-specific DllOverrides list.
410  */
411 static HANDLE get_app_key( const WCHAR *app_name )
412 {
413     OBJECT_ATTRIBUTES attr;
414     UNICODE_STRING nameW;
415     HANDLE root;
416     WCHAR *str;
417     static const WCHAR AppDefaultsW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
418                                          'A','p','p','D','e','f','a','u','l','t','s','\\',0};
419     static const WCHAR DllOverridesW[] = {'\\','D','l','l','O','v','e','r','r','i','d','e','s',0};
420     static HANDLE app_key = (HANDLE)-1;
421
422     if (app_key != (HANDLE)-1) return app_key;
423
424     str = RtlAllocateHeap( GetProcessHeap(), 0,
425                            sizeof(AppDefaultsW) + sizeof(DllOverridesW) +
426                            strlenW(app_name) * sizeof(WCHAR) );
427     if (!str) return 0;
428     strcpyW( str, AppDefaultsW );
429     strcatW( str, app_name );
430     strcatW( str, DllOverridesW );
431
432     RtlOpenCurrentUser( KEY_ALL_ACCESS, &root );
433     attr.Length = sizeof(attr);
434     attr.RootDirectory = root;
435     attr.ObjectName = &nameW;
436     attr.Attributes = 0;
437     attr.SecurityDescriptor = NULL;
438     attr.SecurityQualityOfService = NULL;
439     RtlInitUnicodeString( &nameW, str );
440
441     /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DllOverrides */
442     if (NtOpenKey( &app_key, KEY_ALL_ACCESS, &attr )) app_key = 0;
443     NtClose( root );
444     RtlFreeHeap( GetProcessHeap(), 0, str );
445     return app_key;
446 }
447
448
449 /***************************************************************************
450  *      get_registry_value
451  *
452  * Load the registry loadorder value for a given module.
453  */
454 static BOOL get_registry_value( HANDLE hkey, const WCHAR *module, enum loadorder_type lo[] )
455 {
456     UNICODE_STRING valueW;
457     char buffer[80];
458     DWORD count;
459     BOOL ret;
460
461     RtlInitUnicodeString( &valueW, module );
462
463     if ((ret = !NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation,
464                                  buffer, sizeof(buffer), &count )))
465     {
466         int i, n = 0;
467         WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
468
469         while (*str)
470         {
471             enum loadorder_type type = LOADORDER_INVALID;
472
473             while (*str == ',' || isspaceW(*str)) str++;
474             if (!*str) break;
475
476             switch(tolowerW(*str))
477             {
478             case 'n': type = LOADORDER_DLL; break;
479             case 'b': type = LOADORDER_BI; break;
480             case 's': break;  /* no longer supported, ignore */
481             case 0:   break;  /* end of string */
482             default:
483                 ERR("Invalid load order module-type %s, ignored\n", debugstr_w(str));
484                 break;
485             }
486             if (type != LOADORDER_INVALID)
487             {
488                 for (i = 0; i < n; i++) if (lo[i] == type) break;  /* already specified */
489                 if (i == n) lo[n++] = type;
490             }
491             while (*str && *str != ',' && !isspaceW(*str)) str++;
492         }
493         lo[n] = LOADORDER_INVALID;
494     }
495     return ret;
496 }
497
498
499 /***************************************************************************
500  *      get_load_order_value
501  *
502  * Get the load order for the exact specified module string, looking in:
503  * 1. The WINEDLLOVERRIDES environment variable
504  * 2. The per-application DllOverrides key
505  * 3. The standard DllOverrides key
506  */
507 static BOOL get_load_order_value( HANDLE std_key, HANDLE app_key, const WCHAR *module,
508                                   enum loadorder_type loadorder[] )
509 {
510     if (get_env_load_order( module, loadorder ))
511     {
512         TRACE( "got environment %s for %s\n",
513                debugstr_loadorder(loadorder), debugstr_w(module) );
514         return TRUE;
515     }
516
517     if (app_key && get_registry_value( app_key, module, loadorder ))
518     {
519         TRACE( "got app defaults %s for %s\n",
520                debugstr_loadorder(loadorder), debugstr_w(module) );
521         return TRUE;
522     }
523
524     if (std_key && get_registry_value( std_key, module, loadorder ))
525     {
526         TRACE( "got standard key %s for %s\n",
527                debugstr_loadorder(loadorder), debugstr_w(module) );
528         return TRUE;
529     }
530     return FALSE;
531 }
532
533
534 /***************************************************************************
535  *      MODULE_GetLoadOrderW    (internal)
536  *
537  * Return the loadorder of a module.
538  * The system directory and '.dll' extension is stripped from the path.
539  */
540 void MODULE_GetLoadOrderW( enum loadorder_type loadorder[], const WCHAR *app_name,
541                           const WCHAR *path )
542 {
543     static const WCHAR wildcardW[] = {'*',0};
544
545     HANDLE std_key, app_key = 0;
546     WCHAR *module, *basename;
547     UNICODE_STRING path_str;
548     int len;
549
550     if (!init_done) init_load_order();
551     std_key = get_standard_key();
552     if (app_name) app_key = get_app_key( app_name );
553
554     TRACE("looking for %s\n", debugstr_w(path));
555
556     loadorder[0] = LOADORDER_INVALID;  /* in case something bad happens below */
557
558     /* Strip path information if the module resides in the system directory
559      */
560     RtlInitUnicodeString( &path_str, path );
561     if (RtlPrefixUnicodeString( &system_dir, &path_str, TRUE ))
562     {
563         const WCHAR *p = path + system_dir.Length / sizeof(WCHAR);
564         while (*p == '\\' || *p == '/') p++;
565         if (!strchrW( p, '\\' ) && !strchrW( p, '/' )) path = p;
566     }
567
568     if (!(len = strlenW(path))) return;
569     if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return;
570     strcpyW( module+1, path );  /* reserve module[0] for the wildcard char */
571     basename = (WCHAR *)get_basename( module+1 );
572
573     if (len >= 4) remove_dll_ext( module + 1 + len - 4 );
574
575     /* first explicit module name */
576     if (get_load_order_value( std_key, app_key, module+1, loadorder ))
577         goto done;
578
579     /* then module basename preceded by '*' */
580     basename[-1] = '*';
581     if (get_load_order_value( std_key, app_key, basename-1, loadorder ))
582         goto done;
583
584     /* then module basename without '*' (only if explicit path) */
585     if (basename != module+1 && get_load_order_value( std_key, app_key, basename, loadorder ))
586         goto done;
587
588     /* then compiled-in defaults */
589     if (get_default_load_order( basename, loadorder ))
590         goto done;
591
592     /* then wildcard entry (only if no explicit path) */
593     if (basename == module+1 && get_load_order_value( std_key, app_key, wildcardW, loadorder ))
594         goto done;
595
596     /* and last the hard-coded default */
597     memcpy( loadorder, default_loadorder, sizeof(default_loadorder) );
598     TRACE( "got hardcoded default %s for %s\n",
599            debugstr_loadorder(loadorder), debugstr_w(path) );
600
601  done:
602     RtlFreeHeap( GetProcessHeap(), 0, module );
603 }