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