Fixed buffer overflow.
[wine] / dlls / setupapi / dirid.c
1 /*
2  * Directory id handling
3  *
4  * Copyright 2002 Alexandre Julliard for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winreg.h"
26 #include "winternl.h"
27 #include "winerror.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "setupapi.h"
32 #include "wine/unicode.h"
33 #include "setupapi_private.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
37
38 #define MAX_SYSTEM_DIRID DIRID_PRINTPROCESSOR
39
40 struct user_dirid
41 {
42     int    id;
43     WCHAR *str;
44 };
45
46 static int nb_user_dirids;     /* number of user dirids in use */
47 static int alloc_user_dirids;  /* number of allocated user dirids */
48 static struct user_dirid *user_dirids;
49 static const WCHAR *system_dirids[MAX_SYSTEM_DIRID+1];
50
51 /* retrieve the string for unknown dirids */
52 static const WCHAR *get_unknown_dirid(void)
53 {
54     static WCHAR *unknown_dirid;
55     static const WCHAR unknown_str[] = {'\\','u','n','k','n','o','w','n',0};
56
57     if (!unknown_dirid)
58     {
59         UINT len = GetSystemDirectoryW( NULL, 0 ) + strlenW(unknown_str);
60         if (!(unknown_dirid = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
61         GetSystemDirectoryW( unknown_dirid, len );
62         strcatW( unknown_dirid, unknown_str );
63     }
64     return unknown_dirid;
65 }
66
67 /* create the string for a system dirid */
68 static const WCHAR *create_system_dirid( int dirid )
69 {
70     static const WCHAR Null[]    = {0};
71     static const WCHAR C_Root[]  = {'C',':','\\',0};
72     static const WCHAR Drivers[] = {'\\','d','r','i','v','e','r','s',0};
73     static const WCHAR Inf[]     = {'\\','i','n','f',0};
74     static const WCHAR Help[]    = {'\\','h','e','l','p',0};
75     static const WCHAR Fonts[]   = {'\\','f','o','n','t','s',0};
76     static const WCHAR Viewers[] = {'\\','v','i','e','w','e','r','s',0};
77     static const WCHAR System[]  = {'\\','s','y','s','t','e','m',0};
78     static const WCHAR Spool[]   = {'\\','s','p','o','o','l',0};
79
80     WCHAR buffer[MAX_PATH+16], *str;
81     int len;
82
83     switch(dirid)
84     {
85     case DIRID_NULL:
86         return Null;
87     case DIRID_WINDOWS:
88         GetWindowsDirectoryW( buffer, MAX_PATH );
89         break;
90     case DIRID_SYSTEM:
91         GetSystemDirectoryW( buffer, MAX_PATH );
92         break;
93     case DIRID_DRIVERS:
94         GetSystemDirectoryW( buffer, MAX_PATH );
95         strcatW( buffer, Drivers );
96         break;
97     case DIRID_INF:
98         GetWindowsDirectoryW( buffer, MAX_PATH );
99         strcatW( buffer, Inf );
100         break;
101     case DIRID_HELP:
102         GetWindowsDirectoryW( buffer, MAX_PATH );
103         strcatW( buffer, Help );
104         break;
105     case DIRID_FONTS:
106         GetWindowsDirectoryW( buffer, MAX_PATH );
107         strcatW( buffer, Fonts );
108         break;
109     case DIRID_VIEWERS:
110         GetSystemDirectoryW( buffer, MAX_PATH );
111         strcatW( buffer, Viewers );
112         break;
113     case DIRID_APPS:
114         return C_Root;  /* FIXME */
115     case DIRID_SHARED:
116         GetWindowsDirectoryW( buffer, MAX_PATH );
117         break;
118     case DIRID_BOOT:
119         return C_Root;  /* FIXME */
120     case DIRID_SYSTEM16:
121         GetWindowsDirectoryW( buffer, MAX_PATH );
122         strcatW( buffer, System );
123         break;
124     case DIRID_SPOOL:
125     case DIRID_SPOOLDRIVERS:  /* FIXME */
126         GetWindowsDirectoryW( buffer, MAX_PATH );
127         strcatW( buffer, Spool );
128         break;
129     case DIRID_LOADER:
130         return C_Root;  /* FIXME */
131     case DIRID_USERPROFILE:  /* FIXME */
132     case DIRID_COLOR:  /* FIXME */
133     case DIRID_PRINTPROCESSOR:  /* FIXME */
134     default:
135         FIXME( "unknown dirid %d\n", dirid );
136         return get_unknown_dirid();
137     }
138     len = (strlenW(buffer) + 1) * sizeof(WCHAR);
139     if ((str = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( str, buffer, len );
140     return str;
141 }
142
143 /* retrieve the string corresponding to a dirid, or NULL if none */
144 const WCHAR *DIRID_get_string( HINF hinf, int dirid )
145 {
146     int i;
147
148     if (dirid == DIRID_ABSOLUTE || dirid == DIRID_ABSOLUTE_16BIT) dirid = DIRID_NULL;
149
150     if (dirid >= DIRID_USER)
151     {
152         for (i = 0; i < nb_user_dirids; i++)
153             if (user_dirids[i].id == dirid) return user_dirids[i].str;
154         ERR("user id %d not found\n", dirid );
155         return NULL;
156     }
157     else
158     {
159         if (dirid > MAX_SYSTEM_DIRID) return get_unknown_dirid();
160         if (dirid == DIRID_SRCPATH) return PARSER_get_src_root( hinf );
161         if (!system_dirids[dirid]) system_dirids[dirid] = create_system_dirid( dirid );
162         return system_dirids[dirid];
163     }
164 }
165
166 /* store a user dirid string */
167 static BOOL store_user_dirid( HINF hinf, int id, WCHAR *str )
168 {
169     int i;
170
171     for (i = 0; i < nb_user_dirids; i++) if (user_dirids[i].id == id) break;
172
173     if (i < nb_user_dirids) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
174     else
175     {
176         if (nb_user_dirids >= alloc_user_dirids)
177         {
178             int new_size = max( 32, alloc_user_dirids * 2 );
179
180             struct user_dirid *new;
181
182             if (user_dirids)
183                 new = HeapReAlloc( GetProcessHeap(), 0, user_dirids,
184                                                   new_size * sizeof(*new) );
185             else
186                 new = HeapAlloc( GetProcessHeap(), 0, 
187                                                   new_size * sizeof(*new) );
188
189             if (!new) return FALSE;
190             user_dirids = new;
191             alloc_user_dirids = new_size;
192         }
193         nb_user_dirids++;
194     }
195     user_dirids[i].id  = id;
196     user_dirids[i].str = str;
197     TRACE("id %d -> %s\n", id, debugstr_w(str) );
198     return TRUE;
199 }
200
201
202 /***********************************************************************
203  *              SetupSetDirectoryIdA    (SETUPAPI.@)
204  */
205 BOOL WINAPI SetupSetDirectoryIdA( HINF hinf, DWORD id, PCSTR dir )
206 {
207     UNICODE_STRING dirW;
208     int i;
209
210     if (!id)  /* clear everything */
211     {
212         for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
213         nb_user_dirids = 0;
214         return TRUE;
215     }
216     if (id < DIRID_USER)
217     {
218         SetLastError( ERROR_INVALID_PARAMETER );
219         return FALSE;
220     }
221
222     /* duplicate the string */
223     if (!RtlCreateUnicodeStringFromAsciiz( &dirW, dir ))
224     {
225         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
226         return FALSE;
227     }
228     return store_user_dirid( hinf, id, dirW.Buffer );
229 }
230
231
232 /***********************************************************************
233  *              SetupSetDirectoryIdW    (SETUPAPI.@)
234  */
235 BOOL WINAPI SetupSetDirectoryIdW( HINF hinf, DWORD id, PCWSTR dir )
236 {
237     int i, len;
238     WCHAR *str;
239
240     if (!id)  /* clear everything */
241     {
242         for (i = 0; i < nb_user_dirids; i++) HeapFree( GetProcessHeap(), 0, user_dirids[i].str );
243         nb_user_dirids = 0;
244         return TRUE;
245     }
246     if (id < DIRID_USER)
247     {
248         SetLastError( ERROR_INVALID_PARAMETER );
249         return FALSE;
250     }
251
252     /* duplicate the string */
253     len = (strlenW(dir)+1) * sizeof(WCHAR);
254     if (!(str = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
255     memcpy( str, dir, len );
256     return store_user_dirid( hinf, id, str );
257 }