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