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.

820 lines
22 KiB

  1. #include "stdafx.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <io.h>
  6. #include <fcntl.h>
  7. #include <dos.h>
  8. #include "cabfunc.h"
  9. #include "resource.h"
  10. #include "filestuff.h"
  11. #include "fdi.h"
  12. BOOL test_fdi(char *cabinet_fullpath);
  13. //static char dest_dir[MAX_PATH];
  14. BOOL explode_cab(char *cabinet_fullpath, char *destination)
  15. {
  16. char cab_path[MAX_PATH];
  17. strcpy(dest_dir, destination);
  18. strcpy(cab_path, cabinet_fullpath);
  19. return test_fdi(cabinet_fullpath);
  20. }
  21. //---------------------------------------------------------------------------
  22. // The following definitions are pulled from stat.h and types.h. I was having
  23. // trouble getting the build tree make to pull them in, so I just copied the
  24. // relevant stuff. This may very well need to be changed if those include
  25. // files change.
  26. //---------------------------------------------------------------------------
  27. #define _S_IREAD 0000400 /* read permission, owner */
  28. #define _S_IWRITE 0000200 /* write permission, owner */
  29. //---------------------------------------------------------------------------
  30. // All of these functions may be called by the unCAB library.
  31. //---------------------------------------------------------------------------
  32. FNALLOC(mem_alloc) { return malloc(cb); }
  33. FNFREE(mem_free) { free(pv); }
  34. FNOPEN(file_open) { return _open(pszFile, oflag, pmode); }
  35. FNREAD(file_read) { return _read((int)hf, pv, cb); }
  36. FNWRITE(file_write) { return _write((int)hf, pv, cb); }
  37. FNCLOSE(file_close) { return _close((int)hf); }
  38. FNSEEK(file_seek) { return _lseek((int)hf, dist, seektype); }
  39. BOOL DoesFileExist(char *szFile)
  40. {
  41. USES_CONVERSION;
  42. HANDLE handle;
  43. handle = CreateFile(A2T(szFile), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  44. if (handle != INVALID_HANDLE_VALUE)
  45. {
  46. CloseHandle(handle);
  47. return TRUE;
  48. }
  49. return FALSE;
  50. }
  51. //---------------------------------------------------------------------------
  52. // This callback will be called by the unCAB library.
  53. //---------------------------------------------------------------------------
  54. FNFDINOTIFY(notification_function)
  55. {
  56. switch (fdint)
  57. {
  58. case fdintCABINET_INFO: // general information about the cabinet
  59. return 0;
  60. case fdintPARTIAL_FILE: // first file in cabinet is continuation
  61. return 0;
  62. case fdintCOPY_FILE: // file to be copied
  63. {
  64. int handle = -1;
  65. char destination[MAX_PATH];
  66. char szBuffer[MAX_PATH], *szFile;
  67. // We no longer want to create a directory tree as we expand the files.
  68. // TSHOOT.EXE, which is used to open some of the files in the CAB, likes
  69. // to find the files in a nice flat directory. Now we will need to handle
  70. // name collisions (although there probably won't be many). If we are
  71. // asked to create a second file with the same name as an existing file,
  72. // we'll prefix the subdirectory name and an underscore to the new file.
  73. if (pfdin->psz1 == NULL)
  74. return 0;
  75. strcpy(szBuffer, pfdin->psz1);
  76. szFile = strrchr(szBuffer, '\\');
  77. while (handle == -1 && szFile != NULL)
  78. {
  79. sprintf(destination, "%s\\%s", dest_dir, szFile + 1);
  80. if (!DoesFileExist(destination))
  81. handle = (int)file_open(destination, _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
  82. else
  83. {
  84. *szFile = '_';
  85. szFile = strrchr(szBuffer, '\\');
  86. }
  87. }
  88. if (handle == -1)
  89. {
  90. sprintf(destination, "%s\\%s", dest_dir, szBuffer);
  91. handle = (int)file_open(destination, _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
  92. }
  93. return handle;
  94. // Old code which created the directory structure:
  95. #if FALSE
  96. // If the file we are supposed to create contains path information,
  97. // we may need to create the directories before create the file.
  98. char szDir[MAX_PATH], szSubDir[MAX_PATH], *p;
  99. p = strrchr(pfdin->psz1, '\\');
  100. if (p)
  101. {
  102. strncpy(szSubDir, pfdin->psz1, MAX_PATH);
  103. p = strchr(szSubDir, '\\');
  104. while (p != NULL)
  105. {
  106. *p = '\0';
  107. sprintf(szDir, "%s\\%s", dest_dir, szSubDir);
  108. CreateDirectory(szDir, NULL);
  109. *p = '\\';
  110. p = strchr(p+1, '\\');
  111. }
  112. }
  113. sprintf(destination, "%s\\%s", dest_dir, pfdin->psz1);
  114. #endif
  115. }
  116. case fdintCLOSE_FILE_INFO: // close the file, set relevant info
  117. {
  118. HANDLE handle;
  119. DWORD attrs;
  120. TCHAR destination[MAX_PATH];
  121. _stprintf(destination, _T("%s\\%s"), dest_dir, pfdin->psz1);
  122. file_close(pfdin->hf);
  123. // Need to use Win32 type handle to set date/time
  124. handle = CreateFile(destination, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  125. if (handle != INVALID_HANDLE_VALUE)
  126. {
  127. FILETIME datetime;
  128. if (TRUE == DosDateTimeToFileTime(pfdin->date, pfdin->time, &datetime))
  129. {
  130. FILETIME local_filetime;
  131. if (TRUE == LocalFileTimeToFileTime(&datetime, &local_filetime))
  132. {
  133. (void) SetFileTime(handle, &local_filetime, NULL, &local_filetime);
  134. }
  135. }
  136. CloseHandle(handle);
  137. }
  138. // Mask out attribute bits other than readonly,
  139. // hidden, system, and archive, since the other
  140. // attribute bits are reserved for use by
  141. // the cabinet format.
  142. attrs = pfdin->attribs;
  143. // Actually, let's mask out hidden as well.
  144. // attrs &= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
  145. attrs &= (_A_RDONLY | _A_SYSTEM | _A_ARCH);
  146. (void) SetFileAttributes(destination, attrs);
  147. return TRUE;
  148. }
  149. case fdintNEXT_CABINET: // file continued to next cabinet
  150. return 0;
  151. default:
  152. return 0;
  153. }
  154. }
  155. /**/
  156. //---------------------------------------------------------------------------
  157. // This function is used to actually expand the files in a CAB.
  158. //---------------------------------------------------------------------------
  159. BOOL test_fdi(char *cabinet_fullpath)
  160. {
  161. HFDI hfdi;
  162. ERF erf;
  163. FDICABINETINFO fdici;
  164. int hf;
  165. char *p;
  166. char cabinet_name[256];
  167. char cabinet_path[256];
  168. hfdi = FDICreate(mem_alloc, mem_free, file_open, file_read, file_write, file_close, file_seek, cpu80386, &erf);
  169. if (hfdi == NULL)
  170. {
  171. return FALSE;
  172. }
  173. hf = (int)file_open(cabinet_fullpath, _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0);
  174. if (hf == -1)
  175. {
  176. (void) FDIDestroy(hfdi);
  177. // printf("Unable to open '%s' for input\n", cabinet_fullpath);
  178. return FALSE;
  179. }
  180. if (FALSE == FDIIsCabinet(hfdi, hf, &fdici))
  181. {
  182. _close(hf);
  183. (void) FDIDestroy(hfdi);
  184. return FALSE;
  185. }
  186. else
  187. {
  188. _close(hf);
  189. }
  190. p = strrchr(cabinet_fullpath, '\\');
  191. if (p == NULL)
  192. {
  193. strcpy(cabinet_name, cabinet_fullpath);
  194. strcpy(cabinet_path, "");
  195. }
  196. else
  197. {
  198. strcpy(cabinet_name, p+1);
  199. strncpy(cabinet_path, cabinet_fullpath, (int) (p-cabinet_fullpath)+1);
  200. cabinet_path[ (int) (p-cabinet_fullpath)+1 ] = 0;
  201. }
  202. if (TRUE != FDICopy(hfdi, cabinet_name, cabinet_path, 0, notification_function, NULL, NULL))
  203. {
  204. (void) FDIDestroy(hfdi);
  205. return FALSE;
  206. }
  207. if (FDIDestroy(hfdi) != TRUE)
  208. return FALSE;
  209. return TRUE;
  210. }
  211. /*
  212. * UNI2UTF -- Unicode to/from UTF conversions
  213. *
  214. * Copyright (C) 1996, Microsoft Corporation. All rights reserved.
  215. *
  216. * History:
  217. *
  218. * 10-14-96 msliger Created.
  219. * 12-16-99 moved to .cpp from uni2utf.c
  220. * combined with code from cabfunc.c
  221. */
  222. /*
  223. * Unicode2UTF()
  224. *
  225. * This function converts any 0-terminated Unicode string to the corresponding
  226. * nul-terminated UTF string, and returns a pointer to the resulting string.
  227. * The pointer references a single, static internal buffer, so the result will
  228. * be destroyed on the next call.
  229. *
  230. * If the generated UTF string would be too long, NULL is returned.
  231. */
  232. char *Unicode2UTF(const wchar_t *unicode)
  233. {
  234. static char utfbuffer[MAX_UTF_LENGTH + 4];
  235. int utfindex = 0;
  236. while (*unicode != 0)
  237. {
  238. if (utfindex >= MAX_UTF_LENGTH)
  239. {
  240. return(NULL);
  241. }
  242. if (*unicode < 0x0080)
  243. {
  244. utfbuffer[utfindex++] = (char) *unicode;
  245. }
  246. else if (*unicode < 0x0800)
  247. {
  248. utfbuffer[utfindex++] = (char) (0xC0 + (*unicode >> 6));
  249. utfbuffer[utfindex++] = (char) (0x80 + (*unicode & 0x3F));
  250. }
  251. else
  252. {
  253. utfbuffer[utfindex++] = (char) (0xE0 + (*unicode >> 12));
  254. utfbuffer[utfindex++] = (char) (0x80 + ((*unicode >> 6) & 0x3F));
  255. utfbuffer[utfindex++] = (char) (0x80 + (*unicode & 0x3F));
  256. }
  257. unicode++;
  258. }
  259. utfbuffer[utfindex] = '\0';
  260. return(utfbuffer);
  261. }
  262. /*
  263. * UTF2Unicode()
  264. *
  265. * This function converts a valid UTF string into the corresponding unicode string,
  266. * and returns a pointer to the resulting unicode. The pointer references a single,
  267. * internal static buffer, which will be destroyed on the next call.
  268. *
  269. * If the generated unicode string would be too long, or if the UTF string contains
  270. * any illegal UTF values, NULL is returned.
  271. */
  272. wchar_t *UTF2Unicode(const char *utfString)
  273. {
  274. static wchar_t unicodebuffer[MAX_UNICODE_LENGTH + 1];
  275. int unicodeindex = 0;
  276. int c;
  277. while (*utfString != 0)
  278. {
  279. if (unicodeindex >= MAX_UNICODE_LENGTH)
  280. {
  281. return(NULL);
  282. }
  283. c = (*utfString++ & 0x00FF);
  284. if (c < 0x0080)
  285. {
  286. unicodebuffer[unicodeindex] = (unsigned short) c;
  287. }
  288. else if (c < 0x00C0)
  289. {
  290. return(NULL); /* 0x0080..0x00BF illegal */
  291. }
  292. else if (c < 0x00E0)
  293. {
  294. unicodebuffer[unicodeindex] = (unsigned short) ((c & 0x001F) << 6);
  295. c = (*utfString++ & 0x00FF);
  296. if ((c < 0x0080) || (c > 0x00BF))
  297. {
  298. return(NULL); /* trail must be 0x0080..0x00BF */
  299. }
  300. unicodebuffer[unicodeindex] |= (c & 0x003F);
  301. }
  302. else if (c < 0x00F0)
  303. {
  304. unicodebuffer[unicodeindex] = (unsigned short) ((c & 0x000F) << 12);
  305. c = (*utfString++ & 0x00FF);
  306. if ((c < 0x0080) || (c > 0x00BF))
  307. {
  308. return(NULL); /* trails must be 0x0080..0x00BF */
  309. }
  310. unicodebuffer[unicodeindex] |= ((c & 0x003F) << 6);
  311. c = (*utfString++ & 0x00FF);
  312. if ((c < 0x0080) || (c > 0x00BF))
  313. {
  314. return(NULL); /* trails must be 0x0080..0x00BF */
  315. }
  316. unicodebuffer[unicodeindex] |= (c & 0x003F);
  317. }
  318. else
  319. {
  320. return(NULL); /* lead can't be > 0x00EF */
  321. }
  322. unicodeindex++;
  323. }
  324. unicodebuffer[unicodeindex] = 0;
  325. return(unicodebuffer);
  326. }
  327. //---------------------------------------------------------------------------
  328. // This function will expand the specified CAB file, putting all of the
  329. // files in the specified destination directory.
  330. //---------------------------------------------------------------------------
  331. BOOL OpenCABFile(const CString & filename, const CString & destination)
  332. {
  333. char szFilebuffer[MAX_UTF_LENGTH];
  334. char szDestination[MAX_UTF_LENGTH];
  335. // If the filename has Unicode characters which can't be represented
  336. // directly by ANSI characters, we need to make a copy of it to the
  337. // temp directory, and give it an ANSI name. The code we've borrowed
  338. // for expanding CAB files can't open Unicode named files.
  339. BOOL fNonANSICharacter = FALSE;
  340. const TCHAR * pChar = (LPCTSTR) filename;
  341. while (pChar && *pChar)
  342. if (*pChar++ >= (TCHAR)0x0080)
  343. {
  344. fNonANSICharacter = TRUE;
  345. break;
  346. }
  347. CString strFilename(filename);
  348. BOOL fMadeCopy = FALSE;
  349. if (fNonANSICharacter)
  350. {
  351. TCHAR szNewFile[MAX_PATH + 10];
  352. DWORD dwLength = 0;
  353. dwLength = ::GetTempPath(MAX_PATH, szNewFile);
  354. if (dwLength != 0 && dwLength < MAX_PATH)
  355. {
  356. _tcscat(szNewFile, _T("msitemp.cab"));
  357. fMadeCopy = ::CopyFile((LPCTSTR) strFilename, szNewFile, FALSE);
  358. strFilename = szNewFile;
  359. }
  360. }
  361. BOOL fResult = FALSE;
  362. //TD: better way to handle UNICODE vs non-unicode strings?
  363. // for Unicode system
  364. char * szFilename = Unicode2UTF((wchar_t*)(LPCTSTR)strFilename);
  365. if (szFilename)
  366. {
  367. ::strcpy(szFilebuffer, szFilename);
  368. szFilename = Unicode2UTF((wchar_t*)(LPCTSTR)destination);
  369. if (szFilename)
  370. {
  371. ::strcpy(szDestination, szFilename);
  372. fResult = explode_cab(szFilebuffer, szDestination);
  373. }
  374. }
  375. //for non-Unicode system
  376. if (!fResult)
  377. {
  378. fResult = explode_cab((char *)(LPCTSTR) filename, (char *)(LPCTSTR) destination);
  379. }
  380. // If we made a copy of the CAB file, we should delete it now.
  381. if (fMadeCopy)
  382. ::DeleteFile((LPCTSTR)strFilename);
  383. return fResult;
  384. }
  385. //---------------------------------------------------------------------------
  386. // This function looks in the specified directory for an NFO file. If it
  387. // finds one, it assigns it to filename and returns TRUE. This function
  388. // will only find the first NFO file in a directory.
  389. //
  390. // If an NFO file cannot be found, then we'll look for another file type
  391. // to open. Grab the string entry in the registry = "cabdefaultopen". An
  392. // example value would be "*.nfo|hwinfo.dat|*.dat|*.txt" which would be
  393. // interpreted as follows:
  394. //
  395. // 1. First look for any NFO file to open.
  396. // 2. Then try to open a file called "hwinfo.dat".
  397. // 3. Then try to open any file with a DAT extension.
  398. // 4. Then try for any TXT file.
  399. // 5. Finally, if none of these can be found, present an open dialog
  400. // to the user.
  401. //---------------------------------------------------------------------------
  402. LPCTSTR VAL_CABDEFAULTOPEN = _T("cabdefaultopen");
  403. LPCTSTR cszDirSeparator = _T("\\");
  404. BOOL IsDataspecFilePresent(CString strCabExplodedDir)
  405. {
  406. CStringList filesfound;
  407. DirectorySearch(_T("dataspec.xml"), strCabExplodedDir, filesfound);
  408. if (filesfound.GetHeadPosition() != NULL)
  409. {
  410. return TRUE;
  411. }
  412. return FALSE;
  413. }
  414. BOOL IsIncidentXMLFilePresent(CString strCabExplodedDir, CString strIncidentFileName)
  415. {
  416. CStringList filesfound;
  417. DirectorySearch(strIncidentFileName, strCabExplodedDir, filesfound);
  418. if (filesfound.GetHeadPosition() != NULL)
  419. {
  420. return TRUE;
  421. }
  422. return FALSE;
  423. }
  424. BOOL FindFileToOpen(const CString & destination, CString & filename)
  425. {
  426. CString strCABDefaultOpen, strRegBase, strDirectory;
  427. HKEY hkey;
  428. filename.Empty();
  429. strDirectory = destination;
  430. if (strDirectory.Right(1) != CString(cszDirSeparator))
  431. strDirectory += CString(cszDirSeparator);
  432. // Set up a fallback string of the NFO file type, in case we can't
  433. // find the registry entry.
  434. strCABDefaultOpen.LoadString(IDS_DEFAULTEXTENSION);
  435. strCABDefaultOpen = CString("*.") + strCABDefaultOpen;
  436. // Load the string of files and file types to open from the registry.
  437. strRegBase.LoadString(IDS_MSI_REG_BASE);
  438. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strRegBase, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  439. {
  440. char szData[MAX_PATH];
  441. DWORD dwType, dwSize = MAX_PATH;
  442. if (RegQueryValueEx(hkey, VAL_CABDEFAULTOPEN, NULL, &dwType, (LPBYTE) szData, &dwSize) == ERROR_SUCCESS)
  443. if (dwType == REG_SZ)
  444. strCABDefaultOpen = szData;
  445. RegCloseKey(hkey);
  446. }
  447. // Look through each of the potential files and file types. If we find
  448. // a match, return TRUE after setting filename appropriately. Note that
  449. // we need to recurse down through directories.
  450. CString strFileSpec;
  451. CStringList filesfound;
  452. POSITION pos;
  453. while (!strCABDefaultOpen.IsEmpty())
  454. {
  455. if (strCABDefaultOpen.Find('|') == -1)
  456. strFileSpec = strCABDefaultOpen;
  457. else
  458. strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
  459. filesfound.RemoveAll();
  460. DirectorySearch(strFileSpec, strDirectory, filesfound);
  461. pos = filesfound.GetHeadPosition();
  462. if (pos != NULL)
  463. {
  464. filename = filesfound.GetNext(pos);
  465. return TRUE;
  466. }
  467. strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
  468. if (strCABDefaultOpen.Find('|') == 0)
  469. strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
  470. }
  471. //a-kjaw
  472. ////Look for incident.xml file. It has to be an unicode file.
  473. strCABDefaultOpen = _T("*.XML");
  474. TCHAR pBuf[MAX_PATH];
  475. WCHAR pwBuf[MAX_PATH];
  476. HANDLE handle;
  477. DWORD dw;
  478. while (!strCABDefaultOpen.IsEmpty())
  479. {
  480. if (strCABDefaultOpen.Find('|') == -1)
  481. strFileSpec = strCABDefaultOpen;
  482. else
  483. strFileSpec = strCABDefaultOpen.Left(strCABDefaultOpen.Find('|'));
  484. filesfound.RemoveAll();
  485. DirectorySearch(strFileSpec, strDirectory, filesfound);
  486. pos = filesfound.GetHeadPosition();
  487. while (pos != NULL)
  488. {
  489. filename = filesfound.GetNext(pos);
  490. handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  491. if (INVALID_HANDLE_VALUE == handle)
  492. continue;
  493. ReadFile(handle , pBuf , 1 , &dw , NULL);
  494. if( pBuf[0] == _T('<'))
  495. {
  496. do
  497. {
  498. ReadFile(handle , pBuf , _tcslen(_T("MachineID")) * sizeof(TCHAR) , &dw , NULL);
  499. if(_tcsicmp(pBuf , _T("MachineID")) == 0)
  500. {
  501. CloseHandle( handle );
  502. return TRUE;
  503. }
  504. else
  505. {
  506. SetFilePointer(handle , (1 - _tcslen(_T("MachineID")) )* sizeof(TCHAR) , 0 , FILE_CURRENT );
  507. }
  508. }while( dw == _tcslen(_T("MachineID")) );
  509. }
  510. else //Unicode?
  511. {
  512. ReadFile(handle , pwBuf , 1 , &dw , NULL);
  513. do
  514. {
  515. ReadFile(handle , pwBuf , lstrlenW(L"MachineID") * sizeof(WCHAR) , &dw , NULL);
  516. pwBuf[ lstrlenW(L"MachineID") ] = L'\0';
  517. if(lstrcmpiW(pwBuf , L"MachineID") == 0)
  518. {
  519. CloseHandle( handle );
  520. return TRUE;
  521. }
  522. else
  523. {
  524. SetFilePointer(handle , (1 - lstrlenW(L"MachineID"))* sizeof(WCHAR) , 0 , FILE_CURRENT );
  525. }
  526. }while( dw == _tcslen(_T("MachineID")) * sizeof(WCHAR) );
  527. }
  528. CloseHandle( handle );
  529. }
  530. strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - strFileSpec.GetLength());
  531. if (strCABDefaultOpen.Find('|') == 0)
  532. strCABDefaultOpen = strCABDefaultOpen.Right(strCABDefaultOpen.GetLength() - 1);
  533. }
  534. return FALSE;
  535. }
  536. //---------------------------------------------------------------------------
  537. // DirectorySearch is used to locate all of the files in a directory or
  538. // one of its subdirectories which match a file spec.
  539. //---------------------------------------------------------------------------
  540. void DirectorySearch(const CString & strSpec, const CString & strDir, CStringList &results)
  541. {
  542. // Look for all of the files which match the file spec in the directory
  543. // specified by strDir.
  544. WIN32_FIND_DATA finddata;
  545. CString strSearch, strDirectory;
  546. strDirectory = strDir;
  547. if (strDirectory.Right(1) != CString(cszDirSeparator)) strDirectory += CString(cszDirSeparator);
  548. strSearch = strDirectory + strSpec;
  549. HANDLE hFind = FindFirstFile(strSearch, &finddata);
  550. if (hFind != INVALID_HANDLE_VALUE)
  551. {
  552. do
  553. {
  554. results.AddHead(strDirectory + CString(finddata.cFileName));
  555. } while (FindNextFile(hFind, &finddata));
  556. FindClose(hFind);
  557. }
  558. // Now call this function recursively, with each of the subdirectories.
  559. strSearch = strDirectory + CString(_T("*"));
  560. hFind = FindFirstFile(strSearch, &finddata);
  561. if (hFind != INVALID_HANDLE_VALUE)
  562. {
  563. do
  564. {
  565. if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  566. if (::_tcscmp(finddata.cFileName, _T(".")) != 0 && ::_tcscmp(finddata.cFileName, _T("..")) != 0)
  567. DirectorySearch(strSpec, strDirectory + CString(finddata.cFileName), results);
  568. } while (FindNextFile(hFind, &finddata));
  569. FindClose(hFind);
  570. }
  571. }
  572. //---------------------------------------------------------------------------
  573. // This function gets the directory in which to put exploded CAB files.
  574. // This will be the same directory each time, so this function will create
  575. // the directory (if necessary) and delete any files in the directory.
  576. //---------------------------------------------------------------------------
  577. BOOL GetCABExplodeDir(CString &destination, BOOL fDeleteFiles, const CString & strDontDelete)
  578. {
  579. CString strMSInfoDir, strExplodeTo, strSubDirName;
  580. // Determine the temporary path and add on a subdir name.
  581. TCHAR szTempDir[MAX_PATH];
  582. if (::GetTempPath(MAX_PATH, szTempDir) > MAX_PATH)
  583. {
  584. destination = _T("");
  585. return FALSE;
  586. }
  587. strSubDirName.LoadString(IDS_CAB_DIR_NAME);
  588. strExplodeTo = szTempDir;
  589. if (strExplodeTo.Right(1) == CString(cszDirSeparator))
  590. strExplodeTo = strExplodeTo + strSubDirName;
  591. else
  592. strExplodeTo = strExplodeTo + CString(cszDirSeparator) + strSubDirName;
  593. // Kill the directory if it already exists.
  594. if (fDeleteFiles)
  595. KillDirectory(strExplodeTo, strDontDelete);
  596. // Create the subdirectory.
  597. if (!CreateDirectoryEx(szTempDir, strExplodeTo, NULL))
  598. {
  599. if (GetLastError() != ERROR_ALREADY_EXISTS)
  600. {
  601. // MSIError(IDS_GENERAL_ERROR, "couldn't create the target directory");
  602. destination = "";
  603. return FALSE;
  604. }
  605. }
  606. destination = strExplodeTo;
  607. return TRUE;
  608. }
  609. //---------------------------------------------------------------------------
  610. // This functions kills a directory by recursively deleting files and
  611. // subdirectories.
  612. //---------------------------------------------------------------------------
  613. void KillDirectory(const CString & strDir, const CString & strDontDelete)
  614. {
  615. CString strDirectory = strDir;
  616. if (strDirectory.Right(1) == CString(cszDirSeparator))
  617. strDirectory = strDirectory.Left(strDirectory.GetLength() - 1);
  618. // Delete any files in directory.
  619. CString strFilesToDelete = strDirectory + CString(_T("\\*.*"));
  620. CString strDeleteFile;
  621. WIN32_FIND_DATA filedata;
  622. BOOL bFound = TRUE;
  623. HANDLE hFindFile = FindFirstFile(strFilesToDelete, &filedata);
  624. while (hFindFile != INVALID_HANDLE_VALUE && bFound)
  625. {
  626. if ((filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0L)
  627. {
  628. strDeleteFile = strDirectory + CString(cszDirSeparator) + filedata.cFileName;
  629. if (strDontDelete.CompareNoCase(strDeleteFile) != 0)
  630. {
  631. ::SetFileAttributes(strDeleteFile, FILE_ATTRIBUTE_NORMAL);
  632. ::DeleteFile(strDeleteFile);
  633. }
  634. }
  635. bFound = FindNextFile(hFindFile, &filedata);
  636. }
  637. FindClose(hFindFile);
  638. // Now call this function on any subdirectories in this directory.
  639. CString strSearch = strDirectory + CString(_T("\\*"));
  640. hFindFile = FindFirstFile(strSearch, &filedata);
  641. if (hFindFile != INVALID_HANDLE_VALUE)
  642. {
  643. do
  644. {
  645. if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  646. if (::_tcscmp(filedata.cFileName, _T(".")) != 0 && ::_tcscmp(filedata.cFileName, _T("..")) != 0)
  647. KillDirectory(strDirectory + CString(cszDirSeparator) + CString(filedata.cFileName));
  648. } while (FindNextFile(hFindFile, &filedata));
  649. FindClose(hFindFile);
  650. }
  651. // Finally, remove this directory.
  652. ::RemoveDirectory(strDirectory);
  653. }