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