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