Reactos
at master 1884 lines 65 kB view raw
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 */ 26static const WCHAR DotSecurity[] = {'.','S','e','c','u','r','i','t','y',0}; 27 28/* context structure for the default queue callback */ 29struct default_callback_context 30{ 31 HWND owner; 32 HWND progress; 33 UINT message; 34}; 35 36struct 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 50struct file_op_queue 51{ 52 struct file_op *head; 53 struct file_op *tail; 54 unsigned int count; 55}; 56 57struct 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 66static 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 77static 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 */ 90static 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 */ 100static 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 */ 121static 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 */ 150static 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 */ 187UINT 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 */ 272static 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 */ 353static 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 364struct extract_cab_ctx 365{ 366 const WCHAR *src; 367 const WCHAR *dst; 368}; 369 370static UINT WINAPI extract_cab_cb( void *arg, UINT message, UINT_PTR param1, UINT_PTR param2 ) 371{ 372 struct extract_cab_ctx *ctx = arg; 373 374 switch (message) 375 { 376 case SPFILENOTIFY_FILEINCABINET: 377 { 378 FILE_IN_CABINET_INFO_W *info = (FILE_IN_CABINET_INFO_W *)param1; 379 const WCHAR *filename; 380 381 if ((filename = strrchrW( info->NameInCabinet, '\\' ))) 382 filename++; 383 else 384 filename = info->NameInCabinet; 385 386 if (lstrcmpiW( filename, ctx->src )) 387 return FILEOP_SKIP; 388 389 strcpyW( info->FullTargetName, ctx->dst ); 390 return FILEOP_DOIT; 391 } 392 case SPFILENOTIFY_FILEEXTRACTED: 393 { 394 const FILEPATHS_W *paths = (const FILEPATHS_W *)param1; 395 return paths->Win32Error; 396 } 397 case SPFILENOTIFY_NEEDNEWCABINET: 398 { 399 const CABINET_INFO_W *info = (const CABINET_INFO_W *)param1; 400 strcpyW( (WCHAR *)param2, info->CabinetPath ); 401 return ERROR_SUCCESS; 402 } 403 case SPFILENOTIFY_CABINETINFO: 404 return 0; 405 default: 406 FIXME("Unexpected message %#x.\n", message); 407 return 0; 408 } 409} 410 411/*********************************************************************** 412 * extract_cabinet_file 413 * 414 * Extract a file from a .cab file. 415 */ 416static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root, 417 const WCHAR *src, const WCHAR *dst ) 418{ 419#ifndef __REACTOS__ 420 static const WCHAR extW[] = {'.','c','a','b',0}; 421#endif 422 static const WCHAR backslashW[] = {'\\',0}; 423 WCHAR path[MAX_PATH]; 424 struct extract_cab_ctx ctx = {src, dst}; 425 426#ifdef __REACTOS__ 427 TRACE("extract_cabinet_file(cab = '%s' ; root = '%s' ; src = '%s' ; dst = '%s')\n", 428 debugstr_w(cabinet), debugstr_w(root), debugstr_w(src), debugstr_w(dst)); 429#else 430 int len = strlenW( cabinet ); 431 /* make sure the cabinet file has a .cab extension */ 432 if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE; 433#endif 434 strcpyW(path, root); 435 strcatW(path, backslashW); 436 strcatW(path, cabinet); 437 438 return SetupIterateCabinetW( path, 0, extract_cab_cb, &ctx ); 439} 440 441 442/*********************************************************************** 443 * SetupOpenFileQueue (SETUPAPI.@) 444 */ 445HSPFILEQ WINAPI SetupOpenFileQueue(void) 446{ 447 struct file_queue *queue; 448 449 if (!(queue = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*queue)))) 450 return INVALID_HANDLE_VALUE; 451 return queue; 452} 453 454 455/*********************************************************************** 456 * SetupCloseFileQueue (SETUPAPI.@) 457 */ 458BOOL WINAPI SetupCloseFileQueue( HSPFILEQ handle ) 459{ 460 struct file_queue *queue = handle; 461 462 free_file_op_queue( &queue->copy_queue ); 463 free_file_op_queue( &queue->rename_queue ); 464 free_file_op_queue( &queue->delete_queue ); 465 HeapFree( GetProcessHeap(), 0, queue ); 466 return TRUE; 467} 468 469 470/*********************************************************************** 471 * SetupQueueCopyIndirectA (SETUPAPI.@) 472 */ 473BOOL WINAPI SetupQueueCopyIndirectA( PSP_FILE_COPY_PARAMS_A params ) 474{ 475 struct file_queue *queue = params->QueueHandle; 476 struct file_op *op; 477 478 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; 479 op->style = params->CopyStyle; 480 op->src_root = strdupAtoW( params->SourceRootPath ); 481 op->src_path = strdupAtoW( params->SourcePath ); 482 op->src_file = strdupAtoW( params->SourceFilename ); 483 op->src_descr = strdupAtoW( params->SourceDescription ); 484 op->src_tag = strdupAtoW( params->SourceTagfile ); 485 op->dst_path = strdupAtoW( params->TargetDirectory ); 486 op->dst_file = strdupAtoW( params->TargetFilename ); 487 op->dst_sd = NULL; 488 489 /* some defaults */ 490 if (!op->src_file) op->src_file = op->dst_file; 491 if (params->LayoutInf) 492 { 493 get_src_file_info( params->LayoutInf, op ); 494 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file ); 495 } 496 497 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", 498 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), 499 debugstr_w(op->dst_path), debugstr_w(op->dst_file), 500 debugstr_w(op->src_descr), debugstr_w(op->src_tag) ); 501 502 queue_file_op( &queue->copy_queue, op ); 503 return TRUE; 504} 505 506 507/*********************************************************************** 508 * SetupQueueCopyIndirectW (SETUPAPI.@) 509 */ 510BOOL WINAPI SetupQueueCopyIndirectW( PSP_FILE_COPY_PARAMS_W params ) 511{ 512 struct file_queue *queue = params->QueueHandle; 513 struct file_op *op; 514 515 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; 516 op->style = params->CopyStyle; 517 op->src_root = strdupW( params->SourceRootPath ); 518 op->src_path = strdupW( params->SourcePath ); 519 op->src_file = strdupW( params->SourceFilename ); 520 op->src_descr = strdupW( params->SourceDescription ); 521 op->src_tag = strdupW( params->SourceTagfile ); 522 op->dst_path = strdupW( params->TargetDirectory ); 523 op->dst_file = strdupW( params->TargetFilename ); 524 op->dst_sd = NULL; 525 if (params->SecurityDescriptor) 526 ConvertStringSecurityDescriptorToSecurityDescriptorW( params->SecurityDescriptor, SDDL_REVISION_1, &op->dst_sd, NULL ); 527 528 /* some defaults */ 529 if (!op->src_file) op->src_file = op->dst_file; 530 if (params->LayoutInf) 531 { 532 get_src_file_info( params->LayoutInf, op ); 533 if (!op->dst_path) op->dst_path = get_destination_dir( params->LayoutInf, op->dst_file ); 534 } 535 536 TRACE( "root=%s path=%s file=%s -> dir=%s file=%s descr=%s tag=%s\n", 537 debugstr_w(op->src_root), debugstr_w(op->src_path), debugstr_w(op->src_file), 538 debugstr_w(op->dst_path), debugstr_w(op->dst_file), 539 debugstr_w(op->src_descr), debugstr_w(op->src_tag) ); 540 541 queue_file_op( &queue->copy_queue, op ); 542 return TRUE; 543} 544 545 546/*********************************************************************** 547 * SetupQueueCopyA (SETUPAPI.@) 548 */ 549BOOL WINAPI SetupQueueCopyA( HSPFILEQ queue, PCSTR src_root, PCSTR src_path, PCSTR src_file, 550 PCSTR src_descr, PCSTR src_tag, PCSTR dst_dir, PCSTR dst_file, 551 DWORD style ) 552{ 553 SP_FILE_COPY_PARAMS_A params; 554 555 params.cbSize = sizeof(params); 556 params.QueueHandle = queue; 557 params.SourceRootPath = src_root; 558 params.SourcePath = src_path; 559 params.SourceFilename = src_file; 560 params.SourceDescription = src_descr; 561 params.SourceTagfile = src_tag; 562 params.TargetDirectory = dst_dir; 563 params.TargetFilename = dst_file; 564 params.CopyStyle = style; 565 params.LayoutInf = 0; 566 params.SecurityDescriptor = NULL; 567 return SetupQueueCopyIndirectA( &params ); 568} 569 570 571/*********************************************************************** 572 * SetupQueueCopyW (SETUPAPI.@) 573 */ 574BOOL WINAPI SetupQueueCopyW( HSPFILEQ queue, PCWSTR src_root, PCWSTR src_path, PCWSTR src_file, 575 PCWSTR src_descr, PCWSTR src_tag, PCWSTR dst_dir, PCWSTR dst_file, 576 DWORD style ) 577{ 578 SP_FILE_COPY_PARAMS_W params; 579 580 params.cbSize = sizeof(params); 581 params.QueueHandle = queue; 582 params.SourceRootPath = src_root; 583 params.SourcePath = src_path; 584 params.SourceFilename = src_file; 585 params.SourceDescription = src_descr; 586 params.SourceTagfile = src_tag; 587 params.TargetDirectory = dst_dir; 588 params.TargetFilename = dst_file; 589 params.CopyStyle = style; 590 params.LayoutInf = 0; 591 params.SecurityDescriptor = NULL; 592 return SetupQueueCopyIndirectW( &params ); 593} 594 595 596/*********************************************************************** 597 * SetupQueueDefaultCopyA (SETUPAPI.@) 598 */ 599BOOL WINAPI SetupQueueDefaultCopyA( HSPFILEQ queue, HINF hinf, PCSTR src_root, PCSTR src_file, 600 PCSTR dst_file, DWORD style ) 601{ 602 SP_FILE_COPY_PARAMS_A params; 603 604 params.cbSize = sizeof(params); 605 params.QueueHandle = queue; 606 params.SourceRootPath = src_root; 607 params.SourcePath = NULL; 608 params.SourceFilename = src_file; 609 params.SourceDescription = NULL; 610 params.SourceTagfile = NULL; 611 params.TargetDirectory = NULL; 612 params.TargetFilename = dst_file; 613 params.CopyStyle = style; 614 params.LayoutInf = hinf; 615 params.SecurityDescriptor = NULL; 616 return SetupQueueCopyIndirectA( &params ); 617} 618 619 620/*********************************************************************** 621 * SetupQueueDefaultCopyW (SETUPAPI.@) 622 */ 623BOOL WINAPI SetupQueueDefaultCopyW( HSPFILEQ queue, HINF hinf, PCWSTR src_root, PCWSTR src_file, 624 PCWSTR dst_file, 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 = NULL; 632 params.SourceFilename = src_file; 633 params.SourceDescription = NULL; 634 params.SourceTagfile = NULL; 635 params.TargetDirectory = NULL; 636 params.TargetFilename = dst_file; 637 params.CopyStyle = style; 638 params.LayoutInf = hinf; 639 params.SecurityDescriptor = NULL; 640 return SetupQueueCopyIndirectW( &params ); 641} 642 643 644/*********************************************************************** 645 * SetupQueueDeleteA (SETUPAPI.@) 646 */ 647BOOL WINAPI SetupQueueDeleteA( HSPFILEQ handle, PCSTR part1, PCSTR part2 ) 648{ 649 struct file_queue *queue = handle; 650 struct file_op *op; 651 652 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; 653 op->style = 0; 654 op->src_root = NULL; 655 op->src_path = NULL; 656 op->src_file = NULL; 657 op->src_descr = NULL; 658 op->src_tag = NULL; 659 op->dst_path = strdupAtoW( part1 ); 660 op->dst_file = strdupAtoW( part2 ); 661 op->dst_sd = NULL; 662 queue_file_op( &queue->delete_queue, op ); 663 return TRUE; 664} 665 666 667/*********************************************************************** 668 * SetupQueueDeleteW (SETUPAPI.@) 669 */ 670BOOL WINAPI SetupQueueDeleteW( HSPFILEQ handle, PCWSTR part1, PCWSTR part2 ) 671{ 672 struct file_queue *queue = handle; 673 struct file_op *op; 674 675 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; 676 op->style = 0; 677 op->src_root = NULL; 678 op->src_path = NULL; 679 op->src_file = NULL; 680 op->src_descr = NULL; 681 op->src_tag = NULL; 682 op->dst_path = strdupW( part1 ); 683 op->dst_file = strdupW( part2 ); 684 op->dst_sd = NULL; 685 queue_file_op( &queue->delete_queue, op ); 686 return TRUE; 687} 688 689 690/*********************************************************************** 691 * SetupQueueRenameA (SETUPAPI.@) 692 */ 693BOOL WINAPI SetupQueueRenameA( HSPFILEQ handle, PCSTR SourcePath, PCSTR SourceFilename, 694 PCSTR TargetPath, PCSTR TargetFilename ) 695{ 696 struct file_queue *queue = handle; 697 struct file_op *op; 698 699 if (!(op = HeapAlloc( GetProcessHeap(), 0, sizeof(*op) ))) return FALSE; 700 op->style = 0; 701 op->src_root = NULL; 702 op->src_path = strdupAtoW( SourcePath ); 703 op->src_file = strdupAtoW( SourceFilename ); 704 op->src_descr = NULL; 705 op->src_tag = NULL; 706 op->dst_path = strdupAtoW( TargetPath ); 707 op->dst_file = strdupAtoW( TargetFilename ); 708 op->dst_sd = NULL; 709 queue_file_op( &queue->rename_queue, op ); 710 return TRUE; 711} 712 713 714/*********************************************************************** 715 * SetupQueueRenameW (SETUPAPI.@) 716 */ 717BOOL WINAPI SetupQueueRenameW( HSPFILEQ handle, PCWSTR SourcePath, PCWSTR SourceFilename, 718 PCWSTR TargetPath, PCWSTR TargetFilename ) 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 = strdupW( SourcePath ); 727 op->src_file = strdupW( SourceFilename ); 728 op->src_descr = NULL; 729 op->src_tag = NULL; 730 op->dst_path = strdupW( TargetPath ); 731 op->dst_file = strdupW( TargetFilename ); 732 op->dst_sd = NULL; 733 queue_file_op( &queue->rename_queue, op ); 734 return TRUE; 735} 736 737 738/*********************************************************************** 739 * SetupQueueCopySectionA (SETUPAPI.@) 740 */ 741BOOL WINAPI SetupQueueCopySectionA( HSPFILEQ queue, PCSTR src_root, HINF hinf, HINF hlist, 742 PCSTR section, DWORD style ) 743{ 744 UNICODE_STRING sectionW; 745 BOOL ret = FALSE; 746 747 if (!RtlCreateUnicodeStringFromAsciiz( &sectionW, section )) 748 { 749 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 750 return FALSE; 751 } 752 if (!src_root) 753 ret = SetupQueueCopySectionW( queue, NULL, hinf, hlist, sectionW.Buffer, style ); 754 else 755 { 756 UNICODE_STRING srcW; 757 if (RtlCreateUnicodeStringFromAsciiz( &srcW, src_root )) 758 { 759 ret = SetupQueueCopySectionW( queue, srcW.Buffer, hinf, hlist, sectionW.Buffer, style ); 760 RtlFreeUnicodeString( &srcW ); 761 } 762 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 763 } 764 RtlFreeUnicodeString( &sectionW ); 765 return ret; 766} 767 768 769/*********************************************************************** 770 * SetupQueueCopySectionW (SETUPAPI.@) 771 */ 772BOOL WINAPI SetupQueueCopySectionW( HSPFILEQ queue, PCWSTR src_root, HINF hinf, HINF hlist, 773 PCWSTR section, DWORD style ) 774{ 775 SP_FILE_COPY_PARAMS_W params; 776 LPWSTR security_key, security_descriptor = NULL; 777 INFCONTEXT context, security_context; 778 WCHAR dest[MAX_PATH], src[MAX_PATH]; 779 INT flags; 780 DWORD required; 781 BOOL ret; 782 783 TRACE( "hinf=%p/%p section=%s root=%s\n", 784 hinf, hlist, debugstr_w(section), debugstr_w(src_root) ); 785 786 /* Check for .Security section */ 787 security_key = MyMalloc( (strlenW( section ) + strlenW( DotSecurity )) * sizeof(WCHAR) + sizeof(UNICODE_NULL) ); 788 if (!security_key) 789 { 790 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 791 return FALSE; 792 } 793 strcpyW( security_key, section ); 794 strcatW( security_key, DotSecurity ); 795 ret = SetupFindFirstLineW( hinf, security_key, NULL, &security_context ); 796 MyFree(security_key); 797 if (ret) 798 { 799 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, NULL, 0, &required )) 800 return FALSE; 801 security_descriptor = MyMalloc( required * sizeof(WCHAR) ); 802 if (!security_descriptor) 803 { 804 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 805 return FALSE; 806 } 807 if (!SetupGetLineTextW( &security_context, NULL, NULL, NULL, security_descriptor, required, NULL )) 808 { 809 MyFree( security_descriptor ); 810 return FALSE; 811 } 812 } 813 814 params.cbSize = sizeof(params); 815 params.QueueHandle = queue; 816 params.SourceRootPath = src_root; 817 params.SourcePath = NULL; 818 params.SourceDescription = NULL; 819 params.SourceTagfile = NULL; 820 params.TargetFilename = dest; 821 params.CopyStyle = style; 822 params.LayoutInf = hinf; 823 params.SecurityDescriptor = security_descriptor; 824 825 ret = FALSE; 826 if (!hlist) hlist = hinf; 827 if (!hinf) hinf = hlist; 828 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) goto done; 829 if (!(params.TargetDirectory = get_destination_dir( hinf, section ))) goto done; 830 do 831 { 832 if (!SetupGetStringFieldW( &context, 1, dest, sizeof(dest)/sizeof(WCHAR), NULL )) 833 goto done; 834 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) *src = 0; 835 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; /* FIXME */ 836 837 params.SourceFilename = *src ? src : NULL; 838 if (!SetupQueueCopyIndirectW( &params )) goto done; 839 } while (SetupFindNextLine( &context, &context )); 840 ret = TRUE; 841 842done: 843 if (security_descriptor) 844 MyFree( security_descriptor ); 845 return ret; 846} 847 848 849/*********************************************************************** 850 * SetupQueueDeleteSectionA (SETUPAPI.@) 851 */ 852BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section ) 853{ 854 UNICODE_STRING sectionW; 855 BOOL ret = FALSE; 856 857 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section )) 858 { 859 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer ); 860 RtlFreeUnicodeString( &sectionW ); 861 } 862 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 863 return ret; 864} 865 866 867/*********************************************************************** 868 * SetupQueueDeleteSectionW (SETUPAPI.@) 869 */ 870BOOL WINAPI SetupQueueDeleteSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section ) 871{ 872 INFCONTEXT context; 873 WCHAR *dest_dir; 874 WCHAR buffer[MAX_PATH]; 875 BOOL ret = FALSE; 876 INT flags; 877 878 TRACE( "hinf=%p/%p section=%s\n", hinf, hlist, debugstr_w(section) ); 879 880 if (!hlist) hlist = hinf; 881 if (!SetupFindFirstLineW( hlist, section, NULL, &context )) return FALSE; 882 if (!(dest_dir = get_destination_dir( hinf, section ))) return FALSE; 883 do 884 { 885 if (!SetupGetStringFieldW( &context, 1, buffer, sizeof(buffer)/sizeof(WCHAR), NULL )) 886 goto done; 887 if (!SetupGetIntField( &context, 4, &flags )) flags = 0; 888 if (!SetupQueueDeleteW( queue, dest_dir, buffer )) goto done; 889 } while (SetupFindNextLine( &context, &context )); 890 891 ret = TRUE; 892 done: 893 HeapFree( GetProcessHeap(), 0, dest_dir ); 894 return ret; 895} 896 897 898/*********************************************************************** 899 * SetupQueueRenameSectionA (SETUPAPI.@) 900 */ 901BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section ) 902{ 903 UNICODE_STRING sectionW; 904 BOOL ret = FALSE; 905 906 if (RtlCreateUnicodeStringFromAsciiz( &sectionW, section )) 907 { 908 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer ); 909 RtlFreeUnicodeString( &sectionW ); 910 } 911 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 912 return ret; 913} 914 915 916/*********************************************************************** 917 * SetupQueueRenameSectionW (SETUPAPI.@) 918 */ 919BOOL WINAPI SetupQueueRenameSectionW( HSPFILEQ queue, HINF hinf, HINF hlist, PCWSTR section ) 920{ 921 INFCONTEXT context; 922 WCHAR *dest_dir; 923 WCHAR src[MAX_PATH], dst[MAX_PATH]; 924 BOOL ret = FALSE; 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, dst, sizeof(dst)/sizeof(WCHAR), NULL )) 934 goto done; 935 if (!SetupGetStringFieldW( &context, 2, src, sizeof(src)/sizeof(WCHAR), NULL )) 936 goto done; 937 if (!SetupQueueRenameW( queue, dest_dir, src, NULL, dst )) goto done; 938 } while (SetupFindNextLine( &context, &context )); 939 940 ret = TRUE; 941 done: 942 HeapFree( GetProcessHeap(), 0, dest_dir ); 943 return ret; 944} 945 946 947/*********************************************************************** 948 * SetupCommitFileQueueA (SETUPAPI.@) 949 */ 950BOOL WINAPI SetupCommitFileQueueA( HWND owner, HSPFILEQ queue, PSP_FILE_CALLBACK_A handler, 951 PVOID context ) 952{ 953 struct callback_WtoA_context ctx; 954 955 ctx.orig_context = context; 956 ctx.orig_handler = handler; 957 return SetupCommitFileQueueW( owner, queue, QUEUE_callback_WtoA, &ctx ); 958} 959 960 961/*********************************************************************** 962 * create_full_pathW 963 * 964 * Recursively create all directories in the path. 965 */ 966static BOOL create_full_pathW(const WCHAR *path) 967{ 968 BOOL ret = TRUE; 969 int len; 970 WCHAR *new_path; 971 972 new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * sizeof(WCHAR)); 973 strcpyW(new_path, path); 974 975 while((len = strlenW(new_path)) && new_path[len - 1] == '\\') 976 new_path[len - 1] = 0; 977 978 while(!CreateDirectoryW(new_path, NULL)) 979 { 980 WCHAR *slash; 981 DWORD last_error = GetLastError(); 982 983 if(last_error == ERROR_ALREADY_EXISTS) 984 break; 985 986 if(last_error != ERROR_PATH_NOT_FOUND) 987 { 988 ret = FALSE; 989 break; 990 } 991 992 if(!(slash = strrchrW(new_path, '\\'))) 993 { 994 ret = FALSE; 995 break; 996 } 997 998 len = slash - new_path; 999 new_path[len] = 0; 1000 if(!create_full_pathW(new_path)) 1001 { 1002 ret = FALSE; 1003 break; 1004 } 1005 new_path[len] = '\\'; 1006 } 1007 1008 HeapFree(GetProcessHeap(), 0, new_path); 1009 return ret; 1010} 1011 1012static BOOL do_file_copyW( LPCWSTR source, LPCWSTR target, DWORD style, 1013 PSP_FILE_CALLBACK_W handler, PVOID context ) 1014{ 1015 BOOL rc = FALSE; 1016 BOOL docopy = TRUE; 1017#ifdef __REACTOS__ 1018 INT hSource, hTemp; 1019 OFSTRUCT OfStruct; 1020 WCHAR TempPath[MAX_PATH]; 1021 WCHAR TempFile[MAX_PATH]; 1022 LONG lRes; 1023 DWORD dwLastError; 1024#endif 1025 1026 TRACE("copy %s to %s style 0x%x\n",debugstr_w(source),debugstr_w(target),style); 1027 1028#ifdef __REACTOS__ 1029 /* Get a temp file name */ 1030 if (!GetTempPathW(ARRAYSIZE(TempPath), TempPath)) 1031 { 1032 ERR("GetTempPathW error\n"); 1033 return FALSE; 1034 } 1035 1036 /* Try to open the source file */ 1037 hSource = LZOpenFileW((LPWSTR)source, &OfStruct, OF_READ); 1038 if (hSource < 0) 1039 { 1040 TRACE("LZOpenFileW(1) error %d %s\n", (int)hSource, debugstr_w(source)); 1041 return FALSE; 1042 } 1043 1044 if (!GetTempFileNameW(TempPath, L"", 0, TempFile)) 1045 { 1046 dwLastError = GetLastError(); 1047 1048 ERR("GetTempFileNameW(%s) error\n", debugstr_w(TempPath)); 1049 1050 /* Close the source handle */ 1051 LZClose(hSource); 1052 1053 /* Restore error condition triggered by GetTempFileNameW */ 1054 SetLastError(dwLastError); 1055 1056 return FALSE; 1057 } 1058 1059 /* Extract the compressed file to a temp location */ 1060 hTemp = LZOpenFileW(TempFile, &OfStruct, OF_CREATE); 1061 if (hTemp < 0) 1062 { 1063 dwLastError = GetLastError(); 1064 1065 ERR("LZOpenFileW(2) error %d %s\n", (int)hTemp, debugstr_w(TempFile)); 1066 1067 /* Close the source handle */ 1068 LZClose(hSource); 1069 1070 /* Delete temp file if an error is signaled */ 1071 DeleteFileW(TempFile); 1072 1073 /* Restore error condition triggered by LZOpenFileW */ 1074 SetLastError(dwLastError); 1075 1076 return FALSE; 1077 } 1078 1079 lRes = LZCopy(hSource, hTemp); 1080 1081 dwLastError = GetLastError(); 1082 1083 LZClose(hSource); 1084 LZClose(hTemp); 1085 1086 if (lRes < 0) 1087 { 1088 ERR("LZCopy error %d (%s, %s)\n", (int)lRes, debugstr_w(source), debugstr_w(TempFile)); 1089 1090 /* Delete temp file if copy was not successful */ 1091 DeleteFileW(TempFile); 1092 1093 /* Restore error condition triggered by LZCopy */ 1094 SetLastError(dwLastError); 1095 1096 return FALSE; 1097 } 1098#endif 1099 1100 /* before copy processing */ 1101 if (style & SP_COPY_REPLACEONLY) 1102 { 1103 if (GetFileAttributesW(target) == INVALID_FILE_ATTRIBUTES) 1104 docopy = FALSE; 1105 } 1106 if (style & (SP_COPY_NEWER_OR_SAME | SP_COPY_NEWER_ONLY | SP_COPY_FORCE_NEWER)) 1107 { 1108 DWORD VersionSizeSource=0; 1109 DWORD VersionSizeTarget=0; 1110 DWORD zero=0; 1111 1112 /* 1113 * This is sort of an interesting workaround. You see, calling 1114 * GetVersionInfoSize on a builtin dll loads that dll into memory 1115 * and we do not properly unload builtin dlls.. so we effectively 1116 * lock into memory all the targets we are replacing. This leads 1117 * to problems when we try to register the replaced dlls. 1118 * 1119 * So I will test for the existence of the files first so that 1120 * we just basically unconditionally replace the builtin versions. 1121 */ 1122 if ((GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) && 1123 (GetFileAttributesW(TempFile) != INVALID_FILE_ATTRIBUTES)) 1124 { 1125 VersionSizeSource = GetFileVersionInfoSizeW(TempFile,&zero); 1126 VersionSizeTarget = GetFileVersionInfoSizeW((LPWSTR)target,&zero); 1127 } 1128 1129 TRACE("SizeTarget %i ... SizeSource %i\n",VersionSizeTarget, 1130 VersionSizeSource); 1131 1132 if (VersionSizeSource && VersionSizeTarget) 1133 { 1134 LPVOID VersionSource; 1135 LPVOID VersionTarget; 1136 VS_FIXEDFILEINFO *TargetInfo; 1137 VS_FIXEDFILEINFO *SourceInfo; 1138 UINT length; 1139 WCHAR SubBlock[2]={'\\',0}; 1140 DWORD ret; 1141 1142 VersionSource = HeapAlloc(GetProcessHeap(),0,VersionSizeSource); 1143 VersionTarget = HeapAlloc(GetProcessHeap(),0,VersionSizeTarget); 1144 1145 ret = GetFileVersionInfoW(TempFile,0,VersionSizeSource,VersionSource); 1146 if (ret) 1147 ret = GetFileVersionInfoW((LPWSTR)target, 0, VersionSizeTarget, 1148 VersionTarget); 1149 1150 if (ret) 1151 { 1152 ret = VerQueryValueW(VersionSource, SubBlock, 1153 (LPVOID*)&SourceInfo, &length); 1154 if (ret) 1155 ret = VerQueryValueW(VersionTarget, SubBlock, 1156 (LPVOID*)&TargetInfo, &length); 1157 1158 if (ret) 1159 { 1160 FILEPATHS_W filepaths; 1161 1162 TRACE("Versions: Source %i.%i target %i.%i\n", 1163 SourceInfo->dwFileVersionMS, SourceInfo->dwFileVersionLS, 1164 TargetInfo->dwFileVersionMS, TargetInfo->dwFileVersionLS); 1165 1166 /* used in case of notification */ 1167 filepaths.Target = target; 1168 filepaths.Source = source; 1169 filepaths.Win32Error = 0; 1170 filepaths.Flags = 0; 1171 1172 if (TargetInfo->dwFileVersionMS > SourceInfo->dwFileVersionMS) 1173 { 1174 if (handler) 1175 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0); 1176 else 1177 docopy = FALSE; 1178 } 1179 else if ((TargetInfo->dwFileVersionMS == SourceInfo->dwFileVersionMS) 1180 && (TargetInfo->dwFileVersionLS > SourceInfo->dwFileVersionLS)) 1181 { 1182 if (handler) 1183 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0); 1184 else 1185 docopy = FALSE; 1186 } 1187 else if ((style & SP_COPY_NEWER_ONLY) && 1188 (TargetInfo->dwFileVersionMS == 1189 SourceInfo->dwFileVersionMS) 1190 &&(TargetInfo->dwFileVersionLS == 1191 SourceInfo->dwFileVersionLS)) 1192 { 1193 if (handler) 1194 docopy = handler (context, SPFILENOTIFY_TARGETNEWER, (UINT_PTR)&filepaths, 0); 1195 else 1196 docopy = FALSE; 1197 } 1198 } 1199 } 1200 HeapFree(GetProcessHeap(),0,VersionSource); 1201 HeapFree(GetProcessHeap(),0,VersionTarget); 1202 } 1203 } 1204 if (style & (SP_COPY_NOOVERWRITE | SP_COPY_FORCE_NOOVERWRITE)) 1205 { 1206 if (GetFileAttributesW(target) != INVALID_FILE_ATTRIBUTES) 1207 { 1208 FIXME("Notify user target file exists\n"); 1209 docopy = FALSE; 1210 } 1211 } 1212 if (style & (SP_COPY_NODECOMP | SP_COPY_LANGUAGEAWARE | SP_COPY_FORCE_IN_USE | 1213 SP_COPY_IN_USE_NEEDS_REBOOT | SP_COPY_NOSKIP | SP_COPY_WARNIFSKIP)) 1214 { 1215 ERR("Unsupported style(s) 0x%x\n",style); 1216 } 1217 1218 if (docopy) 1219 { 1220 rc = MoveFileExW(TempFile,target,MOVEFILE_REPLACE_EXISTING); 1221 TRACE("Did copy... rc was %i\n",rc); 1222 } 1223 1224 /* after copy processing */ 1225 if (style & SP_COPY_DELETESOURCE) 1226 { 1227 if (rc) 1228 DeleteFileW(source); 1229 } 1230 1231 return rc; 1232} 1233 1234/*********************************************************************** 1235 * SetupInstallFileA (SETUPAPI.@) 1236 */ 1237BOOL WINAPI SetupInstallFileA( HINF hinf, PINFCONTEXT inf_context, PCSTR source, PCSTR root, 1238 PCSTR dest, DWORD style, PSP_FILE_CALLBACK_A handler, PVOID context ) 1239{ 1240 BOOL ret = FALSE; 1241 struct callback_WtoA_context ctx; 1242 UNICODE_STRING sourceW, rootW, destW; 1243 1244 TRACE("%p %p %s %s %s %x %p %p\n", hinf, inf_context, debugstr_a(source), debugstr_a(root), 1245 debugstr_a(dest), style, handler, context); 1246 1247 sourceW.Buffer = rootW.Buffer = destW.Buffer = NULL; 1248 if (source && !RtlCreateUnicodeStringFromAsciiz( &sourceW, source )) 1249 { 1250 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1251 return FALSE; 1252 } 1253 if (root && !RtlCreateUnicodeStringFromAsciiz( &rootW, root )) 1254 { 1255 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1256 goto exit; 1257 } 1258 if (dest && !RtlCreateUnicodeStringFromAsciiz( &destW, dest )) 1259 { 1260 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1261 goto exit; 1262 } 1263 1264 ctx.orig_context = context; 1265 ctx.orig_handler = handler; 1266 1267 ret = SetupInstallFileW( hinf, inf_context, sourceW.Buffer, rootW.Buffer, destW.Buffer, style, QUEUE_callback_WtoA, &ctx ); 1268 1269exit: 1270 RtlFreeUnicodeString( &sourceW ); 1271 RtlFreeUnicodeString( &rootW ); 1272 RtlFreeUnicodeString( &destW ); 1273 return ret; 1274} 1275 1276/*********************************************************************** 1277 * SetupInstallFileW (SETUPAPI.@) 1278 */ 1279BOOL WINAPI SetupInstallFileW( HINF hinf, PINFCONTEXT inf_context, PCWSTR source, PCWSTR root, 1280 PCWSTR dest, DWORD style, PSP_FILE_CALLBACK_W handler, PVOID context ) 1281{ 1282 static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; 1283 1284 BOOL ret, absolute = (root && *root && !(style & SP_COPY_SOURCE_ABSOLUTE)); 1285 WCHAR *buffer, *p, *inf_source = NULL; 1286 unsigned int len; 1287 1288 TRACE("%p %p %s %s %s %x %p %p\n", hinf, inf_context, debugstr_w(source), debugstr_w(root), 1289 debugstr_w(dest), style, handler, context); 1290 1291 if (hinf) 1292 { 1293 INFCONTEXT ctx; 1294 1295 if (!inf_context) 1296 { 1297 inf_context = &ctx; 1298 if (!SetupFindFirstLineW( hinf, CopyFiles, NULL, inf_context )) return FALSE; 1299 } 1300 if (!SetupGetStringFieldW( inf_context, 1, NULL, 0, (PDWORD) &len )) return FALSE; 1301 if (!(inf_source = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 1302 { 1303 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1304 return FALSE; 1305 } 1306 if (!SetupGetStringFieldW( inf_context, 1, inf_source, len, NULL )) 1307 { 1308 HeapFree( GetProcessHeap(), 0, inf_source ); 1309 return FALSE; 1310 } 1311 source = inf_source; 1312 } 1313 else if (!source) 1314 { 1315 SetLastError( ERROR_INVALID_PARAMETER ); 1316 return FALSE; 1317 } 1318 1319 len = strlenW( source ) + 1; 1320 if (absolute) len += strlenW( root ) + 1; 1321 1322 if (!(p = buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 1323 { 1324 HeapFree( GetProcessHeap(), 0, inf_source ); 1325 SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 1326 return FALSE; 1327 } 1328 1329 if (absolute) 1330 { 1331 strcpyW( buffer, root ); 1332 p += strlenW( buffer ); 1333 if (p[-1] != '\\') *p++ = '\\'; 1334 } 1335 while (*source == '\\') source++; 1336 strcpyW( p, source ); 1337 1338 ret = do_file_copyW( buffer, dest, style, handler, context ); 1339 1340 HeapFree( GetProcessHeap(), 0, inf_source ); 1341 HeapFree( GetProcessHeap(), 0, buffer ); 1342 return ret; 1343} 1344 1345/*********************************************************************** 1346 * SetupCommitFileQueueW (SETUPAPI.@) 1347 */ 1348BOOL WINAPI SetupCommitFileQueueW( HWND owner, HSPFILEQ handle, PSP_FILE_CALLBACK_W handler, 1349 PVOID context ) 1350{ 1351 struct file_queue *queue = handle; 1352 struct file_op *op; 1353 BOOL result = FALSE; 1354 FILEPATHS_W paths; 1355 UINT op_result; 1356 1357 paths.Source = paths.Target = NULL; 1358 1359 if (!queue->copy_queue.count && !queue->delete_queue.count && !queue->rename_queue.count) 1360 return TRUE; /* nothing to do */ 1361 1362 if (!handler( context, SPFILENOTIFY_STARTQUEUE, (UINT_PTR)owner, 0 )) return FALSE; 1363 1364 /* perform deletes */ 1365 1366 if (queue->delete_queue.count) 1367 { 1368 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_DELETE, 1369 queue->delete_queue.count ))) goto done; 1370 for (op = queue->delete_queue.head; op; op = op->next) 1371 { 1372 build_filepathsW( op, &paths ); 1373 op_result = handler( context, SPFILENOTIFY_STARTDELETE, (UINT_PTR)&paths, FILEOP_DELETE); 1374 if (op_result == FILEOP_ABORT) goto done; 1375 while (op_result == FILEOP_DOIT) 1376 { 1377 TRACE( "deleting file %s\n", debugstr_w(paths.Target) ); 1378 if (DeleteFileW( paths.Target )) break; /* success */ 1379 paths.Win32Error = GetLastError(); 1380 op_result = handler( context, SPFILENOTIFY_DELETEERROR, (UINT_PTR)&paths, 0 ); 1381 if (op_result == FILEOP_ABORT) goto done; 1382 } 1383 handler( context, SPFILENOTIFY_ENDDELETE, (UINT_PTR)&paths, 0 ); 1384 } 1385 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_DELETE, 0 ); 1386 } 1387 1388 /* perform renames */ 1389 1390 if (queue->rename_queue.count) 1391 { 1392 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_RENAME, 1393 queue->rename_queue.count ))) goto done; 1394 for (op = queue->rename_queue.head; op; op = op->next) 1395 { 1396 build_filepathsW( op, &paths ); 1397 op_result = handler( context, SPFILENOTIFY_STARTRENAME, (UINT_PTR)&paths, FILEOP_RENAME); 1398 if (op_result == FILEOP_ABORT) goto done; 1399 while (op_result == FILEOP_DOIT) 1400 { 1401 TRACE( "renaming file %s -> %s\n", 1402 debugstr_w(paths.Source), debugstr_w(paths.Target) ); 1403 if (MoveFileW( paths.Source, paths.Target )) break; /* success */ 1404 paths.Win32Error = GetLastError(); 1405 op_result = handler( context, SPFILENOTIFY_RENAMEERROR, (UINT_PTR)&paths, 0 ); 1406 if (op_result == FILEOP_ABORT) goto done; 1407 } 1408 handler( context, SPFILENOTIFY_ENDRENAME, (UINT_PTR)&paths, 0 ); 1409 } 1410 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_RENAME, 0 ); 1411 } 1412 1413 /* perform copies */ 1414 1415 if (queue->copy_queue.count) 1416 { 1417 if (!(handler( context, SPFILENOTIFY_STARTSUBQUEUE, FILEOP_COPY, 1418 queue->copy_queue.count ))) goto done; 1419 for (op = queue->copy_queue.head; op; op = op->next) 1420 { 1421 WCHAR newpath[MAX_PATH]; 1422 1423 build_filepathsW( op, &paths ); 1424 op_result = handler( context, SPFILENOTIFY_STARTCOPY, (UINT_PTR)&paths, FILEOP_COPY ); 1425 if (op_result == FILEOP_ABORT) goto done; 1426 if (op_result == FILEOP_NEWPATH) op_result = FILEOP_DOIT; 1427 while (op_result == FILEOP_DOIT || op_result == FILEOP_NEWPATH) 1428 { 1429 TRACE( "copying file %s -> %s\n", 1430 debugstr_w( op_result == FILEOP_NEWPATH ? newpath : paths.Source ), 1431 debugstr_w(paths.Target) ); 1432 if (op->dst_path) 1433 { 1434 if (!create_full_pathW( op->dst_path )) 1435 { 1436 paths.Win32Error = GetLastError(); 1437 op_result = handler( context, SPFILENOTIFY_COPYERROR, 1438 (UINT_PTR)&paths, (UINT_PTR)newpath ); 1439 if (op_result == FILEOP_ABORT) goto done; 1440 } 1441 } 1442 if (do_file_copyW( op_result == FILEOP_NEWPATH ? newpath : paths.Source, 1443 paths.Target, op->style, handler, context )) break; /* success */ 1444 /* try to extract it from the cabinet file */ 1445 if (op->src_tag) 1446 { 1447 if (extract_cabinet_file( op->src_tag, op->src_root, 1448 op->src_file, paths.Target )) break; 1449 } 1450 paths.Win32Error = GetLastError(); 1451 op_result = handler( context, SPFILENOTIFY_COPYERROR, 1452 (UINT_PTR)&paths, (UINT_PTR)newpath ); 1453 if (op_result == FILEOP_ABORT) goto done; 1454 } 1455 if (op->dst_sd) 1456 { 1457 PSID psidOwner = NULL, psidGroup = NULL; 1458 PACL pDacl = NULL, pSacl = NULL; 1459 SECURITY_INFORMATION security_info = 0; 1460 BOOL present, dummy; 1461 1462 if (GetSecurityDescriptorOwner( op->dst_sd, &psidOwner, &dummy ) && psidOwner) 1463 security_info |= OWNER_SECURITY_INFORMATION; 1464 if (GetSecurityDescriptorGroup( op->dst_sd, &psidGroup, &dummy ) && psidGroup) 1465 security_info |= GROUP_SECURITY_INFORMATION; 1466 if (GetSecurityDescriptorDacl( op->dst_sd, &present, &pDacl, &dummy )) 1467 security_info |= DACL_SECURITY_INFORMATION; 1468 if (GetSecurityDescriptorSacl( op->dst_sd, &present, &pSacl, &dummy )) 1469 security_info |= DACL_SECURITY_INFORMATION; 1470 SetNamedSecurityInfoW( (LPWSTR)paths.Target, SE_FILE_OBJECT, security_info, 1471 psidOwner, psidGroup, pDacl, pSacl ); 1472 /* Yes, ignore the return code... */ 1473 } 1474 handler( context, SPFILENOTIFY_ENDCOPY, (UINT_PTR)&paths, 0 ); 1475 } 1476 handler( context, SPFILENOTIFY_ENDSUBQUEUE, FILEOP_COPY, 0 ); 1477 } 1478 1479 1480 result = TRUE; 1481 1482 done: 1483 handler( context, SPFILENOTIFY_ENDQUEUE, result, 0 ); 1484 HeapFree( GetProcessHeap(), 0, (void *)paths.Source ); 1485 HeapFree( GetProcessHeap(), 0, (void *)paths.Target ); 1486 return result; 1487} 1488 1489 1490/*********************************************************************** 1491 * SetupScanFileQueueA (SETUPAPI.@) 1492 */ 1493BOOL WINAPI SetupScanFileQueueA( HSPFILEQ handle, DWORD flags, HWND window, 1494 PSP_FILE_CALLBACK_A handler, PVOID context, PDWORD result ) 1495{ 1496 struct callback_WtoA_context ctx; 1497 1498 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result); 1499 1500 ctx.orig_context = context; 1501 ctx.orig_handler = handler; 1502 1503 return SetupScanFileQueueW( handle, flags, window, QUEUE_callback_WtoA, &ctx, result ); 1504} 1505 1506 1507/*********************************************************************** 1508 * SetupScanFileQueueW (SETUPAPI.@) 1509 */ 1510BOOL WINAPI SetupScanFileQueueW( HSPFILEQ handle, DWORD flags, HWND window, 1511 PSP_FILE_CALLBACK_W handler, PVOID context, PDWORD result ) 1512{ 1513 struct file_queue *queue = handle; 1514 struct file_op *op; 1515 FILEPATHS_W paths; 1516 UINT notification = 0; 1517 BOOL ret = FALSE; 1518 1519 TRACE("%p %x %p %p %p %p\n", handle, flags, window, handler, context, result); 1520 1521 *result = FALSE; 1522 1523 if (!queue->copy_queue.count) return TRUE; 1524 1525 if (flags & SPQ_SCAN_USE_CALLBACK) notification = SPFILENOTIFY_QUEUESCAN; 1526 else if (flags & SPQ_SCAN_USE_CALLBACKEX) notification = SPFILENOTIFY_QUEUESCAN_EX; 1527 1528 if (flags & ~(SPQ_SCAN_USE_CALLBACK | SPQ_SCAN_USE_CALLBACKEX)) 1529 { 1530 FIXME("flags %x not fully implemented\n", flags); 1531 } 1532 1533 paths.Source = paths.Target = NULL; 1534 1535 for (op = queue->copy_queue.head; op; op = op->next) 1536 { 1537 build_filepathsW( op, &paths ); 1538 switch (notification) 1539 { 1540 case SPFILENOTIFY_QUEUESCAN: 1541 /* FIXME: handle delay flag */ 1542 if (handler( context, notification, (UINT_PTR)paths.Target, 0 )) goto done; 1543 break; 1544 case SPFILENOTIFY_QUEUESCAN_EX: 1545 if (handler( context, notification, (UINT_PTR)&paths, 0 )) goto done; 1546 break; 1547 default: 1548 ret = TRUE; goto done; 1549 } 1550 } 1551 1552 *result = TRUE; 1553 1554 done: 1555 HeapFree( GetProcessHeap(), 0, (void *)paths.Source ); 1556 HeapFree( GetProcessHeap(), 0, (void *)paths.Target ); 1557 return ret; 1558} 1559 1560 1561/*********************************************************************** 1562 * SetupGetFileQueueCount (SETUPAPI.@) 1563 */ 1564BOOL WINAPI SetupGetFileQueueCount( HSPFILEQ handle, UINT op, PUINT result ) 1565{ 1566 struct file_queue *queue = handle; 1567 1568 switch(op) 1569 { 1570 case FILEOP_COPY: 1571 *result = queue->copy_queue.count; 1572 return TRUE; 1573 case FILEOP_RENAME: 1574 *result = queue->rename_queue.count; 1575 return TRUE; 1576 case FILEOP_DELETE: 1577 *result = queue->delete_queue.count; 1578 return TRUE; 1579 } 1580 return FALSE; 1581} 1582 1583 1584/*********************************************************************** 1585 * SetupGetFileQueueFlags (SETUPAPI.@) 1586 */ 1587BOOL WINAPI SetupGetFileQueueFlags( HSPFILEQ handle, PDWORD flags ) 1588{ 1589 struct file_queue *queue = handle; 1590 *flags = queue->flags; 1591 return TRUE; 1592} 1593 1594 1595/*********************************************************************** 1596 * SetupSetFileQueueFlags (SETUPAPI.@) 1597 */ 1598BOOL WINAPI SetupSetFileQueueFlags( HSPFILEQ handle, DWORD mask, DWORD flags ) 1599{ 1600 struct file_queue *queue = handle; 1601 queue->flags = (queue->flags & ~mask) | flags; 1602 return TRUE; 1603} 1604 1605 1606/*********************************************************************** 1607 * SetupSetFileQueueAlternatePlatformA (SETUPAPI.@) 1608 */ 1609BOOL WINAPI SetupSetFileQueueAlternatePlatformA(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCSTR catalogfile) 1610{ 1611 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_a(catalogfile)); 1612 return FALSE; 1613} 1614 1615 1616/*********************************************************************** 1617 * SetupSetFileQueueAlternatePlatformW (SETUPAPI.@) 1618 */ 1619BOOL WINAPI SetupSetFileQueueAlternatePlatformW(HSPFILEQ handle, PSP_ALTPLATFORM_INFO platform, PCWSTR catalogfile) 1620{ 1621 FIXME("(%p, %p, %s) stub!\n", handle, platform, debugstr_w(catalogfile)); 1622 return FALSE; 1623} 1624 1625 1626/*********************************************************************** 1627 * SetupInitDefaultQueueCallback (SETUPAPI.@) 1628 */ 1629PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner ) 1630{ 1631 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL ); 1632} 1633 1634 1635/*********************************************************************** 1636 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@) 1637 */ 1638PVOID WINAPI SetupInitDefaultQueueCallbackEx( HWND owner, HWND progress, UINT msg, 1639 DWORD reserved1, PVOID reserved2 ) 1640{ 1641 struct default_callback_context *context; 1642 1643 if ((context = HeapAlloc( GetProcessHeap(), 0, sizeof(*context) ))) 1644 { 1645 context->owner = owner; 1646 context->progress = progress; 1647 context->message = msg; 1648 } 1649 return context; 1650} 1651 1652 1653/*********************************************************************** 1654 * SetupTermDefaultQueueCallback (SETUPAPI.@) 1655 */ 1656void WINAPI SetupTermDefaultQueueCallback( PVOID context ) 1657{ 1658 HeapFree( GetProcessHeap(), 0, context ); 1659} 1660 1661 1662/*********************************************************************** 1663 * SetupDefaultQueueCallbackA (SETUPAPI.@) 1664 */ 1665UINT WINAPI SetupDefaultQueueCallbackA( PVOID context, UINT notification, 1666 UINT_PTR param1, UINT_PTR param2 ) 1667{ 1668 FILEPATHS_A *paths = (FILEPATHS_A *)param1; 1669 struct default_callback_context *ctx = (struct default_callback_context *)context; 1670 1671 switch(notification) 1672 { 1673 case SPFILENOTIFY_STARTQUEUE: 1674 TRACE( "start queue\n" ); 1675 return TRUE; 1676 case SPFILENOTIFY_ENDQUEUE: 1677 TRACE( "end queue\n" ); 1678 return 0; 1679 case SPFILENOTIFY_STARTSUBQUEUE: 1680 TRACE( "start subqueue %ld count %ld\n", param1, param2 ); 1681 return TRUE; 1682 case SPFILENOTIFY_ENDSUBQUEUE: 1683 TRACE( "end subqueue %ld\n", param1 ); 1684 return 0; 1685 case SPFILENOTIFY_STARTDELETE: 1686 TRACE( "start delete %s\n", debugstr_a(paths->Target) ); 1687 return FILEOP_DOIT; 1688 case SPFILENOTIFY_ENDDELETE: 1689 TRACE( "end delete %s\n", debugstr_a(paths->Target) ); 1690 return 0; 1691 case SPFILENOTIFY_DELETEERROR: 1692 /*Windows Ignores attempts to delete files / folders which do not exist*/ 1693 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND)) 1694 SetupDeleteErrorA(ctx->owner, NULL, paths->Target, paths->Win32Error, 0); 1695 return FILEOP_SKIP; 1696 case SPFILENOTIFY_STARTRENAME: 1697 TRACE( "start rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); 1698 return FILEOP_DOIT; 1699 case SPFILENOTIFY_ENDRENAME: 1700 TRACE( "end rename %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); 1701 return 0; 1702 case SPFILENOTIFY_RENAMEERROR: 1703 SetupRenameErrorA(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0); 1704 return FILEOP_SKIP; 1705 case SPFILENOTIFY_STARTCOPY: 1706 TRACE( "start copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); 1707 return FILEOP_DOIT; 1708 case SPFILENOTIFY_ENDCOPY: 1709 TRACE( "end copy %s -> %s\n", debugstr_a(paths->Source), debugstr_a(paths->Target) ); 1710 return 0; 1711 case SPFILENOTIFY_COPYERROR: 1712 ERR( "copy error %d %s -> %s\n", paths->Win32Error, 1713 debugstr_a(paths->Source), debugstr_a(paths->Target) ); 1714 return FILEOP_SKIP; 1715 case SPFILENOTIFY_NEEDMEDIA: 1716 TRACE( "need media\n" ); 1717 return FILEOP_SKIP; 1718 default: 1719 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 ); 1720 break; 1721 } 1722 return 0; 1723} 1724 1725 1726/*********************************************************************** 1727 * SetupDefaultQueueCallbackW (SETUPAPI.@) 1728 */ 1729UINT WINAPI SetupDefaultQueueCallbackW( PVOID context, UINT notification, 1730 UINT_PTR param1, UINT_PTR param2 ) 1731{ 1732 FILEPATHS_W *paths = (FILEPATHS_W *)param1; 1733 struct default_callback_context *ctx = (struct default_callback_context *)context; 1734 1735 switch(notification) 1736 { 1737 case SPFILENOTIFY_STARTQUEUE: 1738 TRACE( "start queue\n" ); 1739 return TRUE; 1740 case SPFILENOTIFY_ENDQUEUE: 1741 TRACE( "end queue\n" ); 1742 return 0; 1743 case SPFILENOTIFY_STARTSUBQUEUE: 1744 TRACE( "start subqueue %ld count %ld\n", param1, param2 ); 1745 return TRUE; 1746 case SPFILENOTIFY_ENDSUBQUEUE: 1747 TRACE( "end subqueue %ld\n", param1 ); 1748 return 0; 1749 case SPFILENOTIFY_STARTDELETE: 1750 TRACE( "start delete %s\n", debugstr_w(paths->Target) ); 1751 return FILEOP_DOIT; 1752 case SPFILENOTIFY_ENDDELETE: 1753 TRACE( "end delete %s\n", debugstr_w(paths->Target) ); 1754 return 0; 1755 case SPFILENOTIFY_DELETEERROR: 1756 /*Windows Ignores attempts to delete files / folders which do not exist*/ 1757 if ((paths->Win32Error != ERROR_FILE_NOT_FOUND) && (paths->Win32Error != ERROR_PATH_NOT_FOUND)) 1758 SetupDeleteErrorW(ctx->owner, NULL, paths->Target, paths->Win32Error, 0); 1759 return FILEOP_SKIP; 1760 case SPFILENOTIFY_STARTRENAME: 1761 SetupRenameErrorW(ctx->owner, NULL, paths->Source, paths->Target, paths->Win32Error, 0); 1762 return FILEOP_DOIT; 1763 case SPFILENOTIFY_ENDRENAME: 1764 TRACE( "end rename %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); 1765 return 0; 1766 case SPFILENOTIFY_RENAMEERROR: 1767 ERR( "rename error %d %s -> %s\n", paths->Win32Error, 1768 debugstr_w(paths->Source), debugstr_w(paths->Target) ); 1769 return FILEOP_SKIP; 1770 case SPFILENOTIFY_STARTCOPY: 1771 TRACE( "start copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); 1772 return FILEOP_DOIT; 1773 case SPFILENOTIFY_ENDCOPY: 1774 TRACE( "end copy %s -> %s\n", debugstr_w(paths->Source), debugstr_w(paths->Target) ); 1775 return 0; 1776 case SPFILENOTIFY_COPYERROR: 1777 TRACE( "copy error %d %s -> %s\n", paths->Win32Error, 1778 debugstr_w(paths->Source), debugstr_w(paths->Target) ); 1779 return FILEOP_SKIP; 1780 case SPFILENOTIFY_NEEDMEDIA: 1781 TRACE( "need media\n" ); 1782 return FILEOP_SKIP; 1783 default: 1784 FIXME( "notification %d params %lx,%lx\n", notification, param1, param2 ); 1785 break; 1786 } 1787 return 0; 1788} 1789 1790/*********************************************************************** 1791 * SetupDeleteErrorA (SETUPAPI.@) 1792 */ 1793 1794UINT WINAPI SetupDeleteErrorA( HWND parent, PCSTR dialogTitle, PCSTR file, 1795 UINT w32error, DWORD style) 1796{ 1797 FIXME( "stub: (Error Number %d when attempting to delete %s)\n", 1798 w32error, debugstr_a(file) ); 1799 return DPROMPT_SKIPFILE; 1800} 1801 1802/*********************************************************************** 1803 * SetupDeleteErrorW (SETUPAPI.@) 1804 */ 1805 1806UINT WINAPI SetupDeleteErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR file, 1807 UINT w32error, DWORD style) 1808{ 1809 FIXME( "stub: (Error Number %d when attempting to delete %s)\n", 1810 w32error, debugstr_w(file) ); 1811 return DPROMPT_SKIPFILE; 1812} 1813 1814/*********************************************************************** 1815 * SetupRenameErrorA (SETUPAPI.@) 1816 */ 1817 1818UINT WINAPI SetupRenameErrorA( HWND parent, PCSTR dialogTitle, PCSTR source, 1819 PCSTR target, UINT w32error, DWORD style) 1820{ 1821 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n", 1822 w32error, debugstr_a(source), debugstr_a(target)); 1823 return DPROMPT_SKIPFILE; 1824} 1825 1826/*********************************************************************** 1827 * SetupRenameErrorW (SETUPAPI.@) 1828 */ 1829 1830UINT WINAPI SetupRenameErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR source, 1831 PCWSTR target, UINT w32error, DWORD style) 1832{ 1833 FIXME( "stub: (Error Number %d when attempting to rename %s to %s)\n", 1834 w32error, debugstr_w(source), debugstr_w(target)); 1835 return DPROMPT_SKIPFILE; 1836} 1837 1838 1839/*********************************************************************** 1840 * SetupCopyErrorA (SETUPAPI.@) 1841 */ 1842 1843UINT WINAPI SetupCopyErrorA( HWND parent, PCSTR dialogTitle, PCSTR diskname, 1844 PCSTR sourcepath, PCSTR sourcefile, PCSTR targetpath, 1845 UINT w32error, DWORD style, PSTR pathbuffer, 1846 DWORD buffersize, PDWORD requiredsize) 1847{ 1848 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n", 1849 w32error, debugstr_a(sourcefile), debugstr_a(sourcepath) ,debugstr_a(targetpath)); 1850 return DPROMPT_SKIPFILE; 1851} 1852 1853/*********************************************************************** 1854 * SetupCopyErrorW (SETUPAPI.@) 1855 */ 1856 1857UINT WINAPI SetupCopyErrorW( HWND parent, PCWSTR dialogTitle, PCWSTR diskname, 1858 PCWSTR sourcepath, PCWSTR sourcefile, PCWSTR targetpath, 1859 UINT w32error, DWORD style, PWSTR pathbuffer, 1860 DWORD buffersize, PDWORD requiredsize) 1861{ 1862 FIXME( "stub: (Error Number %d when attempting to copy file %s from %s to %s)\n", 1863 w32error, debugstr_w(sourcefile), debugstr_w(sourcepath) ,debugstr_w(targetpath)); 1864 return DPROMPT_SKIPFILE; 1865} 1866 1867/*********************************************************************** 1868 * pSetupGetQueueFlags (SETUPAPI.@) 1869 */ 1870DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle ) 1871{ 1872 struct file_queue *queue = handle; 1873 return queue->flags; 1874} 1875 1876/*********************************************************************** 1877 * pSetupSetQueueFlags (SETUPAPI.@) 1878 */ 1879BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags ) 1880{ 1881 struct file_queue *queue = handle; 1882 queue->flags = flags; 1883 return TRUE; 1884}