Source code of Windows XP (NT5)
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.

761 lines
17 KiB

  1. #include <windows.h>
  2. #include <lzexpand.h>
  3. #include <fcntl.h>
  4. /************************************************************************\
  5. *
  6. * NOTE!!!!
  7. *
  8. * While the 'Diamond' interfaced functions defined in this file are
  9. * multi thread safe, EACH THREAD MUST ONLY HAVE ONE DIAMOND FILE
  10. * OPEN AT A TIME! (ie. You can not nest InitDiamond()/TermDiamond()
  11. * pairs in one thread of execution.)
  12. *
  13. \************************************************************************/
  14. //
  15. // diamond headers
  16. //
  17. #include <diamondd.h>
  18. #include "mydiam.h"
  19. HINSTANCE hCabinet;
  20. DWORD cCabinetLoad;
  21. typedef HFDI (DIAMONDAPI * tFDICreate) (PFNALLOC pfnalloc,
  22. PFNFREE pfnfree,
  23. PFNOPEN pfnopen,
  24. PFNREAD pfnread,
  25. PFNWRITE pfnwrite,
  26. PFNCLOSE pfnclose,
  27. PFNSEEK pfnseek,
  28. int cpuType,
  29. PERF perf);
  30. typedef BOOL (DIAMONDAPI * tFDIIsCabinet)(HFDI hfdi,
  31. INT_PTR hf,
  32. PFDICABINETINFO pfdici);
  33. typedef BOOL (DIAMONDAPI * tFDICopy)(HFDI hfdi,
  34. char FAR *pszCabinet,
  35. char FAR *pszCabPath,
  36. int flags,
  37. PFNFDINOTIFY pfnfdin,
  38. PFNFDIDECRYPT pfnfdid,
  39. void FAR *pvUser);
  40. typedef BOOL (DIAMONDAPI * tFDIDestroy)(HFDI hfdi);
  41. tFDICreate pFDICreate;
  42. tFDIIsCabinet pFDIIsCabinet;
  43. tFDICopy pFDICopy;
  44. tFDIDestroy pFDIDestroy;
  45. // this function is the same as CharNextA, available locally
  46. extern LPSTR WINAPI VerCharNextA(LPCSTR lpCurrentChar);
  47. INT CopyDateTimeStamp(INT_PTR doshFrom, INT_PTR doshTo)
  48. {
  49. FILETIME lpCreationTime, lpLastAccessTime, lpLastWriteTime;
  50. if (!GetFileTime((HANDLE) doshFrom, &lpCreationTime, &lpLastAccessTime,
  51. &lpLastWriteTime)) {
  52. return ((INT)LZERROR_BADINHANDLE);
  53. }
  54. if (!SetFileTime((HANDLE) doshTo, &lpCreationTime, &lpLastAccessTime,
  55. &lpLastWriteTime)) {
  56. return ((INT)LZERROR_BADINHANDLE);
  57. }
  58. return (TRUE);
  59. }
  60. INT_PTR
  61. DIAMONDAPI
  62. SpdFdiOpen(
  63. IN PSTR FileName,
  64. IN int oflag,
  65. IN int pmode
  66. );
  67. int
  68. DIAMONDAPI
  69. SpdFdiClose(
  70. IN INT_PTR Handle
  71. );
  72. typedef struct _DIAMOND_INFO {
  73. //
  74. // A read handle to the source file.
  75. //
  76. INT_PTR SourceFileHandle;
  77. //
  78. // File names.
  79. //
  80. PSTR SourceFileName;
  81. PSTR TargetFileName;
  82. //
  83. // Flag indicating whether to rename the target file.
  84. //
  85. BOOL RenameTargetFile;
  86. //
  87. // Pointer to LZ information structure.
  88. // We'll fill in some of the fields to fool expand.
  89. //
  90. PLZINFO pLZI;
  91. } DIAMOND_INFO, *PDIAMOND_INFO;
  92. PSTR
  93. StringRevChar(
  94. IN PSTR String,
  95. IN CHAR Char
  96. )
  97. {
  98. //
  99. // Although not the most efficient possible algoeithm in each case,
  100. // this algorithm is correct for unicode, sbcs, or dbcs.
  101. //
  102. PCHAR Occurrence,Next;
  103. //
  104. // Check each character in the string and remember
  105. // the most recently encountered occurrence of the desired char.
  106. //
  107. for (Occurrence=NULL,Next=VerCharNextA(String); *String; ) {
  108. if (!memcmp(String,&Char,(int)((PUCHAR)Next-(PUCHAR)String))) {
  109. Occurrence = String;
  110. }
  111. String = Next;
  112. Next = VerCharNextA(Next);
  113. }
  114. //
  115. // Return address of final occurrence of the character
  116. // (will be NULL if not found at all).
  117. //
  118. return (Occurrence);
  119. }
  120. INT_PTR
  121. DIAMONDAPI
  122. DiamondNotifyFunction(
  123. IN FDINOTIFICATIONTYPE Operation,
  124. IN PFDINOTIFICATION Parameters
  125. )
  126. {
  127. switch (Operation) {
  128. case fdintCABINET_INFO:
  129. case fdintNEXT_CABINET:
  130. case fdintPARTIAL_FILE:
  131. case fdintENUMERATE:
  132. //
  133. // Cabinet management functions which we don't use.
  134. // Return success.
  135. //
  136. return (0);
  137. case fdintCOPY_FILE:
  138. //
  139. // Diamond is asking us whether we want to copy the file.
  140. //
  141. {
  142. PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
  143. HFILE h;
  144. //
  145. // If we need to rename the target file, do that here.
  146. // The name stored in the cabinet file will be used as
  147. // the uncompressed name.
  148. //
  149. if (Info->RenameTargetFile) {
  150. PSTR p,q;
  151. //
  152. // Find the start of the filename part of the target.
  153. //
  154. if (p = StringRevChar(Info->TargetFileName,'\\')) {
  155. p++;
  156. } else {
  157. p = Info->TargetFileName;
  158. }
  159. //
  160. // Find the start of the filename part of the name in the cabinet.
  161. //
  162. if (q = StringRevChar(Parameters->psz1,'\\')) {
  163. q++;
  164. } else {
  165. q = Parameters->psz1;
  166. }
  167. //
  168. // Copy the filename part of the name in the cabinet over
  169. // the filename part of the name in the target spec.
  170. //
  171. lstrcpyA(p,q);
  172. }
  173. {
  174. // Check they're not the same file
  175. CHAR Source[MAX_PATH];
  176. CHAR Target[MAX_PATH];
  177. PSTR FileName;
  178. DWORD PathLenSource;
  179. DWORD PathLenTarget;
  180. PathLenSource = GetFullPathNameA(Info->SourceFileName,
  181. MAX_PATH,
  182. Source,
  183. &FileName);
  184. PathLenTarget = GetFullPathNameA(Info->TargetFileName,
  185. MAX_PATH,
  186. Target,
  187. &FileName);
  188. if (PathLenSource == 0 || PathLenSource >= MAX_PATH ||
  189. PathLenTarget == 0 || PathLenTarget >= MAX_PATH ||
  190. lstrcmpiA(Source, Target) == 0) {
  191. return 0;
  192. }
  193. }
  194. //
  195. // Remember the uncompressed size and open the file.
  196. // Returns -1 if an error occurs opening the file.
  197. //
  198. Info->pLZI->cblOutSize = Parameters->cb;
  199. h = _lcreat(Info->TargetFileName,0);
  200. if (h == HFILE_ERROR) {
  201. DiamondLastIoError = LZERROR_BADOUTHANDLE;
  202. return (-1);
  203. }
  204. return (h);
  205. }
  206. case fdintCLOSE_FILE_INFO:
  207. //
  208. // Diamond is done with the target file and wants us to close it.
  209. // (ie, this is the counterpart to fdint_COPY_FILE).
  210. //
  211. {
  212. PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
  213. CopyDateTimeStamp(Info->SourceFileHandle,Parameters->hf);
  214. _lclose((HFILE)Parameters->hf);
  215. }
  216. return (TRUE);
  217. default:
  218. //
  219. // invalid operation
  220. //
  221. return(-1);
  222. }
  223. }
  224. PVOID
  225. DIAMONDAPI
  226. SpdFdiAlloc(
  227. IN ULONG NumberOfBytes
  228. )
  229. /*++
  230. Routine Description:
  231. Callback used by FDICopy to allocate memory.
  232. Arguments:
  233. NumberOfBytes - supplies desired size of block.
  234. Return Value:
  235. Returns pointer to a block of memory or NULL
  236. if memory cannot be allocated.
  237. --*/
  238. {
  239. return ((PVOID)LocalAlloc(LMEM_FIXED,NumberOfBytes));
  240. }
  241. VOID
  242. DIAMONDAPI
  243. SpdFdiFree(
  244. IN PVOID Block
  245. )
  246. /*++
  247. Routine Description:
  248. Callback used by FDICopy to free a memory block.
  249. The block must have been allocated with SpdFdiAlloc().
  250. Arguments:
  251. Block - supplies pointer to block of memory to be freed.
  252. Return Value:
  253. None.
  254. --*/
  255. {
  256. LocalFree((HLOCAL)Block);
  257. }
  258. INT_PTR
  259. DIAMONDAPI
  260. SpdFdiOpen(
  261. IN PSTR FileName,
  262. IN int oflag,
  263. IN int pmode
  264. )
  265. /*++
  266. Routine Description:
  267. Callback used by FDICopy to open files.
  268. Arguments:
  269. FileName - supplies name of file to be opened.
  270. oflag - supplies flags for open.
  271. pmode - supplies additional flags for open.
  272. Return Value:
  273. Handle to open file or -1 if error occurs.
  274. --*/
  275. {
  276. HFILE h;
  277. int OpenMode;
  278. if (oflag & _O_WRONLY) {
  279. OpenMode = OF_WRITE;
  280. } else {
  281. if (oflag & _O_RDWR) {
  282. OpenMode = OF_READWRITE;
  283. } else {
  284. OpenMode = OF_READ;
  285. }
  286. }
  287. h = _lopen(FileName,OpenMode | OF_SHARE_DENY_WRITE);
  288. if (h == HFILE_ERROR) {
  289. DiamondLastIoError = LZERROR_BADINHANDLE;
  290. return (-1);
  291. }
  292. return ((INT_PTR)h);
  293. }
  294. UINT
  295. DIAMONDAPI
  296. SpdFdiRead(
  297. IN INT_PTR Handle,
  298. OUT PVOID pv,
  299. IN UINT ByteCount
  300. )
  301. /*++
  302. Routine Description:
  303. Callback used by FDICopy to read from a file.
  304. Arguments:
  305. Handle - supplies handle to open file to be read from.
  306. pv - supplies pointer to buffer to receive bytes we read.
  307. ByteCount - supplies number of bytes to read.
  308. Return Value:
  309. Number of bytes read (ByteCount) or -1 if an error occurs.
  310. --*/
  311. {
  312. UINT rc;
  313. rc = _lread((HFILE)Handle,pv,ByteCount);
  314. if (rc == HFILE_ERROR) {
  315. rc = (UINT)(-1);
  316. DiamondLastIoError = LZERROR_READ;
  317. }
  318. return (rc);
  319. }
  320. UINT
  321. DIAMONDAPI
  322. SpdFdiWrite(
  323. IN INT_PTR Handle,
  324. IN PVOID pv,
  325. IN UINT ByteCount
  326. )
  327. /*++
  328. Routine Description:
  329. Callback used by FDICopy to write to a file.
  330. Arguments:
  331. Handle - supplies handle to open file to be written to.
  332. pv - supplies pointer to buffer containing bytes to write.
  333. ByteCount - supplies number of bytes to write.
  334. Return Value:
  335. Number of bytes written (ByteCount) or -1 if an error occurs.
  336. --*/
  337. {
  338. UINT rc;
  339. rc = _lwrite((HFILE)Handle,pv,ByteCount);
  340. if (rc == HFILE_ERROR) {
  341. DiamondLastIoError = (GetLastError() == ERROR_DISK_FULL) ? LZERROR_WRITE : LZERROR_BADOUTHANDLE;
  342. } else {
  343. if (rc != ByteCount) {
  344. //
  345. // let caller interpret return value but record last error just in case
  346. //
  347. DiamondLastIoError = LZERROR_WRITE;
  348. }
  349. }
  350. return (rc);
  351. }
  352. int
  353. DIAMONDAPI
  354. SpdFdiClose(
  355. IN INT_PTR Handle
  356. )
  357. /*++
  358. Routine Description:
  359. Callback used by FDICopy to close files.
  360. Arguments:
  361. Handle - handle of file to close.
  362. Return Value:
  363. 0 (success).
  364. --*/
  365. {
  366. _lclose((HFILE)Handle);
  367. return (0);
  368. }
  369. LONG
  370. DIAMONDAPI
  371. SpdFdiSeek(
  372. IN INT_PTR Handle,
  373. IN long Distance,
  374. IN int SeekType
  375. )
  376. /*++
  377. Routine Description:
  378. Callback used by FDICopy to seek files.
  379. Arguments:
  380. Handle - handle of file to close.
  381. Distance - supplies distance to seek. Interpretation of this
  382. parameter depends on the value of SeekType.
  383. SeekType - supplies a value indicating how Distance is to be
  384. interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
  385. Return Value:
  386. New file offset or -1 if an error occurs.
  387. --*/
  388. {
  389. LONG rc;
  390. rc = _llseek((HFILE)Handle,Distance,SeekType);
  391. if (rc == HFILE_ERROR) {
  392. DiamondLastIoError = LZERROR_BADINHANDLE;
  393. rc = -1L;
  394. }
  395. return (rc);
  396. }
  397. //
  398. // this function is linked in from ntdll
  399. //
  400. extern int sprintf(LPSTR, LPCSTR, ...);
  401. INT
  402. ExpandDiamondFile(
  403. IN PSTR SourceFileName, // Note ASCII
  404. IN PTSTR TargetFileNameT,
  405. IN BOOL RenameTarget,
  406. OUT PLZINFO pLZI
  407. )
  408. {
  409. BOOL b;
  410. INT rc;
  411. INT_PTR h;
  412. DIAMOND_INFO DiamondInfo;
  413. CHAR TargetFileName[MAX_PATH];
  414. sprintf(TargetFileName, "%ls", TargetFileNameT);
  415. if (!FdiContext) {
  416. return (LZERROR_BADVALUE);
  417. }
  418. DiamondLastIoError = TRUE;
  419. //
  420. // Get a handle to the source to use to
  421. // copy the date and time stamp.
  422. //
  423. h = SpdFdiOpen(SourceFileName,_O_RDONLY,0);
  424. if (h == -1) {
  425. return (LZERROR_BADINHANDLE);
  426. }
  427. pLZI->cblInSize = GetFileSize((HANDLE)h,NULL);
  428. if (pLZI->cblInSize == -1) {
  429. SpdFdiClose(h);
  430. return (LZERROR_BADINHANDLE);
  431. }
  432. DiamondInfo.SourceFileHandle = h;
  433. DiamondInfo.SourceFileName = SourceFileName;
  434. DiamondInfo.TargetFileName = TargetFileName;
  435. DiamondInfo.RenameTargetFile = RenameTarget;
  436. DiamondInfo.pLZI = pLZI;
  437. b = pFDICopy(
  438. FdiContext,
  439. SourceFileName, // pass the whole path as the name
  440. "", // don't bother with the path part
  441. 0, // flags
  442. DiamondNotifyFunction,
  443. NULL, // no decryption
  444. &DiamondInfo
  445. );
  446. if (b) {
  447. rc = TRUE;
  448. } else {
  449. switch (FdiError.erfOper) {
  450. case FDIERROR_CORRUPT_CABINET:
  451. case FDIERROR_UNKNOWN_CABINET_VERSION:
  452. case FDIERROR_BAD_COMPR_TYPE:
  453. rc = LZERROR_READ; // causes SID_FORMAT_ERROR message
  454. break;
  455. case FDIERROR_ALLOC_FAIL:
  456. rc = LZERROR_GLOBALLOC;
  457. break;
  458. case FDIERROR_TARGET_FILE:
  459. case FDIERROR_USER_ABORT:
  460. rc = DiamondLastIoError;
  461. break;
  462. default:
  463. //
  464. // The rest of the errors are not handled specially.
  465. //
  466. rc = LZERROR_BADVALUE;
  467. break;
  468. }
  469. //
  470. // Remove the partial target file.
  471. //
  472. DeleteFileA(TargetFileName);
  473. }
  474. SpdFdiClose(h);
  475. return (rc);
  476. }
  477. BOOL
  478. IsDiamondFile(
  479. IN PSTR FileName
  480. )
  481. {
  482. FDICABINETINFO CabinetInfo;
  483. BOOL b;
  484. INT_PTR h;
  485. if (!FdiContext) {
  486. return (FALSE);
  487. }
  488. //
  489. // Open the file such that the handle is valid for use
  490. // in the diamond context (ie, seek, read routines above).
  491. //
  492. h = SpdFdiOpen(FileName,_O_RDONLY,0);
  493. if (h == -1) {
  494. return (FALSE);
  495. }
  496. b = pFDIIsCabinet(FdiContext,h,&CabinetInfo);
  497. SpdFdiClose(h);
  498. return (b);
  499. }
  500. DWORD
  501. InitDiamond(
  502. VOID
  503. )
  504. {
  505. PDIAMOND_CONTEXT pdcx;
  506. if (!GotDmdTlsSlot())
  507. return VIF_OUTOFMEMORY;
  508. if (GotDmdContext())
  509. return VIF_OUTOFMEMORY;
  510. pdcx = LocalAlloc(LPTR, sizeof(DIAMOND_CONTEXT));
  511. if (pdcx == NULL || !TlsSetValue(itlsDiamondContext, pdcx)) {
  512. /*
  513. * For some unknown reason, we can't associate
  514. * our thread storage with the slot, so free
  515. * it and say we never got one.
  516. */
  517. if (pdcx) {
  518. LocalFree(pdcx);
  519. }
  520. return VIF_OUTOFMEMORY;
  521. }
  522. if (!cCabinetLoad) {
  523. hCabinet = LoadLibraryW(L"CABINET.DLL");
  524. if (!hCabinet) {
  525. return (VIF_CANNOTLOADCABINET);
  526. }
  527. pFDICreate = (tFDICreate) GetProcAddress(hCabinet, "FDICreate");
  528. pFDIDestroy = (tFDIDestroy) GetProcAddress(hCabinet, "FDIDestroy");
  529. pFDIIsCabinet = (tFDIIsCabinet) GetProcAddress(hCabinet, "FDIIsCabinet");
  530. pFDICopy = (tFDICopy) GetProcAddress(hCabinet, "FDICopy");
  531. if (!(pFDICreate && pFDIDestroy && pFDIIsCabinet && pFDICopy)) {
  532. FreeLibrary(hCabinet);
  533. return (VIF_CANNOTLOADCABINET);
  534. }
  535. if (InterlockedExchangeAdd(&cCabinetLoad, 1) != 0) {
  536. // Multiple threads are attempting to LoadLib
  537. // Free one here.
  538. FreeLibrary(hCabinet);
  539. }
  540. }
  541. SetFdiContext( pFDICreate(
  542. SpdFdiAlloc,
  543. SpdFdiFree,
  544. SpdFdiOpen,
  545. SpdFdiRead,
  546. SpdFdiWrite,
  547. SpdFdiClose,
  548. SpdFdiSeek,
  549. cpuUNKNOWN,
  550. &FdiError
  551. ));
  552. return ((FdiContext == NULL) ? VIF_CANNOTLOADCABINET : 0);
  553. }
  554. VOID
  555. TermDiamond(
  556. VOID
  557. )
  558. {
  559. if (!GotDmdTlsSlot() || !GotDmdContext())
  560. return;
  561. if (FdiContext) {
  562. pFDIDestroy(FdiContext);
  563. SetFdiContext( NULL );
  564. }
  565. LocalFree( TlsGetValue(itlsDiamondContext) );
  566. TlsSetValue(itlsDiamondContext, NULL);
  567. }