Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[wine] / dlls / kernel / oldconfig.c
1 /*
2  * Support for converting from old configuration format
3  *
4  * Copyright 2005 Alexandre Julliard
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  * NOTES
21  *   This file should be removed after a suitable transition period.
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
33 #endif
34 #include <fcntl.h>
35 #include <dirent.h>
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_LINUX_HDREG_H
40 # include <linux/hdreg.h>
41 #endif
42
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winnls.h"
48 #include "winternl.h"
49 #include "winioctl.h"
50 #include "ntddscsi.h"
51 #include "wine/library.h"
52 #include "wine/server.h"
53 #include "wine/unicode.h"
54 #include "wine/debug.h"
55 #include "kernel_private.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(reg);
58
59
60 /* registry initialisation, allocates some default keys. */
61 static ULONG allocate_default_keys(void)
62 {
63     static const WCHAR StatDataW[] = {'D','y','n','D','a','t','a','\\',
64                                       'P','e','r','f','S','t','a','t','s','\\',
65                                       'S','t','a','t','D','a','t','a',0};
66     static const WCHAR ConfigManagerW[] = {'D','y','n','D','a','t','a','\\',
67                                            'C','o','n','f','i','g',' ','M','a','n','a','g','e','r','\\',
68                                             'E','n','u','m',0};
69     HANDLE hkey;
70     ULONG dispos;
71     OBJECT_ATTRIBUTES attr;
72     UNICODE_STRING nameW;
73
74     attr.Length = sizeof(attr);
75     attr.RootDirectory = 0;
76     attr.ObjectName = &nameW;
77     attr.Attributes = 0;
78     attr.SecurityDescriptor = NULL;
79     attr.SecurityQualityOfService = NULL;
80
81     RtlInitUnicodeString( &nameW, StatDataW );
82     if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, &dispos )) NtClose( hkey );
83     if (dispos == REG_OPENED_EXISTING_KEY)
84         return dispos; /* someone else already loaded the registry */
85
86     RtlInitUnicodeString( &nameW, ConfigManagerW );
87     if (!NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL )) NtClose( hkey );
88
89     return dispos;
90 }
91
92 /******************************************************************
93  *              create_scsi_entry
94  *
95  * Initializes registry to contain scsi info about the cdrom in NT.
96  * All devices (even not real scsi ones) have this info in NT.
97  * NOTE: programs usually read these registry entries after sending the
98  *       IOCTL_SCSI_GET_ADDRESS ioctl to the cdrom
99  */
100 static void create_scsi_entry( PSCSI_ADDRESS scsi_addr, LPSTR lpDriver, UINT uDriveType,
101     LPSTR lpDriveName, LPSTR lpUnixDeviceName )
102 {
103     static UCHAR uCdromNumber = 0;
104     static UCHAR uTapeNumber = 0;
105
106     OBJECT_ATTRIBUTES attr;
107     UNICODE_STRING nameW;
108     WCHAR dataW[50];
109     DWORD lenW;
110     char buffer[40];
111     DWORD value;
112     const char *data;
113     HANDLE scsiKey;
114     HANDLE portKey;
115     HANDLE busKey;
116     HANDLE targetKey;
117     HANDLE lunKey;
118     DWORD disp;
119
120     attr.Length = sizeof(attr);
121     attr.RootDirectory = 0;
122     attr.ObjectName = &nameW;
123     attr.Attributes = 0;
124     attr.SecurityDescriptor = NULL;
125     attr.SecurityQualityOfService = NULL;
126
127     /* Ensure there is Scsi key */
128     if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Machine\\HARDWARE\\DEVICEMAP\\Scsi" ) ||
129         NtCreateKey( &scsiKey, KEY_ALL_ACCESS, &attr, 0,
130                      NULL, REG_OPTION_VOLATILE, &disp ))
131     {
132         ERR("Cannot create DEVICEMAP\\Scsi registry key\n" );
133         return;
134     }
135     RtlFreeUnicodeString( &nameW );
136
137     snprintf(buffer,sizeof(buffer),"Scsi Port %d",scsi_addr->PortNumber);
138     attr.RootDirectory = scsiKey;
139     if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
140         NtCreateKey( &portKey, KEY_ALL_ACCESS, &attr, 0,
141                      NULL, REG_OPTION_VOLATILE, &disp ))
142     {
143         ERR("Cannot create DEVICEMAP\\Scsi Port registry key\n" );
144         return;
145     }
146     RtlFreeUnicodeString( &nameW );
147
148     RtlCreateUnicodeStringFromAsciiz( &nameW, "Driver" );
149     RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, lpDriver, strlen(lpDriver));
150     NtSetValueKey( portKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
151     RtlFreeUnicodeString( &nameW );
152     value = 10;
153     RtlCreateUnicodeStringFromAsciiz( &nameW, "FirstBusTimeScanInMs" );
154     NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
155     RtlFreeUnicodeString( &nameW );
156
157     value = 0;
158     if (strcmp(lpDriver, "atapi") == 0)
159     {
160 #ifdef HDIO_GET_DMA
161         int fd, dma;
162         
163         fd = open(lpUnixDeviceName, O_RDONLY|O_NONBLOCK);
164         if (fd)
165         {
166             if (ioctl(fd, HDIO_GET_DMA, &dma) != -1) value = dma;
167             close(fd);
168         }else
169             ERR("Can't open %s", buffer);
170 #endif
171         RtlCreateUnicodeStringFromAsciiz( &nameW, "DMAEnabled" );
172         NtSetValueKey( portKey,&nameW, 0, REG_DWORD, (BYTE *)&value, sizeof(DWORD));
173         RtlFreeUnicodeString( &nameW );
174     }
175
176     snprintf(buffer, sizeof(buffer),"Scsi Bus %d", scsi_addr->PathId);
177     attr.RootDirectory = portKey;
178     if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
179         NtCreateKey( &busKey, KEY_ALL_ACCESS, &attr, 0,
180                      NULL, REG_OPTION_VOLATILE, &disp ))
181     {
182         ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus registry key\n" );
183         return;
184     }
185     RtlFreeUnicodeString( &nameW );
186
187     attr.RootDirectory = busKey;
188     /* FIXME: get real controller Id for SCSI */
189     if (!RtlCreateUnicodeStringFromAsciiz( &nameW, "Initiator Id 255" ) ||
190         NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
191                      NULL, REG_OPTION_VOLATILE, &disp ))
192     {
193         ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus\\Initiator Id 255 registry key\n" );
194         return;
195     }
196     RtlFreeUnicodeString( &nameW );
197     NtClose( targetKey );
198
199     snprintf(buffer, sizeof(buffer),"Target Id %d", scsi_addr->TargetId);
200     attr.RootDirectory = busKey;
201     if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
202         NtCreateKey( &targetKey, KEY_ALL_ACCESS, &attr, 0,
203                      NULL, REG_OPTION_VOLATILE, &disp ))
204     {
205         ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\n" );
206         return;
207     }
208     RtlFreeUnicodeString( &nameW );
209
210     snprintf(buffer, sizeof(buffer),"Logical Unit Id %d", scsi_addr->Lun);
211     attr.RootDirectory = targetKey;
212     if (!RtlCreateUnicodeStringFromAsciiz( &nameW, buffer ) ||
213         NtCreateKey( &lunKey, KEY_ALL_ACCESS, &attr, 0,
214                      NULL, REG_OPTION_VOLATILE, &disp ))
215     {
216         ERR("Cannot create DEVICEMAP\\Scsi Port\\Scsi Bus 0\\Target Id registry key\\Logical Unit Id\n" );
217         return;
218     }
219     RtlFreeUnicodeString( &nameW );
220
221     switch (uDriveType)
222     {
223         case DRIVE_NO_ROOT_DIR:
224         default:
225             data = "OtherPeripheral"; break;
226         case DRIVE_FIXED:
227             data = "DiskPeripheral"; break;
228         case DRIVE_REMOVABLE:
229             data = "TapePeripheral";
230             snprintf(buffer, sizeof(buffer), "Tape%d", uTapeNumber++);
231             break;
232         case DRIVE_CDROM:
233             data = "CdRomPeripheral";
234             snprintf(buffer, sizeof(buffer), "Cdrom%d", uCdromNumber++);
235             break;
236     }
237     RtlCreateUnicodeStringFromAsciiz( &nameW, "Type" );
238     RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, data, strlen(data));
239     NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
240     RtlFreeUnicodeString( &nameW );
241
242     RtlCreateUnicodeStringFromAsciiz( &nameW, "Identifier" );
243     RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, lpDriveName, strlen(lpDriveName));
244     NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
245     RtlFreeUnicodeString( &nameW );
246
247     if (uDriveType == DRIVE_CDROM || uDriveType == DRIVE_REMOVABLE)
248     {
249         RtlCreateUnicodeStringFromAsciiz( &nameW, "DeviceName" );
250         RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, buffer, strlen(buffer));
251         NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
252         RtlFreeUnicodeString( &nameW );
253     }
254
255     RtlCreateUnicodeStringFromAsciiz( &nameW, "UnixDeviceName" );
256     RtlMultiByteToUnicodeN( dataW, sizeof(dataW), &lenW, lpUnixDeviceName, strlen(lpUnixDeviceName));
257     NtSetValueKey( lunKey, &nameW, 0, REG_SZ, (BYTE*)dataW, lenW );
258     RtlFreeUnicodeString( &nameW );
259
260     NtClose( lunKey );
261     NtClose( targetKey );
262     NtClose( busKey );
263     NtClose( portKey );
264     NtClose( scsiKey );
265 }
266
267 struct LinuxProcScsiDevice
268 {
269     int host;
270     int channel;
271     int target;
272     int lun;
273     char vendor[9];
274     char model[17];
275     char rev[5];
276     char type[33];
277     int ansirev;
278 };
279
280 /*
281  * we need to declare white spaces explicitly via %*1[ ],
282  * as there are very dainbread CD-ROM devices out there
283  * which have their manufacturer name blanked out via spaces,
284  * which confuses fscanf's parsing (skips all blank spaces)
285  */
286 static int SCSI_getprocentry( FILE * procfile, struct LinuxProcScsiDevice * dev )
287 {
288     int result;
289
290     result = fscanf( procfile,
291         "Host:%*1[ ]scsi%d%*1[ ]Channel:%*1[ ]%d%*1[ ]Id:%*1[ ]%d%*1[ ]Lun:%*1[ ]%d\n",
292         &dev->host,
293         &dev->channel,
294         &dev->target,
295         &dev->lun );
296     if( result == EOF )
297     {
298         /* "end of entries" return, so no TRACE() here */
299         return EOF;
300     }
301     if( result != 4 )
302     {
303         ERR("bus id line scan count error (fscanf returns %d, expected 4)\n", result);
304         return 0;
305     }
306     result = fscanf( procfile,
307         "  Vendor:%*1[ ]%8c%*1[ ]Model:%*1[ ]%16c%*1[ ]Rev:%*1[ ]%4c\n",
308         dev->vendor,
309         dev->model,
310         dev->rev );
311     if( result != 3 )
312     {
313         ERR("model line scan count error (fscanf returns %d, expected 3)\n", result);
314         return 0;
315     }
316
317     result = fscanf( procfile,
318         "  Type:%*3[ ]%32c%*1[ ]ANSI%*1[ ]SCSI%*1[ ]revision:%*1[ ]%x\n",
319         dev->type,
320         &dev->ansirev );
321     if( result != 2 )
322     {
323         ERR("SCSI type line scan count error (fscanf returns %d, expected 2)\n", result);
324         return 0;
325     }
326     /* Since we fscanf with %XXc instead of %s.. put a NULL at end */
327     dev->vendor[8] = 0;
328     dev->model[16] = 0;
329     dev->rev[4] = 0;
330     dev->type[32] = 0;
331
332     return 1;
333 }
334
335
336 /* create the hardware registry branch */
337 static void create_hardware_branch(void)
338 {
339     /* The following mostly will work on Linux, but should not cause
340      * problems on other systems. */
341     static const char procname_ide_media[] = "/proc/ide/%s/media";
342     static const char procname_ide_model[] = "/proc/ide/%s/model";
343     static const char procname_scsi[] = "/proc/scsi/scsi";
344     DIR *idedir;
345     struct dirent *dent = NULL;
346     FILE *procfile = NULL;
347     char cStr[40], cDevModel[40], cUnixDeviceName[40], read1[10] = "\0", read2[10] = "\0";
348     SCSI_ADDRESS scsi_addr;
349     UINT nType;
350     struct LinuxProcScsiDevice dev;
351     int result = 0, nSgNumber = 0;
352     UCHAR uFirstSCSIPort = 0;
353
354     /* Enumerate all ide devices first */
355     idedir = opendir("/proc/ide");
356     if (idedir)
357     {
358         while ((dent = readdir(idedir)))
359         {
360             if (strncmp(dent->d_name, "hd", 2) == 0)
361             {
362                 sprintf(cStr, procname_ide_media, dent->d_name);
363                 procfile = fopen(cStr, "r");
364                 if (!procfile)
365                 {
366                     ERR("Could not open %s\n", cStr);
367                     continue;
368                 } else {
369                     fgets(cStr, sizeof(cStr), procfile);
370                     fclose(procfile);
371                     nType = DRIVE_UNKNOWN;
372                     if (strncasecmp(cStr, "disk", 4)  == 0) nType = DRIVE_FIXED;
373                     if (strncasecmp(cStr, "cdrom", 5) == 0) nType = DRIVE_CDROM;
374
375                     if (nType == DRIVE_UNKNOWN) continue;
376                 }
377
378                 sprintf(cStr, procname_ide_model, dent->d_name);
379                 procfile = fopen(cStr, "r");
380                 if (!procfile)
381                 {
382                     ERR("Could not open %s\n", cStr);
383                     switch (nType)
384                     {
385                     case DRIVE_FIXED: strcpy(cDevModel, "Wine harddisk"); break;
386                     case DRIVE_CDROM: strcpy(cDevModel, "Wine CDROM"); break;
387                     }
388                 } else {
389                     fgets(cDevModel, sizeof(cDevModel), procfile);
390                     fclose(procfile);
391                     cDevModel[strlen(cDevModel) - 1] = 0;
392                 }
393
394                 sprintf(cUnixDeviceName, "/dev/%s", dent->d_name);
395                 scsi_addr.PortNumber = (dent->d_name[2] - 'a') / 2;
396                 scsi_addr.PathId = 0;
397                 scsi_addr.TargetId = (dent->d_name[2] - 'a') % 2;
398                 scsi_addr.Lun = 0;
399                 if (scsi_addr.PortNumber + 1 > uFirstSCSIPort)
400                     uFirstSCSIPort = scsi_addr.PortNumber + 1;
401
402                 create_scsi_entry(&scsi_addr, "atapi", nType, cDevModel, cUnixDeviceName);
403             }
404         }
405         closedir(idedir);
406     }
407
408     /* Now goes SCSI */
409     procfile = fopen(procname_scsi, "r");
410     if (!procfile)
411     {
412         TRACE("Could not open %s\n", procname_scsi);
413         return;
414     }
415     fgets(cStr, 40, procfile);
416     sscanf(cStr, "Attached %9s %9s", read1, read2);
417
418     if (strcmp(read1, "devices:") != 0)
419     {
420         WARN("Incorrect %s format\n", procname_scsi);
421         fclose( procfile );
422         return;
423     }
424     if (strcmp(read2, "none") == 0)
425     {
426         TRACE("No SCSI devices found in %s.\n", procname_scsi);
427         fclose( procfile );
428         return;
429     }
430
431     /* Read info for one device */
432     while ((result = SCSI_getprocentry(procfile, &dev)) > 0)
433     {
434         scsi_addr.PortNumber = dev.host;
435         scsi_addr.PathId = dev.channel;
436         scsi_addr.TargetId = dev.target;
437         scsi_addr.Lun = dev.lun;
438
439         scsi_addr.PortNumber += uFirstSCSIPort;
440         if (strncmp(dev.type, "Direct-Access", 13) == 0) nType = DRIVE_FIXED;
441         else if (strncmp(dev.type, "Sequential-Access", 17) == 0) nType = DRIVE_REMOVABLE;
442         else if (strncmp(dev.type, "CD-ROM", 6) == 0) nType = DRIVE_CDROM;
443         else if (strncmp(dev.type, "Processor", 9) == 0) nType = DRIVE_NO_ROOT_DIR;
444         else continue;
445
446         strcpy(cDevModel, dev.vendor);
447         strcat(cDevModel, dev.model);
448         strcat(cDevModel, dev.rev);
449         sprintf(cUnixDeviceName, "/dev/sg%d", nSgNumber++);
450         /* FIXME: get real driver name */
451         create_scsi_entry(&scsi_addr, "WINE SCSI", nType, cDevModel, cUnixDeviceName);
452     }
453     if( result != EOF )
454         WARN("Incorrect %s format\n", procname_scsi);
455     fclose( procfile );
456 }
457
458
459 /***********************************************************************
460  *              convert_old_config
461  */
462 void convert_old_config(void)
463 {
464     if (allocate_default_keys() == REG_OPENED_EXISTING_KEY)
465         return; /* someone else already loaded the registry */
466
467     /* create some hardware keys (FIXME: should not be done here) */
468     create_hardware_branch();
469 }