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.

476 lines
15 KiB

  1. #include "verpriv.h"
  2. #include <lzexpand.h>
  3. #include "diamondd.h"
  4. #include "mydiam.h"
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. /*
  9. ** Prototypes
  10. */
  11. // For the time being, private APIS exported
  12. INT
  13. LZCreateFileW(
  14. LPWSTR,
  15. DWORD,
  16. DWORD,
  17. DWORD,
  18. LPWSTR);
  19. VOID
  20. LZCloseFile(
  21. INT);
  22. #ifdef __cplusplus
  23. }
  24. #endif
  25. BOOL FileInUse(LPWSTR lpszFilePath, LPWSTR lpszFileName);
  26. DWORD MakeFileName(LPWSTR lpDst, LPWSTR lpDir, LPWSTR lpFile, int cchDst);
  27. typedef struct tagVS_VERSION {
  28. WORD wTotLen;
  29. WORD wValLen;
  30. WORD wType;
  31. WCHAR szSig[16];
  32. VS_FIXEDFILEINFO vInfo;
  33. } VS_VERSION;
  34. typedef struct tagLANGANDCP {
  35. WORD wLanguage;
  36. WORD wCodePage;
  37. } LANGANDCP;
  38. WCHAR szTrans[] = TEXT("\\VarFileInfo\\Translation");
  39. WCHAR szTempHdr[] = TEXT("temp.");
  40. /* The routines in here will find a file on a path, and an environment
  41. * variable. The constants _MAX_PATH and need to be defined
  42. * by the including module, plus the constant WINDOWS should
  43. * be defined if this is to be used in Windows, so that lstrcmpi
  44. * and lstrlen will not be compiled
  45. */
  46. VOID Ver3IToA(LPWSTR lpwStr, int n)
  47. {
  48. int nShift;
  49. WCHAR cTemp;
  50. for (nShift=8; nShift>=0; nShift-=4, ++lpwStr) {
  51. if ((cTemp = (WCHAR)((n>>nShift)&0x000f)) >= 10)
  52. *lpwStr = (WCHAR)('A' + cTemp - 10);
  53. else
  54. *lpwStr = (WCHAR)('0' + cTemp );
  55. }
  56. *lpwStr = 0;
  57. }
  58. /* Convert a DOS error into an error flag
  59. */
  60. DWORD FileErrFlag(int err)
  61. {
  62. switch (err) {
  63. case 0x05:
  64. return (VIF_ACCESSVIOLATION);
  65. case 0x20:
  66. return (VIF_SHARINGVIOLATION);
  67. default:
  68. return (0);
  69. }
  70. }
  71. /* Create the given file with default flags; global nFileErr will
  72. * receive any DOS error; returns -1 on error, otherwise the DOS
  73. * file handle.
  74. */
  75. HANDLE VerCreateFile(LPWSTR lpszFile)
  76. {
  77. HANDLE hFile;
  78. hFile = CreateFile(lpszFile, GENERIC_READ | GENERIC_WRITE,
  79. FILE_SHARE_READ, NULL, CREATE_NEW,
  80. FILE_ATTRIBUTE_NORMAL, NULL);
  81. return (hFile);
  82. }
  83. VOID VerClose(HANDLE hW32File)
  84. {
  85. CloseHandle(hW32File);
  86. }
  87. #define MyAlloc(x) ((WCHAR *)LocalAlloc(LMEM_FIXED, x))
  88. #define MyFree(x) LocalFree((HANDLE)(x))
  89. LPVOID MyGetFileVersionInfo(LPWSTR lpFileName)
  90. {
  91. WCHAR *pInfo;
  92. WORD wLen = 2048;
  93. TryAgain:
  94. if (!(pInfo=MyAlloc(wLen)))
  95. goto Error1;
  96. if (!GetFileVersionInfo(lpFileName, 0L, wLen, pInfo))
  97. goto Error2;
  98. if (wLen < *(WORD *)pInfo) {
  99. wLen = *(WORD *)pInfo;
  100. MyFree(pInfo);
  101. goto TryAgain;
  102. }
  103. return (pInfo);
  104. Error2:
  105. MyFree(pInfo);
  106. Error1:
  107. return (NULL);
  108. }
  109. HINSTANCE hLz32;
  110. DWORD cLz32Load;
  111. typedef INT (APIENTRY *tLZInit)( INT );
  112. typedef INT (APIENTRY *tLZOpenFileW)(LPWSTR, LPOFSTRUCT, WORD );
  113. typedef INT (APIENTRY *tLZCreateFileW)(LPWSTR, DWORD, DWORD, DWORD, LPWSTR);
  114. typedef VOID (APIENTRY *tLZClose)( INT );
  115. typedef VOID (APIENTRY *tLZCloseFile)( INT );
  116. typedef LONG (APIENTRY *tLZCopy)( INT, INT );
  117. tLZInit pLZInit;
  118. tLZOpenFileW pLZOpenFileW;
  119. tLZCreateFileW pLZCreateFileW;
  120. tLZClose pLZClose;
  121. tLZCloseFile pLZCloseFile;
  122. tLZCopy pLZCopy;
  123. DWORD
  124. APIENTRY
  125. VerInstallFileW(
  126. DWORD wFlags,
  127. LPWSTR lpszSrcFileName,
  128. LPWSTR lpszDstFileName,
  129. LPWSTR lpszSrcDir,
  130. LPWSTR lpszDstDir,
  131. LPWSTR lpszCurDir,
  132. LPWSTR lpszTmpFile,
  133. PUINT puTmpFileLen
  134. )
  135. {
  136. WCHAR szSrcFile[_MAX_PATH];
  137. WCHAR szDstFile[_MAX_PATH];
  138. WCHAR szCurFile[_MAX_PATH];
  139. DWORD dwRetVal = 0L, dwSrcAttr;
  140. WORD wDirLen;
  141. LONG lCopy;
  142. HANDLE hW32Out;
  143. int i, fIn, fDosOut;
  144. WCHAR szCompFile[_MAX_PATH];
  145. CHAR szOemFile[_MAX_PATH];
  146. int iOemString;
  147. BOOL bDefaultCharUsed;
  148. BOOL DiamondFile;
  149. if (!cLz32Load) {
  150. hLz32 = LoadLibraryW(L"LZ32.DLL");
  151. if (!hLz32) {
  152. return (VIF_CANNOTLOADLZ32);
  153. }
  154. pLZOpenFileW = (tLZOpenFileW) GetProcAddress(hLz32, "LZOpenFileW");
  155. pLZCreateFileW = (tLZCreateFileW) GetProcAddress(hLz32, "LZCreateFileW");
  156. pLZInit = (tLZInit) GetProcAddress(hLz32, "LZInit");
  157. pLZCopy = (tLZCopy) GetProcAddress(hLz32, "LZCopy");
  158. pLZClose = (tLZClose) GetProcAddress(hLz32, "LZClose");
  159. pLZCloseFile = (tLZCloseFile) GetProcAddress(hLz32, "LZCloseFile");
  160. if (!(pLZOpenFileW && pLZInit && pLZCopy && pLZClose && pLZCreateFileW && pLZCloseFile)) {
  161. FreeLibrary(hLz32);
  162. return (VIF_CANNOTLOADLZ32);
  163. }
  164. if (InterlockedExchangeAdd(&cLz32Load, 1) != 0) {
  165. // Multiple threads are attempting to LoadLib
  166. // Free one here.
  167. FreeLibrary(hLz32);
  168. }
  169. }
  170. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  171. /* LZ Open the source for reading
  172. */
  173. MakeFileName(szSrcFile, lpszSrcDir, lpszSrcFileName, ARRAYSIZE(szSrcFile));
  174. dwRetVal = InitDiamond();
  175. if (dwRetVal) {
  176. return (dwRetVal);
  177. }
  178. if((fIn=pLZCreateFileW(szSrcFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, szCompFile)) < 0) {
  179. dwRetVal |= VIF_CANNOTREADSRC;
  180. goto doReturn;
  181. }
  182. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  183. /*
  184. * now we don't have any unicode interface for Diamond API. we need to convert
  185. * it to OEM charset string. we will use the converted string instead of of.szPathName.
  186. */
  187. DiamondFile = FALSE;
  188. iOemString = WideCharToMultiByte( CP_OEMCP, // Oem Codepage
  189. 0, // no option flag
  190. szCompFile, // Unicode string
  191. -1, // should be NULL terminated
  192. szOemFile, // Oem string
  193. ARRAYSIZE(szOemFile),// Oem string buffer size
  194. NULL, // use nls default char
  195. &bDefaultCharUsed
  196. );
  197. if( ( iOemString != 0 ) && // should succeed conversion.
  198. ( iOemString <= OFS_MAXPATHNAME ) && // should be <= 128 for OpenFile() API.
  199. ( bDefaultCharUsed == FALSE ) // the def. char should not be contain.
  200. )
  201. {
  202. DiamondFile = IsDiamondFile(szOemFile);
  203. }
  204. if (DiamondFile) {
  205. pLZCloseFile(fIn);
  206. }
  207. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  208. /* If the dest file exists and is read only, return immediately;
  209. * the calling app must change the attributes before continuing
  210. * In the library version, we assume the file is in use if it exists
  211. * and we are in a VM; check all other possible errors and then return,
  212. * so the calling app can override our determination of "in use"
  213. * on a second call, along with all other problems
  214. */
  215. wDirLen = (WORD)MakeFileName(szDstFile, lpszDstDir, lpszDstFileName, ARRAYSIZE(szDstFile));
  216. lstrcpyn(szSrcFile, szDstFile, ARRAYSIZE(szSrcFile));
  217. if (!HIWORD(dwSrcAttr=GetFileAttributes(szSrcFile))) {
  218. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  219. if (LOWORD(dwSrcAttr)&0x01) {
  220. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  221. dwRetVal |= VIF_WRITEPROT;
  222. goto doCloseSrc;
  223. }
  224. }
  225. /* If this is a force install and there is a temp file name from a
  226. * previous call to this function, use that as the temp file name
  227. */
  228. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  229. if ((wFlags&VIFF_FORCEINSTALL) && *lpszTmpFile) {
  230. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  231. LogData("fnam", (DWORD)lpszDstDir, (DWORD)lpszTmpFile);
  232. MakeFileName(szSrcFile, lpszDstDir, lpszTmpFile, ARRAYSIZE(szSrcFile));
  233. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  234. LogData("srcf", (DWORD)szSrcFile, *(LPDWORD)szSrcFile);
  235. if (!HIWORD(GetFileAttributes(szSrcFile))) {
  236. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  237. goto doCheckDstFile;
  238. }
  239. }
  240. /* Determine a file name that is not in use; try names of the form:
  241. * temp.nnn where nnn is a three digit hex number. If we get to
  242. * 0xfff, we have a serious file system problem. Create the file.
  243. */
  244. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  245. lstrcpy(szSrcFile+wDirLen, szTempHdr);
  246. for (i=0; ; ++i) {
  247. Ver3IToA(szSrcFile+wDirLen+lstrlen(szTempHdr), i);
  248. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  249. if (HIWORD(GetFileAttributes(szSrcFile)))
  250. break;
  251. if (i > 0xfff) {
  252. dwRetVal |= VIF_CANNOTCREATE;
  253. goto doCloseSrc;
  254. }
  255. }
  256. /* Copy the file, and fill in appropriate errors
  257. */
  258. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  259. if (DiamondFile) {
  260. LZINFO lzi;
  261. lCopy = ExpandDiamondFile(szOemFile,
  262. szSrcFile,
  263. FALSE,
  264. &lzi);
  265. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  266. } else {
  267. if ((hW32Out=VerCreateFile(szSrcFile)) == INVALID_HANDLE_VALUE) {
  268. dwRetVal |= VIF_CANNOTCREATE | FileErrFlag(GetLastError());
  269. goto doCloseSrc;
  270. }
  271. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  272. fDosOut = pLZInit((INT)((DWORD_PTR)hW32Out));
  273. lCopy = pLZCopy(fIn, fDosOut);
  274. pLZClose(fDosOut);
  275. }
  276. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  277. switch (lCopy) {
  278. case LZERROR_BADINHANDLE:
  279. case LZERROR_READ:
  280. case LZERROR_BADVALUE:
  281. case LZERROR_UNKNOWNALG:
  282. dwRetVal |= VIF_CANNOTREADSRC;
  283. goto doDelTempFile;
  284. case LZERROR_BADOUTHANDLE:
  285. case LZERROR_WRITE:
  286. dwRetVal |= VIF_OUTOFSPACE;
  287. goto doDelTempFile;
  288. case LZERROR_GLOBALLOC:
  289. case LZERROR_GLOBLOCK:
  290. dwRetVal |= VIF_OUTOFMEMORY;
  291. goto doDelTempFile;
  292. default:
  293. break;
  294. }
  295. /* If the destination exists, check the versions of the two files,
  296. * and only copy if the src file is at least as new as the dst, and
  297. * they are the same type and in the same language and codepage
  298. */
  299. doCheckDstFile:
  300. if (!HIWORD(dwSrcAttr)) {
  301. VS_VERSION *pSrcVer, *pDstVer;
  302. LANGANDCP *lpSrcTrans, *lpDstTrans;
  303. DWORD dwSrcNum, dwDstNum;
  304. DWORD dwSrcTrans, dwDstTrans;
  305. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  306. if (!(wFlags & VIFF_FORCEINSTALL) &&
  307. (pDstVer=MyGetFileVersionInfo(szDstFile))) {
  308. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  309. if (!(pSrcVer=MyGetFileVersionInfo(szSrcFile))) {
  310. dwRetVal |= VIF_MISMATCH | VIF_SRCOLD;
  311. } else {
  312. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  313. if (pDstVer->vInfo.dwFileVersionMS>pSrcVer->vInfo.dwFileVersionMS
  314. || (pDstVer->vInfo.dwFileVersionMS==pSrcVer->vInfo.dwFileVersionMS &&
  315. pDstVer->vInfo.dwFileVersionLS>pSrcVer->vInfo.dwFileVersionLS))
  316. dwRetVal |= VIF_MISMATCH | VIF_SRCOLD;
  317. if (pDstVer->vInfo.dwFileType!=pSrcVer->vInfo.dwFileType ||
  318. pDstVer->vInfo.dwFileSubtype!=pSrcVer->vInfo.dwFileSubtype)
  319. dwRetVal |= VIF_MISMATCH | VIF_DIFFTYPE;
  320. if (VerQueryValueW(pDstVer, szTrans, (LPVOID)&lpDstTrans, &dwDstNum) &&
  321. VerQueryValueW(pSrcVer, szTrans, (LPVOID)&lpSrcTrans, &dwSrcNum)) {
  322. dwDstNum /= sizeof(DWORD);
  323. dwSrcNum /= sizeof(DWORD);
  324. for (dwDstTrans=0; dwDstTrans<dwDstNum; ++dwDstTrans) {
  325. for (dwSrcTrans=0; ; ++dwSrcTrans) {
  326. if (dwSrcTrans >= dwSrcNum) {
  327. dwRetVal |= VIF_MISMATCH | VIF_DIFFLANG;
  328. break;
  329. }
  330. if (lpDstTrans[dwDstTrans].wLanguage
  331. == lpSrcTrans[dwSrcTrans].wLanguage) {
  332. /* OK if dst is CP0 and src is not UNICODE
  333. */
  334. if (lpDstTrans[dwDstTrans].wCodePage==0 &&
  335. lpSrcTrans[dwSrcTrans].wCodePage!=1200)
  336. break;
  337. if (lpDstTrans[dwDstTrans].wCodePage
  338. == lpSrcTrans[dwSrcTrans].wCodePage)
  339. break;
  340. }
  341. }
  342. }
  343. }
  344. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  345. MyFree(pSrcVer);
  346. }
  347. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  348. MyFree(pDstVer);
  349. }
  350. /* If there were no errors, delete the currently existing file
  351. */
  352. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  353. if (FileInUse(szDstFile, lpszDstFileName)) {
  354. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  355. dwRetVal |= VIF_FILEINUSE;
  356. }
  357. if (!dwRetVal && !DeleteFile(szDstFile)) {
  358. dwRetVal |= VIF_CANNOTDELETE | FileErrFlag(GetLastError());
  359. goto doDelTempFile;
  360. }
  361. }
  362. /* If there were no errors, rename the temp file (any existing file
  363. * should have been deleted by now). Otherwise, if we created a valid
  364. * temp file, then pass along the temp file name.
  365. */
  366. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  367. if (dwRetVal) {
  368. DWORD wTemp;
  369. if (*puTmpFileLen > (wTemp=lstrlen(szSrcFile+wDirLen))) {
  370. lstrcpy(lpszTmpFile, szSrcFile+wDirLen);
  371. dwRetVal |= VIF_TEMPFILE;
  372. } else {
  373. dwRetVal |= VIF_BUFFTOOSMALL;
  374. DeleteFile(szSrcFile);
  375. }
  376. *puTmpFileLen = wTemp + 1;
  377. } else {
  378. /* Delete the currently existing file; this gets done before renaming
  379. * the temp file in case someone has tried to mess us up with a weird
  380. * directory name that would allow us to delete the newly installed
  381. * file.
  382. */
  383. if (!(wFlags&VIFF_DONTDELETEOLD) &&
  384. lpszCurDir && *lpszCurDir && lstrcmpi(lpszCurDir, lpszDstDir)) {
  385. MakeFileName(szCurFile, lpszCurDir, lpszDstFileName, ARRAYSIZE(szCurFile));
  386. if (!HIWORD(GetFileAttributes(szCurFile)) &&
  387. (FileInUse(szCurFile, lpszDstFileName) ||
  388. !DeleteFile(szCurFile)))
  389. dwRetVal |= VIF_CANNOTDELETECUR | FileErrFlag(GetLastError());
  390. }
  391. if (!MoveFile(szSrcFile, szDstFile)) {
  392. dwRetVal |= VIF_CANNOTRENAME | FileErrFlag(GetLastError());
  393. doDelTempFile:
  394. DeleteFile(szSrcFile);
  395. }
  396. }
  397. doCloseSrc:
  398. if (!DiamondFile) {
  399. pLZCloseFile(fIn);
  400. }
  401. doReturn:
  402. LogData("inst", __LINE__, (DWORD)puTmpFileLen);
  403. TermDiamond();
  404. return (dwRetVal);
  405. }