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 struct extract_cab_ctx 365 { 366 const WCHAR *src; 367 const WCHAR *dst; 368 }; 369 370 static 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 */ 416 static 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 */ 445 HSPFILEQ 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 */ 458 BOOL 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 */ 473 BOOL 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 */ 510 BOOL 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 */ 549 BOOL 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( ¶ms ); 568 } 569 570 571 /*********************************************************************** 572 * SetupQueueCopyW (SETUPAPI.@) 573 */ 574 BOOL 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( ¶ms ); 593 } 594 595 596 /*********************************************************************** 597 * SetupQueueDefaultCopyA (SETUPAPI.@) 598 */ 599 BOOL 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( ¶ms ); 617 } 618 619 620 /*********************************************************************** 621 * SetupQueueDefaultCopyW (SETUPAPI.@) 622 */ 623 BOOL 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( ¶ms ); 641 } 642 643 644 /*********************************************************************** 645 * SetupQueueDeleteA (SETUPAPI.@) 646 */ 647 BOOL 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 */ 670 BOOL 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 */ 693 BOOL 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 */ 717 BOOL 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 */ 741 BOOL 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( §ionW, 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( §ionW ); 765 return ret; 766 } 767 768 769 /*********************************************************************** 770 * SetupQueueCopySectionW (SETUPAPI.@) 771 */ 772 BOOL 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( ¶ms )) goto done; 839 } while (SetupFindNextLine( &context, &context )); 840 ret = TRUE; 841 842 done: 843 if (security_descriptor) 844 MyFree( security_descriptor ); 845 return ret; 846 } 847 848 849 /*********************************************************************** 850 * SetupQueueDeleteSectionA (SETUPAPI.@) 851 */ 852 BOOL WINAPI SetupQueueDeleteSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section ) 853 { 854 UNICODE_STRING sectionW; 855 BOOL ret = FALSE; 856 857 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 858 { 859 ret = SetupQueueDeleteSectionW( queue, hinf, hlist, sectionW.Buffer ); 860 RtlFreeUnicodeString( §ionW ); 861 } 862 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 863 return ret; 864 } 865 866 867 /*********************************************************************** 868 * SetupQueueDeleteSectionW (SETUPAPI.@) 869 */ 870 BOOL 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 */ 901 BOOL WINAPI SetupQueueRenameSectionA( HSPFILEQ queue, HINF hinf, HINF hlist, PCSTR section ) 902 { 903 UNICODE_STRING sectionW; 904 BOOL ret = FALSE; 905 906 if (RtlCreateUnicodeStringFromAsciiz( §ionW, section )) 907 { 908 ret = SetupQueueRenameSectionW( queue, hinf, hlist, sectionW.Buffer ); 909 RtlFreeUnicodeString( §ionW ); 910 } 911 else SetLastError( ERROR_NOT_ENOUGH_MEMORY ); 912 return ret; 913 } 914 915 916 /*********************************************************************** 917 * SetupQueueRenameSectionW (SETUPAPI.@) 918 */ 919 BOOL 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 */ 950 BOOL 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 */ 966 static 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 1012 static 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 */ 1237 BOOL 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 1269 exit: 1270 RtlFreeUnicodeString( &sourceW ); 1271 RtlFreeUnicodeString( &rootW ); 1272 RtlFreeUnicodeString( &destW ); 1273 return ret; 1274 } 1275 1276 /*********************************************************************** 1277 * SetupInstallFileW (SETUPAPI.@) 1278 */ 1279 BOOL 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 */ 1348 BOOL 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 */ 1493 BOOL 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 */ 1510 BOOL 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 */ 1564 BOOL 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 */ 1587 BOOL 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 */ 1598 BOOL 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 */ 1609 BOOL 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 */ 1619 BOOL 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 */ 1629 PVOID WINAPI SetupInitDefaultQueueCallback( HWND owner ) 1630 { 1631 return SetupInitDefaultQueueCallbackEx( owner, 0, 0, 0, NULL ); 1632 } 1633 1634 1635 /*********************************************************************** 1636 * SetupInitDefaultQueueCallbackEx (SETUPAPI.@) 1637 */ 1638 PVOID 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 */ 1656 void WINAPI SetupTermDefaultQueueCallback( PVOID context ) 1657 { 1658 HeapFree( GetProcessHeap(), 0, context ); 1659 } 1660 1661 1662 /*********************************************************************** 1663 * SetupDefaultQueueCallbackA (SETUPAPI.@) 1664 */ 1665 UINT 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 */ 1729 UINT 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 1794 UINT 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 1806 UINT 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 1818 UINT 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 1830 UINT 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 1843 UINT 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 1857 UINT 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 */ 1870 DWORD WINAPI pSetupGetQueueFlags( HSPFILEQ handle ) 1871 { 1872 struct file_queue *queue = handle; 1873 return queue->flags; 1874 } 1875 1876 /*********************************************************************** 1877 * pSetupSetQueueFlags (SETUPAPI.@) 1878 */ 1879 BOOL WINAPI pSetupSetQueueFlags( HSPFILEQ handle, DWORD flags ) 1880 { 1881 struct file_queue *queue = handle; 1882 queue->flags = flags; 1883 return TRUE; 1884 } 1885