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