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