1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS text-mode setup 22 * FILE: base/setup/lib/fileqsup.c 23 * PURPOSE: Interfacing with Setup* API File Queue support functions 24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 25 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 26 */ 27 28 /* INCLUDES *****************************************************************/ 29 30 #ifndef _USETUP_PCH_ 31 #include "usetup.h" 32 #endif 33 34 #define NDEBUG 35 #include <debug.h> 36 37 /* DEFINITIONS **************************************************************/ 38 39 typedef struct _QUEUEENTRY 40 { 41 LIST_ENTRY ListEntry; 42 PWSTR SourceCabinet; /* May be NULL if the file is not in a cabinet */ 43 PWSTR SourceRootPath; 44 PWSTR SourcePath; 45 PWSTR SourceFileName; 46 PWSTR TargetDirectory; 47 PWSTR TargetFileName; 48 } QUEUEENTRY, *PQUEUEENTRY; 49 50 typedef struct _FILEQUEUEHEADER 51 { 52 LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries 53 ULONG DeleteCount; 54 55 LIST_ENTRY RenameQueue; // PQUEUEENTRY entries 56 ULONG RenameCount; 57 58 LIST_ENTRY CopyQueue; // PQUEUEENTRY entries 59 ULONG CopyCount; 60 61 BOOLEAN HasCurrentCabinet; 62 CABINET_CONTEXT CabinetContext; 63 CAB_SEARCH Search; 64 WCHAR CurrentCabinetName[MAX_PATH]; 65 } FILEQUEUEHEADER, *PFILEQUEUEHEADER; 66 67 68 /* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/ 69 70 static NTSTATUS 71 SetupExtractFile( 72 IN OUT PFILEQUEUEHEADER QueueHeader, 73 IN PCWSTR CabinetFileName, 74 IN PCWSTR SourceFileName, 75 IN PCWSTR DestinationPathName) 76 { 77 ULONG CabStatus; 78 79 DPRINT("SetupExtractFile(CabinetFileName: '%S', SourceFileName: '%S', DestinationPathName: '%S')\n", 80 CabinetFileName, SourceFileName, DestinationPathName); 81 82 if (QueueHeader->HasCurrentCabinet) 83 { 84 DPRINT("CurrentCabinetName: '%S'\n", QueueHeader->CurrentCabinetName); 85 } 86 87 if (QueueHeader->HasCurrentCabinet && 88 (wcscmp(CabinetFileName, QueueHeader->CurrentCabinetName) == 0)) 89 { 90 DPRINT("Using same cabinet as last time\n"); 91 92 /* Use our last location because the files should be sequential */ 93 CabStatus = CabinetFindNextFileSequential(&QueueHeader->CabinetContext, 94 SourceFileName, 95 &QueueHeader->Search); 96 if (CabStatus != CAB_STATUS_SUCCESS) 97 { 98 DPRINT("Sequential miss on file: %S\n", SourceFileName); 99 100 /* Looks like we got unlucky */ 101 CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext, 102 SourceFileName, 103 &QueueHeader->Search); 104 } 105 } 106 else 107 { 108 DPRINT("Using new cabinet\n"); 109 110 if (QueueHeader->HasCurrentCabinet) 111 { 112 QueueHeader->HasCurrentCabinet = FALSE; 113 CabinetCleanup(&QueueHeader->CabinetContext); 114 } 115 116 RtlStringCchCopyW(QueueHeader->CurrentCabinetName, 117 ARRAYSIZE(QueueHeader->CurrentCabinetName), 118 CabinetFileName); 119 120 CabinetInitialize(&QueueHeader->CabinetContext); 121 CabinetSetEventHandlers(&QueueHeader->CabinetContext, 122 NULL, NULL, NULL, NULL); 123 CabinetSetCabinetName(&QueueHeader->CabinetContext, CabinetFileName); 124 125 CabStatus = CabinetOpen(&QueueHeader->CabinetContext); 126 if (CabStatus == CAB_STATUS_SUCCESS) 127 { 128 DPRINT("Opened cabinet %S\n", CabinetFileName /*CabinetGetCabinetName(&QueueHeader->CabinetContext)*/); 129 QueueHeader->HasCurrentCabinet = TRUE; 130 } 131 else 132 { 133 DPRINT("Cannot open cabinet (%d)\n", CabStatus); 134 return STATUS_UNSUCCESSFUL; 135 } 136 137 /* We have to start at the beginning here */ 138 CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext, 139 SourceFileName, 140 &QueueHeader->Search); 141 } 142 143 if (CabStatus != CAB_STATUS_SUCCESS) 144 { 145 DPRINT1("Unable to find '%S' in cabinet '%S'\n", 146 SourceFileName, CabinetGetCabinetName(&QueueHeader->CabinetContext)); 147 return STATUS_UNSUCCESSFUL; 148 } 149 150 CabinetSetDestinationPath(&QueueHeader->CabinetContext, DestinationPathName); 151 CabStatus = CabinetExtractFile(&QueueHeader->CabinetContext, &QueueHeader->Search); 152 if (CabStatus != CAB_STATUS_SUCCESS) 153 { 154 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus); 155 return STATUS_UNSUCCESSFUL; 156 } 157 158 return STATUS_SUCCESS; 159 } 160 161 HSPFILEQ 162 WINAPI 163 SetupOpenFileQueue(VOID) 164 { 165 PFILEQUEUEHEADER QueueHeader; 166 167 /* Allocate the queue header */ 168 QueueHeader = RtlAllocateHeap(ProcessHeap, 0, sizeof(FILEQUEUEHEADER)); 169 if (QueueHeader == NULL) 170 return NULL; 171 172 RtlZeroMemory(QueueHeader, sizeof(FILEQUEUEHEADER)); 173 174 /* Initialize the file queues */ 175 InitializeListHead(&QueueHeader->DeleteQueue); 176 QueueHeader->DeleteCount = 0; 177 InitializeListHead(&QueueHeader->RenameQueue); 178 QueueHeader->RenameCount = 0; 179 InitializeListHead(&QueueHeader->CopyQueue); 180 QueueHeader->CopyCount = 0; 181 182 QueueHeader->HasCurrentCabinet = FALSE; 183 184 return (HSPFILEQ)QueueHeader; 185 } 186 187 static VOID 188 SetupDeleteQueueEntry( 189 IN PQUEUEENTRY Entry) 190 { 191 if (Entry == NULL) 192 return; 193 194 /* Delete all strings */ 195 if (Entry->SourceCabinet != NULL) 196 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet); 197 198 if (Entry->SourceRootPath != NULL) 199 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath); 200 201 if (Entry->SourcePath != NULL) 202 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 203 204 if (Entry->SourceFileName != NULL) 205 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName); 206 207 if (Entry->TargetDirectory != NULL) 208 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory); 209 210 if (Entry->TargetFileName != NULL) 211 RtlFreeHeap(ProcessHeap, 0, Entry->TargetFileName); 212 213 /* Delete queue entry */ 214 RtlFreeHeap(ProcessHeap, 0, Entry); 215 } 216 217 BOOL 218 WINAPI 219 SetupCloseFileQueue( 220 IN HSPFILEQ QueueHandle) 221 { 222 PFILEQUEUEHEADER QueueHeader; 223 PLIST_ENTRY ListEntry; 224 PQUEUEENTRY Entry; 225 226 if (QueueHandle == NULL) 227 return FALSE; 228 229 QueueHeader = (PFILEQUEUEHEADER)QueueHandle; 230 231 /* Delete the delete queue */ 232 while (!IsListEmpty(&QueueHeader->DeleteQueue)) 233 { 234 ListEntry = RemoveHeadList(&QueueHeader->DeleteQueue); 235 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry); 236 SetupDeleteQueueEntry(Entry); 237 } 238 239 /* Delete the rename queue */ 240 while (!IsListEmpty(&QueueHeader->RenameQueue)) 241 { 242 ListEntry = RemoveHeadList(&QueueHeader->RenameQueue); 243 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry); 244 SetupDeleteQueueEntry(Entry); 245 } 246 247 /* Delete the copy queue */ 248 while (!IsListEmpty(&QueueHeader->CopyQueue)) 249 { 250 ListEntry = RemoveHeadList(&QueueHeader->CopyQueue); 251 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry); 252 SetupDeleteQueueEntry(Entry); 253 } 254 255 /* Delete queue header */ 256 RtlFreeHeap(ProcessHeap, 0, QueueHeader); 257 258 return TRUE; 259 } 260 261 /* A simplified version of SetupQueueCopyW that wraps Cabinet support around */ 262 BOOL 263 WINAPI 264 SetupQueueCopyWithCab( 265 IN HSPFILEQ QueueHandle, 266 IN PCWSTR SourceRootPath, 267 IN PCWSTR SourcePath OPTIONAL, 268 IN PCWSTR SourceFileName, 269 IN PCWSTR SourceDescription OPTIONAL, 270 IN PCWSTR SourceCabinet OPTIONAL, 271 IN PCWSTR SourceTagFile OPTIONAL, 272 IN PCWSTR TargetDirectory, 273 IN PCWSTR TargetFileName OPTIONAL, 274 IN ULONG CopyStyle) 275 { 276 PFILEQUEUEHEADER QueueHeader; 277 PQUEUEENTRY Entry; 278 ULONG Length; 279 280 if (QueueHandle == NULL || 281 SourceRootPath == NULL || 282 SourceFileName == NULL || 283 TargetDirectory == NULL) 284 { 285 return FALSE; 286 } 287 288 QueueHeader = (PFILEQUEUEHEADER)QueueHandle; 289 290 DPRINT("SetupQueueCopy(Cab '%S', SrcRootPath '%S', SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n", 291 SourceCabinet ? SourceCabinet : L"n/a", 292 SourceRootPath, SourcePath, SourceFileName, 293 TargetDirectory, TargetFileName); 294 295 /* Allocate new queue entry */ 296 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY)); 297 if (Entry == NULL) 298 return FALSE; 299 300 RtlZeroMemory(Entry, sizeof(QUEUEENTRY)); 301 302 /* Copy source cabinet if available */ 303 Entry->SourceCabinet = NULL; 304 if (SourceCabinet != NULL) 305 { 306 Length = wcslen(SourceCabinet); 307 Entry->SourceCabinet = RtlAllocateHeap(ProcessHeap, 308 0, 309 (Length + 1) * sizeof(WCHAR)); 310 if (Entry->SourceCabinet == NULL) 311 { 312 RtlFreeHeap(ProcessHeap, 0, Entry); 313 return FALSE; 314 } 315 RtlStringCchCopyW(Entry->SourceCabinet, Length + 1, SourceCabinet); 316 } 317 318 /* Copy source root path */ 319 Length = wcslen(SourceRootPath); 320 Entry->SourceRootPath = RtlAllocateHeap(ProcessHeap, 321 0, 322 (Length + 1) * sizeof(WCHAR)); 323 if (Entry->SourceRootPath == NULL) 324 { 325 if (Entry->SourceCabinet != NULL) 326 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet); 327 328 RtlFreeHeap(ProcessHeap, 0, Entry); 329 return FALSE; 330 } 331 RtlStringCchCopyW(Entry->SourceRootPath, Length + 1, SourceRootPath); 332 333 /* Copy source path */ 334 Entry->SourcePath = NULL; 335 if (SourcePath != NULL) 336 { 337 Length = wcslen(SourcePath); 338 if ((Length > 0) && (SourcePath[Length - 1] == L'\\')) 339 Length--; 340 Entry->SourcePath = RtlAllocateHeap(ProcessHeap, 341 0, 342 (Length + 1) * sizeof(WCHAR)); 343 if (Entry->SourcePath == NULL) 344 { 345 if (Entry->SourceCabinet != NULL) 346 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet); 347 348 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath); 349 RtlFreeHeap(ProcessHeap, 0, Entry); 350 return FALSE; 351 } 352 RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath); 353 } 354 355 /* Copy source file name */ 356 Length = wcslen(SourceFileName); 357 Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap, 358 0, 359 (Length + 1) * sizeof(WCHAR)); 360 if (Entry->SourceFileName == NULL) 361 { 362 if (Entry->SourcePath != NULL) 363 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 364 365 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath); 366 367 if (Entry->SourceCabinet != NULL) 368 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet); 369 370 RtlFreeHeap(ProcessHeap, 0, Entry); 371 return FALSE; 372 } 373 RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName); 374 375 /* Copy target directory */ 376 Length = wcslen(TargetDirectory); 377 if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\')) 378 Length--; 379 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap, 380 0, 381 (Length + 1) * sizeof(WCHAR)); 382 if (Entry->TargetDirectory == NULL) 383 { 384 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName); 385 386 if (Entry->SourcePath != NULL) 387 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 388 389 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath); 390 391 if (Entry->SourceCabinet != NULL) 392 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet); 393 394 RtlFreeHeap(ProcessHeap, 0, Entry); 395 return FALSE; 396 } 397 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetDirectory); 398 399 /* Copy optional target filename */ 400 Entry->TargetFileName = NULL; 401 if (TargetFileName != NULL) 402 { 403 Length = wcslen(TargetFileName); 404 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap, 405 0, 406 (Length + 1) * sizeof(WCHAR)); 407 if (Entry->TargetFileName == NULL) 408 { 409 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory); 410 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName); 411 412 if (Entry->SourcePath != NULL) 413 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 414 415 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath); 416 417 if (Entry->SourceCabinet != NULL) 418 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet); 419 420 RtlFreeHeap(ProcessHeap, 0, Entry); 421 return FALSE; 422 } 423 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName); 424 } 425 426 /* Append queue entry */ 427 InsertTailList(&QueueHeader->CopyQueue, &Entry->ListEntry); 428 ++QueueHeader->CopyCount; 429 430 return TRUE; 431 } 432 433 BOOL 434 WINAPI 435 SetupQueueDeleteW( 436 IN HSPFILEQ QueueHandle, 437 IN PCWSTR PathPart1, 438 IN PCWSTR PathPart2 OPTIONAL) 439 { 440 PFILEQUEUEHEADER QueueHeader; 441 PQUEUEENTRY Entry; 442 ULONG Length; 443 444 if (QueueHandle == NULL || PathPart1 == NULL) 445 { 446 return FALSE; 447 } 448 449 QueueHeader = (PFILEQUEUEHEADER)QueueHandle; 450 451 DPRINT1("SetupQueueDeleteW(PathPart1 '%S', PathPart2 '%S')\n", 452 PathPart1, PathPart2); 453 454 /* Allocate new queue entry */ 455 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY)); 456 if (Entry == NULL) 457 return FALSE; 458 459 RtlZeroMemory(Entry, sizeof(QUEUEENTRY)); 460 461 Entry->SourceCabinet = NULL; 462 Entry->SourceRootPath = NULL; 463 Entry->SourcePath = NULL; 464 Entry->SourceFileName = NULL; 465 466 /* Copy first part of path */ 467 Length = wcslen(PathPart1); 468 // if ((Length > 0) && (SourcePath[Length - 1] == L'\\')) 469 // Length--; 470 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap, 471 0, 472 (Length + 1) * sizeof(WCHAR)); 473 if (Entry->TargetDirectory == NULL) 474 { 475 RtlFreeHeap(ProcessHeap, 0, Entry); 476 return FALSE; 477 } 478 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, PathPart1); 479 480 /* Copy optional second part of path */ 481 if (PathPart2 != NULL) 482 { 483 Length = wcslen(PathPart2); 484 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap, 485 0, 486 (Length + 1) * sizeof(WCHAR)); 487 if (Entry->TargetFileName == NULL) 488 { 489 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory); 490 RtlFreeHeap(ProcessHeap, 0, Entry); 491 return FALSE; 492 } 493 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, PathPart2); 494 } 495 496 /* Append the queue entry */ 497 InsertTailList(&QueueHeader->DeleteQueue, &Entry->ListEntry); 498 ++QueueHeader->DeleteCount; 499 500 return TRUE; 501 } 502 503 BOOL 504 WINAPI 505 SetupQueueRenameW( 506 IN HSPFILEQ QueueHandle, 507 IN PCWSTR SourcePath, 508 IN PCWSTR SourceFileName OPTIONAL, 509 IN PCWSTR TargetPath OPTIONAL, 510 IN PCWSTR TargetFileName) 511 { 512 PFILEQUEUEHEADER QueueHeader; 513 PQUEUEENTRY Entry; 514 ULONG Length; 515 516 if (QueueHandle == NULL || 517 SourcePath == NULL || 518 TargetFileName == NULL) 519 { 520 return FALSE; 521 } 522 523 QueueHeader = (PFILEQUEUEHEADER)QueueHandle; 524 525 DPRINT1("SetupQueueRenameW(SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n", 526 SourcePath, SourceFileName, TargetPath, TargetFileName); 527 528 /* Allocate a new queue entry */ 529 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY)); 530 if (Entry == NULL) 531 return FALSE; 532 533 RtlZeroMemory(Entry, sizeof(QUEUEENTRY)); 534 535 Entry->SourceCabinet = NULL; 536 Entry->SourceRootPath = NULL; 537 538 /* Copy source path */ 539 Length = wcslen(SourcePath); 540 if ((Length > 0) && (SourcePath[Length - 1] == L'\\')) 541 Length--; 542 Entry->SourcePath = RtlAllocateHeap(ProcessHeap, 543 0, 544 (Length + 1) * sizeof(WCHAR)); 545 if (Entry->SourcePath == NULL) 546 { 547 RtlFreeHeap(ProcessHeap, 0, Entry); 548 return FALSE; 549 } 550 RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath); 551 552 /* Copy optional source file name */ 553 Entry->SourceFileName = NULL; 554 if (SourceFileName != NULL) 555 { 556 Length = wcslen(SourceFileName); 557 Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap, 558 0, 559 (Length + 1) * sizeof(WCHAR)); 560 if (Entry->SourceFileName == NULL) 561 { 562 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 563 RtlFreeHeap(ProcessHeap, 0, Entry); 564 return FALSE; 565 } 566 RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName); 567 } 568 569 /* Copy optional target directory */ 570 Entry->TargetDirectory = NULL; 571 if (TargetPath != NULL) 572 { 573 Length = wcslen(TargetPath); 574 if ((Length > 0) && (TargetPath[Length - 1] == L'\\')) 575 Length--; 576 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap, 577 0, 578 (Length + 1) * sizeof(WCHAR)); 579 if (Entry->TargetDirectory == NULL) 580 { 581 if (Entry->SourceFileName != NULL) 582 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName); 583 584 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 585 RtlFreeHeap(ProcessHeap, 0, Entry); 586 return FALSE; 587 } 588 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetPath); 589 } 590 591 /* Copy target filename */ 592 Length = wcslen(TargetFileName); 593 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap, 594 0, 595 (Length + 1) * sizeof(WCHAR)); 596 if (Entry->TargetFileName == NULL) 597 { 598 if (Entry->TargetDirectory != NULL) 599 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory); 600 601 if (Entry->SourceFileName != NULL) 602 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName); 603 604 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath); 605 RtlFreeHeap(ProcessHeap, 0, Entry); 606 return FALSE; 607 } 608 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName); 609 610 /* Append the queue entry */ 611 InsertTailList(&QueueHeader->RenameQueue, &Entry->ListEntry); 612 ++QueueHeader->RenameCount; 613 614 return TRUE; 615 } 616 617 BOOL 618 WINAPI 619 SetupCommitFileQueueW( 620 IN HWND Owner, 621 IN HSPFILEQ QueueHandle, 622 IN PSP_FILE_CALLBACK_W MsgHandler, 623 IN PVOID Context OPTIONAL) 624 { 625 BOOL Success = TRUE; // Suppose success 626 UINT Result; 627 NTSTATUS Status; 628 PFILEQUEUEHEADER QueueHeader; 629 PLIST_ENTRY ListEntry; 630 PQUEUEENTRY Entry; 631 FILEPATHS_W FilePathInfo; 632 WCHAR FileSrcPath[MAX_PATH]; 633 WCHAR FileDstPath[MAX_PATH]; 634 635 if (QueueHandle == NULL) 636 return FALSE; 637 638 QueueHeader = (PFILEQUEUEHEADER)QueueHandle; 639 640 Result = MsgHandler(Context, 641 SPFILENOTIFY_STARTQUEUE, 642 (UINT_PTR)Owner, 643 0); 644 if (Result == FILEOP_ABORT) 645 return FALSE; 646 647 648 /* 649 * Commit the delete queue 650 */ 651 652 if (!IsListEmpty(&QueueHeader->DeleteQueue)) 653 { 654 Result = MsgHandler(Context, 655 SPFILENOTIFY_STARTSUBQUEUE, 656 FILEOP_DELETE, 657 QueueHeader->DeleteCount); 658 if (Result == FILEOP_ABORT) 659 { 660 Success = FALSE; 661 goto Quit; 662 } 663 } 664 665 for (ListEntry = QueueHeader->DeleteQueue.Flink; 666 ListEntry != &QueueHeader->DeleteQueue; 667 ListEntry = ListEntry->Flink) 668 { 669 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry); 670 671 /* Build the full target path */ 672 CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2, 673 Entry->TargetDirectory, Entry->TargetFileName); 674 675 DPRINT1(" -----> " "Delete: '%S'\n", FileDstPath); 676 677 FilePathInfo.Target = FileDstPath; 678 FilePathInfo.Source = NULL; 679 FilePathInfo.Win32Error = STATUS_SUCCESS; 680 FilePathInfo.Flags = 0; // FIXME: Unused yet... 681 682 Result = MsgHandler(Context, 683 SPFILENOTIFY_STARTDELETE, 684 (UINT_PTR)&FilePathInfo, 685 FILEOP_DELETE); 686 if (Result == FILEOP_ABORT) 687 { 688 Success = FALSE; 689 goto EndDelete; 690 } 691 else if (Result == FILEOP_SKIP) 692 goto EndDelete; 693 // else (Result == FILEOP_DOIT) 694 695 RetryDelete: 696 /* Force-delete the file */ 697 Status = SetupDeleteFile(FileDstPath, TRUE); 698 if (!NT_SUCCESS(Status)) 699 { 700 /* An error happened */ 701 FilePathInfo.Win32Error = (UINT)Status; 702 Result = MsgHandler(Context, 703 SPFILENOTIFY_DELETEERROR, 704 (UINT_PTR)&FilePathInfo, 705 0); 706 if (Result == FILEOP_ABORT) 707 { 708 Success = FALSE; 709 goto EndDelete; 710 } 711 else if (Result == FILEOP_SKIP) 712 goto EndDelete; 713 else if (Result == FILEOP_RETRY) 714 goto RetryDelete; 715 716 Success = FALSE; 717 } 718 719 EndDelete: 720 /* This notification is always sent, even in case of error */ 721 FilePathInfo.Win32Error = (UINT)Status; 722 MsgHandler(Context, 723 SPFILENOTIFY_ENDDELETE, 724 (UINT_PTR)&FilePathInfo, 725 0); 726 if (Success == FALSE /* && Result == FILEOP_ABORT */) 727 goto Quit; 728 } 729 730 if (!IsListEmpty(&QueueHeader->DeleteQueue)) 731 { 732 MsgHandler(Context, 733 SPFILENOTIFY_ENDSUBQUEUE, 734 FILEOP_DELETE, 735 0); 736 } 737 738 739 /* 740 * Commit the rename queue 741 */ 742 743 if (!IsListEmpty(&QueueHeader->RenameQueue)) 744 { 745 Result = MsgHandler(Context, 746 SPFILENOTIFY_STARTSUBQUEUE, 747 FILEOP_RENAME, 748 QueueHeader->RenameCount); 749 if (Result == FILEOP_ABORT) 750 { 751 Success = FALSE; 752 goto Quit; 753 } 754 } 755 756 for (ListEntry = QueueHeader->RenameQueue.Flink; 757 ListEntry != &QueueHeader->RenameQueue; 758 ListEntry = ListEntry->Flink) 759 { 760 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry); 761 762 /* Build the full source path */ 763 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 2, 764 Entry->SourcePath, Entry->SourceFileName); 765 766 /* Build the full target path */ 767 CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2, 768 Entry->TargetDirectory, Entry->TargetFileName); 769 770 DPRINT1(" -----> " "Rename: '%S' ==> '%S'\n", FileSrcPath, FileDstPath); 771 772 FilePathInfo.Target = FileDstPath; 773 FilePathInfo.Source = FileSrcPath; 774 FilePathInfo.Win32Error = STATUS_SUCCESS; 775 FilePathInfo.Flags = 0; // FIXME: Unused yet... 776 777 Result = MsgHandler(Context, 778 SPFILENOTIFY_STARTRENAME, 779 (UINT_PTR)&FilePathInfo, 780 FILEOP_RENAME); 781 if (Result == FILEOP_ABORT) 782 { 783 Success = FALSE; 784 goto EndRename; 785 } 786 else if (Result == FILEOP_SKIP) 787 goto EndRename; 788 // else (Result == FILEOP_DOIT) 789 790 RetryRename: 791 /* Move or rename the file */ 792 Status = SetupMoveFile(FileSrcPath, FileDstPath, 793 MOVEFILE_REPLACE_EXISTING 794 | MOVEFILE_COPY_ALLOWED 795 | MOVEFILE_WRITE_THROUGH); 796 if (!NT_SUCCESS(Status)) 797 { 798 /* An error happened */ 799 FilePathInfo.Win32Error = (UINT)Status; 800 Result = MsgHandler(Context, 801 SPFILENOTIFY_RENAMEERROR, 802 (UINT_PTR)&FilePathInfo, 803 0); 804 if (Result == FILEOP_ABORT) 805 { 806 Success = FALSE; 807 goto EndRename; 808 } 809 else if (Result == FILEOP_SKIP) 810 goto EndRename; 811 else if (Result == FILEOP_RETRY) 812 goto RetryRename; 813 814 Success = FALSE; 815 } 816 817 EndRename: 818 /* This notification is always sent, even in case of error */ 819 FilePathInfo.Win32Error = (UINT)Status; 820 MsgHandler(Context, 821 SPFILENOTIFY_ENDRENAME, 822 (UINT_PTR)&FilePathInfo, 823 0); 824 if (Success == FALSE /* && Result == FILEOP_ABORT */) 825 goto Quit; 826 } 827 828 if (!IsListEmpty(&QueueHeader->RenameQueue)) 829 { 830 MsgHandler(Context, 831 SPFILENOTIFY_ENDSUBQUEUE, 832 FILEOP_RENAME, 833 0); 834 } 835 836 837 /* 838 * Commit the copy queue 839 */ 840 841 if (!IsListEmpty(&QueueHeader->CopyQueue)) 842 { 843 Result = MsgHandler(Context, 844 SPFILENOTIFY_STARTSUBQUEUE, 845 FILEOP_COPY, 846 QueueHeader->CopyCount); 847 if (Result == FILEOP_ABORT) 848 { 849 Success = FALSE; 850 goto Quit; 851 } 852 } 853 854 for (ListEntry = QueueHeader->CopyQueue.Flink; 855 ListEntry != &QueueHeader->CopyQueue; 856 ListEntry = ListEntry->Flink) 857 { 858 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry); 859 860 // 861 // TODO: Send a SPFILENOTIFY_NEEDMEDIA notification 862 // when we switch to a new installation media. 863 // Param1 = (UINT_PTR)(PSOURCE_MEDIA)SourceMediaInfo; 864 // Param2 = (UINT_PTR)(TCHAR[MAX_PATH])NewPathInfo; 865 // 866 867 /* Build the full source path */ 868 if (Entry->SourceCabinet == NULL) 869 { 870 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3, 871 Entry->SourceRootPath, Entry->SourcePath, 872 Entry->SourceFileName); 873 } 874 else 875 { 876 /* 877 * The cabinet must be in Entry->SourceRootPath only! 878 * (Should we ignore Entry->SourcePath?) 879 */ 880 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3, 881 Entry->SourceRootPath, Entry->SourcePath, 882 Entry->SourceCabinet); 883 } 884 885 /* Build the full target path */ 886 RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory); 887 if (Entry->SourceCabinet == NULL) 888 { 889 /* If the file is not in a cabinet, possibly use a different target name */ 890 if (Entry->TargetFileName != NULL) 891 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName); 892 else 893 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName); 894 } 895 else 896 { 897 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName); 898 } 899 900 DPRINT(" -----> " "Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath); 901 902 // 903 // Technically, here we should create the target directory, 904 // if it does not already exist... before calling the handler! 905 // 906 907 FilePathInfo.Target = FileDstPath; 908 FilePathInfo.Source = FileSrcPath; 909 FilePathInfo.Win32Error = STATUS_SUCCESS; 910 FilePathInfo.Flags = 0; // FIXME: Unused yet... 911 912 Result = MsgHandler(Context, 913 SPFILENOTIFY_STARTCOPY, 914 (UINT_PTR)&FilePathInfo, 915 FILEOP_COPY); 916 if (Result == FILEOP_ABORT) 917 { 918 Success = FALSE; 919 goto EndCopy; 920 } 921 else if (Result == FILEOP_SKIP) 922 goto EndCopy; 923 // else (Result == FILEOP_DOIT) 924 925 RetryCopy: 926 if (Entry->SourceCabinet != NULL) 927 { 928 /* 929 * The file is in a cabinet, use only the destination path 930 * and keep the source name as the target name. 931 */ 932 /* Extract the file from the cabinet */ 933 Status = SetupExtractFile(QueueHeader, 934 FileSrcPath, // Specifies the cabinet path 935 Entry->SourceFileName, 936 Entry->TargetDirectory); 937 } 938 else 939 { 940 /* Copy the file */ 941 Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE); 942 } 943 944 if (!NT_SUCCESS(Status)) 945 { 946 /* An error happened */ 947 FilePathInfo.Win32Error = (UINT)Status; 948 Result = MsgHandler(Context, 949 SPFILENOTIFY_COPYERROR, 950 (UINT_PTR)&FilePathInfo, 951 (UINT_PTR)NULL); // FIXME: Unused yet... 952 if (Result == FILEOP_ABORT) 953 { 954 Success = FALSE; 955 goto EndCopy; 956 } 957 else if (Result == FILEOP_SKIP) 958 goto EndCopy; 959 else if (Result == FILEOP_RETRY) 960 goto RetryCopy; 961 else if (Result == FILEOP_NEWPATH) 962 goto RetryCopy; // TODO! 963 964 Success = FALSE; 965 } 966 967 EndCopy: 968 /* This notification is always sent, even in case of error */ 969 FilePathInfo.Win32Error = (UINT)Status; 970 MsgHandler(Context, 971 SPFILENOTIFY_ENDCOPY, 972 (UINT_PTR)&FilePathInfo, 973 0); 974 if (Success == FALSE /* && Result == FILEOP_ABORT */) 975 goto Quit; 976 } 977 978 if (!IsListEmpty(&QueueHeader->CopyQueue)) 979 { 980 MsgHandler(Context, 981 SPFILENOTIFY_ENDSUBQUEUE, 982 FILEOP_COPY, 983 0); 984 } 985 986 987 Quit: 988 /* All the queues have been committed */ 989 MsgHandler(Context, 990 SPFILENOTIFY_ENDQUEUE, 991 (UINT_PTR)Success, 992 0); 993 994 return Success; 995 } 996 997 998 /* GLOBALS *******************************************************************/ 999 1000 pSpFileQueueOpen SpFileQueueOpen = SetupOpenFileQueue; 1001 pSpFileQueueClose SpFileQueueClose = SetupCloseFileQueue; 1002 pSpFileQueueCopy SpFileQueueCopy = SetupQueueCopyWithCab; 1003 pSpFileQueueDelete SpFileQueueDelete = SetupQueueDeleteW; 1004 pSpFileQueueRename SpFileQueueRename = SetupQueueRenameW; 1005 pSpFileQueueCommit SpFileQueueCommit = SetupCommitFileQueueW; 1006 1007 /* EOF */ 1008