Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1316 lines
30 KiB

  1. /*++
  2. Copyright (c) 1993-2000 Microsoft Corporation
  3. Module Name:
  4. diamond.c
  5. Abstract:
  6. Diamond MSZIP decompression support.
  7. Author:
  8. Ted Miller (tedm) 31-Jan-1995
  9. Revision History:
  10. Jamie Hunter (JamieHun) Jul-12-2000
  11. Made this behave better in MUI scenario
  12. changed all handles to be of type HANDLE rather than HFILE
  13. use UNICODE where we can
  14. convert path to short filename in the one place we can't
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. BOOL
  19. DiamondInitialize(
  20. VOID
  21. );
  22. INT_PTR
  23. DIAMONDAPI
  24. SpdFdiOpen(
  25. IN PSTR FileName,
  26. IN int oflag,
  27. IN int pmode
  28. );
  29. int
  30. DIAMONDAPI
  31. SpdFdiClose(
  32. IN INT_PTR Handle
  33. );
  34. UINT
  35. pDiamondNotifyFileDone(
  36. IN PDIAMOND_THREAD_DATA PerThread,
  37. IN DWORD Win32Error
  38. )
  39. {
  40. UINT u;
  41. FILEPATHS FilePaths;
  42. MYASSERT(PerThread->CurrentTargetFile);
  43. FilePaths.Source = PerThread->CabinetFile;
  44. FilePaths.Target = PerThread->CurrentTargetFile;
  45. FilePaths.Win32Error = Win32Error;
  46. u = pSetupCallMsgHandler(
  47. NULL, // LogContext - we get from thread log context
  48. PerThread->MsgHandler,
  49. PerThread->IsMsgHandlerNativeCharWidth,
  50. PerThread->Context,
  51. SPFILENOTIFY_FILEEXTRACTED,
  52. (UINT_PTR)&FilePaths,
  53. 0
  54. );
  55. return(u);
  56. }
  57. INT_PTR
  58. DIAMONDAPI
  59. DiamondNotifyFunction(
  60. IN FDINOTIFICATIONTYPE Operation,
  61. IN PFDINOTIFICATION Parameters
  62. )
  63. {
  64. PSETUP_TLS pTLS;
  65. PDIAMOND_THREAD_DATA PerThread;
  66. INT_PTR rc;
  67. HANDLE hFile;
  68. CABINET_INFO CabInfo;
  69. FILE_IN_CABINET_INFO FileInCab;
  70. FILETIME FileTime, UtcTime;
  71. TCHAR NewPath[MAX_PATH];
  72. PTSTR p;
  73. DWORD err;
  74. UINT action;
  75. pTLS = SetupGetTlsData();
  76. if(!pTLS) {
  77. return (INT_PTR)(-1);
  78. }
  79. PerThread = &pTLS->Diamond;
  80. switch(Operation) {
  81. case fdintCABINET_INFO:
  82. //
  83. // Tell the callback function, in case it wants to do something
  84. // with this information.
  85. //
  86. err = ERROR_NOT_ENOUGH_MEMORY;
  87. CabInfo.CabinetFile = NewPortableString(Parameters->psz1);
  88. if(CabInfo.CabinetFile) {
  89. CabInfo.DiskName = NewPortableString(Parameters->psz2);
  90. if(CabInfo.DiskName) {
  91. CabInfo.CabinetPath = NewPortableString(Parameters->psz3);
  92. if(CabInfo.CabinetPath) {
  93. CabInfo.SetId = Parameters->setID;
  94. CabInfo.CabinetNumber = Parameters->iCabinet;
  95. err = (DWORD)pSetupCallMsgHandler(
  96. NULL, // LogContext - we get from thread log context
  97. PerThread->MsgHandler,
  98. PerThread->IsMsgHandlerNativeCharWidth,
  99. PerThread->Context,
  100. SPFILENOTIFY_CABINETINFO,
  101. (UINT_PTR)&CabInfo,
  102. 0
  103. );
  104. MyFree(CabInfo.CabinetPath);
  105. }
  106. MyFree(CabInfo.DiskName);
  107. }
  108. MyFree(CabInfo.CabinetFile);
  109. }
  110. if(err != NO_ERROR) {
  111. PerThread->LastError = err;
  112. }
  113. return (INT_PTR)((err == NO_ERROR) ? 0 : -1);
  114. case fdintCOPY_FILE:
  115. //
  116. // Diamond is asking us whether we want to copy the file.
  117. // If we switched cabinets, then the answer is no.
  118. //
  119. if(PerThread->SwitchedCabinets) {
  120. PerThread->LastError = NO_ERROR;
  121. return (INT_PTR)(-1);
  122. }
  123. // Pass the information on to the callback function and
  124. // let it decide.
  125. //
  126. FileInCab.NameInCabinet = NewPortableString(Parameters->psz1);
  127. FileInCab.FileSize = Parameters->cb;
  128. FileInCab.DosDate = Parameters->date;
  129. FileInCab.DosTime = Parameters->time;
  130. FileInCab.DosAttribs = Parameters->attribs;
  131. FileInCab.Win32Error = NO_ERROR;
  132. if(!FileInCab.NameInCabinet) {
  133. PerThread->LastError = ERROR_NOT_ENOUGH_MEMORY;
  134. return (INT_PTR)(-1);
  135. }
  136. //
  137. // Call the callback function.
  138. //
  139. action = pSetupCallMsgHandler(NULL, // LogContext - we get from thread log context
  140. PerThread->MsgHandler,
  141. PerThread->IsMsgHandlerNativeCharWidth,
  142. PerThread->Context,
  143. SPFILENOTIFY_FILEINCABINET,
  144. (UINT_PTR)&FileInCab,
  145. (UINT_PTR)PerThread->CabinetFile
  146. );
  147. MyFree (FileInCab.NameInCabinet);
  148. switch(action) {
  149. case FILEOP_SKIP:
  150. rc = 0;
  151. break;
  152. case FILEOP_DOIT:
  153. //
  154. // The callback wants to copy the file. In this case it has
  155. // provided us the full target pathname to use.
  156. //
  157. MYASSERT(PerThread->CurrentTargetFile == NULL);
  158. if(p = DuplicateString(FileInCab.FullTargetName)) {
  159. //
  160. // we need ANSI version of filename for sake of Diamond API's
  161. // note that the handle returned here must be compatible with
  162. // the handle returned by SpdFdiOpen
  163. //
  164. hFile = CreateFile(FileInCab.FullTargetName,
  165. GENERIC_READ | GENERIC_WRITE,
  166. FILE_SHARE_READ | FILE_SHARE_WRITE, // should probably be 0
  167. NULL,
  168. CREATE_ALWAYS,
  169. FILE_ATTRIBUTE_NORMAL,
  170. NULL);
  171. if(hFile == INVALID_HANDLE_VALUE) {
  172. PerThread->LastError = GetLastError();
  173. rc = -1;
  174. MyFree(p);
  175. } else {
  176. rc = (INT_PTR)hFile;
  177. PerThread->CurrentTargetFile = p;
  178. }
  179. } else {
  180. PerThread->LastError = ERROR_NOT_ENOUGH_MEMORY;
  181. rc = -1;
  182. }
  183. break;
  184. case FILEOP_ABORT:
  185. //
  186. // Abort.
  187. //
  188. rc = -1;
  189. PerThread->LastError = FileInCab.Win32Error;
  190. //
  191. // here, if PerThread->LastError is still NO_ERROR, this is ok
  192. // it was the callback's intent
  193. // we know callback itself is ok, since internal failure returns
  194. // FILEOP_INTERNAL_FAILED
  195. //
  196. break;
  197. case FILEOP_INTERNAL_FAILED:
  198. //
  199. // should only be returned by callback wrapper
  200. //
  201. PerThread->LastError = GetLastError();
  202. if(!PerThread->LastError) {
  203. MYASSERT(PerThread->LastError);
  204. PerThread->LastError = ERROR_OPERATION_ABORTED;
  205. }
  206. rc = -1;
  207. break;
  208. default:
  209. PerThread->LastError = ERROR_OPERATION_ABORTED;
  210. }
  211. return rc;
  212. case fdintCLOSE_FILE_INFO:
  213. //
  214. // Diamond is done with the target file and wants us to close it.
  215. // (ie, this is the counterpart to fdintCOPY_FILE).
  216. //
  217. // We want the timestamp to be what is stored in the cabinet.
  218. // Note that we lose the create and last access times in this case.
  219. //
  220. if(DosDateTimeToFileTime(Parameters->date,Parameters->time,&FileTime) &&
  221. LocalFileTimeToFileTime(&FileTime, &UtcTime)) {
  222. SetFileTime((HANDLE)Parameters->hf,NULL,NULL,&UtcTime);
  223. }
  224. SpdFdiClose(Parameters->hf);
  225. //
  226. // Call the callback function to inform it that the file has been
  227. // successfully extracted from the cabinet.
  228. //
  229. MYASSERT(PerThread->CurrentTargetFile);
  230. err = (DWORD)pDiamondNotifyFileDone(PerThread,NO_ERROR);
  231. if(err != NO_ERROR) {
  232. PerThread->LastError = err;
  233. }
  234. MyFree(PerThread->CurrentTargetFile);
  235. PerThread->CurrentTargetFile = NULL;
  236. return (INT_PTR)((err == NO_ERROR) ? TRUE : -1);
  237. case fdintPARTIAL_FILE:
  238. case fdintENUMERATE:
  239. //
  240. // We don't do anything with this.
  241. //
  242. return (INT_PTR)(0);
  243. case fdintNEXT_CABINET:
  244. if((Parameters->fdie == FDIERROR_NONE) || (Parameters->fdie == FDIERROR_WRONG_CABINET)) {
  245. //
  246. // A file continues into another cabinet.
  247. // Inform the callback function, who is responsible for
  248. // making sure the cabinet is accessible when it returns.
  249. //
  250. err = ERROR_NOT_ENOUGH_MEMORY;
  251. CabInfo.SetId = 0;
  252. CabInfo.CabinetNumber = 0;
  253. CabInfo.CabinetPath = NewPortableString(Parameters->psz3);
  254. if(CabInfo.CabinetPath) {
  255. CabInfo.CabinetFile = NewPortableString(Parameters->psz1);
  256. if(CabInfo.CabinetFile) {
  257. CabInfo.DiskName = NewPortableString(Parameters->psz2);
  258. if(CabInfo.DiskName) {
  259. err = (DWORD)pSetupCallMsgHandler(NULL, // LogContext - we get from thread log context
  260. PerThread->MsgHandler,
  261. PerThread->IsMsgHandlerNativeCharWidth,
  262. PerThread->Context,
  263. SPFILENOTIFY_NEEDNEWCABINET,
  264. (UINT_PTR)&CabInfo,
  265. (UINT_PTR)NewPath
  266. );
  267. if(err == NO_ERROR) {
  268. //
  269. // See if a new path was specified.
  270. //
  271. if(NewPath[0]) {
  272. lstrcpyn(PerThread->UserPath,NewPath,MAX_PATH);
  273. if(!pSetupConcatenatePaths(PerThread->UserPath,TEXT("\\"),MAX_PATH,NULL)) {
  274. err = ERROR_BUFFER_OVERFLOW;
  275. } else {
  276. PSTR pp = NewAnsiString(PerThread->UserPath);
  277. if(strlen(pp)>=CB_MAX_CAB_PATH) {
  278. err = ERROR_BUFFER_OVERFLOW;
  279. } else {
  280. strcpy(Parameters->psz3,pp);
  281. }
  282. MyFree(pp);
  283. }
  284. }
  285. }
  286. if(err == NO_ERROR) {
  287. //
  288. // Remember that we switched cabinets.
  289. //
  290. PerThread->SwitchedCabinets = TRUE;
  291. }
  292. MyFree(CabInfo.DiskName);
  293. }
  294. MyFree(CabInfo.CabinetFile);
  295. }
  296. MyFree(CabInfo.CabinetPath);
  297. }
  298. } else {
  299. //
  300. // Some other error we don't understand -- this indicates
  301. // a bad cabinet.
  302. //
  303. err = ERROR_INVALID_DATA;
  304. }
  305. if(err != NO_ERROR) {
  306. PerThread->LastError = err;
  307. }
  308. return (INT_PTR)((err == NO_ERROR) ? 0 : -1);
  309. default:
  310. //
  311. // Unknown notification type. Should never get here.
  312. //
  313. MYASSERT(0);
  314. return (INT_PTR)(0);
  315. }
  316. }
  317. PVOID
  318. DIAMONDAPI
  319. SpdFdiAlloc(
  320. IN ULONG NumberOfBytes
  321. )
  322. /*++
  323. Routine Description:
  324. Callback used by FDICopy to allocate memory.
  325. Arguments:
  326. NumberOfBytes - supplies desired size of block.
  327. Return Value:
  328. Returns pointer to a block of memory or NULL
  329. if memory cannot be allocated.
  330. --*/
  331. {
  332. return(MyMalloc(NumberOfBytes));
  333. }
  334. VOID
  335. DIAMONDAPI
  336. SpdFdiFree(
  337. IN PVOID Block
  338. )
  339. /*++
  340. Routine Description:
  341. Callback used by FDICopy to free a memory block.
  342. The block must have been allocated with SpdFdiAlloc().
  343. Arguments:
  344. Block - supplies pointer to block of memory to be freed.
  345. Return Value:
  346. None.
  347. --*/
  348. {
  349. MyFree(Block);
  350. }
  351. INT_PTR
  352. DIAMONDAPI
  353. SpdFdiOpen(
  354. IN PSTR FileName,
  355. IN int oflag,
  356. IN int pmode
  357. )
  358. /*++
  359. Routine Description:
  360. Callback used by FDICopy to open files.
  361. This routine is capable only of opening existing files.
  362. When making changes here, also take note of other places
  363. that open the file directly (search for SpdFdiOpen)
  364. Arguments:
  365. FileName - supplies name of file to be opened.
  366. oflag - supplies flags for open.
  367. pmode - supplies additional flags for open.
  368. Return Value:
  369. Handle to open file or -1 if error occurs.
  370. --*/
  371. {
  372. HANDLE h;
  373. PDIAMOND_THREAD_DATA PerThread;
  374. PSETUP_TLS pTLS;
  375. UNREFERENCED_PARAMETER(pmode);
  376. pTLS = SetupGetTlsData();
  377. if (!pTLS) {
  378. return -1;
  379. }
  380. PerThread = &pTLS->Diamond;
  381. MYASSERT(PerThread);
  382. if(oflag & (_O_WRONLY | _O_RDWR | _O_APPEND | _O_CREAT | _O_TRUNC | _O_EXCL)) {
  383. PerThread->LastError = ERROR_INVALID_PARAMETER;
  384. return(-1);
  385. }
  386. h = CreateFileA(FileName,
  387. GENERIC_READ,
  388. FILE_SHARE_READ,
  389. NULL,
  390. OPEN_EXISTING,
  391. 0,
  392. NULL);
  393. if(h == INVALID_HANDLE_VALUE) {
  394. PerThread->LastError = GetLastError();
  395. return(-1);
  396. }
  397. return (INT_PTR)h;
  398. }
  399. UINT
  400. DIAMONDAPI
  401. SpdFdiRead(
  402. IN INT_PTR Handle,
  403. OUT PVOID pv,
  404. IN UINT ByteCount
  405. )
  406. /*++
  407. Routine Description:
  408. Callback used by FDICopy to read from a file.
  409. Arguments:
  410. Handle - supplies handle to open file to be read from.
  411. pv - supplies pointer to buffer to receive bytes we read.
  412. ByteCount - supplies number of bytes to read.
  413. Return Value:
  414. Number of bytes read or -1 if an error occurs.
  415. --*/
  416. {
  417. PDIAMOND_THREAD_DATA PerThread;
  418. PSETUP_TLS pTLS;
  419. DWORD d;
  420. HANDLE hFile = (HANDLE)Handle;
  421. DWORD bytes;
  422. UINT rc;
  423. if(ReadFile(hFile,pv,(DWORD)ByteCount,&bytes,NULL)) {
  424. rc = (UINT)bytes;
  425. } else {
  426. d = GetLastError();
  427. rc = (UINT)(-1);
  428. pTLS = SetupGetTlsData();
  429. MYASSERT(pTLS);
  430. PerThread = &pTLS->Diamond;
  431. PerThread->LastError = d;
  432. }
  433. return rc;
  434. }
  435. UINT
  436. DIAMONDAPI
  437. SpdFdiWrite(
  438. IN INT_PTR Handle,
  439. IN PVOID pv,
  440. IN UINT ByteCount
  441. )
  442. /*++
  443. Routine Description:
  444. Callback used by FDICopy to write to a file.
  445. Arguments:
  446. Handle - supplies handle to open file to be written to.
  447. pv - supplies pointer to buffer containing bytes to write.
  448. ByteCount - supplies number of bytes to write.
  449. Return Value:
  450. Number of bytes written (ByteCount) or -1 if an error occurs.
  451. --*/
  452. {
  453. UINT rc;
  454. PDIAMOND_THREAD_DATA PerThread;
  455. PSETUP_TLS pTLS;
  456. DWORD d;
  457. HANDLE hFile = (HANDLE)Handle;
  458. DWORD bytes;
  459. if(WriteFile(hFile,pv,(DWORD)ByteCount,&bytes,NULL)) {
  460. rc = (UINT)bytes;
  461. } else {
  462. d = GetLastError();
  463. rc = (UINT)(-1);
  464. pTLS = SetupGetTlsData();
  465. MYASSERT(pTLS);
  466. PerThread = &pTLS->Diamond;
  467. PerThread->LastError = d;
  468. }
  469. return rc;
  470. }
  471. int
  472. DIAMONDAPI
  473. SpdFdiClose(
  474. IN INT_PTR Handle
  475. )
  476. /*++
  477. Routine Description:
  478. Callback used by FDICopy to close files.
  479. Arguments:
  480. Handle - handle of file to close.
  481. Return Value:
  482. 0 (success).
  483. --*/
  484. {
  485. HANDLE hFile = (HANDLE)Handle;
  486. BOOL success = FALSE;
  487. //
  488. // diamond has in the past given us an invalid file handle
  489. // actually it gives us the same file handle twice.
  490. //
  491. //
  492. try {
  493. success = CloseHandle(hFile);
  494. } except(EXCEPTION_EXECUTE_HANDLER) {
  495. success = FALSE;
  496. }
  497. MYASSERT(success);
  498. //
  499. // Always act like we succeeded.
  500. //
  501. return 0;
  502. }
  503. long
  504. DIAMONDAPI
  505. SpdFdiSeek(
  506. IN INT_PTR Handle,
  507. IN long Distance,
  508. IN int SeekType
  509. )
  510. /*++
  511. Routine Description:
  512. Callback used by FDICopy to seek files.
  513. Arguments:
  514. Handle - handle of file to close.
  515. Distance - supplies distance to seek. Interpretation of this
  516. parameter depends on the value of SeekType.
  517. SeekType - supplies a value indicating how Distance is to be
  518. interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
  519. Return Value:
  520. New file offset or -1 if an error occurs.
  521. --*/
  522. {
  523. LONG rc;
  524. DWORD d;
  525. PDIAMOND_THREAD_DATA PerThread;
  526. PSETUP_TLS pTLS;
  527. HANDLE hFile = (HANDLE)Handle;
  528. DWORD pos_low;
  529. DWORD method;
  530. switch(SeekType) {
  531. case SEEK_SET:
  532. method = FILE_BEGIN;
  533. break;
  534. case SEEK_CUR:
  535. method = FILE_CURRENT;
  536. break;
  537. case SEEK_END:
  538. method = FILE_END;
  539. break;
  540. default:
  541. return -1;
  542. }
  543. pos_low = SetFilePointer(hFile,(DWORD)Distance,NULL,method);
  544. if(pos_low == INVALID_SET_FILE_POINTER) {
  545. d = GetLastError();
  546. rc = -1L;
  547. pTLS = SetupGetTlsData();
  548. MYASSERT(pTLS);
  549. PerThread = &pTLS->Diamond;
  550. PerThread->LastError = d;
  551. } else {
  552. rc = (long)pos_low;
  553. }
  554. return(rc);
  555. }
  556. DWORD
  557. DiamondProcessCabinet(
  558. IN PCTSTR CabinetFile,
  559. IN DWORD Flags,
  560. IN PVOID MsgHandler,
  561. IN PVOID Context,
  562. IN BOOL IsMsgHandlerNativeCharWidth
  563. )
  564. /*++
  565. Routine Description:
  566. Process a diamond cabinet file, iterating through all files
  567. contained within it and calling the callback function with
  568. information about each file.
  569. Arguments:
  570. SourceFileName - supplies name of cabinet file.
  571. Flags - supplies flags to control behavior of cabinet processing.
  572. MsgHandler - Supplies a callback routine to be notified
  573. of various significant events in cabinet processing.
  574. Context - Supplies a value that is passed to the MsgHandler
  575. callback function.
  576. Return Value:
  577. Win32 error code indicating result. If the cabinet was corrupt,
  578. ERROR_INVALID_DATA is returned.
  579. --*/
  580. {
  581. BOOL b;
  582. DWORD rc;
  583. PDIAMOND_THREAD_DATA PerThread;
  584. PSETUP_TLS pTLS;
  585. PSTR FilePartA = NULL;
  586. PSTR PathPartA = NULL;
  587. PCTSTR FileTitle;
  588. CHAR c;
  589. int h;
  590. UNREFERENCED_PARAMETER(Flags);
  591. //
  592. // Fetch pointer to per-thread data.
  593. // may cause initialization
  594. //
  595. pTLS = SetupGetTlsData();
  596. if(!pTLS) {
  597. rc = ERROR_NOT_ENOUGH_MEMORY;
  598. goto c0;
  599. }
  600. PerThread = &pTLS->Diamond;
  601. MYASSERT(PerThread->FdiContext);
  602. //
  603. // Because diamond does not really give us a truly comprehensive
  604. // context mechanism, our diamond support is NOT reentrant.
  605. // No synchronization is required to check this state because
  606. // it is stored in per-thread data.
  607. //
  608. if(PerThread->InDiamond) {
  609. rc = ERROR_INVALID_FUNCTION;
  610. goto c0;
  611. }
  612. PerThread->InDiamond = TRUE;
  613. //
  614. // Split the cabinet name into path and name.
  615. // we need to convert to short-name format before
  616. // passing it on, so that diamond doesn't get upset
  617. // in MUI install situations
  618. //
  619. FileTitle = pSetupGetFileTitle(CabinetFile);
  620. FilePartA = GetAnsiMuiSafeFilename(FileTitle);
  621. PathPartA = GetAnsiMuiSafePathname(CabinetFile);
  622. if(!FilePartA || !PathPartA) {
  623. rc = ERROR_NOT_ENOUGH_MEMORY;
  624. goto c1;
  625. }
  626. //
  627. // Initialize thread globals.
  628. //
  629. PerThread->LastError = NO_ERROR;
  630. PerThread->CabinetFile = CabinetFile;
  631. PerThread->MsgHandler = MsgHandler;
  632. PerThread->IsMsgHandlerNativeCharWidth = IsMsgHandlerNativeCharWidth;
  633. PerThread->Context = Context;
  634. PerThread->SwitchedCabinets = FALSE;
  635. PerThread->UserPath[0] = 0;
  636. PerThread->CurrentTargetFile = NULL;
  637. //
  638. // Perform the copy.
  639. //
  640. b = FDICopy(
  641. PerThread->FdiContext,
  642. FilePartA,
  643. PathPartA,
  644. 0, // flags
  645. DiamondNotifyFunction,
  646. NULL, // no decryption
  647. NULL // don't bother with user-specified data
  648. );
  649. if(b) {
  650. //
  651. // Everything succeeded so we shouldn't have any partially
  652. // processed files.
  653. //
  654. MYASSERT(!PerThread->CurrentTargetFile);
  655. rc = NO_ERROR;
  656. } else {
  657. switch(PerThread->FdiError.erfOper) {
  658. case FDIERROR_NONE:
  659. //
  660. // We shouldn't see this -- if there was no error
  661. // then FDICopy should have returned TRUE.
  662. //
  663. MYASSERT(PerThread->FdiError.erfOper != FDIERROR_NONE);
  664. rc = ERROR_INVALID_DATA;
  665. break;
  666. case FDIERROR_CABINET_NOT_FOUND:
  667. rc = ERROR_FILE_NOT_FOUND;
  668. break;
  669. case FDIERROR_CORRUPT_CABINET:
  670. //
  671. // Read/open/seek error or corrupt cabinet
  672. //
  673. rc = PerThread->LastError;
  674. if(rc == NO_ERROR) {
  675. rc = ERROR_INVALID_DATA;
  676. }
  677. break;
  678. case FDIERROR_ALLOC_FAIL:
  679. rc = ERROR_NOT_ENOUGH_MEMORY;
  680. break;
  681. case FDIERROR_TARGET_FILE:
  682. case FDIERROR_USER_ABORT:
  683. rc = PerThread->LastError;
  684. break;
  685. case FDIERROR_NOT_A_CABINET:
  686. case FDIERROR_UNKNOWN_CABINET_VERSION:
  687. case FDIERROR_BAD_COMPR_TYPE:
  688. case FDIERROR_MDI_FAIL:
  689. case FDIERROR_RESERVE_MISMATCH:
  690. case FDIERROR_WRONG_CABINET:
  691. default:
  692. //
  693. // Cabinet is corrupt or not actually a cabinet, etc.
  694. //
  695. rc = ERROR_INVALID_DATA;
  696. break;
  697. }
  698. if(PerThread->CurrentTargetFile) {
  699. //
  700. // Call the callback function to inform it that the last file
  701. // was not successfully extracted from the cabinet.
  702. // Also remove the partially copied file.
  703. //
  704. DeleteFile(PerThread->CurrentTargetFile);
  705. pDiamondNotifyFileDone(PerThread,rc);
  706. MyFree(PerThread->CurrentTargetFile);
  707. PerThread->CurrentTargetFile = NULL;
  708. }
  709. }
  710. c1:
  711. if(FilePartA) {
  712. MyFree(FilePartA);
  713. }
  714. if(PathPartA) {
  715. MyFree(PathPartA);
  716. }
  717. PerThread->InDiamond = FALSE;
  718. c0:
  719. return(rc);
  720. }
  721. BOOL
  722. DiamondIsCabinet(
  723. IN PCTSTR FileName
  724. )
  725. /*++
  726. Routine Description:
  727. Determine if a file is a diamond cabinet.
  728. Arguments:
  729. FileName - supplies name of file to be checked.
  730. Return Value:
  731. TRUE if file is diamond file. FALSE if not;
  732. --*/
  733. {
  734. FDICABINETINFO CabinetInfo;
  735. BOOL b;
  736. INT_PTR h;
  737. HANDLE hFile;
  738. PDIAMOND_THREAD_DATA PerThread;
  739. PSETUP_TLS pTLS;
  740. b = FALSE;
  741. //
  742. // Get TLS data, may cause initialization
  743. //
  744. pTLS = SetupGetTlsData();
  745. if(!pTLS) {
  746. goto c0;
  747. }
  748. if (!FileExists(FileName,NULL)) {
  749. return FALSE;
  750. }
  751. PerThread = &pTLS->Diamond;
  752. MYASSERT(PerThread->FdiContext);
  753. //
  754. // Because diamond does not really give us a truly comprehensive
  755. // context mechanism, our diamond support is NOT reentrant.
  756. // No synchronization is required to check this state because
  757. // it is stored in per-thread data.
  758. //
  759. if(PerThread->InDiamond) {
  760. MYASSERT( FALSE && TEXT("PerThread->InDiamond failed") );
  761. goto c0;
  762. }
  763. PerThread->InDiamond = TRUE;
  764. //
  765. // The handle returned here must be compatible with
  766. // that returnd by SpdFdiOpen
  767. //
  768. hFile = CreateFile(FileName,
  769. GENERIC_READ,
  770. FILE_SHARE_READ,
  771. NULL,
  772. OPEN_EXISTING,
  773. 0,
  774. NULL);
  775. if(hFile == INVALID_HANDLE_VALUE) {
  776. goto c1;
  777. }
  778. h = (INT_PTR)hFile;
  779. SpdFdiSeek(h , 0, SEEK_SET);
  780. b = FDIIsCabinet(PerThread->FdiContext,h,&CabinetInfo);
  781. #if DBG
  782. if (!b) {
  783. LPCTSTR p;
  784. p = _tcsrchr(FileName, TEXT('.'));
  785. while (p && *p) {
  786. if (*p == '_') {
  787. MYASSERT(FALSE && TEXT("FDIIsCabinetFailed for a file ending in _"));
  788. SpdFdiSeek(h , 0, SEEK_SET);
  789. FDIIsCabinet(PerThread->FdiContext,h,&CabinetInfo);
  790. }
  791. p++;
  792. }
  793. }
  794. #endif
  795. SpdFdiClose(h);
  796. c1:
  797. PerThread->InDiamond = FALSE;
  798. c0:
  799. return(b);
  800. }
  801. BOOL
  802. DiamondInitialize(
  803. VOID
  804. )
  805. /*++
  806. Routine Description:
  807. Per-thread initialization routine for Diamond.
  808. Called once per thread.
  809. Arguments:
  810. None.
  811. Return Value:
  812. Boolean result indicating success or failure.
  813. Failure can be assumed to be out of memory.
  814. --*/
  815. {
  816. HFDI FdiContext;
  817. PDIAMOND_THREAD_DATA PerThread;
  818. PSETUP_TLS pTLS;
  819. BOOL retval = FALSE;
  820. pTLS = SetupGetTlsData();
  821. MYASSERT(pTLS);
  822. PerThread = &pTLS->Diamond;
  823. PerThread->FdiContext = NULL;
  824. retval = FALSE;
  825. try {
  826. //
  827. // Initialize a diamond context.
  828. //
  829. FdiContext = FDICreate(
  830. SpdFdiAlloc,
  831. SpdFdiFree,
  832. SpdFdiOpen,
  833. SpdFdiRead,
  834. SpdFdiWrite,
  835. SpdFdiClose,
  836. SpdFdiSeek,
  837. cpuUNKNOWN,
  838. &PerThread->FdiError
  839. );
  840. if(FdiContext) {
  841. PerThread->FdiContext = FdiContext;
  842. retval = TRUE;
  843. }
  844. } except(EXCEPTION_EXECUTE_HANDLER) {
  845. retval = FALSE;
  846. }
  847. return(retval);
  848. }
  849. VOID
  850. DiamondTerminate(
  851. VOID
  852. )
  853. /*++
  854. Routine Description:
  855. Per-thread termination routine for Diamond.
  856. Called internally.
  857. Arguments:
  858. None.
  859. Return Value:
  860. Boolean result indicating success or failure.
  861. Failure can be assumed to be out of memory.
  862. --*/
  863. {
  864. PSETUP_TLS pTLS;
  865. PDIAMOND_THREAD_DATA PerThread;
  866. pTLS = SetupGetTlsData();
  867. PerThread = pTLS? &pTLS->Diamond : NULL;
  868. if(PerThread && PerThread->FdiContext) {
  869. FDIDestroy(PerThread->FdiContext);
  870. PerThread->FdiContext = NULL;
  871. }
  872. }
  873. BOOL
  874. DiamondProcessAttach(
  875. IN BOOL Attach
  876. )
  877. /*++
  878. Routine Description:
  879. Process attach routine. Must be called by the DLL entry point routine
  880. on DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH notifications.
  881. Arguments:
  882. Attach - TRUE if process is attaching; FALSE if not.
  883. Return Value:
  884. Boolean result indicating success or failure. Meaningful only if
  885. Attach is TRUE.
  886. --*/
  887. {
  888. return TRUE;
  889. }
  890. BOOL
  891. DiamondTlsInit(
  892. IN BOOL Init
  893. )
  894. /*++
  895. Routine Description:
  896. The routine initializes per-thread data used by diamond.
  897. Arguments:
  898. Init - TRUE if thread initialization; FALSE to cleanup
  899. Return Value:
  900. None.
  901. --*/
  902. {
  903. if(Init) {
  904. return DiamondInitialize();
  905. } else {
  906. DiamondTerminate();
  907. return TRUE;
  908. }
  909. }
  910. ///////////////////////////////////////////////////////////////////////////
  911. BOOL
  912. _SetupIterateCabinet(
  913. IN PCTSTR CabinetFile,
  914. IN DWORD Flags,
  915. IN PVOID MsgHandler,
  916. IN PVOID Context,
  917. IN BOOL IsMsgHandlerNativeCharWidth
  918. )
  919. {
  920. PTSTR cabinetFile;
  921. DWORD rc;
  922. //
  923. // Flags param not used. Make sure it's zero.
  924. //
  925. if(Flags) {
  926. rc = ERROR_INVALID_PARAMETER;
  927. goto c0;
  928. }
  929. //
  930. // Get a copy of the cabinet file name to validate
  931. // the caller's buffer.
  932. //
  933. try {
  934. cabinetFile = DuplicateString(CabinetFile);
  935. } except(EXCEPTION_EXECUTE_HANDLER) {
  936. rc = ERROR_INVALID_PARAMETER;
  937. goto c0;
  938. }
  939. if(!cabinetFile) {
  940. rc = ERROR_NOT_ENOUGH_MEMORY;
  941. goto c0;
  942. }
  943. rc = DiamondProcessCabinet(cabinetFile,Flags,MsgHandler,Context,IsMsgHandlerNativeCharWidth);
  944. MyFree(cabinetFile);
  945. c0:
  946. SetLastError(rc);
  947. return(rc == NO_ERROR);
  948. }
  949. #ifdef UNICODE
  950. //
  951. // ANSI version
  952. //
  953. BOOL
  954. SetupIterateCabinetA(
  955. IN PCSTR CabinetFile,
  956. IN DWORD Flags,
  957. IN PSP_FILE_CALLBACK_A MsgHandler,
  958. IN PVOID Context
  959. )
  960. {
  961. BOOL b;
  962. DWORD rc;
  963. PCWSTR cabinetFile;
  964. rc = pSetupCaptureAndConvertAnsiArg(CabinetFile,&cabinetFile);
  965. if(rc == NO_ERROR) {
  966. b = _SetupIterateCabinet(cabinetFile,Flags,MsgHandler,Context,FALSE);
  967. rc = GetLastError();
  968. MyFree(cabinetFile);
  969. } else {
  970. b = FALSE;
  971. }
  972. SetLastError(rc);
  973. return(b);
  974. }
  975. #else
  976. //
  977. // Unicode stub
  978. //
  979. BOOL
  980. SetupIterateCabinetW(
  981. IN PCWSTR CabinetFile,
  982. IN DWORD Flags,
  983. IN PSP_FILE_CALLBACK_W MsgHandler,
  984. IN PVOID Context
  985. )
  986. {
  987. UNREFERENCED_PARAMETER(CabinetFile);
  988. UNREFERENCED_PARAMETER(Flags);
  989. UNREFERENCED_PARAMETER(MsgHandler);
  990. UNREFERENCED_PARAMETER(Context);
  991. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  992. return(FALSE);
  993. }
  994. #endif
  995. BOOL
  996. SetupIterateCabinet(
  997. IN PCTSTR CabinetFile,
  998. IN DWORD Flags,
  999. IN PSP_FILE_CALLBACK MsgHandler,
  1000. IN PVOID Context
  1001. )
  1002. {
  1003. return(_SetupIterateCabinet(CabinetFile,Flags,MsgHandler,Context,TRUE));
  1004. }