[SETUPAPI] - Add missing error checks in do_file_copyW. Patch by Carlo Bramini. CORE...
[reactos.git] / reactos / dll / win32 / 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 "setupapi_private.h"
22
23 #include <aclapi.h>
24
25 /* Unicode constants */
26 static const WCHAR DotSecurity[] = {'.','S','e','c','u','r','i','t','y',0};
27
28 /* context structure for the default queue callback */
29 struct default_callback_context
30 {
31 HWND owner;
32 HWND progress;
33 UINT message;
34 };
35
36 struct 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
50 struct file_op_queue
51 {
52 struct file_op *head;
53 struct file_op *tail;
54 unsigned int count;
55 };
56
57 struct 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
66 static 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
77 static 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 */
90 static 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 */
100 static 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 */
121 static 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 */
150 static 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 */
187 UINT 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 */
272 static 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 */
353 static 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
364
365 static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
366
367 /***********************************************************************
368 * extract_cabinet_file
369 *
370 * Extract a file from a .cab file.
371 */
372 static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root,
373 const WCHAR *src, const WCHAR *dst )
374 {
375 static const WCHAR extW[] = {'.','c','a','b',0};
376 static HMODULE advpack;
377
378 char *cab_path, *cab_file;
379 int len = strlenW( cabinet );
380
381 /* make sure the cabinet file has a .cab extension */
382 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
383 if (!pExtractFiles)
384 {
385 if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
386 {
387 ERR( "could not load advpack.dll\n" );
388 return FALSE;
389 }
390 if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles" )))
391 {
392 ERR( "could not find ExtractFiles in advpack.dll\n" );
393 return FALSE;
394 }
395 }
396
397 if (!(cab_path = strdupWtoA( root ))) return FALSE;
398 len = WideCharToMultiByte( CP_ACP, 0, cabinet, -1, NULL, 0, NULL, NULL );
399 if (!(cab_file = HeapAlloc( GetProcessHeap(), 0, strlen(cab_path) + len + 1 )))
400 {
401 HeapFree( GetProcessHeap(), 0, cab_path );
402 return FALSE;
403 }
404 strcpy( cab_file, cab_path );
405 if (cab_file[0] && cab_file[strlen(cab_file)-1] != '\\') strcat( cab_file, "\\" );
406 WideCharToMultiByte( CP_ACP, 0, cabinet, -1, cab_file + strlen(cab_file), len, NULL, NULL );
407 FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
408 pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
409 HeapFree( GetProcessHeap(), 0, cab_file );
410 HeapFree( GetProcessHeap(), 0, cab_path );
411 return CopyFileW( src, dst, FALSE /*FIXME*/ );
412 }
413
414
415 /***********************************************************************
416 * SetupOpenFileQueue (SETUPAPI.@)
417 */
418 HSPFILEQ WINAPI SetupOpenFileQueue(void)
419 {
420 struct file_queue *queue;
421
422 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue))))
423 return INVALID_HANDLE_VALUE;
424 return queue;
425 }
426
427
428 /***********************************************************************
429 * SetupCloseFileQueue (SETUPAPI.@)
430 */
431 BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle )
432 {
433 struct file_queue *queue = handle;
434
435 free_file_op_queue( &queue->copy_queue );
436 free_file_op_queue( &queue->rename_queue );
437 free_file_op_queue( &queue->delete_queue );
438 HeapFree( GetProcessHeap(), 0, queue );
439 return TRUE;
440 }
441
442
443 /***********************************************************************
444 * SetupQueueCopyIndirectA (SETUPAPI.@)
445 */
446 BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params )
447 {
448 struct file_queue *queue = params->QueueHandle;
449 struct file_op *op;
450
451 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
452 op->style = params->CopyStyle;
453 op->src_root = strdupAtoW( params->SourceRootPath );
454 op->src_path = strdupAtoW( params->SourcePath );
455 op->src_file = strdupAtoW( params->SourceFilename );
456 op->src_descr = strdupAtoW( params->SourceDescription );
457 op->src_tag = strdupAtoW( params->SourceTagfile );
458 op->dst_path = strdupAtoW( params->TargetDirectory );
459 op->dst_file = strdupAtoW( params->TargetFilename );
460 op->dst_sd = NULL;
461
462 /* some defaults */
463 if (!op->src_file) op->src_file = op->dst_file;
464 if (params->LayoutInf)
465 {
466 get_src_file_info( params->LayoutInf, op );
467 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
468 }
469
470 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
471 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
472 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
473 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
474
475 queue_file_op( &queue->copy_queue, op );
476 return TRUE;
477 }
478
479
480 /***********************************************************************
481 * SetupQueueCopyIndirectW (SETUPAPI.@)
482 */
483 BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params )
484 {
485 struct file_queue *queue = params->QueueHandle;
486 struct file_op *op;
487
488 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
489 op->style = params->CopyStyle;
490 op->src_root = strdupW( params->SourceRootPath );
491 op->src_path = strdupW( params->SourcePath );
492 op->src_file = strdupW( params->SourceFilename );
493 op->src_descr = strdupW( params->SourceDescription );
494 op->src_tag = strdupW( params->SourceTagfile );
495 op->dst_path = strdupW( params->TargetDirectory );
496 op->dst_file = strdupW( params->TargetFilename );
497 op->dst_sd = NULL;
498 if (params->SecurityDescriptor)
499 ConvertStringSecurityDescriptorToSecurityDescriptorW( params->SecurityDescriptor, SDDL_REVISION_1, &op->dst_sd, NULL );
500
501 /* some defaults */
502 if (!op->src_file) op->src_file = op->dst_file;
503 if (params->LayoutInf)
504 {
505 get_src_file_info( params->LayoutInf, op );
506 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file );
507 }
508
509 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n",
510 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file),
511 debugstr_w(op->dst_path), debugstr_w(op->dst_file),
512 debugstr_w(op->src_descr), debugstr_w(op->src_tag) );
513
514 queue_file_op( &queue->copy_queue, op );
515 return TRUE;
516 }
517
518
519 /***********************************************************************
520 * SetupQueueCopyA (SETUPAPI.@)
521 */
522 BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file,
523 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file,
524 DWORD style )
525 {
526 SP_FILE_COPY_PARAMS_A params;
527
528 params.cbSize = sizeof(params);
529 params.QueueHandle = queue;
530 params.SourceRootPath = src_root;
531 params.SourcePath = src_path;
532 params.SourceFilename = src_file;
533 params.SourceDescription = src_descr;
534 params.SourceTagfile = src_tag;
535 params.TargetDirectory = dst_dir;
536 params.TargetFilename = dst_file;
537 params.CopyStyle = style;
538 params.LayoutInf = 0;
539 params.SecurityDescriptor = NULL;
540 return SetupQueueCopyIndirectA( &params );
541 }
542
543
544 /***********************************************************************
545 * SetupQueueCopyW (SETUPAPI.@)
546 */
547 BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file,
548 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file,
549 DWORD style )
550 {
551 SP_FILE_COPY_PARAMS_W params;
552
553 params.cbSize = sizeof(params);
554 params.QueueHandle = queue;
555 params.SourceRootPath = src_root;
556 params.SourcePath = src_path;
557 params.SourceFilename = src_file;
558 params.SourceDescription = src_descr;
559 params.SourceTagfile = src_tag;
560 params.TargetDirectory = dst_dir;
561 params.TargetFilename = dst_file;
562 params.CopyStyle = style;
563 params.LayoutInf = 0;
564 params.SecurityDescriptor = NULL;
565 return SetupQueueCopyIndirectW( &params );
566 }
567
568
569 /***********************************************************************
570 * SetupQueueDefaultCopyA (SETUPAPI.@)
571 */
572 BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file,
573 PCSTR dst_file, DWORD style )
574 {
575 SP_FILE_COPY_PARAMS_A params;
576
577 params.cbSize = sizeof(params);
578 params.QueueHandle = queue;
579 params.SourceRootPath = src_root;
580 params.SourcePath = NULL;
581 params.SourceFilename = src_file;
582 params.SourceDescription = NULL;
583 params.SourceTagfile = NULL;
584 params.TargetDirectory = NULL;
585 params.TargetFilename = dst_file;
586 params.CopyStyle = style;
587 params.LayoutInf = hinf;
588 params.SecurityDescriptor = NULL;
589 return SetupQueueCopyIndirectA( &params );
590 }
591
592
593 /***********************************************************************
594 * SetupQueueDefaultCopyW (SETUPAPI.@)
595 */
596 BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file,
597 PCWSTR dst_file, DWORD style )
598 {
599 SP_FILE_COPY_PARAMS_W params;
600
601 params.cbSize = sizeof(params);
602 params.QueueHandle = queue;
603 params.SourceRootPath = src_root;
604 params.SourcePath = NULL;
605 params.SourceFilename = src_file;
606 params.SourceDescription = NULL;
607 params.SourceTagfile = NULL;
608 params.TargetDirectory = NULL;
609 params.TargetFilename = dst_file;
610 params.CopyStyle = style;
611 params.LayoutInf = hinf;
612 params.SecurityDescriptor = NULL;
613 return SetupQueueCopyIndirectW( &params );
614 }
615
616
617 /***********************************************************************
618 * SetupQueueDeleteA (SETUPAPI.@)
619 */
620 BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 )
621 {
622 struct file_queue *queue = handle;
623 struct file_op *op;
624
625 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
626 op->style = 0;
627 op->src_root = NULL;
628 op->src_path = NULL;
629 op->src_file = NULL;
630 op->src_descr = NULL;
631 op->src_tag = NULL;
632 op->dst_path = strdupAtoW( part1 );
633 op->dst_file = strdupAtoW( part2 );
634 op->dst_sd = NULL;
635 queue_file_op( &queue->delete_queue, op );
636 return TRUE;
637 }
638
639
640 /***********************************************************************
641 * SetupQueueDeleteW (SETUPAPI.@)
642 */
643 BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 )
644 {
645 struct file_queue *queue = handle;
646 struct file_op *op;
647
648 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
649 op->style = 0;
650 op->src_root = NULL;
651 op->src_path = NULL;
652 op->src_file = NULL;
653 op->src_descr = NULL;
654 op->src_tag = NULL;
655 op->dst_path = strdupW( part1 );
656 op->dst_file = strdupW( part2 );
657 op->dst_sd = NULL;
658 queue_file_op( &queue->delete_queue, op );
659 return TRUE;
660 }
661
662
663 /***********************************************************************
664 * SetupQueueRenameA (SETUPAPI.@)
665 */
666 BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename,
667 PCSTR TargetPath, PCSTR 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 = strdupAtoW( SourcePath );
676 op->src_file = strdupAtoW( SourceFilename );
677 op->src_descr = NULL;
678 op->src_tag = NULL;
679 op->dst_path = strdupAtoW( TargetPath );
680 op->dst_file = strdupAtoW( TargetFilename );
681 op->dst_sd = NULL;
682 queue_file_op( &queue->rename_queue, op );
683 return TRUE;
684 }
685
686
687 /***********************************************************************
688 * SetupQueueRenameW (SETUPAPI.@)
689 */
690 BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename,
691 PCWSTR TargetPath, PCWSTR TargetFilename )
692 {
693 struct file_queue *queue = handle;
694 struct file_op *op;
695
696 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE;
697 op->style = 0;
698 op->src_root = NULL;
699 op->src_path = strdupW( SourcePath );
700 op->src_file = strdupW( SourceFilename );
701 op->src_descr = NULL;
702 op->src_tag = NULL;
703 op->dst_path = strdupW( TargetPath );
704 op->dst_file = strdupW( TargetFilename );
705 op->dst_sd = NULL;
706 queue_file_op( &queue->rename_queue, op );
707 return TRUE;
708 }
709
710
711 /***********************************************************************
712 * SetupQueueCopySectionA (SETUPAPI.@)
713 */
714 BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist,
715 PCSTR section, DWORD style )
716 {
717 UNICODE_STRING sectionW;
718 BOOL ret = FALSE;
719
720 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
721 {
722 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
723 return FALSE;
724 }
725 if (!src_root)
726 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style );
727 else
728 {
729 UNICODE_STRING srcW;
730 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root ))
731 {
732 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style );
733 RtlFreeUnicodeString( &srcW );
734 }
735 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
736 }
737 RtlFreeUnicodeString( &sectionW );
738 return ret;
739 }
740
741
742 /***********************************************************************
743 * SetupQueueCopySectionW (SETUPAPI.@)
744 */
745 BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist,
746 PCWSTR section, DWORD style )
747 {
748 SP_FILE_COPY_PARAMS_W params;
749 LPWSTR security_key, security_descriptor = NULL;
750 INFCONTEXT context, security_context;
751 WCHAR dest[MAX_PATH], src[MAX_PATH];
752 INT flags;
753 DWORD required;
754 BOOL ret;
755
756 TRACE( "hinf=%p/%p section=%s root=%s\n",
757 hinf, hlist, debugstr_w(section), debugstr_w(src_root) );
758
759 /* Check for .Security section */
760 security_key = MyMalloc( (strlenW( section ) + strlenW( DotSecurity )) * sizeof(WCHAR) + sizeof(UNICODE_NULL) );
761 if (!security_key)
762 {
763 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
764 return FALSE;
765 }
766 strcpyW( security_key, section );
767 strcatW( security_key, DotSecurity );
768 ret = SetupFindFirstLineW( hinf, security_key, NULL, &security_context );
769 MyFree(security_key);
770 if (ret)
771 {
772 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, NULL, 0, &required ))
773 return FALSE;
774 security_descriptor = MyMalloc( required * sizeof(WCHAR) );
775 if (!security_descriptor)
776 {
777 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
778 return FALSE;
779 }
780 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, security_descriptor, required, NULL ))
781 {
782 MyFree( security_descriptor );
783 return FALSE;
784 }
785 }
786
787 params.cbSize = sizeof(params);
788 params.QueueHandle = queue;
789 params.SourceRootPath = src_root;
790 params.SourcePath = NULL;
791 params.SourceDescription = NULL;
792 params.SourceTagfile = NULL;
793 params.TargetFilename = dest;
794 params.CopyStyle = style;
795 params.LayoutInf = hinf;
796 params.SecurityDescriptor = security_descriptor;
797
798 ret = FALSE;
799 if (!hlist) hlist = hinf;
800 if (!hinf) hinf = hlist;
801 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) goto done;
802 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) goto done;
803 do
804 {
805 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL ))
806 goto done;
807 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0;
808 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */
809
810 params.SourceFilename = *src ? src : NULL;
811 if (!SetupQueueCopyIndirectW( &params )) goto done;
812 } while (SetupFindNextLine( &context, &context ));
813 ret = TRUE;
814
815 done:
816 if (security_descriptor)
817 MyFree( security_descriptor );
818 return ret;
819 }
820
821
822 /***********************************************************************
823 * SetupQueueDeleteSectionA (SETUPAPI.@)
824 */
825 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
826 {
827 UNICODE_STRING sectionW;
828 BOOL ret = FALSE;
829
830 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
831 {
832 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer );
833 RtlFreeUnicodeString( &sectionW );
834 }
835 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
836 return ret;
837 }
838
839
840 /***********************************************************************
841 * SetupQueueDeleteSectionW (SETUPAPI.@)
842 */
843 BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
844 {
845 INFCONTEXT context;
846 WCHAR *dest_dir;
847 WCHAR buffer[MAX_PATH];
848 BOOL ret = FALSE;
849 INT flags;
850
851 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
852
853 if (!hlist) hlist = hinf;
854 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
855 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
856 do
857 {
858 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL ))
859 goto done;
860 if (!SetupGetIntField( &context, 4, &flags )) flags = 0;
861 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done;
862 } while (SetupFindNextLine( &context, &context ));
863
864 ret = TRUE;
865 done:
866 HeapFree( GetProcessHeap(), 0, dest_dir );
867 return ret;
868 }
869
870
871 /***********************************************************************
872 * SetupQueueRenameSectionA (SETUPAPI.@)
873 */
874 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section )
875 {
876 UNICODE_STRING sectionW;
877 BOOL ret = FALSE;
878
879 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section ))
880 {
881 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer );
882 RtlFreeUnicodeString( &sectionW );
883 }
884 else SetLastError( ERROR_NOT_ENOUGH_MEMORY );
885 return ret;
886 }
887
888
889 /***********************************************************************
890 * SetupQueueRenameSectionW (SETUPAPI.@)
891 */
892 BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section )
893 {
894 INFCONTEXT context;
895 WCHAR *dest_dir;
896 WCHAR src[MAX_PATH], dst[MAX_PATH];
897 BOOL ret = FALSE;
898
899 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) );
900
901 if (!hlist) hlist = hinf;
902 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE;
903 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE;
904 do
905 {
906 if (!SetupGetStringFieldW( &context, 1, dst, sizeof(dst)/sizeof(WCHAR), NULL ))
907 goto done;
908 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL ))
909 goto done;
910 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done;
911 } while (SetupFindNextLine( &context, &context ));
912
913 ret = TRUE;
914 done:
915 HeapFree( GetProcessHeap(), 0, dest_dir );
916 return ret;
917 }
918
919
920 /***********************************************************************
921 * SetupCommitFileQueueA (SETUPAPI.@)
922 */
923 BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler,
924 PVOID context )
925 {
926 struct callback_WtoA_context ctx;
927
928 ctx.orig_context = context;
929 ctx.orig_handler = handler;
930 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx );
931 }
932
933
934 /***********************************************************************
935 * create_full_pathW
936 *
937 * Recursively create all directories in the path.
938 */
939 static BOOL create_full_pathW(const WCHAR *path)
940 {
941 BOOL ret = TRUE;
942 int len;
943 WCHAR *new_path;
944
945 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR));
946 strcpyW(new_path, path);
947
948 while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
949 new_path[len - 1] = 0;
950
951 while(!CreateDirectoryW(new_path, NULL))
952 {
953 WCHAR *slash;
954 DWORD last_error = GetLastError();
955
956 if(last_error == ERROR_ALREADY_EXISTS)
957 break;
958
959 if(last_error != ERROR_PATH_NOT_FOUND)
960 {
961 ret = FALSE;
962 break;
963 }
964
965 if(!(slash = strrchrW(new_path, '\\')))
966 {
967 ret = FALSE;
968 break;
969 }
970
971 len = slash - new_path;
972 new_path[len] = 0;
973 if(!create_full_pathW(new_path))
974 {
975 ret = FALSE;
976 break;
977 }
978 new_path[len] = '\\';
979 }
980
981 HeapFree(GetProcessHeap(), 0, new_path);
982 return ret;
983 }
984
985 static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style,
986 PSP_FILE_CALLBACK_W handler, PVOID context )
987 {
988 BOOL rc = FALSE;
989 BOOL docopy = TRUE;
990 WCHAR TempFile[MAX_PATH];
991 INT hSource, hTemp;
992 OFSTRUCT OfStruct;
993 WCHAR TempPath[MAX_PATH];
994
995 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style);
996
997 /* Get a temp file name */
998 if (!GetTempPathW(sizeof(TempPath) / sizeof(WCHAR), TempPath))
999 {
1000 ERR("GetTempPathW error\n");
1001 return FALSE;
1002 }
1003 if (!GetTempFileNameW(TempPath, L"", 0, TempFile))
1004 {
1005 ERR("GetTempFileNameW(%s) error\n", debugstr_w(TempPath));
1006 return FALSE;
1007 }
1008
1009 /* Try to open the source file */
1010 hSource = LZOpenFileW((LPWSTR)source, &OfStruct, OF_READ);
1011 if (hSource < 0)
1012 {
1013 ERR("LZOpenFileW(1) error %d %s\n", (int)hSource, debugstr_w(source));
1014 return FALSE;
1015 }
1016
1017 /* Extract the compressed file to a temp location */
1018 hTemp = LZOpenFileW(TempFile, &OfStruct, OF_CREATE);
1019 if (hTemp < 0)
1020 {
1021 DWORD dwLastError = GetLastError();
1022
1023 ERR("LZOpenFileW(2) error %d %s\n", (int)hTemp, debugstr_w(TempFile));
1024
1025 /* Close the source handle */
1026 LZClose(hSource);
1027
1028 /* Restore error condition triggered by LZOpenFileW */
1029 SetLastError(dwLastError);
1030 return FALSE;
1031 }
1032
1033 LZCopy(hSource, hTemp);
1034 LZClose(hSource);
1035 LZClose(hTemp);
1036
1037 /* before copy processing */
1038 if (style & SP_COPY_REPLACEONLY)
1039 {
1040 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES)
1041 docopy = FALSE;
1042 }
1043 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER))
1044 {
1045 DWORD VersionSizeSource=0;
1046 DWORD VersionSizeTarget=0;
1047 DWORD zero=0;
1048
1049 /*
1050 * This is sort of an interesting workaround. You see, calling
1051 * GetVersionInfoSize on a builtin dll loads that dll into memory
1052 * and we do not properly unload builtin dlls.. so we effectively
1053 * lock into memory all the targets we are replacing. This leads
1054 * to problems when we try to register the replaced dlls.
1055 *
1056 * So I will test for the existence of the files first so that
1057 * we just basically unconditionally replace the builtin versions.
1058 */
1059 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) &&
1060 (GetFileAttributesW(TempFile) != INVALID_FILE_ATTRIBUTES))
1061 {
1062 VersionSizeSource = GetFileVersionInfoSizeW(TempFile,&zero);
1063 VersionSizeTarget = GetFileVersionInfoSizeW((LPWSTR)target,&zero);
1064 }
1065
1066 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget,
1067 VersionSizeSource);
1068
1069 if (VersionSizeSource && VersionSizeTarget)
1070 {
1071 LPVOID VersionSource;
1072 LPVOID VersionTarget;
1073 VS_FIXEDFILEINFO *TargetInfo;
1074 VS_FIXEDFILEINFO *SourceInfo;
1075 UINT length;
1076 WCHAR SubBlock[2]={'\\',0};
1077 DWORD ret;
1078
1079 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource);
1080 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget);
1081
1082 ret = GetFileVersionInfoW(TempFile,0,VersionSizeSource,VersionSource);
1083 if (ret)
1084 ret = GetFileVersionInfoW((LPWSTR)target, 0, VersionSizeTarget,
1085 VersionTarget);
1086
1087 if (ret)
1088 {
1089 ret = VerQueryValueW(VersionSource, SubBlock,
1090 (LPVOID*)&SourceInfo, &length);
1091 if (ret)
1092 ret = VerQueryValueW(VersionTarget, SubBlock,
1093 (LPVOID*)&TargetInfo, &length);
1094
1095 if (ret)
1096 {
1097 FILEPATHS_W filepaths;
1098
1099 TRACE("Versions: Source %i.%i target %i.%i\n",
1100 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS,
1101 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS);
1102
1103 /* used in case of notification */
1104 filepaths.Target = target;
1105 filepaths.Source = source;
1106 filepaths.Win32Error = 0;
1107 filepaths.Flags = 0;
1108
1109 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS)
1110 {
1111 if (handler)
1112 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1113 else
1114 docopy = FALSE;
1115 }
1116 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS)
1117 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS))
1118 {
1119 if (handler)
1120 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1121 else
1122 docopy = FALSE;
1123 }
1124 else if ((style & SP_COPY_NEWER_ONLY) &&
1125 (TargetInfo->dwFileVersionMS ==
1126 SourceInfo->dwFileVersionMS)
1127 &&(TargetInfo->dwFileVersionLS ==
1128 SourceInfo->dwFileVersionLS))
1129 {
1130 if (handler)
1131 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0);
1132 else
1133 docopy = FALSE;
1134 }
1135 }
1136 }
1137 HeapFree(GetProcessHeap(),0,VersionSource);
1138 HeapFree(GetProcessHeap(),0,VersionTarget);
1139 }
1140 }
1141 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE))
1142 {
1143 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES)
1144 {
1145 FIXME("Notify user target file exists\n");
1146 docopy = FALSE;
1147 }
1148 }
1149 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE |
1150 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP))
1151 {
1152 ERR("Unsupported style(s) 0x%x\n",style);
1153 }
1154
1155 if (docopy)
1156 {
1157 rc = MoveFileExW(TempFile,target,MOVEFILE_REPLACE_EXISTING);
1158 TRACE("Did copy... rc was %i\n",rc);
1159 }
1160
1161 /* after copy processing */
1162 if (style & SP_COPY_DELETESOURCE)
1163 {
1164 if (rc)
1165 DeleteFileW(source);
1166 }
1167
1168 return rc;
1169 }
1170
1171 /***********************************************************************
1172 * SetupInstallFileA (SETUPAPI.@)
1173 */
1174 BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root,
1175 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context )
1176 {
1177 BOOL ret = FALSE;
1178 struct callback_WtoA_context ctx;
1179 UNICODE_STRING sourceW, rootW, destW;
1180
1181 TRACE("%p %p %s %s %s %x %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root),
1182 debugstr_a(dest), style, handler, context);
1183
1184 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL;
1185 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source ))
1186 {
1187 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1188 return FALSE;
1189 }
1190 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root ))
1191 {
1192 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1193 goto exit;
1194 }
1195 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest ))
1196 {
1197 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1198 goto exit;
1199 }
1200
1201 ctx.orig_context = context;
1202 ctx.orig_handler = handler;
1203
1204 ret = SetupInstallFileW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx );
1205
1206 exit:
1207 RtlFreeUnicodeString( &sourceW );
1208 RtlFreeUnicodeString( &rootW );
1209 RtlFreeUnicodeString( &destW );
1210 return ret;
1211 }
1212
1213 /***********************************************************************
1214 * SetupInstallFileW (SETUPAPI.@)
1215 */
1216 BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root,
1217 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context )
1218 {
1219 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0};
1220
1221 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE));
1222 WCHAR *buffer, *p, *inf_source = NULL;
1223 unsigned int len;
1224
1225 TRACE("%p %p %s %s %s %x %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root),
1226 debugstr_w(dest), style, handler, context);
1227
1228 if (hinf)
1229 {
1230 INFCONTEXT ctx;
1231
1232 if (!inf_context)
1233 {
1234 inf_context = &ctx;
1235 if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE;
1236 }
1237 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, (PDWORD) &len )) return FALSE;
1238 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1239 {
1240 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1241 return FALSE;
1242 }
1243 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL ))
1244 {
1245 HeapFree( GetProcessHeap(), 0, inf_source );
1246 return FALSE;
1247 }
1248 source = inf_source;
1249 }
1250 else if (!source)
1251 {
1252 SetLastError( ERROR_INVALID_PARAMETER );
1253 return FALSE;
1254 }
1255
1256 len = strlenW( source ) + 1;
1257 if (absolute) len += strlenW( root ) + 1;
1258
1259 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1260 {
1261 HeapFree( GetProcessHeap(), 0, inf_source );
1262 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1263 return FALSE;
1264 }
1265
1266 if (absolute)
1267 {
1268 strcpyW( buffer, root );
1269 p += strlenW( buffer );
1270 if (p[-1] != '\\') *p++ = '\\';
1271 }
1272 while (*source == '\\') source++;
1273 strcpyW( p, source );
1274
1275 ret = do_file_copyW( buffer, dest, style, handler, context );
1276
1277 HeapFree( GetProcessHeap(), 0, inf_source );
1278 HeapFree( GetProcessHeap(), 0, buffer );
1279 return ret;
1280 }
1281
1282 /***********************************************************************
1283 * SetupCommitFileQueueW (SETUPAPI.@)
1284 */
1285 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1286 PVOID context )
1287 {
1288 struct file_queue *queue = handle;
1289 struct file_op *op;
1290 BOOL result = FALSE;
1291 FILEPATHS_W paths;
1292 UINT op_result;
1293
1294 paths.Source = paths.Target = NULL;
1295
1296 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1297 return TRUE; /* nothing to do */
1298
1299 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1300
1301 /* perform deletes */
1302
1303 if (queue->delete_queue.count)
1304 {
1305 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1306 queue->delete_queue.count ))) goto done;
1307 for (op = queue->delete_queue.head; op; op = op->next)
1308 {
1309 build_filepathsW( op, &paths );
1310 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1311 if (op_result == FILEOP_ABORT) goto done;
1312 while (op_result == FILEOP_DOIT)
1313 {
1314 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1315 if (DeleteFileW( paths.Target )) break; /* success */
1316 paths.Win32Error = GetLastError();
1317 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1318 if (op_result == FILEOP_ABORT) goto done;
1319 }
1320 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1321 }
1322 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1323 }
1324
1325 /* perform renames */
1326
1327 if (queue->rename_queue.count)
1328 {
1329 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1330 queue->rename_queue.count ))) goto done;
1331 for (op = queue->rename_queue.head; op; op = op->next)
1332 {
1333 build_filepathsW( op, &paths );
1334 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1335 if (op_result == FILEOP_ABORT) goto done;
1336 while (op_result == FILEOP_DOIT)
1337 {
1338 TRACE( "renaming file %s -> %s\n",
1339 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1340 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1341 paths.Win32Error = GetLastError();
1342 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1343 if (op_result == FILEOP_ABORT) goto done;
1344 }
1345 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1346 }
1347 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1348 }
1349
1350 /* perform copies */
1351
1352 if (queue->copy_queue.count)
1353 {
1354 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1355 queue->copy_queue.count ))) goto done;
1356 for (op = queue->copy_queue.head; op; op = op->next)
1357 {
1358 WCHAR newpath[MAX_PATH];
1359
1360 build_filepathsW( op, &paths );
1361 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1362 if (op_result == FILEOP_ABORT) goto done;
1363 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1364 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1365 {
1366 TRACE( "copying file %s -> %s\n",
1367 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1368 debugstr_w(paths.Target) );
1369 if (op->dst_path)
1370 {
1371 if (!create_full_pathW( op->dst_path ))
1372 {
1373 paths.Win32Error = GetLastError();
1374 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1375 (UINT_PTR)&paths, (UINT_PTR)newpath );
1376 if (op_result == FILEOP_ABORT) goto done;
1377 }
1378 }
1379 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1380 paths.Target, op->style, handler, context )) break; /* success */
1381 /* try to extract it from the cabinet file */
1382 if (op->src_tag)
1383 {
1384 if (extract_cabinet_file( op->src_tag, op->src_root,
1385 paths.Source, paths.Target )) break;
1386 }
1387 paths.Win32Error = GetLastError();
1388 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1389 (UINT_PTR)&paths, (UINT_PTR)newpath );
1390 if (op_result == FILEOP_ABORT) goto done;
1391 }
1392 if (op->dst_sd)
1393 {
1394 PSID psidOwner = NULL, psidGroup = NULL;
1395 PACL pDacl = NULL, pSacl = NULL;
1396 SECURITY_INFORMATION security_info = 0;
1397 BOOL present, dummy;
1398
1399 if (GetSecurityDescriptorOwner( op->dst_sd, &psidOwner, &dummy ) && psidOwner)
1400 security_info |= OWNER_SECURITY_INFORMATION;
1401 if (GetSecurityDescriptorGroup( op->dst_sd, &psidGroup, &dummy ) && psidGroup)
1402 security_info |= GROUP_SECURITY_INFORMATION;
1403 if (GetSecurityDescriptorDacl( op->dst_sd, &present, &pDacl, &dummy ))
1404 security_info |= DACL_SECURITY_INFORMATION;
1405 if (GetSecurityDescriptorSacl( op->dst_sd, &present, &pSacl, &dummy ))
1406 security_info |= DACL_SECURITY_INFORMATION;
1407 SetNamedSecurityInfoW( (LPWSTR)paths.Target, SE_FILE_OBJECT, security_info,
1408 psidOwner, psidGroup, pDacl, pSacl );
1409 /* Yes, ignore the return code... */
1410 }
1411 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1412 }
1413 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1414 }
1415
1416
1417 result = TRUE;
1418
1419 done:
1420 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1421 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1422 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1423 return result;
1424 }
1425
1426
1427 /***********************************************************************
1428 * SetupScanFileQueueA (SETUPAPI.@)
1429 */
1430 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1431 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1432 {
1433 struct callback_WtoA_context ctx;
1434
1435 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1436
1437 ctx.orig_context = context;
1438 ctx.orig_handler = handler;
1439
1440 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1441 }
1442
1443
1444 /***********************************************************************
1445 * SetupScanFileQueueW (SETUPAPI.@)
1446 */
1447 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1448 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1449 {
1450 struct file_queue *queue = handle;
1451 struct file_op *op;
1452 FILEPATHS_W paths;
1453 UINT notification = 0;
1454 BOOL ret = FALSE;
1455
1456 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1457
1458 *result = FALSE;
1459
1460 if (!queue->copy_queue.count) return TRUE;
1461
1462 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1463 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1464
1465 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1466 {
1467 FIXME("flags %x not fully implemented\n", flags);
1468 }
1469
1470 paths.Source = paths.Target = NULL;
1471
1472 for (op = queue->copy_queue.head; op; op = op->next)
1473 {
1474 build_filepathsW( op, &paths );
1475 switch (notification)
1476 {
1477 case SPFILENOTIFY_QUEUESCAN:
1478 /* FIXME: handle delay flag */
1479 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1480 break;
1481 case SPFILENOTIFY_QUEUESCAN_EX:
1482 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1483 break;
1484 default:
1485 ret = TRUE; goto done;
1486 }
1487 }
1488
1489 *result = TRUE;
1490
1491 done:
1492 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1493 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1494 return ret;
1495 }
1496
1497
1498 /***********************************************************************
1499 * SetupGetFileQueueCount (SETUPAPI.@)
1500 */
1501 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1502 {
1503 struct file_queue *queue = handle;
1504
1505 switch(op)
1506 {
1507 case FILEOP_COPY:
1508 *result = queue->copy_queue.count;
1509 return TRUE;
1510 case FILEOP_RENAME:
1511 *result = queue->rename_queue.count;
1512 return TRUE;
1513 case FILEOP_DELETE:
1514 *result = queue->delete_queue.count;
1515 return TRUE;
1516 }
1517 return FALSE;
1518 }
1519
1520
1521 /***********************************************************************
1522 * SetupGetFileQueueFlags (SETUPAPI.@)
1523 */
1524 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1525 {
1526 struct file_queue *queue = handle;
1527 *flags = queue->flags;
1528 return TRUE;
1529 }
1530
1531
1532 /***********************************************************************
1533 * SetupSetFileQueueFlags (SETUPAPI.@)
1534 */
1535 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1536 {
1537 struct file_queue *queue = handle;
1538 queue->flags = (queue->flags & ~mask) | flags;
1539 return TRUE;
1540 }
1541
1542
1543 /***********************************************************************
1544 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1545 */
1546 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1547 {
1548 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1549 return FALSE;
1550 }
1551
1552
1553 /***********************************************************************
1554 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1555 */
1556 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1557 {
1558 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1559 return FALSE;
1560 }
1561
1562
1563 /***********************************************************************
1564 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1565 */
1566 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1567 {
1568 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1569 }
1570
1571
1572 /***********************************************************************
1573 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1574 */
1575 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1576 DWORD reserved1, PVOID reserved2 )
1577 {
1578 struct default_callback_context *context;
1579
1580 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1581 {
1582 context->owner = owner;
1583 context->progress = progress;
1584 context->message = msg;
1585 }
1586 return context;
1587 }
1588
1589
1590 /***********************************************************************
1591 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1592 */
1593 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1594 {
1595 HeapFree( GetProcessHeap(), 0, context );
1596 }
1597
1598
1599 /***********************************************************************
1600 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1601 */
1602 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1603 UINT_PTR param1, UINT_PTR param2 )
1604 {
1605 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1606 struct default_callback_context *ctx = (struct default_callback_context *)context;
1607
1608 switch(notification)
1609 {
1610 case SPFILENOTIFY_STARTQUEUE:
1611 TRACE( "start queue\n" );
1612 return TRUE;
1613 case SPFILENOTIFY_ENDQUEUE:
1614 TRACE( "end queue\n" );
1615 return 0;
1616 case SPFILENOTIFY_STARTSUBQUEUE:
1617 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1618 return TRUE;
1619 case SPFILENOTIFY_ENDSUBQUEUE:
1620 TRACE( "end subqueue %ld\n", param1 );
1621 return 0;
1622 case SPFILENOTIFY_STARTDELETE:
1623 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1624 return FILEOP_DOIT;
1625 case SPFILENOTIFY_ENDDELETE:
1626 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1627 return 0;
1628 case SPFILENOTIFY_DELETEERROR:
1629 /*Windows Ignores attempts to delete files / folders which do not exist*/
1630 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1631 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1632 return FILEOP_SKIP;
1633 case SPFILENOTIFY_STARTRENAME:
1634 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1635 return FILEOP_DOIT;
1636 case SPFILENOTIFY_ENDRENAME:
1637 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1638 return 0;
1639 case SPFILENOTIFY_RENAMEERROR:
1640 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1641 return FILEOP_SKIP;
1642 case SPFILENOTIFY_STARTCOPY:
1643 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1644 return FILEOP_DOIT;
1645 case SPFILENOTIFY_ENDCOPY:
1646 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1647 return 0;
1648 case SPFILENOTIFY_COPYERROR:
1649 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1650 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1651 return FILEOP_SKIP;
1652 case SPFILENOTIFY_NEEDMEDIA:
1653 TRACE( "need media\n" );
1654 return FILEOP_SKIP;
1655 default:
1656 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1657 break;
1658 }
1659 return 0;
1660 }
1661
1662
1663 /***********************************************************************
1664 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1665 */
1666 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1667 UINT_PTR param1, UINT_PTR param2 )
1668 {
1669 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1670 struct default_callback_context *ctx = (struct default_callback_context *)context;
1671
1672 switch(notification)
1673 {
1674 case SPFILENOTIFY_STARTQUEUE:
1675 TRACE( "start queue\n" );
1676 return TRUE;
1677 case SPFILENOTIFY_ENDQUEUE:
1678 TRACE( "end queue\n" );
1679 return 0;
1680 case SPFILENOTIFY_STARTSUBQUEUE:
1681 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1682 return TRUE;
1683 case SPFILENOTIFY_ENDSUBQUEUE:
1684 TRACE( "end subqueue %ld\n", param1 );
1685 return 0;
1686 case SPFILENOTIFY_STARTDELETE:
1687 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1688 return FILEOP_DOIT;
1689 case SPFILENOTIFY_ENDDELETE:
1690 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1691 return 0;
1692 case SPFILENOTIFY_DELETEERROR:
1693 /*Windows Ignores attempts to delete files / folders which do not exist*/
1694 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1695 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1696 return FILEOP_SKIP;
1697 case SPFILENOTIFY_STARTRENAME:
1698 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1699 return FILEOP_DOIT;
1700 case SPFILENOTIFY_ENDRENAME:
1701 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1702 return 0;
1703 case SPFILENOTIFY_RENAMEERROR:
1704 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1705 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1706 return FILEOP_SKIP;
1707 case SPFILENOTIFY_STARTCOPY:
1708 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1709 return FILEOP_DOIT;
1710 case SPFILENOTIFY_ENDCOPY:
1711 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1712 return 0;
1713 case SPFILENOTIFY_COPYERROR:
1714 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1715 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1716 return FILEOP_SKIP;
1717 case SPFILENOTIFY_NEEDMEDIA:
1718 TRACE( "need media\n" );
1719 return FILEOP_SKIP;
1720 default:
1721 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1722 break;
1723 }
1724 return 0;
1725 }
1726
1727 /***********************************************************************
1728 * SetupDeleteErrorA (SETUPAPI.@)
1729 */
1730
1731 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1732 UINT w32error, DWORD style)
1733 {
1734 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1735 w32error, debugstr_a(file) );
1736 return DPROMPT_SKIPFILE;
1737 }
1738
1739 /***********************************************************************
1740 * SetupDeleteErrorW (SETUPAPI.@)
1741 */
1742
1743 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1744 UINT w32error, DWORD style)
1745 {
1746 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1747 w32error, debugstr_w(file) );
1748 return DPROMPT_SKIPFILE;
1749 }
1750
1751 /***********************************************************************
1752 * SetupRenameErrorA (SETUPAPI.@)
1753 */
1754
1755 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1756 PCSTR target, UINT w32error, DWORD style)
1757 {
1758 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1759 w32error, debugstr_a(source), debugstr_a(target));
1760 return DPROMPT_SKIPFILE;
1761 }
1762
1763 /***********************************************************************
1764 * SetupRenameErrorW (SETUPAPI.@)
1765 */
1766
1767 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1768 PCWSTR target, UINT w32error, DWORD style)
1769 {
1770 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1771 w32error, debugstr_w(source), debugstr_w(target));
1772 return DPROMPT_SKIPFILE;
1773 }
1774
1775
1776 /***********************************************************************
1777 * SetupCopyErrorA (SETUPAPI.@)
1778 */
1779
1780 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1781 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1782 UINT w32error, DWORD style, PSTR pathbuffer,
1783 DWORD buffersize, PDWORD requiredsize)
1784 {
1785 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1786 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1787 return DPROMPT_SKIPFILE;
1788 }
1789
1790 /***********************************************************************
1791 * SetupCopyErrorW (SETUPAPI.@)
1792 */
1793
1794 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1795 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1796 UINT w32error, DWORD style, PWSTR pathbuffer,
1797 DWORD buffersize, PDWORD requiredsize)
1798 {
1799 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1800 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1801 return DPROMPT_SKIPFILE;
1802 }
1803
1804 /***********************************************************************
1805 * pSetupGetQueueFlags (SETUPAPI.@)
1806 */
1807 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1808 {
1809 struct file_queue *queue = handle;
1810 return queue->flags;
1811 }
1812
1813 /***********************************************************************
1814 * pSetupSetQueueFlags (SETUPAPI.@)
1815 */
1816 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1817 {
1818 struct file_queue *queue = handle;
1819 queue->flags = flags;
1820 return TRUE;
1821 }