d10f1e0344c5ccb4db4ff4da44cdee274c58d366
[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 )) return FALSE;
1220 source = inf_source;
1221 }
1222 else if (!source)
1223 {
1224 SetLastError( ERROR_INVALID_PARAMETER );
1225 return FALSE;
1226 }
1227
1228 len = strlenW( source ) + 1;
1229 if (absolute) len += strlenW( root ) + 1;
1230
1231 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1232 {
1233 HeapFree( GetProcessHeap(), 0, inf_source );
1234 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1235 return FALSE;
1236 }
1237
1238 if (absolute)
1239 {
1240 strcpyW( buffer, root );
1241 p += strlenW( buffer );
1242 if (p[-1] != '\\') *p++ = '\\';
1243 }
1244 while (*source == '\\') source++;
1245 strcpyW( p, source );
1246
1247 ret = do_file_copyW( buffer, dest, style, handler, context );
1248
1249 HeapFree( GetProcessHeap(), 0, inf_source );
1250 HeapFree( GetProcessHeap(), 0, buffer );
1251 return ret;
1252 }
1253
1254 /***********************************************************************
1255 * SetupCommitFileQueueW (SETUPAPI.@)
1256 */
1257 BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler,
1258 PVOID context )
1259 {
1260 struct file_queue *queue = handle;
1261 struct file_op *op;
1262 BOOL result = FALSE;
1263 FILEPATHS_W paths;
1264 UINT op_result;
1265
1266 paths.Source = paths.Target = NULL;
1267
1268 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count)
1269 return TRUE; /* nothing to do */
1270
1271 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE;
1272
1273 /* perform deletes */
1274
1275 if (queue->delete_queue.count)
1276 {
1277 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE,
1278 queue->delete_queue.count ))) goto done;
1279 for (op = queue->delete_queue.head; op; op = op->next)
1280 {
1281 build_filepathsW( op, &paths );
1282 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE);
1283 if (op_result == FILEOP_ABORT) goto done;
1284 while (op_result == FILEOP_DOIT)
1285 {
1286 TRACE( "deleting file %s\n", debugstr_w(paths.Target) );
1287 if (DeleteFileW( paths.Target )) break; /* success */
1288 paths.Win32Error = GetLastError();
1289 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 );
1290 if (op_result == FILEOP_ABORT) goto done;
1291 }
1292 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 );
1293 }
1294 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 );
1295 }
1296
1297 /* perform renames */
1298
1299 if (queue->rename_queue.count)
1300 {
1301 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME,
1302 queue->rename_queue.count ))) goto done;
1303 for (op = queue->rename_queue.head; op; op = op->next)
1304 {
1305 build_filepathsW( op, &paths );
1306 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME);
1307 if (op_result == FILEOP_ABORT) goto done;
1308 while (op_result == FILEOP_DOIT)
1309 {
1310 TRACE( "renaming file %s -> %s\n",
1311 debugstr_w(paths.Source), debugstr_w(paths.Target) );
1312 if (MoveFileW( paths.Source, paths.Target )) break; /* success */
1313 paths.Win32Error = GetLastError();
1314 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 );
1315 if (op_result == FILEOP_ABORT) goto done;
1316 }
1317 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 );
1318 }
1319 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 );
1320 }
1321
1322 /* perform copies */
1323
1324 if (queue->copy_queue.count)
1325 {
1326 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY,
1327 queue->copy_queue.count ))) goto done;
1328 for (op = queue->copy_queue.head; op; op = op->next)
1329 {
1330 WCHAR newpath[MAX_PATH];
1331
1332 build_filepathsW( op, &paths );
1333 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY );
1334 if (op_result == FILEOP_ABORT) goto done;
1335 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT;
1336 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH)
1337 {
1338 TRACE( "copying file %s -> %s\n",
1339 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ),
1340 debugstr_w(paths.Target) );
1341 if (op->dst_path)
1342 {
1343 if (!create_full_pathW( op->dst_path ))
1344 {
1345 paths.Win32Error = GetLastError();
1346 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1347 (UINT_PTR)&paths, (UINT_PTR)newpath );
1348 if (op_result == FILEOP_ABORT) goto done;
1349 }
1350 }
1351 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source,
1352 paths.Target, op->style, handler, context )) break; /* success */
1353 /* try to extract it from the cabinet file */
1354 if (op->src_tag)
1355 {
1356 if (extract_cabinet_file( op->src_tag, op->src_root,
1357 paths.Source, paths.Target )) break;
1358 }
1359 paths.Win32Error = GetLastError();
1360 op_result = handler( context, SPFILENOTIFY_COPYERROR,
1361 (UINT_PTR)&paths, (UINT_PTR)newpath );
1362 if (op_result == FILEOP_ABORT) goto done;
1363 }
1364 if (op->dst_sd)
1365 {
1366 PSID psidOwner = NULL, psidGroup = NULL;
1367 PACL pDacl = NULL, pSacl = NULL;
1368 SECURITY_INFORMATION security_info = 0;
1369 BOOL present, dummy;
1370
1371 if (GetSecurityDescriptorOwner( op->dst_sd, &psidOwner, &dummy ) && psidOwner)
1372 security_info |= OWNER_SECURITY_INFORMATION;
1373 if (GetSecurityDescriptorGroup( op->dst_sd, &psidGroup, &dummy ) && psidGroup)
1374 security_info |= GROUP_SECURITY_INFORMATION;
1375 if (GetSecurityDescriptorDacl( op->dst_sd, &present, &pDacl, &dummy ))
1376 security_info |= DACL_SECURITY_INFORMATION;
1377 if (GetSecurityDescriptorSacl( op->dst_sd, &present, &pSacl, &dummy ))
1378 security_info |= DACL_SECURITY_INFORMATION;
1379 SetNamedSecurityInfoW( (LPWSTR)paths.Target, SE_FILE_OBJECT, security_info,
1380 psidOwner, psidGroup, pDacl, pSacl );
1381 /* Yes, ignore the return code... */
1382 }
1383 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 );
1384 }
1385 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 );
1386 }
1387
1388
1389 result = TRUE;
1390
1391 done:
1392 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 );
1393 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1394 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1395 return result;
1396 }
1397
1398
1399 /***********************************************************************
1400 * SetupScanFileQueueA (SETUPAPI.@)
1401 */
1402 BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window,
1403 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result )
1404 {
1405 struct callback_WtoA_context ctx;
1406
1407 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1408
1409 ctx.orig_context = context;
1410 ctx.orig_handler = handler;
1411
1412 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result );
1413 }
1414
1415
1416 /***********************************************************************
1417 * SetupScanFileQueueW (SETUPAPI.@)
1418 */
1419 BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window,
1420 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result )
1421 {
1422 struct file_queue *queue = handle;
1423 struct file_op *op;
1424 FILEPATHS_W paths;
1425 UINT notification = 0;
1426 BOOL ret = FALSE;
1427
1428 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result);
1429
1430 *result = FALSE;
1431
1432 if (!queue->copy_queue.count) return TRUE;
1433
1434 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN;
1435 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX;
1436
1437 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX))
1438 {
1439 FIXME("flags %x not fully implemented\n", flags);
1440 }
1441
1442 paths.Source = paths.Target = NULL;
1443
1444 for (op = queue->copy_queue.head; op; op = op->next)
1445 {
1446 build_filepathsW( op, &paths );
1447 switch (notification)
1448 {
1449 case SPFILENOTIFY_QUEUESCAN:
1450 /* FIXME: handle delay flag */
1451 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done;
1452 break;
1453 case SPFILENOTIFY_QUEUESCAN_EX:
1454 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done;
1455 break;
1456 default:
1457 ret = TRUE; goto done;
1458 }
1459 }
1460
1461 *result = TRUE;
1462
1463 done:
1464 HeapFree( GetProcessHeap(), 0, (void *)paths.Source );
1465 HeapFree( GetProcessHeap(), 0, (void *)paths.Target );
1466 return ret;
1467 }
1468
1469
1470 /***********************************************************************
1471 * SetupGetFileQueueCount (SETUPAPI.@)
1472 */
1473 BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result )
1474 {
1475 struct file_queue *queue = handle;
1476
1477 switch(op)
1478 {
1479 case FILEOP_COPY:
1480 *result = queue->copy_queue.count;
1481 return TRUE;
1482 case FILEOP_RENAME:
1483 *result = queue->rename_queue.count;
1484 return TRUE;
1485 case FILEOP_DELETE:
1486 *result = queue->delete_queue.count;
1487 return TRUE;
1488 }
1489 return FALSE;
1490 }
1491
1492
1493 /***********************************************************************
1494 * SetupGetFileQueueFlags (SETUPAPI.@)
1495 */
1496 BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags )
1497 {
1498 struct file_queue *queue = handle;
1499 *flags = queue->flags;
1500 return TRUE;
1501 }
1502
1503
1504 /***********************************************************************
1505 * SetupSetFileQueueFlags (SETUPAPI.@)
1506 */
1507 BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags )
1508 {
1509 struct file_queue *queue = handle;
1510 queue->flags = (queue->flags & ~mask) | flags;
1511 return TRUE;
1512 }
1513
1514
1515 /***********************************************************************
1516 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@)
1517 */
1518 BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile)
1519 {
1520 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile));
1521 return FALSE;
1522 }
1523
1524
1525 /***********************************************************************
1526 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@)
1527 */
1528 BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile)
1529 {
1530 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile));
1531 return FALSE;
1532 }
1533
1534
1535 /***********************************************************************
1536 * SetupInitDefaultQueueCallback (SETUPAPI.@)
1537 */
1538 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner )
1539 {
1540 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL );
1541 }
1542
1543
1544 /***********************************************************************
1545 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@)
1546 */
1547 PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg,
1548 DWORD reserved1, PVOID reserved2 )
1549 {
1550 struct default_callback_context *context;
1551
1552 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) )))
1553 {
1554 context->owner = owner;
1555 context->progress = progress;
1556 context->message = msg;
1557 }
1558 return context;
1559 }
1560
1561
1562 /***********************************************************************
1563 * SetupTermDefaultQueueCallback (SETUPAPI.@)
1564 */
1565 void WINAPI SetupTermDefaultQueueCallback( PVOID context )
1566 {
1567 HeapFree( GetProcessHeap(), 0, context );
1568 }
1569
1570
1571 /***********************************************************************
1572 * SetupDefaultQueueCallbackA (SETUPAPI.@)
1573 */
1574 UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification,
1575 UINT_PTR param1, UINT_PTR param2 )
1576 {
1577 FILEPATHS_A *paths = (FILEPATHS_A *)param1;
1578 struct default_callback_context *ctx = (struct default_callback_context *)context;
1579
1580 switch(notification)
1581 {
1582 case SPFILENOTIFY_STARTQUEUE:
1583 TRACE( "start queue\n" );
1584 return TRUE;
1585 case SPFILENOTIFY_ENDQUEUE:
1586 TRACE( "end queue\n" );
1587 return 0;
1588 case SPFILENOTIFY_STARTSUBQUEUE:
1589 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1590 return TRUE;
1591 case SPFILENOTIFY_ENDSUBQUEUE:
1592 TRACE( "end subqueue %ld\n", param1 );
1593 return 0;
1594 case SPFILENOTIFY_STARTDELETE:
1595 TRACE( "start delete %s\n", debugstr_a(paths->Target) );
1596 return FILEOP_DOIT;
1597 case SPFILENOTIFY_ENDDELETE:
1598 TRACE( "end delete %s\n", debugstr_a(paths->Target) );
1599 return 0;
1600 case SPFILENOTIFY_DELETEERROR:
1601 /*Windows Ignores attempts to delete files / folders which do not exist*/
1602 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1603 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1604 return FILEOP_SKIP;
1605 case SPFILENOTIFY_STARTRENAME:
1606 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1607 return FILEOP_DOIT;
1608 case SPFILENOTIFY_ENDRENAME:
1609 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1610 return 0;
1611 case SPFILENOTIFY_RENAMEERROR:
1612 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1613 return FILEOP_SKIP;
1614 case SPFILENOTIFY_STARTCOPY:
1615 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1616 return FILEOP_DOIT;
1617 case SPFILENOTIFY_ENDCOPY:
1618 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) );
1619 return 0;
1620 case SPFILENOTIFY_COPYERROR:
1621 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1622 debugstr_a(paths->Source), debugstr_a(paths->Target) );
1623 return FILEOP_SKIP;
1624 case SPFILENOTIFY_NEEDMEDIA:
1625 TRACE( "need media\n" );
1626 return FILEOP_SKIP;
1627 default:
1628 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1629 break;
1630 }
1631 return 0;
1632 }
1633
1634
1635 /***********************************************************************
1636 * SetupDefaultQueueCallbackW (SETUPAPI.@)
1637 */
1638 UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification,
1639 UINT_PTR param1, UINT_PTR param2 )
1640 {
1641 FILEPATHS_W *paths = (FILEPATHS_W *)param1;
1642 struct default_callback_context *ctx = (struct default_callback_context *)context;
1643
1644 switch(notification)
1645 {
1646 case SPFILENOTIFY_STARTQUEUE:
1647 TRACE( "start queue\n" );
1648 return TRUE;
1649 case SPFILENOTIFY_ENDQUEUE:
1650 TRACE( "end queue\n" );
1651 return 0;
1652 case SPFILENOTIFY_STARTSUBQUEUE:
1653 TRACE( "start subqueue %ld count %ld\n", param1, param2 );
1654 return TRUE;
1655 case SPFILENOTIFY_ENDSUBQUEUE:
1656 TRACE( "end subqueue %ld\n", param1 );
1657 return 0;
1658 case SPFILENOTIFY_STARTDELETE:
1659 TRACE( "start delete %s\n", debugstr_w(paths->Target) );
1660 return FILEOP_DOIT;
1661 case SPFILENOTIFY_ENDDELETE:
1662 TRACE( "end delete %s\n", debugstr_w(paths->Target) );
1663 return 0;
1664 case SPFILENOTIFY_DELETEERROR:
1665 /*Windows Ignores attempts to delete files / folders which do not exist*/
1666 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND))
1667 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0);
1668 return FILEOP_SKIP;
1669 case SPFILENOTIFY_STARTRENAME:
1670 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0);
1671 return FILEOP_DOIT;
1672 case SPFILENOTIFY_ENDRENAME:
1673 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1674 return 0;
1675 case SPFILENOTIFY_RENAMEERROR:
1676 ERR( "rename error %d %s -> %s\n", paths->Win32Error,
1677 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1678 return FILEOP_SKIP;
1679 case SPFILENOTIFY_STARTCOPY:
1680 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1681 return FILEOP_DOIT;
1682 case SPFILENOTIFY_ENDCOPY:
1683 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) );
1684 return 0;
1685 case SPFILENOTIFY_COPYERROR:
1686 ERR( "copy error %d %s -> %s\n", paths->Win32Error,
1687 debugstr_w(paths->Source), debugstr_w(paths->Target) );
1688 return FILEOP_SKIP;
1689 case SPFILENOTIFY_NEEDMEDIA:
1690 TRACE( "need media\n" );
1691 return FILEOP_SKIP;
1692 default:
1693 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 );
1694 break;
1695 }
1696 return 0;
1697 }
1698
1699 /***********************************************************************
1700 * SetupDeleteErrorA (SETUPAPI.@)
1701 */
1702
1703 UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file,
1704 UINT w32error, DWORD style)
1705 {
1706 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1707 w32error, debugstr_a(file) );
1708 return DPROMPT_SKIPFILE;
1709 }
1710
1711 /***********************************************************************
1712 * SetupDeleteErrorW (SETUPAPI.@)
1713 */
1714
1715 UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file,
1716 UINT w32error, DWORD style)
1717 {
1718 FIXME( "stub: (Error Number %d when attempting to delete %s)\n",
1719 w32error, debugstr_w(file) );
1720 return DPROMPT_SKIPFILE;
1721 }
1722
1723 /***********************************************************************
1724 * SetupRenameErrorA (SETUPAPI.@)
1725 */
1726
1727 UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source,
1728 PCSTR target, UINT w32error, DWORD style)
1729 {
1730 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1731 w32error, debugstr_a(source), debugstr_a(target));
1732 return DPROMPT_SKIPFILE;
1733 }
1734
1735 /***********************************************************************
1736 * SetupRenameErrorW (SETUPAPI.@)
1737 */
1738
1739 UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source,
1740 PCWSTR target, UINT w32error, DWORD style)
1741 {
1742 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n",
1743 w32error, debugstr_w(source), debugstr_w(target));
1744 return DPROMPT_SKIPFILE;
1745 }
1746
1747
1748 /***********************************************************************
1749 * SetupCopyErrorA (SETUPAPI.@)
1750 */
1751
1752 UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname,
1753 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath,
1754 UINT w32error, DWORD style, PSTR pathbuffer,
1755 DWORD buffersize, PDWORD requiredsize)
1756 {
1757 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1758 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath));
1759 return DPROMPT_SKIPFILE;
1760 }
1761
1762 /***********************************************************************
1763 * SetupCopyErrorW (SETUPAPI.@)
1764 */
1765
1766 UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname,
1767 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath,
1768 UINT w32error, DWORD style, PWSTR pathbuffer,
1769 DWORD buffersize, PDWORD requiredsize)
1770 {
1771 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n",
1772 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath));
1773 return DPROMPT_SKIPFILE;
1774 }
1775
1776 /***********************************************************************
1777 * pSetupGetQueueFlags (SETUPAPI.@)
1778 */
1779 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle )
1780 {
1781 struct file_queue *queue = handle;
1782 return queue->flags;
1783 }
1784
1785 /***********************************************************************
1786 * pSetupSetQueueFlags (SETUPAPI.@)
1787 */
1788 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags )
1789 {
1790 struct file_queue *queue = handle;
1791 queue->flags = flags;
1792 return TRUE;
1793 }