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