wined3d: Whitelist pixelformats instead of blacklisting.
[wine] / dlls / setupapi / queue.c
1 /*
2  * Setupapi file queue routines
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "winver.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(setupapi);
38
39 /* context structure for the default queue callback */
40 struct default_callback_context
41 {
42     HWND owner;
43     HWND progress;
44     UINT message;
45 };
46
47 struct file_op
48 {
49     struct file_op *next;
50     UINT            style;
51     WCHAR          *src_root;
52     WCHAR          *src_path;
53     WCHAR          *src_file;
54     WCHAR          *src_descr;
55     WCHAR          *src_tag;
56     WCHAR          *dst_path;
57     WCHAR          *dst_file;
58 };
59
60 struct file_op_queue
61 {
62     struct file_op *head;
63     struct file_op *tail;
64     unsigned int count;
65 };
66
67 struct file_queue
68 {
69     struct file_op_queue copy_queue;
70     struct file_op_queue delete_queue;
71     struct file_op_queue rename_queue;
72     DWORD                flags;
73 };
74
75
76 inline static WCHAR *strdupW( const WCHAR *str )
77 {
78     WCHAR *ret = NULL;
79     if (str)
80     {
81         int len = (strlenW(str) + 1) * sizeof(WCHAR);
82         if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, str, len );
83     }
84     return ret;
85 }
86
87
88 inline static WCHAR *strdupAtoW( const char *str )
89 {
90     WCHAR *ret = NULL;
91     if (str)
92     {
93         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
94         if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
95             MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
96     }
97     return ret;
98 }
99
100 inline static char *strdupWtoA( const WCHAR *str )
101 {
102     char *ret = NULL;
103     if (str)
104     {
105         DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
106         if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
107             WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
108     }
109     return ret;
110 }
111
112 /* append a file operation to a queue */
113 inline static void queue_file_op( struct file_op_queue *queue, struct file_op *op )
114 {
115     op->next = NULL;
116     if (queue->tail) queue->tail->next = op;
117     else queue->head = op;
118     queue->tail = op;
119     queue->count++;
120 }
121
122 /* free all the file operations on a given queue */
123 static void free_file_op_queue( struct file_op_queue *queue )
124 {
125     struct file_op *t, *op = queue->head;
126
127     while( op )
128     {
129         HeapFree( GetProcessHeap(), 0, op->src_root );
130         HeapFree( GetProcessHeap(), 0, op->src_path );
131         HeapFree( GetProcessHeap(), 0, op->src_file );
132         HeapFree( GetProcessHeap(), 0, op->src_descr );
133         HeapFree( GetProcessHeap(), 0, op->src_tag );
134         HeapFree( GetProcessHeap(), 0, op->dst_path );
135         if (op->dst_file != op->src_file) HeapFree( GetProcessHeap(), 0, op->dst_file );
136         t = op;
137         op = op->next;
138         HeapFree( GetProcessHeap(), 0, t );
139     }
140 }
141
142 /* concat 3 strings to make a path, handling separators correctly */
143 static void concat_W( WCHAR *buffer, const WCHAR *src1, const WCHAR *src2, const WCHAR *src3 )
144 {
145     *buffer = 0;
146     if (src1 && *src1)
147     {
148         strcpyW( buffer, src1 );
149         buffer += strlenW(buffer );
150         if (buffer[-1] != '\\') *buffer++ = '\\';
151         if (src2) while (*src2 == '\\') src2++;
152     }
153
154     if (src2)
155     {
156         strcpyW( buffer, src2 );
157         buffer += strlenW(buffer );
158         if (buffer[-1] != '\\') *buffer++ = '\\';
159         if (src3) while (*src3 == '\\') src3++;
160     }
161     if (src3)
162     {
163         strcpyW( buffer, src3 );
164         buffer += strlenW(buffer );
165     }
166 }
167
168
169 /***********************************************************************
170  *            build_filepathsW
171  *
172  * Build a FILEPATHS_W structure for a given file operation.
173  */
174 static BOOL build_filepathsW( const struct file_op *op, FILEPATHS_W *paths )
175 {
176     unsigned int src_len = 1, dst_len = 1;
177     WCHAR *source = (PWSTR)paths->Source, *target = (PWSTR)paths->Target;
178
179     if (op->src_root) src_len += strlenW(op->src_root) + 1;
180     if (op->src_path) src_len += strlenW(op->src_path) + 1;
181     if (op->src_file) src_len += strlenW(op->src_file) + 1;
182     if (op->dst_path) dst_len += strlenW(op->dst_path) + 1;
183     if (op->dst_file) dst_len += strlenW(op->dst_file) + 1;
184     src_len *= sizeof(WCHAR);
185     dst_len *= sizeof(WCHAR);
186
187     if (!source || HeapSize( GetProcessHeap(), 0, source ) < src_len )
188     {
189         HeapFree( GetProcessHeap(), 0, source );
190         paths->Source = source = HeapAlloc( GetProcessHeap(), 0, src_len );
191     }
192     if (!target || HeapSize( GetProcessHeap(), 0, target ) < dst_len )
193     {
194         HeapFree( GetProcessHeap(), 0, target );
195         paths->Target = target = HeapAlloc( GetProcessHeap(), 0, dst_len );
196     }
197     if (!source || !target) return FALSE;
198     concat_W( source, op->src_root, op->src_path, op->src_file );
199     concat_W( target, NULL, op->dst_path, op->dst_file );
200     paths->Win32Error = 0;
201     paths->Flags      = 0;
202     return TRUE;
203 }
204
205
206 /***********************************************************************
207  *            QUEUE_callback_WtoA
208  *
209  * Map a file callback parameters from W to A and call the A callback.
210  */
211 UINT CALLBACK QUEUE_callback_WtoA( void *context, UINT notification,
212                                    UINT_PTR param1, UINT_PTR param2 )
213 {
214     struct callback_WtoA_context *callback_ctx = context;
215     char buffer[MAX_PATH];
216     UINT ret;
217     UINT_PTR old_param2 = param2;
218
219     switch(notification)
220     {
221     case SPFILENOTIFY_COPYERROR:
222         param2 = (UINT_PTR)&buffer;
223         /* fall through */
224     case SPFILENOTIFY_STARTDELETE:
225     case SPFILENOTIFY_ENDDELETE:
226     case SPFILENOTIFY_DELETEERROR:
227     case SPFILENOTIFY_STARTRENAME:
228     case SPFILENOTIFY_ENDRENAME:
229     case SPFILENOTIFY_RENAMEERROR:
230     case SPFILENOTIFY_STARTCOPY:
231     case SPFILENOTIFY_ENDCOPY:
232         {
233             FILEPATHS_W *pathsW = (FILEPATHS_W *)param1;
234             FILEPATHS_A pathsA;
235
236             pathsA.Source     = strdupWtoA( pathsW->Source );
237             pathsA.Target     = strdupWtoA( pathsW->Target );
238             pathsA.Win32Error = pathsW->Win32Error;
239             pathsA.Flags      = pathsW->Flags;
240             ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
241                                               (UINT_PTR)&pathsA, param2 );
242             HeapFree( GetProcessHeap(), 0, (void *)pathsA.Source );
243             HeapFree( GetProcessHeap(), 0, (void *)pathsA.Target );
244         }
245         if (notification == SPFILENOTIFY_COPYERROR)
246             MultiByteToWideChar( CP_ACP, 0, buffer, -1, (WCHAR *)old_param2, MAX_PATH );
247         break;
248
249     case SPFILENOTIFY_STARTREGISTRATION:
250     case SPFILENOTIFY_ENDREGISTRATION:
251         {
252             SP_REGISTER_CONTROL_STATUSW *statusW = (SP_REGISTER_CONTROL_STATUSW *)param1;
253             SP_REGISTER_CONTROL_STATUSA statusA;
254
255             statusA.cbSize = sizeof(statusA);
256             statusA.FileName = strdupWtoA( statusW->FileName );
257             statusA.Win32Error  = statusW->Win32Error;
258             statusA.FailureCode = statusW->FailureCode;
259             ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification,
260                                               (UINT_PTR)&statusA, param2 );
261             HeapFree( GetProcessHeap(), 0, (LPSTR)statusA.FileName );
262         }
263         break;
264
265     case SPFILENOTIFY_NEEDMEDIA:
266     case SPFILENOTIFY_QUEUESCAN:
267         FIXME("mapping for %d not implemented\n",notification);
268     case SPFILENOTIFY_STARTQUEUE:
269     case SPFILENOTIFY_ENDQUEUE:
270     case SPFILENOTIFY_STARTSUBQUEUE:
271     case SPFILENOTIFY_ENDSUBQUEUE:
272     default:
273         ret = callback_ctx->orig_handler( callback_ctx->orig_context, notification, param1, param2 );
274         break;
275     }
276     return ret;
277 }
278
279
280 /***********************************************************************
281  *            get_src_file_info
282  *
283  * Retrieve the source file information for a given file.
284  */
285 static void get_src_file_info( HINF hinf, struct file_op *op )
286 {
287     static const WCHAR SourceDisksNames[] =
288         {'S','o','u','r','c','e','D','i','s','k','s','N','a','m','e','s',0};
289     static const WCHAR SourceDisksFiles[] =
290         {'S','o','u','r','c','e','D','i','s','k','s','F','i','l','e','s',0};
291
292     INFCONTEXT file_ctx, disk_ctx;
293     INT id, diskid;
294     DWORD len, len2;
295
296     /* find the SourceDisksFiles entry */
297     if (!SetupFindFirstLineW( hinf, SourceDisksFiles, op->src_file, &file_ctx ))
298     {
299         if ((op->style & (SP_COPY_SOURCE_ABSOLUTE|SP_COPY_SOURCEPATH_ABSOLUTE))) return;
300         /* no specific info, use .inf file source directory */
301         if (!op->src_root) op->src_root = PARSER_get_src_root( hinf );
302         return;
303     }
304     if (!SetupGetIntField( &file_ctx, 1, &diskid )) return;
305
306     /* now find the diskid in the SourceDisksNames section */
307     if (!SetupFindFirstLineW( hinf, SourceDisksNames, NULL, &disk_ctx )) return;
308     for (;;)
309     {
310         if (SetupGetIntField( &disk_ctx, 0, &id ) && (id == diskid)) break;
311         if (!SetupFindNextLine( &disk_ctx, &disk_ctx )) return;
312     }
313
314     /* and fill in the missing info */
315
316     if (!op->src_descr)
317     {
318         if (SetupGetStringFieldW( &disk_ctx, 1, NULL, 0, &len ) &&
319             (op->src_descr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
320             SetupGetStringFieldW( &disk_ctx, 1, op->src_descr, len, NULL );
321     }
322     if (!op->src_tag)
323     {
324         if (SetupGetStringFieldW( &disk_ctx, 2, NULL, 0, &len ) &&
325             (op->src_tag = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) )))
326             SetupGetStringFieldW( &disk_ctx, 2, op->src_tag, len, NULL );
327     }
328     if (!op->src_path && !(op->style & SP_COPY_SOURCE_ABSOLUTE))
329     {
330         if (!(op->style & SP_COPY_SOURCEPATH_ABSOLUTE))
331         {
332             /* retrieve relative path for this disk */
333             if (!SetupGetStringFieldW( &disk_ctx, 4, NULL, 0, &len )) len = 0;
334         }
335         /* retrieve relative path for this file */
336         if (!SetupGetStringFieldW( &file_ctx, 2, NULL, 0, &len2 )) len2 = 0;
337
338         if ((len || len2) &&
339             (op->src_path = HeapAlloc( GetProcessHeap(), 0, (len+len2)*sizeof(WCHAR) )))
340         {
341             WCHAR *ptr = op->src_path;
342             if (len)
343             {
344                 SetupGetStringFieldW( &disk_ctx, 4, op->src_path, len, NULL );
345                 ptr = op->src_path + strlenW(op->src_path);
346                 if (len2 && ptr > op->src_path && ptr[-1] != '\\') *ptr++ = '\\';
347             }
348             if (!SetupGetStringFieldW( &disk_ctx, 4, ptr, len2, NULL )) *ptr = 0;
349         }
350     }
351     if (!op->src_root) op->src_root = PARSER_get_src_root(hinf);
352 }
353
354
355 /***********************************************************************
356  *            get_destination_dir
357  *
358  * Retrieve the destination dir for a given section.
359  */
360 static WCHAR *get_destination_dir( HINF hinf, const WCHAR *section )
361 {
362     static const WCHAR Dest[] = {'D','e','s','t','i','n','a','t','i','o','n','D','i','r','s',0};
363     static const WCHAR Def[]  = {'D','e','f','a','u','l','t','D','e','s','t','D','i','r',0};
364     INFCONTEXT context;
365
366     if (!SetupFindFirstLineW( hinf, Dest, section, &context ) &&
367         !SetupFindFirstLineW( hinf, Dest, Def, &context )) return NULL;
368     return PARSER_get_dest_dir( &context );
369 }
370
371
372 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
373
374 /***********************************************************************
375  *            extract_cabinet_file
376  *
377  * Extract a file from a .cab file.
378  */
379 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
380                                   const WCHAR *src, const WCHAR *dst )
381 {
382     static const WCHAR extW[] = {'.','c','a','b',0};
383     static HMODULE advpack;
384
385     char *cab_path, *cab_file;
386     int len = strlenW( cabinet );
387
388     /* make sure the cabinet file has a .cab extension */
389     if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
390     if (!pExtractFiles)
391     {
392         if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
393         {
394             ERR( "could not load advpack.dll\n" );
395             return FALSE;
396         }
397         if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
398         {
399             ERR( "could not find ExtractFiles in advpack.dll\n" );
400             return FALSE;
401         }
402     }
403
404     if (!(cab_path = strdupWtoA( root ))) return FALSE;
405     len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
406     if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
407     {
408         HeapFree( GetProcessHeap(), 0, cab_path );
409         return FALSE;
410     }
411     strcpy( cab_file, cab_path );
412     if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
413     WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
414     FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
415     pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
416     HeapFree( GetProcessHeap(), 0, cab_file );
417     HeapFree( GetProcessHeap(), 0, cab_path );
418     return CopyFileW( src, dst, FALSE /*FIXME*/ );
419 }
420
421
422 /***********************************************************************
423  *            SetupOpenFileQueue   (SETUPAPI.@)
424  */
425 HSPFILEQ WINAPI SetupOpenFileQueue(void)
426 {
427     struct file_queue *queue;
428
429     if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
430         return (HSPFILEQ)INVALID_HANDLE_VALUE;
431     return queue;
432 }
433
434
435 /***********************************************************************
436  *            SetupCloseFileQueue   (SETUPAPI.@)
437  */
438 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
439 {
440     struct file_queue *queue = handle;
441
442     free_file_op_queue( &queue->copy_queue );
443     free_file_op_queue( &queue->rename_queue );
444     free_file_op_queue( &queue->delete_queue );
445     HeapFree( GetProcessHeap(), 0, queue );
446     return TRUE;
447 }
448
449
450 /***********************************************************************
451  *            SetupQueueCopyIndirectA   (SETUPAPI.@)
452  */
453 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
454 {
455     struct file_queue *queue = params->QueueHandle;
456     struct file_op *op;
457
458     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
459     op->style      = params->CopyStyle;
460     op->src_root   = strdupAtoW( params->SourceRootPath );
461     op->src_path   = strdupAtoW( params->SourcePath );
462     op->src_file   = strdupAtoW( params->SourceFilename );
463     op->src_descr  = strdupAtoW( params->SourceDescription );
464     op->src_tag    = strdupAtoW( params->SourceTagfile );
465     op->dst_path   = strdupAtoW( params->TargetDirectory );
466     op->dst_file   = strdupAtoW( params->TargetFilename );
467
468     /* some defaults */
469     if (!op->src_file) op->src_file = op->dst_file;
470     if (params->LayoutInf)
471     {
472         get_src_file_info( params->LayoutInf, op );
473         if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
474     }
475
476     TRACE( "root=%s path=%s file=%s -> dir=%s file=%s  descr=%s tag=%s\n",
477            debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
478            debugstr_w(op->dst_path), debugstr_w(op->dst_file),
479            debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
480
481     queue_file_op( &queue->copy_queue, op );
482     return TRUE;
483 }
484
485
486 /***********************************************************************
487  *            SetupQueueCopyIndirectW   (SETUPAPI.@)
488  */
489 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
490 {
491     struct file_queue *queue = params->QueueHandle;
492     struct file_op *op;
493
494     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
495     op->style      = params->CopyStyle;
496     op->src_root   = strdupW( params->SourceRootPath );
497     op->src_path   = strdupW( params->SourcePath );
498     op->src_file   = strdupW( params->SourceFilename );
499     op->src_descr  = strdupW( params->SourceDescription );
500     op->src_tag    = strdupW( params->SourceTagfile );
501     op->dst_path   = strdupW( params->TargetDirectory );
502     op->dst_file   = strdupW( params->TargetFilename );
503
504     /* some defaults */
505     if (!op->src_file) op->src_file = op->dst_file;
506     if (params->LayoutInf)
507     {
508         get_src_file_info( params->LayoutInf, op );
509         if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
510     }
511
512     TRACE( "root=%s path=%s file=%s -> dir=%s file=%s  descr=%s tag=%s\n",
513            debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
514            debugstr_w(op->dst_path), debugstr_w(op->dst_file),
515            debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
516
517     queue_file_op( &queue->copy_queue, op );
518     return TRUE;
519 }
520
521
522 /***********************************************************************
523  *            SetupQueueCopyA   (SETUPAPI.@)
524  */
525 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
526                              PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
527                              DWORD style )
528 {
529     SP_FILE_COPY_PARAMS_A params;
530
531     params.cbSize             = sizeof(params);
532     params.QueueHandle        = queue;
533     params.SourceRootPath     = src_root;
534     params.SourcePath         = src_path;
535     params.SourceFilename     = src_file;
536     params.SourceDescription  = src_descr;
537     params.SourceTagfile      = src_tag;
538     params.TargetDirectory    = dst_dir;
539     params.TargetFilename     = dst_file;
540     params.CopyStyle          = style;
541     params.LayoutInf          = 0;
542     params.SecurityDescriptor = NULL;
543     return SetupQueueCopyIndirectA( &params );
544 }
545
546
547 /***********************************************************************
548  *            SetupQueueCopyW   (SETUPAPI.@)
549  */
550 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
551                              PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
552                              DWORD style )
553 {
554     SP_FILE_COPY_PARAMS_W params;
555
556     params.cbSize             = sizeof(params);
557     params.QueueHandle        = queue;
558     params.SourceRootPath     = src_root;
559     params.SourcePath         = src_path;
560     params.SourceFilename     = src_file;
561     params.SourceDescription  = src_descr;
562     params.SourceTagfile      = src_tag;
563     params.TargetDirectory    = dst_dir;
564     params.TargetFilename     = dst_file;
565     params.CopyStyle          = style;
566     params.LayoutInf          = 0;
567     params.SecurityDescriptor = NULL;
568     return SetupQueueCopyIndirectW( &params );
569 }
570
571
572 /***********************************************************************
573  *            SetupQueueDefaultCopyA   (SETUPAPI.@)
574  */
575 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
576                                     PCSTR dst_file, DWORD style )
577 {
578     SP_FILE_COPY_PARAMS_A params;
579
580     params.cbSize             = sizeof(params);
581     params.QueueHandle        = queue;
582     params.SourceRootPath     = src_root;
583     params.SourcePath         = NULL;
584     params.SourceFilename     = src_file;
585     params.SourceDescription  = NULL;
586     params.SourceTagfile      = NULL;
587     params.TargetDirectory    = NULL;
588     params.TargetFilename     = dst_file;
589     params.CopyStyle          = style;
590     params.LayoutInf          = hinf;
591     params.SecurityDescriptor = NULL;
592     return SetupQueueCopyIndirectA( &params );
593 }
594
595
596 /***********************************************************************
597  *            SetupQueueDefaultCopyW   (SETUPAPI.@)
598  */
599 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
600                                     PCWSTR dst_file, DWORD style )
601 {
602     SP_FILE_COPY_PARAMS_W params;
603
604     params.cbSize             = sizeof(params);
605     params.QueueHandle        = queue;
606     params.SourceRootPath     = src_root;
607     params.SourcePath         = NULL;
608     params.SourceFilename     = src_file;
609     params.SourceDescription  = NULL;
610     params.SourceTagfile      = NULL;
611     params.TargetDirectory    = NULL;
612     params.TargetFilename     = dst_file;
613     params.CopyStyle          = style;
614     params.LayoutInf          = hinf;
615     params.SecurityDescriptor = NULL;
616     return SetupQueueCopyIndirectW( &params );
617 }
618
619
620 /***********************************************************************
621  *            SetupQueueDeleteA   (SETUPAPI.@)
622  */
623 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
624 {
625     struct file_queue *queue = handle;
626     struct file_op *op;
627
628     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
629     op->style      = 0;
630     op->src_root   = NULL;
631     op->src_path   = NULL;
632     op->src_file   = NULL;
633     op->src_descr  = NULL;
634     op->src_tag    = NULL;
635     op->dst_path   = strdupAtoW( part1 );
636     op->dst_file   = strdupAtoW( part2 );
637     queue_file_op( &queue->delete_queue, op );
638     return TRUE;
639 }
640
641
642 /***********************************************************************
643  *            SetupQueueDeleteW   (SETUPAPI.@)
644  */
645 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
646 {
647     struct file_queue *queue = handle;
648     struct file_op *op;
649
650     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
651     op->style      = 0;
652     op->src_root   = NULL;
653     op->src_path   = NULL;
654     op->src_file   = NULL;
655     op->src_descr  = NULL;
656     op->src_tag    = NULL;
657     op->dst_path   = strdupW( part1 );
658     op->dst_file   = strdupW( part2 );
659     queue_file_op( &queue->delete_queue, op );
660     return TRUE;
661 }
662
663
664 /***********************************************************************
665  *            SetupQueueRenameA   (SETUPAPI.@)
666  */
667 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
668                                PCSTR TargetPath, PCSTR TargetFilename )
669 {
670     struct file_queue *queue = handle;
671     struct file_op *op;
672
673     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
674     op->style      = 0;
675     op->src_root   = NULL;
676     op->src_path   = strdupAtoW( SourcePath );
677     op->src_file   = strdupAtoW( SourceFilename );
678     op->src_descr  = NULL;
679     op->src_tag    = NULL;
680     op->dst_path   = strdupAtoW( TargetPath );
681     op->dst_file   = strdupAtoW( TargetFilename );
682     queue_file_op( &queue->rename_queue, op );
683     return TRUE;
684 }
685
686
687 /***********************************************************************
688  *            SetupQueueRenameW   (SETUPAPI.@)
689  */
690 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
691                                PCWSTR TargetPath, PCWSTR TargetFilename )
692 {
693     struct file_queue *queue = handle;
694     struct file_op *op;
695
696     if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
697     op->style      = 0;
698     op->src_root   = NULL;
699     op->src_path   = strdupW( SourcePath );
700     op->src_file   = strdupW( SourceFilename );
701     op->src_descr  = NULL;
702     op->src_tag    = NULL;
703     op->dst_path   = strdupW( TargetPath );
704     op->dst_file   = strdupW( TargetFilename );
705     queue_file_op( &queue->rename_queue, op );
706     return TRUE;
707 }
708
709
710 /***********************************************************************
711  *            SetupQueueCopySectionA   (SETUPAPI.@)
712  */
713 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
714                                     PCSTR section, DWORD style )
715 {
716     UNICODE_STRING sectionW;
717     BOOL ret = FALSE;
718
719     if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
720     {
721         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
722         return FALSE;
723     }
724     if (!src_root)
725         ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
726     else
727     {
728         UNICODE_STRING srcW;
729         if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
730         {
731             ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
732             RtlFreeUnicodeString( &srcW );
733         }
734         else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
735     }
736     RtlFreeUnicodeString( &sectionW );
737     return ret;
738 }
739
740
741 /***********************************************************************
742  *            SetupQueueCopySectionW   (SETUPAPI.@)
743  */
744 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
745                                     PCWSTR section, DWORD style )
746 {
747     SP_FILE_COPY_PARAMS_W params;
748     INFCONTEXT context;
749     WCHAR dest[MAX_PATH], src[MAX_PATH];
750     INT flags;
751
752     TRACE( "hinf=%p/%p section=%s root=%s\n",
753            hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
754
755     params.cbSize             = sizeof(params);
756     params.QueueHandle        = queue;
757     params.SourceRootPath     = src_root;
758     params.SourcePath         = NULL;
759     params.SourceDescription  = NULL;
760     params.SourceTagfile      = NULL;
761     params.TargetFilename     = dest;
762     params.CopyStyle          = style;
763     params.LayoutInf          = hinf;
764     params.SecurityDescriptor = NULL;
765
766     if (!hlist) hlist = hinf;
767     if (!hinf) hinf = hlist;
768     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
769     if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) return FALSE;
770     do
771     {
772         if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
773             return FALSE;
774         if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
775         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;  /* FIXME */
776
777         params.SourceFilename = *src ? src : NULL;
778         if (!SetupQueueCopyIndirectW( &params )) return FALSE;
779     } while (SetupFindNextLine( &context, &context ));
780     return TRUE;
781 }
782
783
784 /***********************************************************************
785  *            SetupQueueDeleteSectionA   (SETUPAPI.@)
786  */
787 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
788 {
789     UNICODE_STRING sectionW;
790     BOOL ret = FALSE;
791
792     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
793     {
794         ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
795         RtlFreeUnicodeString( &sectionW );
796     }
797     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
798     return ret;
799 }
800
801
802 /***********************************************************************
803  *            SetupQueueDeleteSectionW   (SETUPAPI.@)
804  */
805 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
806 {
807     INFCONTEXT context;
808     WCHAR *dest_dir;
809     WCHAR buffer[MAX_PATH];
810     BOOL ret = FALSE;
811     INT flags;
812
813     TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
814
815     if (!hlist) hlist = hinf;
816     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
817     if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
818     do
819     {
820         if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
821             goto done;
822         if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
823         if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
824     } while (SetupFindNextLine( &context, &context ));
825
826     ret = TRUE;
827  done:
828     HeapFree( GetProcessHeap(), 0, dest_dir );
829     return ret;
830 }
831
832
833 /***********************************************************************
834  *            SetupQueueRenameSectionA   (SETUPAPI.@)
835  */
836 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
837 {
838     UNICODE_STRING sectionW;
839     BOOL ret = FALSE;
840
841     if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
842     {
843         ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
844         RtlFreeUnicodeString( &sectionW );
845     }
846     else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
847     return ret;
848 }
849
850
851 /***********************************************************************
852  *            SetupQueueRenameSectionW   (SETUPAPI.@)
853  */
854 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
855 {
856     INFCONTEXT context;
857     WCHAR *dest_dir;
858     WCHAR src[MAX_PATH], dst[MAX_PATH];
859     BOOL ret = FALSE;
860
861     TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
862
863     if (!hlist) hlist = hinf;
864     if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
865     if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
866     do
867     {
868         if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
869             goto done;
870         if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
871             goto done;
872         if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
873     } while (SetupFindNextLine( &context, &context ));
874
875     ret = TRUE;
876  done:
877     HeapFree( GetProcessHeap(), 0, dest_dir );
878     return ret;
879 }
880
881
882 /***********************************************************************
883  *            SetupCommitFileQueueA   (SETUPAPI.@)
884  */
885 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
886                                    PVOID context )
887 {
888     struct callback_WtoA_context ctx;
889
890     ctx.orig_context = context;
891     ctx.orig_handler = handler;
892     return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
893 }
894
895
896 /***********************************************************************
897  *            create_full_pathW
898  *
899  * Recursively create all directories in the path.
900  */
901 static BOOL create_full_pathW(const WCHAR *path)
902 {
903     BOOL ret = TRUE;
904     int len;
905     WCHAR *new_path;
906
907     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
908     strcpyW(new_path, path);
909
910     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
911         new_path[len - 1] = 0;
912
913     while(!CreateDirectoryW(new_path, NULL))
914     {
915         WCHAR *slash;
916         DWORD last_error = GetLastError();
917
918         if(last_error == ERROR_ALREADY_EXISTS)
919             break;
920
921         if(last_error != ERROR_PATH_NOT_FOUND)
922         {
923             ret = FALSE;
924             break;
925         }
926
927         if(!(slash = strrchrW(new_path, '\\')))
928         {
929             ret = FALSE;
930             break;
931         }
932
933         len = slash - new_path;
934         new_path[len] = 0;
935         if(!create_full_pathW(new_path))
936         {
937             ret = FALSE;
938             break;
939         }
940         new_path[len] = '\\';
941     }
942
943     HeapFree(GetProcessHeap(), 0, new_path);
944     return ret;
945 }
946
947 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style)
948 {
949     BOOL rc = FALSE;
950     BOOL docopy = TRUE;
951
952     TRACE("copy %s to %s style 0x%lx\n",debugstr_w(source),debugstr_w(target),style);
953
954     /* before copy processing */
955     if (style & SP_COPY_REPLACEONLY)
956     {
957         if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
958             docopy = FALSE;
959     }
960     if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
961     {
962         DWORD VersionSizeSource=0;
963         DWORD VersionSizeTarget=0;
964         DWORD zero=0;
965
966         /*
967          * This is sort of an interesting workaround. You see, calling
968          * GetVersionInfoSize on a builtin dll loads that dll into memory
969          * and we do not properly unload builtin dlls.. so we effectively
970          * lock into memory all the targets we are replacing. This leads
971          * to problems when we try to register the replaced dlls.
972          *
973          * So I will test for the existence of the files first so that
974          * we just basically unconditionally replace the builtin versions.
975          */
976         if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
977             (GetFileAttributesW(source) != INVALID_FILE_ATTRIBUTES))
978         {
979             VersionSizeSource = GetFileVersionInfoSizeW(source,&zero);
980             VersionSizeTarget = GetFileVersionInfoSizeW(target,&zero);
981         }
982
983         TRACE("SizeTarget %li ... SizeSource %li\n",VersionSizeTarget,
984                 VersionSizeSource);
985
986         if (VersionSizeSource && VersionSizeTarget)
987         {
988             LPVOID VersionSource;
989             LPVOID VersionTarget;
990             VS_FIXEDFILEINFO *TargetInfo;
991             VS_FIXEDFILEINFO *SourceInfo;
992             UINT length;
993             WCHAR  SubBlock[2]={'\\',0};
994             DWORD  ret;
995
996             VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
997             VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
998
999             ret = GetFileVersionInfoW(source,0,VersionSizeSource,VersionSource);
1000             if (ret)
1001               ret = GetFileVersionInfoW(target, 0, VersionSizeTarget,
1002                     VersionTarget);
1003
1004             if (ret)
1005             {
1006                 ret = VerQueryValueW(VersionSource, SubBlock,
1007                                     (LPVOID*)&SourceInfo, &length);
1008                 if (ret)
1009                     ret = VerQueryValueW(VersionTarget, SubBlock,
1010                                          (LPVOID*)&TargetInfo, &length);
1011
1012                 if (ret)
1013                 {
1014                     TRACE("Versions: Source %li.%li target %li.%li\n",
1015                       SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1016                       TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1017
1018                     if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1019                     {
1020                         FIXME("Notify that target version is greater..\n");
1021                         docopy = FALSE;
1022                     }
1023                     else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1024                              && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1025                     {
1026                         FIXME("Notify that target version is greater..\n");
1027                         docopy = FALSE;
1028                     }
1029                     else if ((style & SP_COPY_NEWER_ONLY) &&
1030                         (TargetInfo->dwFileVersionMS ==
1031                          SourceInfo->dwFileVersionMS)
1032                         &&(TargetInfo->dwFileVersionLS ==
1033                         SourceInfo->dwFileVersionLS))
1034                     {
1035                         FIXME("Notify that target version is greater..\n");
1036                         docopy = FALSE;
1037                     }
1038                 }
1039             }
1040             HeapFree(GetProcessHeap(),0,VersionSource);
1041             HeapFree(GetProcessHeap(),0,VersionTarget);
1042         }
1043     }
1044     if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1045     {
1046         if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1047         {
1048             FIXME("Notify user target file exists\n");
1049             docopy = FALSE;
1050         }
1051     }
1052     if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1053                  SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1054     {
1055         ERR("Unsupported style(s) 0x%lx\n",style);
1056     }
1057
1058     if (docopy)
1059     {
1060         rc = CopyFileW(source,target,FALSE);
1061         TRACE("Did copy... rc was %i\n",rc);
1062     }
1063
1064     /* after copy processing */
1065     if (style & SP_COPY_DELETESOURCE)
1066     {
1067        if (rc)
1068             DeleteFileW(source);
1069     }
1070
1071     return rc;
1072 }
1073
1074 /***********************************************************************
1075  *            SetupCommitFileQueueW   (SETUPAPI.@)
1076  */
1077 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1078                                    PVOID context )
1079 {
1080     struct file_queue *queue = handle;
1081     struct file_op *op;
1082     BOOL result = FALSE;
1083     FILEPATHS_W paths;
1084     UINT op_result;
1085
1086     paths.Source = paths.Target = NULL;
1087
1088     if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1089         return TRUE;  /* nothing to do */
1090
1091     if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1092
1093     /* perform deletes */
1094
1095     if (queue->delete_queue.count)
1096     {
1097         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1098                        queue->delete_queue.count ))) goto done;
1099         for (op = queue->delete_queue.head; op; op = op->next)
1100         {
1101             build_filepathsW( op, &paths );
1102             op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1103             if (op_result == FILEOP_ABORT) goto done;
1104             while (op_result == FILEOP_DOIT)
1105             {
1106                 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1107                 if (DeleteFileW( paths.Target )) break;  /* success */
1108                 paths.Win32Error = GetLastError();
1109                 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1110                 if (op_result == FILEOP_ABORT) goto done;
1111             }
1112             handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1113         }
1114         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1115     }
1116
1117     /* perform renames */
1118
1119     if (queue->rename_queue.count)
1120     {
1121         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1122                        queue->rename_queue.count ))) goto done;
1123         for (op = queue->rename_queue.head; op; op = op->next)
1124         {
1125             build_filepathsW( op, &paths );
1126             op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1127             if (op_result == FILEOP_ABORT) goto done;
1128             while (op_result == FILEOP_DOIT)
1129             {
1130                 TRACE( "renaming file %s -> %s\n",
1131                        debugstr_w(paths.Source), debugstr_w(paths.Target) );
1132                 if (MoveFileW( paths.Source, paths.Target )) break;  /* success */
1133                 paths.Win32Error = GetLastError();
1134                 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1135                 if (op_result == FILEOP_ABORT) goto done;
1136             }
1137             handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1138         }
1139         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1140     }
1141
1142     /* perform copies */
1143
1144     if (queue->copy_queue.count)
1145     {
1146         if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1147                        queue->copy_queue.count ))) goto done;
1148         for (op = queue->copy_queue.head; op; op = op->next)
1149         {
1150             WCHAR newpath[MAX_PATH];
1151
1152             build_filepathsW( op, &paths );
1153             op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1154             if (op_result == FILEOP_ABORT) goto done;
1155             if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1156             while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1157             {
1158                 TRACE( "copying file %s -> %s\n",
1159                        debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1160                        debugstr_w(paths.Target) );
1161                 if (op->dst_path)
1162                 {
1163                     if (!create_full_pathW( op->dst_path ))
1164                     {
1165                         paths.Win32Error = GetLastError();
1166                         op_result = handler( context, SPFILENOTIFY_COPYERROR,
1167                                              (UINT_PTR)&paths, (UINT_PTR)newpath );
1168                         if (op_result == FILEOP_ABORT) goto done;
1169                     }
1170                 }
1171                 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1172                                paths.Target, op->style )) break;  /* success */
1173                 /* try to extract it from the cabinet file */
1174                 if (op->src_tag)
1175                 {
1176                     if (extract_cabinet_file( op->src_tag, op->src_root,
1177                                               paths.Source, paths.Target )) break;
1178                 }
1179                 paths.Win32Error = GetLastError();
1180                 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1181                                      (UINT_PTR)&paths, (UINT_PTR)newpath );
1182                 if (op_result == FILEOP_ABORT) goto done;
1183             }
1184             handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1185         }
1186         handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1187     }
1188
1189
1190     result = TRUE;
1191
1192  done:
1193     handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1194     HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1195     HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1196     return result;
1197 }
1198
1199
1200 /***********************************************************************
1201  *            SetupScanFileQueueA   (SETUPAPI.@)
1202  */
1203 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ queue, DWORD flags, HWND window,
1204                                  PSP_FILE_CALLBACK_A callback, PVOID context, PDWORD result )
1205 {
1206     FIXME("stub\n");
1207     return FALSE;
1208 }
1209
1210
1211 /***********************************************************************
1212  *            SetupScanFileQueueW   (SETUPAPI.@)
1213  */
1214 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ queue, DWORD flags, HWND window,
1215                                  PSP_FILE_CALLBACK_W callback, PVOID context, PDWORD result )
1216 {
1217     FIXME("stub\n");
1218     return FALSE;
1219 }
1220
1221
1222 /***********************************************************************
1223  *            SetupGetFileQueueCount   (SETUPAPI.@)
1224  */
1225 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1226 {
1227     struct file_queue *queue = handle;
1228
1229     switch(op)
1230     {
1231     case FILEOP_COPY:
1232         *result = queue->copy_queue.count;
1233         return TRUE;
1234     case FILEOP_RENAME:
1235         *result = queue->rename_queue.count;
1236         return TRUE;
1237     case FILEOP_DELETE:
1238         *result = queue->delete_queue.count;
1239         return TRUE;
1240     }
1241     return FALSE;
1242 }
1243
1244
1245 /***********************************************************************
1246  *            SetupGetFileQueueFlags   (SETUPAPI.@)
1247  */
1248 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1249 {
1250     struct file_queue *queue = handle;
1251     *flags = queue->flags;
1252     return TRUE;
1253 }
1254
1255
1256 /***********************************************************************
1257  *            SetupSetFileQueueFlags   (SETUPAPI.@)
1258  */
1259 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1260 {
1261     struct file_queue *queue = handle;
1262     queue->flags = (queue->flags & ~mask) | flags;
1263     return TRUE;
1264 }
1265
1266
1267 /***********************************************************************
1268  *   SetupSetFileQueueAlternatePlatformA  (SETUPAPI.@)
1269  */
1270 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1271 {
1272     FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1273     return FALSE;
1274 }
1275
1276
1277 /***********************************************************************
1278  *   SetupSetFileQueueAlternatePlatformW  (SETUPAPI.@)
1279  */
1280 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1281 {
1282     FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1283     return FALSE;
1284 }
1285
1286
1287 /***********************************************************************
1288  *            SetupInitDefaultQueueCallback   (SETUPAPI.@)
1289  */
1290 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1291 {
1292     return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1293 }
1294
1295
1296 /***********************************************************************
1297  *            SetupInitDefaultQueueCallbackEx   (SETUPAPI.@)
1298  */
1299 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1300                                               DWORD reserved1, PVOID reserved2 )
1301 {
1302     struct default_callback_context *context;
1303
1304     if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1305     {
1306         context->owner    = owner;
1307         context->progress = progress;
1308         context->message  = msg;
1309     }
1310     return context;
1311 }
1312
1313
1314 /***********************************************************************
1315  *            SetupTermDefaultQueueCallback   (SETUPAPI.@)
1316  */
1317 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1318 {
1319     HeapFree( GetProcessHeap(), 0, context );
1320 }
1321
1322
1323 /***********************************************************************
1324  *            SetupDefaultQueueCallbackA   (SETUPAPI.@)
1325  */
1326 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1327                                         UINT_PTR param1, UINT_PTR param2 )
1328 {
1329     FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1330     struct default_callback_context *ctx = (struct default_callback_context *)context;
1331
1332     switch(notification)
1333     {
1334     case SPFILENOTIFY_STARTQUEUE:
1335         TRACE( "start queue\n" );
1336         return TRUE;
1337     case SPFILENOTIFY_ENDQUEUE:
1338         TRACE( "end queue\n" );
1339         return 0;
1340     case SPFILENOTIFY_STARTSUBQUEUE:
1341         TRACE( "start subqueue %d count %d\n", param1, param2 );
1342         return TRUE;
1343     case SPFILENOTIFY_ENDSUBQUEUE:
1344         TRACE( "end subqueue %d\n", param1 );
1345         return 0;
1346     case SPFILENOTIFY_STARTDELETE:
1347         TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1348         return FILEOP_DOIT;
1349     case SPFILENOTIFY_ENDDELETE:
1350         TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1351         return 0;
1352     case SPFILENOTIFY_DELETEERROR:
1353         /*Windows Ignores attempts to delete files / folders which do not exist*/
1354         if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1355         SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1356         return FILEOP_SKIP;
1357     case SPFILENOTIFY_STARTRENAME:
1358         TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1359         return FILEOP_DOIT;
1360     case SPFILENOTIFY_ENDRENAME:
1361         TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1362         return 0;
1363     case SPFILENOTIFY_RENAMEERROR:
1364         SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1365         return FILEOP_SKIP;
1366     case SPFILENOTIFY_STARTCOPY:
1367         TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1368         return FILEOP_DOIT;
1369     case SPFILENOTIFY_ENDCOPY:
1370         TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1371         return 0;
1372     case SPFILENOTIFY_COPYERROR:
1373         ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1374              debugstr_a(paths->Source), debugstr_a(paths->Target) );
1375         return FILEOP_SKIP;
1376     case SPFILENOTIFY_NEEDMEDIA:
1377         TRACE( "need media\n" );
1378         return FILEOP_SKIP;
1379     default:
1380         FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1381         break;
1382     }
1383     return 0;
1384 }
1385
1386
1387 /***********************************************************************
1388  *            SetupDefaultQueueCallbackW   (SETUPAPI.@)
1389  */
1390 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1391                                         UINT_PTR param1, UINT_PTR param2 )
1392 {
1393     FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1394     struct default_callback_context *ctx = (struct default_callback_context *)context;
1395
1396     switch(notification)
1397     {
1398     case SPFILENOTIFY_STARTQUEUE:
1399         TRACE( "start queue\n" );
1400         return TRUE;
1401     case SPFILENOTIFY_ENDQUEUE:
1402         TRACE( "end queue\n" );
1403         return 0;
1404     case SPFILENOTIFY_STARTSUBQUEUE:
1405         TRACE( "start subqueue %d count %d\n", param1, param2 );
1406         return TRUE;
1407     case SPFILENOTIFY_ENDSUBQUEUE:
1408         TRACE( "end subqueue %d\n", param1 );
1409         return 0;
1410     case SPFILENOTIFY_STARTDELETE:
1411         TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1412         return FILEOP_DOIT;
1413     case SPFILENOTIFY_ENDDELETE:
1414         TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1415         return 0;
1416     case SPFILENOTIFY_DELETEERROR:
1417         /*Windows Ignores attempts to delete files / folders which do not exist*/
1418         if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1419             SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1420         return FILEOP_SKIP;
1421     case SPFILENOTIFY_STARTRENAME:
1422         SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1423         return FILEOP_DOIT;
1424     case SPFILENOTIFY_ENDRENAME:
1425         TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1426         return 0;
1427     case SPFILENOTIFY_RENAMEERROR:
1428         ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1429              debugstr_w(paths->Source), debugstr_w(paths->Target) );
1430         return FILEOP_SKIP;
1431     case SPFILENOTIFY_STARTCOPY:
1432         TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1433         return FILEOP_DOIT;
1434     case SPFILENOTIFY_ENDCOPY:
1435         TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1436         return 0;
1437     case SPFILENOTIFY_COPYERROR:
1438         ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1439              debugstr_w(paths->Source), debugstr_w(paths->Target) );
1440         return FILEOP_SKIP;
1441     case SPFILENOTIFY_NEEDMEDIA:
1442         TRACE( "need media\n" );
1443         return FILEOP_SKIP;
1444     default:
1445         FIXME( "notification %d params %x,%x\n", notification, param1, param2 );
1446         break;
1447     }
1448     return 0;
1449 }
1450
1451 /***********************************************************************
1452  *            SetupDeleteErrorA   (SETUPAPI.@)
1453  */
1454
1455 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1456                                UINT w32error, DWORD style)
1457 {
1458     FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1459            w32error, debugstr_a(file) );
1460     return DPROMPT_SKIPFILE;
1461 }
1462
1463 /***********************************************************************
1464  *            SetupDeleteErrorW   (SETUPAPI.@)
1465  */
1466
1467 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1468                                UINT w32error, DWORD style)
1469 {
1470     FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1471            w32error, debugstr_w(file) );
1472     return DPROMPT_SKIPFILE;
1473 }
1474
1475 /***********************************************************************
1476  *            SetupRenameErrorA   (SETUPAPI.@)
1477  */
1478
1479 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1480                                PCSTR target, UINT w32error, DWORD style)
1481 {
1482     FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1483            w32error, debugstr_a(source), debugstr_a(target));
1484     return DPROMPT_SKIPFILE;
1485 }
1486
1487 /***********************************************************************
1488  *            SetupRenameErrorW   (SETUPAPI.@)
1489  */
1490
1491 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1492                                PCWSTR target, UINT w32error, DWORD style)
1493 {
1494     FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1495            w32error, debugstr_w(source), debugstr_w(target));
1496     return DPROMPT_SKIPFILE;
1497 }
1498
1499
1500 /***********************************************************************
1501  *            SetupCopyErrorA   (SETUPAPI.@)
1502  */
1503
1504 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname, 
1505                              PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1506                              UINT w32error, DWORD style, PSTR pathbuffer, 
1507                              DWORD buffersize, PDWORD requiredsize)
1508 {
1509     FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1510            w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1511     return DPROMPT_SKIPFILE;
1512 }
1513
1514 /***********************************************************************
1515  *            SetupCopyErrorW   (SETUPAPI.@)
1516  */
1517
1518 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname, 
1519                              PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1520                              UINT w32error, DWORD style, PWSTR pathbuffer, 
1521                              DWORD buffersize, PDWORD requiredsize)
1522 {
1523     FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1524            w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1525     return DPROMPT_SKIPFILE;
1526 }