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.

1367 lines
31 KiB

  1. /*++
  2. Module Name:
  3. diamond.c
  4. Abstract:
  5. Diamond compression routines.
  6. This module contains functions to create a cabinet with
  7. files compressed using the mszip compression library.
  8. Author:
  9. Ovidiu Temereanca (ovidiut) 26-Oct-2000
  10. --*/
  11. #include "precomp.h"
  12. #include <fci.h>
  13. #include <fdi.h>
  14. #include <io.h>
  15. #include <fcntl.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <limits.h>
  19. static DWORD g_DiamondLastError;
  20. static PCSTR g_TempDir = NULL;
  21. static ERF g_FciError;
  22. static ERF g_FdiError;
  23. typedef struct {
  24. PSP_FILE_CALLBACK MsgHandler;
  25. PVOID Context;
  26. PCTSTR CabinetFile;
  27. PCTSTR CurrentTargetFile;
  28. DWORD LastError;
  29. TCHAR UserPath[MAX_PATH];
  30. BOOL SwitchedCabinets;
  31. } FDICONTEXT, *PFDICONTEXT;
  32. HFCI
  33. (DIAMONDAPI* g_FCICreate) (
  34. PERF perf,
  35. PFNFCIFILEPLACED pfnfcifp,
  36. PFNFCIALLOC pfna,
  37. PFNFCIFREE pfnf,
  38. PFNFCIOPEN pfnopen,
  39. PFNFCIREAD pfnread,
  40. PFNFCIWRITE pfnwrite,
  41. PFNFCICLOSE pfnclose,
  42. PFNFCISEEK pfnseek,
  43. PFNFCIDELETE pfndelete,
  44. PFNFCIGETTEMPFILE pfnfcigtf,
  45. PCCAB pccab,
  46. void FAR * pv
  47. );
  48. BOOL
  49. (DIAMONDAPI* g_FCIAddFile) (
  50. HFCI hfci,
  51. char *pszSourceFile,
  52. char *pszFileName,
  53. BOOL fExecute,
  54. PFNFCIGETNEXTCABINET pfnfcignc,
  55. PFNFCISTATUS pfnfcis,
  56. PFNFCIGETOPENINFO pfnfcigoi,
  57. TCOMP typeCompress
  58. );
  59. BOOL
  60. (DIAMONDAPI* g_FCIFlushCabinet) (
  61. HFCI hfci,
  62. BOOL fGetNextCab,
  63. PFNFCIGETNEXTCABINET pfnfcignc,
  64. PFNFCISTATUS pfnfcis
  65. );
  66. BOOL
  67. (DIAMONDAPI* g_FCIDestroy) (
  68. HFCI hfci
  69. );
  70. HFDI
  71. (DIAMONDAPI* g_FDICreate ) (
  72. PFNALLOC pfnalloc,
  73. PFNFREE pfnfree,
  74. PFNOPEN pfnopen,
  75. PFNREAD pfnread,
  76. PFNWRITE pfnwrite,
  77. PFNCLOSE pfnclose,
  78. PFNSEEK pfnseek,
  79. int cpuType,
  80. PERF perf
  81. );
  82. BOOL
  83. (DIAMONDAPI* g_FDICopy) (
  84. HFDI hfdi,
  85. char FAR *pszCabinet,
  86. char FAR *pszCabPath,
  87. int flags,
  88. PFNFDINOTIFY pfnfdin,
  89. PFNFDIDECRYPT pfnfdid,
  90. void FAR *pvUser
  91. );
  92. BOOL
  93. (DIAMONDAPI* g_FDIDestroy) (
  94. HFDI hfdi
  95. );
  96. //
  97. // FCI callback functions to perform memory allocation, io, etc.
  98. // We pass addresses of these functions to diamond.
  99. //
  100. int
  101. DIAMONDAPI
  102. fciFilePlacedCB(
  103. OUT PCCAB Cabinet,
  104. IN PSTR FileName,
  105. IN LONG FileSize,
  106. IN BOOL Continuation,
  107. IN PVOID Context
  108. )
  109. /*++
  110. Routine Description:
  111. Callback used by diamond to indicate that a file has been
  112. comitted to a cabinet.
  113. No action is taken and success is returned.
  114. Arguments:
  115. Cabinet - cabinet structure to fill in.
  116. FileName - name of file in cabinet
  117. FileSize - size of file in cabinet
  118. Continuation - TRUE if this is a partial file, continuation
  119. of compression begun in a different cabinet.
  120. Context - supplies context information.
  121. Return Value:
  122. 0 (success).
  123. --*/
  124. {
  125. return(0);
  126. }
  127. PVOID
  128. DIAMONDAPI
  129. myAlloc(
  130. IN ULONG NumberOfBytes
  131. )
  132. /*++
  133. Routine Description:
  134. Callback used by diamond to allocate memory.
  135. Arguments:
  136. NumberOfBytes - supplies desired size of block.
  137. Return Value:
  138. Returns pointer to a block of memory or NULL
  139. if memory cannot be allocated.
  140. --*/
  141. {
  142. return HeapAlloc (GetProcessHeap(), 0, NumberOfBytes);
  143. }
  144. VOID
  145. DIAMONDAPI
  146. myFree(
  147. IN PVOID Block
  148. )
  149. /*++
  150. Routine Description:
  151. Callback used by diamond to free a memory block.
  152. The block must have been allocated with fciAlloc().
  153. Arguments:
  154. Block - supplies pointer to block of memory to be freed.
  155. Return Value:
  156. None.
  157. --*/
  158. {
  159. HeapFree (GetProcessHeap(), 0, Block);
  160. }
  161. //This next line expands to ==> BOOL DIAMONDAPI fciTempFileCB(char *pszTempName,
  162. // int cbTempName,
  163. // void FAR *pv)
  164. FNFCIGETTEMPFILE(fciTempFileCB)
  165. {
  166. //BUGBUG -- should we check that cbTempName >= MAX_PATH, since GetTempFileNameA expects it?
  167. if (!GetTempFileNameA (g_TempDir ? g_TempDir : ".", "dc" , 0, pszTempName)) {
  168. return FALSE;
  169. }
  170. DeleteFileA(pszTempName);
  171. return(TRUE);
  172. }
  173. BOOL
  174. DIAMONDAPI
  175. fciNextCabinetCB(
  176. OUT PCCAB Cabinet,
  177. IN DWORD CabinetSizeEstimate,
  178. IN PVOID Context
  179. )
  180. /*++
  181. Routine Description:
  182. Callback used by diamond to request a new cabinet file.
  183. This functionality is not used in our implementation.
  184. Arguments:
  185. Cabinet - cabinet structure to be filled in.
  186. CabinetSizeEstimate - estimated size of cabinet.
  187. Context - supplies context information.
  188. Return Value:
  189. FALSE (failure).
  190. --*/
  191. {
  192. return(FALSE);
  193. }
  194. BOOL
  195. DIAMONDAPI
  196. fciStatusCB(
  197. IN UINT StatusType,
  198. IN DWORD Count1,
  199. IN DWORD Count2,
  200. IN PVOID Context
  201. )
  202. /*++
  203. Routine Description:
  204. Callback used by diamond to give status on file compression
  205. and cabinet operations, etc.
  206. This routine has no effect.
  207. Arguments:
  208. Status Type - supplies status type.
  209. 0 = statusFile - compressing block into a folder.
  210. Count1 = compressed size
  211. Count2 = uncompressed size
  212. 1 = statusFolder - performing AddFilder.
  213. Count1 = bytes done
  214. Count2 = total bytes
  215. Context - supplies context info.
  216. Return Value:
  217. TRUE (success).
  218. --*/
  219. {
  220. return(TRUE);
  221. }
  222. FNFCIGETOPENINFO(fciOpenInfoCB)
  223. /*++
  224. Routine Description:
  225. Callback used by diamond to open a file and retreive information
  226. about it.
  227. Arguments:
  228. pszName - supplies filename of file about which information
  229. is desired.
  230. pdate - receives last write date of the file if the file exists.
  231. ptime - receives last write time of the file if the file exists.
  232. pattribs - receives file attributes if the file exists.
  233. pv - supplies context information.
  234. Return Value:
  235. C runtime handle to open file if success; -1 if file could
  236. not be located or opened.
  237. --*/
  238. {
  239. int h;
  240. WIN32_FIND_DATAA FindData;
  241. HANDLE FindHandle;
  242. FindHandle = FindFirstFileA(pszName,&FindData);
  243. if(FindHandle == INVALID_HANDLE_VALUE) {
  244. g_DiamondLastError = GetLastError();
  245. return(-1);
  246. }
  247. FindClose(FindHandle);
  248. FileTimeToDosDateTime(&FindData.ftLastWriteTime,pdate,ptime);
  249. *pattribs = (WORD)FindData.dwFileAttributes;
  250. h = _open(pszName,_O_RDONLY | _O_BINARY);
  251. if(h == -1) {
  252. g_DiamondLastError = GetLastError();
  253. return(-1);
  254. }
  255. return(h);
  256. }
  257. FNFCIOPEN(fciOpen)
  258. {
  259. int result;
  260. result = _open(pszFile, oflag, pmode);
  261. if (result == -1) {
  262. *err = errno;
  263. }
  264. return(result);
  265. }
  266. FNFCIREAD(fciRead)
  267. {
  268. UINT result;
  269. result = (UINT) _read((int)hf, memory, cb);
  270. if (result != cb) {
  271. *err = errno;
  272. }
  273. return(result);
  274. }
  275. FNFCIWRITE(fciWrite)
  276. {
  277. UINT result;
  278. result = (UINT) _write((int)hf, memory, cb);
  279. if (result != cb) {
  280. *err = errno;
  281. }
  282. return(result);
  283. }
  284. FNFCICLOSE(fciClose)
  285. {
  286. int result;
  287. result = _close((int)hf);
  288. if (result == -1) {
  289. *err = errno;
  290. }
  291. return(result);
  292. }
  293. FNFCISEEK(fciSeek)
  294. {
  295. long result;
  296. result = _lseek((int)hf, dist, seektype);
  297. if (result == -1) {
  298. *err = errno;
  299. }
  300. return(result);
  301. }
  302. FNFCIDELETE(fciDelete)
  303. {
  304. int result;
  305. result = _unlink(pszFile);
  306. if (result == -1) {
  307. *err = errno;
  308. }
  309. return(result);
  310. }
  311. //
  312. // FDI callback functions
  313. //
  314. INT_PTR
  315. DIAMONDAPI
  316. FdiOpen(
  317. IN PSTR FileName,
  318. IN int oflag,
  319. IN int pmode
  320. )
  321. /*++
  322. Routine Description:
  323. Callback used by FDICopy to open files.
  324. This routine is capable only of opening existing files.
  325. When making changes here, also take note of other places
  326. that open the file directly (search for FdiOpen)
  327. Arguments:
  328. FileName - supplies name of file to be opened.
  329. oflag - supplies flags for open.
  330. pmode - supplies additional flags for open.
  331. Return Value:
  332. Handle to open file or -1 if error occurs.
  333. --*/
  334. {
  335. HANDLE h;
  336. UNREFERENCED_PARAMETER(pmode);
  337. if(oflag & (_O_WRONLY | _O_RDWR | _O_APPEND | _O_CREAT | _O_TRUNC | _O_EXCL)) {
  338. g_DiamondLastError = ERROR_INVALID_PARAMETER;
  339. return(-1);
  340. }
  341. h = CreateFileA(FileName,
  342. GENERIC_READ,
  343. FILE_SHARE_READ,
  344. NULL,
  345. OPEN_EXISTING,
  346. 0,
  347. NULL);
  348. if(h == INVALID_HANDLE_VALUE) {
  349. g_DiamondLastError = GetLastError();
  350. return(-1);
  351. }
  352. return (INT_PTR)h;
  353. }
  354. UINT
  355. DIAMONDAPI
  356. FdiRead(
  357. IN INT_PTR Handle,
  358. OUT PVOID pv,
  359. IN UINT ByteCount
  360. )
  361. /*++
  362. Routine Description:
  363. Callback used by FDICopy to read from a file.
  364. Arguments:
  365. Handle - supplies handle to open file to be read from.
  366. pv - supplies pointer to buffer to receive bytes we read.
  367. ByteCount - supplies number of bytes to read.
  368. Return Value:
  369. Number of bytes read or -1 if an error occurs.
  370. --*/
  371. {
  372. HANDLE hFile = (HANDLE)Handle;
  373. DWORD bytes;
  374. UINT rc;
  375. if(ReadFile(hFile,pv,(DWORD)ByteCount,&bytes,NULL)) {
  376. rc = (UINT)bytes;
  377. } else {
  378. g_DiamondLastError = GetLastError();
  379. rc = (UINT)(-1);
  380. }
  381. return rc;
  382. }
  383. UINT
  384. DIAMONDAPI
  385. FdiWrite(
  386. IN INT_PTR Handle,
  387. IN PVOID pv,
  388. IN UINT ByteCount
  389. )
  390. /*++
  391. Routine Description:
  392. Callback used by FDICopy to write to a file.
  393. Arguments:
  394. Handle - supplies handle to open file to be written to.
  395. pv - supplies pointer to buffer containing bytes to write.
  396. ByteCount - supplies number of bytes to write.
  397. Return Value:
  398. Number of bytes written (ByteCount) or -1 if an error occurs.
  399. --*/
  400. {
  401. UINT rc;
  402. HANDLE hFile = (HANDLE)Handle;
  403. DWORD bytes;
  404. if(WriteFile(hFile,pv,(DWORD)ByteCount,&bytes,NULL)) {
  405. rc = (UINT)bytes;
  406. } else {
  407. g_DiamondLastError = GetLastError();
  408. rc = (UINT)(-1);
  409. }
  410. return rc;
  411. }
  412. int
  413. DIAMONDAPI
  414. FdiClose(
  415. IN INT_PTR Handle
  416. )
  417. /*++
  418. Routine Description:
  419. Callback used by FDICopy to close files.
  420. Arguments:
  421. Handle - handle of file to close.
  422. Return Value:
  423. 0 (success).
  424. --*/
  425. {
  426. HANDLE hFile = (HANDLE)Handle;
  427. BOOL success = FALSE;
  428. //
  429. // diamond has in the past given us an invalid file handle
  430. // actually it gives us the same file handle twice.
  431. //
  432. //
  433. try {
  434. success = CloseHandle(hFile);
  435. } except(EXCEPTION_EXECUTE_HANDLER) {
  436. success = FALSE;
  437. }
  438. MYASSERT(success);
  439. //
  440. // Always act like we succeeded.
  441. //
  442. return 0;
  443. }
  444. long
  445. DIAMONDAPI
  446. FdiSeek(
  447. IN INT_PTR Handle,
  448. IN long Distance,
  449. IN int SeekType
  450. )
  451. /*++
  452. Routine Description:
  453. Callback used by FDICopy to seek files.
  454. Arguments:
  455. Handle - handle of file to close.
  456. Distance - supplies distance to seek. Interpretation of this
  457. parameter depends on the value of SeekType.
  458. SeekType - supplies a value indicating how Distance is to be
  459. interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
  460. Return Value:
  461. New file offset or -1 if an error occurs.
  462. --*/
  463. {
  464. LONG rc;
  465. HANDLE hFile = (HANDLE)Handle;
  466. DWORD pos_low;
  467. DWORD method;
  468. switch(SeekType) {
  469. case SEEK_SET:
  470. method = FILE_BEGIN;
  471. break;
  472. case SEEK_CUR:
  473. method = FILE_CURRENT;
  474. break;
  475. case SEEK_END:
  476. method = FILE_END;
  477. break;
  478. default:
  479. return -1;
  480. }
  481. pos_low = SetFilePointer(hFile,(DWORD)Distance,NULL,method);
  482. if(pos_low == INVALID_SET_FILE_POINTER) {
  483. g_DiamondLastError = GetLastError();
  484. rc = -1L;
  485. } else {
  486. rc = (long)pos_low;
  487. }
  488. return(rc);
  489. }
  490. HANDLE
  491. DiamondInitialize (
  492. IN PCTSTR TempDir
  493. )
  494. {
  495. HMODULE hCabinetDll;
  496. hCabinetDll = LoadLibrary (TEXT("cabinet.dll"));
  497. if (!hCabinetDll) {
  498. return FALSE;
  499. }
  500. (FARPROC)g_FCICreate = GetProcAddress (hCabinetDll, "FCICreate");
  501. (FARPROC)g_FCIAddFile = GetProcAddress (hCabinetDll, "FCIAddFile");
  502. (FARPROC)g_FCIFlushCabinet = GetProcAddress (hCabinetDll, "FCIFlushCabinet");
  503. (FARPROC)g_FCIDestroy = GetProcAddress (hCabinetDll, "FCIDestroy");
  504. (FARPROC)g_FDICreate = GetProcAddress (hCabinetDll, "FDICreate");
  505. (FARPROC)g_FDICopy = GetProcAddress (hCabinetDll, "FDICopy");
  506. (FARPROC)g_FDIDestroy = GetProcAddress (hCabinetDll, "FDIDestroy");
  507. if (!g_FCICreate || !g_FCIAddFile || !g_FCIFlushCabinet || !g_FCIDestroy ||
  508. !g_FDICreate || !g_FDICopy || !g_FDIDestroy) {
  509. DiamondTerminate (hCabinetDll);
  510. return NULL;
  511. }
  512. if (TempDir && !g_TempDir) {
  513. #ifdef UNICODE
  514. g_TempDir = UnicodeToAnsi (TempDir);
  515. #else
  516. g_TempDir = DupString (TempDir);
  517. #endif
  518. }
  519. return hCabinetDll;
  520. }
  521. VOID
  522. DiamondTerminate (
  523. IN HANDLE Handle
  524. )
  525. {
  526. FreeLibrary (Handle);
  527. g_FCICreate = NULL;
  528. g_FCIAddFile = NULL;
  529. g_FCIFlushCabinet = NULL;
  530. g_FCIDestroy = NULL;
  531. g_FDICreate = NULL;
  532. g_FDICopy = NULL;
  533. g_FDIDestroy = NULL;
  534. if (g_TempDir) {
  535. FREE ((PVOID)g_TempDir);
  536. g_TempDir = NULL;
  537. }
  538. }
  539. HANDLE
  540. DiamondStartNewCabinet (
  541. IN PCTSTR CabinetFilePath
  542. )
  543. {
  544. CCAB ccab;
  545. HFCI FciContext;
  546. PSTR p;
  547. //
  548. // Fill in the cabinet structure.
  549. //
  550. ZeroMemory (&ccab, sizeof(ccab));
  551. #ifdef UNICODE
  552. if (!WideCharToMultiByte (
  553. CP_ACP,
  554. 0,
  555. CabinetFilePath,
  556. -1,
  557. ccab.szCabPath,
  558. sizeof (ccab.szCabPath) / sizeof (ccab.szCabPath[0]),
  559. NULL,
  560. NULL
  561. )) {
  562. return NULL;
  563. }
  564. #else
  565. if (FAILED(StringCchCopyA(ccab.szCabPath, ARRAYSIZE(ccab.szCabPath), CabinetFilePath)))
  566. {
  567. return NULL;
  568. }
  569. #endif
  570. p = strrchr (ccab.szCabPath, '\\');
  571. if(!p) {
  572. SetLastError (ERROR_INVALID_PARAMETER);
  573. return NULL;
  574. }
  575. StringCchCopyA(ccab.szCab, ARRAYSIZE(ccab.szCab), ++p);
  576. *p = 0;
  577. ccab.cbFolderThresh = INT_MAX - 1;
  578. g_DiamondLastError = NO_ERROR;
  579. FciContext = g_FCICreate(
  580. &g_FciError,
  581. fciFilePlacedCB,
  582. myAlloc,
  583. myFree,
  584. fciOpen,
  585. fciRead,
  586. fciWrite,
  587. fciClose,
  588. fciSeek,
  589. fciDelete,
  590. fciTempFileCB,
  591. &ccab,
  592. NULL
  593. );
  594. return (HANDLE)FciContext;
  595. }
  596. BOOL
  597. DiamondAddFileToCabinet (
  598. IN HANDLE CabinetContext,
  599. IN PCTSTR SourceFile,
  600. IN PCTSTR NameInCabinet
  601. )
  602. {
  603. HFCI FciContext = (HFCI)CabinetContext;
  604. BOOL b;
  605. CHAR AnsiSourceFile[MAX_PATH];
  606. CHAR AnsiNameInCabinet[MAX_PATH];
  607. #ifdef UNICODE
  608. if (!WideCharToMultiByte (
  609. CP_ACP,
  610. 0,
  611. SourceFile,
  612. -1,
  613. AnsiSourceFile,
  614. sizeof (AnsiSourceFile) / sizeof (AnsiSourceFile[0]),
  615. NULL,
  616. NULL
  617. ) ||
  618. !WideCharToMultiByte (
  619. CP_ACP,
  620. 0,
  621. NameInCabinet,
  622. -1,
  623. AnsiNameInCabinet,
  624. sizeof (AnsiNameInCabinet) / sizeof (AnsiNameInCabinet[0]),
  625. NULL,
  626. NULL
  627. )) {
  628. return FALSE;
  629. }
  630. #else
  631. if (FAILED(StringCchCopyA(AnsiSourceFile, ARRAYSIZE(AnsiSourceFile), SourceFile))
  632. || FAILED(StringCchCopyA(AnsiNameInCabinet, ARRAYSIZE(AnsiNameInCabinet), NameInCabinet)))
  633. {
  634. return FALSE;
  635. }
  636. #endif
  637. b = g_FCIAddFile (
  638. FciContext,
  639. AnsiSourceFile, // file to add to cabinet.
  640. AnsiNameInCabinet, // filename part, name to store in cabinet.
  641. FALSE, // fExecute on extract
  642. fciNextCabinetCB, // routine for next cabinet (always fails)
  643. fciStatusCB,
  644. fciOpenInfoCB,
  645. tcompTYPE_MSZIP
  646. );
  647. if (!b) {
  648. SetLastError (g_DiamondLastError == NO_ERROR ? ERROR_INVALID_FUNCTION : g_DiamondLastError);
  649. }
  650. return b;
  651. }
  652. BOOL
  653. DiamondTerminateCabinet (
  654. IN HANDLE CabinetContext
  655. )
  656. {
  657. HFCI FciContext = (HFCI)CabinetContext;
  658. BOOL b;
  659. b = g_FCIFlushCabinet (
  660. FciContext,
  661. FALSE,
  662. fciNextCabinetCB,
  663. fciStatusCB
  664. );
  665. g_FCIDestroy (FciContext);
  666. if (!b) {
  667. SetLastError (g_DiamondLastError == NO_ERROR ? ERROR_INVALID_FUNCTION : g_DiamondLastError);
  668. }
  669. return b;
  670. }
  671. UINT
  672. pDiamondNotifyFileDone (
  673. IN PFDICONTEXT Context,
  674. IN DWORD Win32Error
  675. )
  676. {
  677. UINT u;
  678. FILEPATHS FilePaths;
  679. MYASSERT(Context->CurrentTargetFile);
  680. FilePaths.Source = Context->CabinetFile;
  681. FilePaths.Target = Context->CurrentTargetFile;
  682. FilePaths.Win32Error = Win32Error;
  683. u = Context->MsgHandler (
  684. Context->Context,
  685. SPFILENOTIFY_FILEEXTRACTED,
  686. (UINT_PTR)&FilePaths,
  687. 0
  688. );
  689. return(u);
  690. }
  691. INT_PTR
  692. DIAMONDAPI
  693. DiamondNotifyFunction(
  694. IN FDINOTIFICATIONTYPE Operation,
  695. IN PFDINOTIFICATION Parameters
  696. )
  697. {
  698. INT_PTR rc;
  699. HANDLE hFile;
  700. CABINET_INFO CabInfo;
  701. FILE_IN_CABINET_INFO FileInCab;
  702. FILETIME FileTime, UtcTime;
  703. TCHAR NewPath[MAX_PATH];
  704. PTSTR p;
  705. PSTR ansi;
  706. DWORD err;
  707. UINT action;
  708. PFDICONTEXT ctx = (PFDICONTEXT)Parameters->pv;
  709. switch(Operation) {
  710. case fdintCABINET_INFO:
  711. //
  712. // Tell the callback function, in case it wants to do something
  713. // with this information.
  714. //
  715. err = ERROR_NOT_ENOUGH_MEMORY;
  716. CabInfo.CabinetFile = NewPortableString(Parameters->psz1);
  717. if(CabInfo.CabinetFile) {
  718. CabInfo.DiskName = NewPortableString(Parameters->psz2);
  719. if(CabInfo.DiskName) {
  720. CabInfo.CabinetPath = NewPortableString(Parameters->psz3);
  721. if(CabInfo.CabinetPath) {
  722. CabInfo.SetId = Parameters->setID;
  723. CabInfo.CabinetNumber = Parameters->iCabinet;
  724. err = (DWORD)ctx->MsgHandler (
  725. ctx->Context,
  726. SPFILENOTIFY_CABINETINFO,
  727. (UINT_PTR)&CabInfo,
  728. 0
  729. );
  730. FREE(CabInfo.CabinetPath);
  731. }
  732. FREE(CabInfo.DiskName);
  733. }
  734. FREE(CabInfo.CabinetFile);
  735. }
  736. if(err != NO_ERROR) {
  737. ctx->LastError = err;
  738. }
  739. return (INT_PTR)((err == NO_ERROR) ? 0 : -1);
  740. case fdintCOPY_FILE:
  741. //
  742. // Diamond is asking us whether we want to copy the file.
  743. // If we switched cabinets, then the answer is no.
  744. //
  745. // Pass the information on to the callback function and
  746. // let it decide.
  747. //
  748. FileInCab.NameInCabinet = NewPortableString(Parameters->psz1);
  749. FileInCab.FileSize = Parameters->cb;
  750. FileInCab.DosDate = Parameters->date;
  751. FileInCab.DosTime = Parameters->time;
  752. FileInCab.DosAttribs = Parameters->attribs;
  753. FileInCab.Win32Error = NO_ERROR;
  754. if(!FileInCab.NameInCabinet) {
  755. ctx->LastError = ERROR_NOT_ENOUGH_MEMORY;
  756. return (INT_PTR)(-1);
  757. }
  758. //
  759. // Call the callback function.
  760. //
  761. action = ctx->MsgHandler (
  762. ctx->Context,
  763. SPFILENOTIFY_FILEINCABINET,
  764. (UINT_PTR)&FileInCab,
  765. (UINT_PTR)ctx->CabinetFile
  766. );
  767. FREE (FileInCab.NameInCabinet);
  768. switch(action) {
  769. case FILEOP_SKIP:
  770. rc = 0;
  771. break;
  772. case FILEOP_DOIT:
  773. //
  774. // The callback wants to copy the file. In this case it has
  775. // provided us the full target pathname to use.
  776. //
  777. if(p = DupString(FileInCab.FullTargetName)) {
  778. //
  779. // we need ANSI version of filename for sake of Diamond API's
  780. // note that the handle returned here must be compatible with
  781. // the handle returned by fdiOpen
  782. //
  783. ansi = NewAnsiString (FileInCab.FullTargetName);
  784. hFile = CreateFile(FileInCab.FullTargetName,
  785. GENERIC_READ | GENERIC_WRITE,
  786. FILE_SHARE_READ | FILE_SHARE_WRITE, // should probably be 0
  787. NULL,
  788. CREATE_ALWAYS,
  789. FILE_ATTRIBUTE_NORMAL,
  790. NULL);
  791. FREE(ansi);
  792. if(hFile == INVALID_HANDLE_VALUE) {
  793. ctx->LastError = GetLastError();
  794. rc = -1;
  795. FREE(p);
  796. } else {
  797. rc = (INT_PTR)hFile;
  798. ctx->CurrentTargetFile = p;
  799. }
  800. } else {
  801. ctx->LastError = ERROR_NOT_ENOUGH_MEMORY;
  802. rc = -1;
  803. }
  804. break;
  805. case FILEOP_ABORT:
  806. //
  807. // Abort.
  808. //
  809. rc = -1;
  810. ctx->LastError = FileInCab.Win32Error;
  811. //
  812. // here, if ctx->LastError is still NO_ERROR, this is ok
  813. // it was the callback's intent
  814. // we know callback itself is ok, since internal failure returns
  815. // FILEOP_INTERNAL_FAILED
  816. //
  817. break;
  818. default:
  819. ctx->LastError = ERROR_OPERATION_ABORTED;
  820. }
  821. return rc;
  822. case fdintCLOSE_FILE_INFO:
  823. //
  824. // Diamond is done with the target file and wants us to close it.
  825. // (ie, this is the counterpart to fdintCOPY_FILE).
  826. //
  827. // We want the timestamp to be what is stored in the cabinet.
  828. // Note that we lose the create and last access times in this case.
  829. //
  830. if(DosDateTimeToFileTime(Parameters->date,Parameters->time,&FileTime) &&
  831. LocalFileTimeToFileTime(&FileTime, &UtcTime)) {
  832. SetFileTime((HANDLE)Parameters->hf,NULL,NULL,&UtcTime);
  833. }
  834. FdiClose(Parameters->hf);
  835. //
  836. // Call the callback function to inform it that the file has been
  837. // successfully extracted from the cabinet.
  838. //
  839. MYASSERT(ctx->CurrentTargetFile);
  840. err = (DWORD)pDiamondNotifyFileDone(ctx, NO_ERROR);
  841. if(err != NO_ERROR) {
  842. ctx->LastError = err;
  843. }
  844. FREE(ctx->CurrentTargetFile);
  845. ctx->CurrentTargetFile = NULL;
  846. return (INT_PTR)((err == NO_ERROR) ? TRUE : -1);
  847. case fdintPARTIAL_FILE:
  848. case fdintENUMERATE:
  849. //
  850. // We don't do anything with this.
  851. //
  852. return (INT_PTR)(0);
  853. case fdintNEXT_CABINET:
  854. if((Parameters->fdie == FDIERROR_NONE) || (Parameters->fdie == FDIERROR_WRONG_CABINET)) {
  855. //
  856. // A file continues into another cabinet.
  857. // Inform the callback function, who is responsible for
  858. // making sure the cabinet is accessible when it returns.
  859. //
  860. err = ERROR_NOT_ENOUGH_MEMORY;
  861. CabInfo.SetId = 0;
  862. CabInfo.CabinetNumber = 0;
  863. CabInfo.CabinetPath = NewPortableString(Parameters->psz3);
  864. if(CabInfo.CabinetPath) {
  865. CabInfo.CabinetFile = NewPortableString(Parameters->psz1);
  866. if(CabInfo.CabinetFile) {
  867. CabInfo.DiskName = NewPortableString(Parameters->psz2);
  868. if(CabInfo.DiskName) {
  869. err = (DWORD)ctx->MsgHandler (
  870. ctx->Context,
  871. SPFILENOTIFY_NEEDNEWCABINET,
  872. (UINT_PTR)&CabInfo,
  873. (UINT_PTR)NewPath
  874. );
  875. if(err == NO_ERROR) {
  876. //
  877. // See if a new path was specified.
  878. //
  879. if(NewPath[0]) {
  880. lstrcpyn(ctx->UserPath,NewPath,MAX_PATH);
  881. if(!ConcatenatePaths(ctx->UserPath,TEXT("\\"),MAX_PATH)) {
  882. err = ERROR_BUFFER_OVERFLOW;
  883. } else {
  884. PSTR pp = NewAnsiString(ctx->UserPath);
  885. if(strlen(pp)>=CB_MAX_CAB_PATH) {
  886. err = ERROR_BUFFER_OVERFLOW;
  887. } else {
  888. strcpy(Parameters->psz3,pp);
  889. }
  890. FREE(pp);
  891. }
  892. }
  893. }
  894. if(err == NO_ERROR) {
  895. //
  896. // Remember that we switched cabinets.
  897. //
  898. ctx->SwitchedCabinets = TRUE;
  899. }
  900. FREE(CabInfo.DiskName);
  901. }
  902. FREE(CabInfo.CabinetFile);
  903. }
  904. FREE(CabInfo.CabinetPath);
  905. }
  906. } else {
  907. //
  908. // Some other error we don't understand -- this indicates
  909. // a bad cabinet.
  910. //
  911. err = ERROR_INVALID_DATA;
  912. }
  913. if(err != NO_ERROR) {
  914. ctx->LastError = err;
  915. }
  916. return (INT_PTR)((err == NO_ERROR) ? 0 : -1);
  917. default:
  918. //
  919. // Unknown notification type. Should never get here.
  920. //
  921. MYASSERT(0);
  922. return (INT_PTR)(0);
  923. }
  924. }
  925. BOOL
  926. MySetupIterateCabinet (
  927. IN PCTSTR CabinetFilePath,
  928. IN DWORD Reserved,
  929. IN PSP_FILE_CALLBACK MsgHandler,
  930. IN PVOID Context
  931. )
  932. {
  933. HFDI fdiContext;
  934. CHAR ansiPath[MAX_PATH];
  935. CHAR ansiName[MAX_PATH];
  936. PSTR filename;
  937. BOOL b;
  938. FDICONTEXT ctx;
  939. DWORD rc;
  940. #ifdef UNICODE
  941. if (!WideCharToMultiByte (
  942. CP_ACP,
  943. 0,
  944. CabinetFilePath,
  945. -1,
  946. ansiPath,
  947. ARRAYSIZE(ansiPath),
  948. NULL,
  949. NULL
  950. )) {
  951. return FALSE;
  952. }
  953. #else
  954. if (FAILED(StringCchCopyA(ansiPath, ARRAYSIZE(ansiPath), CabinetFilePath))) {
  955. return FALSE;
  956. }
  957. #endif
  958. filename = strrchr (ansiPath, '\\');
  959. if(!filename) {
  960. SetLastError (ERROR_INVALID_PARAMETER);
  961. return FALSE;
  962. }
  963. StringCchCopyA(ansiName, ARRAYSIZE(ansiName), ++filename);
  964. *filename = 0;
  965. fdiContext = g_FDICreate (
  966. myAlloc,
  967. myFree,
  968. FdiOpen,
  969. FdiRead,
  970. FdiWrite,
  971. FdiClose,
  972. FdiSeek,
  973. cpuUNKNOWN,
  974. &g_FdiError
  975. );
  976. if (!fdiContext) {
  977. return FALSE;
  978. }
  979. ZeroMemory (&ctx, sizeof(ctx));
  980. ctx.MsgHandler = MsgHandler;
  981. ctx.Context = Context;
  982. ctx.CabinetFile = CabinetFilePath;
  983. b = g_FDICopy (
  984. fdiContext,
  985. ansiName,
  986. ansiPath,
  987. 0,
  988. DiamondNotifyFunction,
  989. NULL,
  990. &ctx
  991. );
  992. if (b) {
  993. rc = NO_ERROR;
  994. } else {
  995. switch(g_FdiError.erfOper) {
  996. case FDIERROR_NONE:
  997. //
  998. // We shouldn't see this -- if there was no error
  999. // then FDICopy should have returned TRUE.
  1000. //
  1001. MYASSERT(g_FdiError.erfOper != FDIERROR_NONE);
  1002. rc = ERROR_INVALID_DATA;
  1003. break;
  1004. case FDIERROR_CABINET_NOT_FOUND:
  1005. rc = ERROR_FILE_NOT_FOUND;
  1006. break;
  1007. case FDIERROR_CORRUPT_CABINET:
  1008. //
  1009. // Read/open/seek error or corrupt cabinet
  1010. //
  1011. rc = ctx.LastError;
  1012. if(rc == NO_ERROR) {
  1013. rc = ERROR_INVALID_DATA;
  1014. }
  1015. break;
  1016. case FDIERROR_ALLOC_FAIL:
  1017. rc = ERROR_NOT_ENOUGH_MEMORY;
  1018. break;
  1019. case FDIERROR_TARGET_FILE:
  1020. case FDIERROR_USER_ABORT:
  1021. rc = ctx.LastError;
  1022. break;
  1023. case FDIERROR_NOT_A_CABINET:
  1024. case FDIERROR_UNKNOWN_CABINET_VERSION:
  1025. case FDIERROR_BAD_COMPR_TYPE:
  1026. case FDIERROR_MDI_FAIL:
  1027. case FDIERROR_RESERVE_MISMATCH:
  1028. case FDIERROR_WRONG_CABINET:
  1029. default:
  1030. //
  1031. // Cabinet is corrupt or not actually a cabinet, etc.
  1032. //
  1033. rc = ERROR_INVALID_DATA;
  1034. break;
  1035. }
  1036. if(ctx.CurrentTargetFile) {
  1037. //
  1038. // Call the callback function to inform it that the last file
  1039. // was not successfully extracted from the cabinet.
  1040. // Also remove the partially copied file.
  1041. //
  1042. DeleteFile(ctx.CurrentTargetFile);
  1043. pDiamondNotifyFileDone(&ctx, rc);
  1044. FREE(ctx.CurrentTargetFile);
  1045. ctx.CurrentTargetFile = NULL;
  1046. }
  1047. }
  1048. g_FDIDestroy (fdiContext);
  1049. SetLastError (rc);
  1050. return rc == NO_ERROR;
  1051. }