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