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.

944 lines
20 KiB

  1. #include <windows.h>
  2. #include <fcntl.h>
  3. //
  4. // lz headers
  5. //
  6. #include "lz_common.h"
  7. #include "lz_buffers.h"
  8. #include "lz_header.h"
  9. //
  10. // diamond headers
  11. //
  12. #include <diamondd.h>
  13. #include "mydiam.h"
  14. HFDI FdiContext;
  15. ERF FdiError;
  16. INT DiamondLastIoError;
  17. BOOL
  18. PatternMatch(
  19. IN PCSTR pszString,
  20. IN PCSTR pszPattern,
  21. IN BOOL fImplyDotAtEnd
  22. );
  23. INT_PTR
  24. DIAMONDAPI
  25. SpdFdiOpen(
  26. IN PSTR FileName,
  27. IN int oflag,
  28. IN int pmode
  29. );
  30. int
  31. DIAMONDAPI
  32. SpdFdiClose(
  33. IN INT_PTR Handle
  34. );
  35. typedef struct _DIAMOND_INFO {
  36. //
  37. // A read handle to the source file.
  38. //
  39. INT_PTR SourceFileHandle;
  40. //
  41. // File names.
  42. //
  43. PSTR SourceFileName;
  44. PSTR TargetFileName;
  45. //
  46. // Flag indicating whether to rename the target file.
  47. //
  48. BOOL RenameTargetFile;
  49. //
  50. // Pointer to LZ information structure.
  51. // We'll fill in some of the fields to fool expand.
  52. //
  53. PLZINFO pLZI;
  54. //
  55. // Expand callback/notification.
  56. //
  57. NOTIFYPROC ExpandNotify;
  58. //
  59. // Selective extraction file spec, ie, "aic*.sys" or NULL
  60. //
  61. PSTR SelectiveFilesSpec;
  62. } DIAMOND_INFO, *PDIAMOND_INFO;
  63. PTSTR
  64. StringRevChar(
  65. IN PTSTR String,
  66. IN TCHAR Char
  67. )
  68. {
  69. //
  70. // Although not the most efficient possible algoeithm in each case,
  71. // this algorithm is correct for unicode, sbcs, or dbcs.
  72. //
  73. PTCHAR Occurrence,Next;
  74. //
  75. // Check each character in the string and remember
  76. // the most recently encountered occurrence of the desired char.
  77. //
  78. for(Occurrence=NULL,Next=CharNext(String); *String; ) {
  79. if(!memcmp(String,&Char,(int)((PUCHAR)Next-(PUCHAR)String))) {
  80. Occurrence = String;
  81. }
  82. String = Next;
  83. Next = CharNext(Next);
  84. }
  85. //
  86. // Return address of final occurrence of the character
  87. // (will be NULL if not found at all).
  88. //
  89. return(Occurrence);
  90. }
  91. #define WILDCARD '*' /* zero or more of any character */
  92. #define WILDCHAR '?' /* one of any character (does not match END) */
  93. #define END '\0' /* terminal character */
  94. #define DOT '.' /* may be implied at end ("hosts" matches "*.") */
  95. static int __inline Lower(c)
  96. {
  97. if ((c >= 'A') && (c <= 'Z'))
  98. {
  99. return(c + ('a' - 'A'));
  100. }
  101. else
  102. {
  103. return(c);
  104. }
  105. }
  106. static int __inline CharacterMatch(char chCharacter, char chPattern)
  107. {
  108. if (Lower(chCharacter) == Lower(chPattern))
  109. {
  110. return(TRUE);
  111. }
  112. else
  113. {
  114. return(FALSE);
  115. }
  116. }
  117. BOOL
  118. PatternMatch(
  119. PCSTR pszString,
  120. PCSTR pszPattern,
  121. IN BOOL fImplyDotAtEnd
  122. )
  123. {
  124. /* RECURSIVE */
  125. //
  126. // This function does not deal with 8.3 conventions which might
  127. // be expected for filename comparisons. (In an 8.3 environment,
  128. // "alongfilename.html" would match "alongfil.htm")
  129. //
  130. // This code is NOT MBCS-enabled
  131. //
  132. for ( ; ; )
  133. {
  134. switch (*pszPattern)
  135. {
  136. case END:
  137. //
  138. // Reached end of pattern, so we're done. Matched if
  139. // end of string, no match if more string remains.
  140. //
  141. return(*pszString == END);
  142. case WILDCHAR:
  143. //
  144. // Next in pattern is a wild character, which matches
  145. // anything except end of string. If we reach the end
  146. // of the string, the implied DOT would also match.
  147. //
  148. if (*pszString == END)
  149. {
  150. if (fImplyDotAtEnd == TRUE)
  151. {
  152. fImplyDotAtEnd = FALSE;
  153. }
  154. else
  155. {
  156. return(FALSE);
  157. }
  158. }
  159. else
  160. {
  161. pszString++;
  162. }
  163. pszPattern++;
  164. break;
  165. case WILDCARD:
  166. //
  167. // Next in pattern is a wildcard, which matches anything.
  168. // Find the required character that follows the wildcard,
  169. // and search the string for it. At each occurence of the
  170. // required character, try to match the remaining pattern.
  171. //
  172. // There are numerous equivalent patterns in which multiple
  173. // WILDCARD and WILDCHAR are adjacent. We deal with these
  174. // before our search for the required character.
  175. //
  176. // Each WILDCHAR burns one non-END from the string. An END
  177. // means we have a match. Additional WILDCARDs are ignored.
  178. //
  179. for ( ; ; )
  180. {
  181. pszPattern++;
  182. if (*pszPattern == END)
  183. {
  184. return(TRUE);
  185. }
  186. else if (*pszPattern == WILDCHAR)
  187. {
  188. if (*pszString == END)
  189. {
  190. if (fImplyDotAtEnd == TRUE)
  191. {
  192. fImplyDotAtEnd = FALSE;
  193. }
  194. else
  195. {
  196. return(FALSE);
  197. }
  198. }
  199. else
  200. {
  201. pszString++;
  202. }
  203. }
  204. else if (*pszPattern != WILDCARD)
  205. {
  206. break;
  207. }
  208. }
  209. //
  210. // Now we have a regular character to search the string for.
  211. //
  212. while (*pszString != END)
  213. {
  214. //
  215. // For each match, use recursion to see if the remainder
  216. // of the pattern accepts the remainder of the string.
  217. // If it does not, continue looking for other matches.
  218. //
  219. if (CharacterMatch(*pszString, *pszPattern) == TRUE)
  220. {
  221. if (PatternMatch(pszString + 1, pszPattern + 1, fImplyDotAtEnd) == TRUE)
  222. {
  223. return(TRUE);
  224. }
  225. }
  226. pszString++;
  227. }
  228. //
  229. // Reached end of string without finding required character
  230. // which followed the WILDCARD. If the required character
  231. // is a DOT, consider matching the implied DOT.
  232. //
  233. // Since the remaining string is empty, the only pattern which
  234. // could match after the DOT would be zero or more WILDCARDs,
  235. // so don't bother with recursion.
  236. //
  237. if ((*pszPattern == DOT) && (fImplyDotAtEnd == TRUE))
  238. {
  239. pszPattern++;
  240. while (*pszPattern != END)
  241. {
  242. if (*pszPattern != WILDCARD)
  243. {
  244. return(FALSE);
  245. }
  246. pszPattern++;
  247. }
  248. return(TRUE);
  249. }
  250. //
  251. // Reached end of the string without finding required character.
  252. //
  253. return(FALSE);
  254. break;
  255. default:
  256. //
  257. // Nothing special about the pattern character, so it
  258. // must match source character.
  259. //
  260. if (CharacterMatch(*pszString, *pszPattern) == FALSE)
  261. {
  262. if ((*pszPattern == DOT) &&
  263. (*pszString == END) &&
  264. (fImplyDotAtEnd == TRUE))
  265. {
  266. fImplyDotAtEnd = FALSE;
  267. }
  268. else
  269. {
  270. return(FALSE);
  271. }
  272. }
  273. if (*pszString != END)
  274. {
  275. pszString++;
  276. }
  277. pszPattern++;
  278. }
  279. }
  280. }
  281. INT_PTR
  282. DIAMONDAPI
  283. DiamondNotifyFunction(
  284. IN FDINOTIFICATIONTYPE Operation,
  285. IN PFDINOTIFICATION Parameters
  286. )
  287. {
  288. switch(Operation) {
  289. case fdintCABINET_INFO:
  290. case fdintNEXT_CABINET:
  291. case fdintPARTIAL_FILE:
  292. default:
  293. //
  294. // Cabinet management functions which we don't use.
  295. // Return success.
  296. //
  297. return(0);
  298. case fdintCOPY_FILE:
  299. //
  300. // Diamond is asking us whether we want to copy the file.
  301. //
  302. {
  303. PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
  304. HFILE h;
  305. //
  306. // If we were given a filespec, see if the name matches.
  307. //
  308. if (Info->SelectiveFilesSpec != NULL) {
  309. //
  310. // Call PatternMatch(), fAllowImpliedDot TRUE if
  311. // there is no '.' in the file's base name.
  312. //
  313. BOOL fAllowImpliedDot = TRUE;
  314. PSTR p;
  315. for (p = Parameters->psz1; *p != '\0'; p++) {
  316. if (*p == '.') {
  317. fAllowImpliedDot = FALSE;
  318. } else if (*p == '\\') {
  319. fAllowImpliedDot = TRUE;
  320. }
  321. }
  322. if (PatternMatch(
  323. Parameters->psz1,
  324. Info->SelectiveFilesSpec,
  325. fAllowImpliedDot) == FALSE) {
  326. return(0); // skip this file
  327. }
  328. }
  329. //
  330. // If we need to rename the target file, do that here.
  331. // The name stored in the cabinet file will be used as
  332. // the uncompressed name.
  333. //
  334. if(Info->RenameTargetFile) {
  335. PSTR p,q;
  336. //
  337. // Find the start of the filename part of the target.
  338. //
  339. if(p = StringRevChar(Info->TargetFileName,'\\')) {
  340. p++;
  341. } else {
  342. p = Info->TargetFileName;
  343. }
  344. //
  345. // Find the start of the filename part of the name in the cabinet.
  346. //
  347. if(q = StringRevChar(Parameters->psz1,'\\')) {
  348. q++;
  349. } else {
  350. q = Parameters->psz1;
  351. }
  352. //
  353. // Copy the filename part of the name in the cabinet over
  354. // the filename part of the name in the target spec.
  355. //
  356. lstrcpy(p,q);
  357. }
  358. //
  359. // Inform the expand callback what we are doing.
  360. //
  361. if(!Info->ExpandNotify(Info->SourceFileName,Info->TargetFileName,NOTIFY_START_EXPAND)) {
  362. return(0); // skip this file.
  363. }
  364. //
  365. // Remember the uncompressed size and open the file.
  366. // Returns -1 if an error occurs opening the file.
  367. //
  368. Info->pLZI->cblOutSize += Parameters->cb;
  369. h = _lcreat(Info->TargetFileName,0);
  370. if(h == HFILE_ERROR) {
  371. DiamondLastIoError = LZERROR_BADOUTHANDLE;
  372. return(-1);
  373. }
  374. return(h);
  375. }
  376. case fdintCLOSE_FILE_INFO:
  377. //
  378. // Diamond is done with the target file and wants us to close it.
  379. // (ie, this is the counterpart to fdint_COPY_FILE).
  380. //
  381. {
  382. PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
  383. HANDLE TargetFileHandle;
  384. FILETIME ftLocal, ftUTC;
  385. _lclose((HFILE)Parameters->hf);
  386. //
  387. // Set the target file's date/time stamp from the value inside
  388. // the CAB.
  389. //
  390. TargetFileHandle = CreateFile(Info->TargetFileName,
  391. GENERIC_READ | GENERIC_WRITE,
  392. 0,
  393. NULL,
  394. OPEN_EXISTING,
  395. 0,
  396. NULL);
  397. if (TargetFileHandle != INVALID_HANDLE_VALUE)
  398. {
  399. if (DosDateTimeToFileTime(Parameters->date, Parameters->time, &ftLocal) &&
  400. LocalFileTimeToFileTime(&ftLocal, &ftUTC))
  401. {
  402. SetFileTime(TargetFileHandle, NULL, NULL, &ftUTC);
  403. }
  404. CloseHandle(TargetFileHandle);
  405. }
  406. }
  407. return(TRUE);
  408. }
  409. }
  410. PVOID
  411. DIAMONDAPI
  412. SpdFdiAlloc(
  413. IN ULONG NumberOfBytes
  414. )
  415. /*++
  416. Routine Description:
  417. Callback used by FDICopy to allocate memory.
  418. Arguments:
  419. NumberOfBytes - supplies desired size of block.
  420. Return Value:
  421. Returns pointer to a block of memory or NULL
  422. if memory cannot be allocated.
  423. --*/
  424. {
  425. return((PVOID)LocalAlloc(LMEM_FIXED,NumberOfBytes));
  426. }
  427. VOID
  428. DIAMONDAPI
  429. SpdFdiFree(
  430. IN PVOID Block
  431. )
  432. /*++
  433. Routine Description:
  434. Callback used by FDICopy to free a memory block.
  435. The block must have been allocated with SpdFdiAlloc().
  436. Arguments:
  437. Block - supplies pointer to block of memory to be freed.
  438. Return Value:
  439. None.
  440. --*/
  441. {
  442. LocalFree((HLOCAL)Block);
  443. }
  444. INT_PTR
  445. DIAMONDAPI
  446. SpdFdiOpen(
  447. IN PSTR FileName,
  448. IN int oflag,
  449. IN int pmode
  450. )
  451. /*++
  452. Routine Description:
  453. Callback used by FDICopy to open files.
  454. Arguments:
  455. FileName - supplies name of file to be opened.
  456. oflag - supplies flags for open.
  457. pmode - supplies additional flags for open.
  458. Return Value:
  459. Handle to open file or -1 if error occurs.
  460. --*/
  461. {
  462. HFILE h;
  463. int OpenMode;
  464. if(oflag & _O_WRONLY) {
  465. OpenMode = OF_WRITE;
  466. } else {
  467. if(oflag & _O_RDWR) {
  468. OpenMode = OF_READWRITE;
  469. } else {
  470. OpenMode = OF_READ;
  471. }
  472. }
  473. h = _lopen(FileName,OpenMode | OF_SHARE_DENY_WRITE);
  474. if(h == HFILE_ERROR) {
  475. DiamondLastIoError = LZERROR_BADINHANDLE;
  476. return(-1);
  477. }
  478. return((INT_PTR)h);
  479. }
  480. UINT
  481. DIAMONDAPI
  482. SpdFdiRead(
  483. IN INT_PTR Handle,
  484. OUT PVOID pv,
  485. IN UINT ByteCount
  486. )
  487. /*++
  488. Routine Description:
  489. Callback used by FDICopy to read from a file.
  490. Arguments:
  491. Handle - supplies handle to open file to be read from.
  492. pv - supplies pointer to buffer to receive bytes we read.
  493. ByteCount - supplies number of bytes to read.
  494. Return Value:
  495. Number of bytes read (ByteCount) or -1 if an error occurs.
  496. --*/
  497. {
  498. UINT rc;
  499. rc = _lread((HFILE)Handle,pv,ByteCount);
  500. if(rc == HFILE_ERROR) {
  501. rc = (UINT)(-1);
  502. DiamondLastIoError = LZERROR_READ;
  503. }
  504. return(rc);
  505. }
  506. UINT
  507. DIAMONDAPI
  508. SpdFdiWrite(
  509. IN INT_PTR Handle,
  510. IN PVOID pv,
  511. IN UINT ByteCount
  512. )
  513. /*++
  514. Routine Description:
  515. Callback used by FDICopy to write to a file.
  516. Arguments:
  517. Handle - supplies handle to open file to be written to.
  518. pv - supplies pointer to buffer containing bytes to write.
  519. ByteCount - supplies number of bytes to write.
  520. Return Value:
  521. Number of bytes written (ByteCount) or -1 if an error occurs.
  522. --*/
  523. {
  524. UINT rc;
  525. rc = _lwrite((HFILE)Handle,pv,ByteCount);
  526. if(rc == HFILE_ERROR) {
  527. DiamondLastIoError = (GetLastError() == ERROR_DISK_FULL) ? LZERROR_WRITE : LZERROR_BADOUTHANDLE;
  528. } else {
  529. if(rc != ByteCount) {
  530. //
  531. // let caller interpret return value but record last error just in case
  532. //
  533. DiamondLastIoError = LZERROR_WRITE;
  534. }
  535. }
  536. return(rc);
  537. }
  538. int
  539. DIAMONDAPI
  540. SpdFdiClose(
  541. IN INT_PTR Handle
  542. )
  543. /*++
  544. Routine Description:
  545. Callback used by FDICopy to close files.
  546. Arguments:
  547. Handle - handle of file to close.
  548. Return Value:
  549. 0 (success).
  550. --*/
  551. {
  552. _lclose((HFILE)Handle);
  553. return(0);
  554. }
  555. LONG
  556. DIAMONDAPI
  557. SpdFdiSeek(
  558. IN INT_PTR Handle,
  559. IN long Distance,
  560. IN int SeekType
  561. )
  562. /*++
  563. Routine Description:
  564. Callback used by FDICopy to seek files.
  565. Arguments:
  566. Handle - handle of file to close.
  567. Distance - supplies distance to seek. Interpretation of this
  568. parameter depends on the value of SeekType.
  569. SeekType - supplies a value indicating how Distance is to be
  570. interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
  571. Return Value:
  572. New file offset or -1 if an error occurs.
  573. --*/
  574. {
  575. LONG rc;
  576. rc = _llseek((HFILE)Handle,Distance,SeekType);
  577. if(rc == HFILE_ERROR) {
  578. DiamondLastIoError = LZERROR_BADINHANDLE;
  579. rc = -1L;
  580. }
  581. return(rc);
  582. }
  583. INT
  584. ExpandDiamondFile(
  585. IN NOTIFYPROC ExpandNotify,
  586. IN PSTR SourceFileName,
  587. IN PSTR TargetFileName,
  588. IN BOOL RenameTarget,
  589. IN PSTR SelectiveFilesSpec,
  590. OUT PLZINFO pLZI
  591. )
  592. {
  593. BOOL b;
  594. INT rc;
  595. INT_PTR h;
  596. DIAMOND_INFO DiamondInfo;
  597. if(!FdiContext) {
  598. return(LZERROR_BADVALUE);
  599. }
  600. DiamondLastIoError = TRUE;
  601. //
  602. // Get a handle to the source to use to
  603. // copy the date and time stamp.
  604. //
  605. h = SpdFdiOpen(SourceFileName,_O_RDONLY,0);
  606. if(h == -1) {
  607. return(LZERROR_BADINHANDLE);
  608. }
  609. pLZI->cblInSize = GetFileSize((HANDLE)h,NULL);
  610. if(pLZI->cblInSize == -1) {
  611. SpdFdiClose(h);
  612. return(LZERROR_BADINHANDLE);
  613. }
  614. DiamondInfo.SourceFileHandle = h;
  615. DiamondInfo.SourceFileName = SourceFileName;
  616. DiamondInfo.TargetFileName = TargetFileName;
  617. DiamondInfo.RenameTargetFile = RenameTarget;
  618. DiamondInfo.ExpandNotify = ExpandNotify;
  619. DiamondInfo.SelectiveFilesSpec = SelectiveFilesSpec;
  620. DiamondInfo.pLZI = pLZI;
  621. b = FDICopy(
  622. FdiContext,
  623. SourceFileName, // pass the whole path as the name
  624. "", // don't bother with the path part
  625. 0, // flags
  626. DiamondNotifyFunction,
  627. NULL, // no decryption
  628. &DiamondInfo
  629. );
  630. if(b) {
  631. rc = TRUE;
  632. } else {
  633. switch(FdiError.erfOper) {
  634. case FDIERROR_CORRUPT_CABINET:
  635. case FDIERROR_UNKNOWN_CABINET_VERSION:
  636. case FDIERROR_BAD_COMPR_TYPE:
  637. rc = LZERROR_READ; // causes SID_FORMAT_ERROR message
  638. break;
  639. case FDIERROR_ALLOC_FAIL:
  640. rc = LZERROR_GLOBALLOC;
  641. break;
  642. case FDIERROR_TARGET_FILE:
  643. case FDIERROR_USER_ABORT:
  644. rc = DiamondLastIoError;
  645. break;
  646. default:
  647. //
  648. // The rest of the errors are not handled specially.
  649. //
  650. rc = LZERROR_BADVALUE;
  651. break;
  652. }
  653. //
  654. // Remove the partial target file.
  655. //
  656. DeleteFile(TargetFileName);
  657. }
  658. SpdFdiClose(h);
  659. return(rc);
  660. }
  661. BOOL
  662. IsDiamondFile(
  663. IN PSTR FileName,
  664. OUT PBOOL ContainsMultipleFiles
  665. )
  666. {
  667. FDICABINETINFO CabinetInfo;
  668. BOOL b;
  669. INT_PTR h;
  670. *ContainsMultipleFiles = FALSE;
  671. if(!FdiContext) {
  672. return(FALSE);
  673. }
  674. //
  675. // Open the file such that the handle is valid for use
  676. // in the diamond context (ie, seek, read routines above).
  677. //
  678. h = SpdFdiOpen(FileName,_O_RDONLY,0);
  679. if(h == -1) {
  680. return(FALSE);
  681. }
  682. b = FDIIsCabinet(FdiContext,h,&CabinetInfo);
  683. SpdFdiClose(h);
  684. if (b && (CabinetInfo.cFiles > 1)) {
  685. *ContainsMultipleFiles = TRUE;
  686. }
  687. return(b);
  688. }
  689. BOOL
  690. InitDiamond(
  691. VOID
  692. )
  693. {
  694. if(FdiContext == NULL) {
  695. FdiContext = FDICreate(
  696. SpdFdiAlloc,
  697. SpdFdiFree,
  698. SpdFdiOpen,
  699. SpdFdiRead,
  700. SpdFdiWrite,
  701. SpdFdiClose,
  702. SpdFdiSeek,
  703. cpuUNKNOWN,
  704. &FdiError
  705. );
  706. }
  707. return(FdiContext != NULL);
  708. }
  709. VOID
  710. TermDiamond(
  711. VOID
  712. )
  713. {
  714. if(FdiContext) {
  715. FDIDestroy(FdiContext);
  716. FdiContext = NULL;
  717. }
  718. }