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