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