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.

333 lines
8.4 KiB

  1. //===========================================================================
  2. // The following code is based on an example of how to explode a CAB file
  3. // to a directory. The sample was supplied by Mike Sliger. The function names
  4. // have been left the same as those in the sample.
  5. //
  6. // Copyright (c) 1998-1999 Microsoft Corporation
  7. //===========================================================================
  8. #pragma warning(disable : 4514)
  9. #pragma warning(disable : 4201 4214 4115)
  10. #include <windows.h>
  11. #pragma warning(default : 4201 4214 4115)
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <io.h>
  16. #include <fcntl.h>
  17. #include <dos.h>
  18. #include <string.h>
  19. #pragma warning(disable : 4201)
  20. #include <fdi.h>
  21. #pragma warning(default : 4201)
  22. //---------------------------------------------------------------------------
  23. // This is the actual entry point called by the C++ code.
  24. //---------------------------------------------------------------------------
  25. BOOL test_fdi(const char *cabinet_fullpath);
  26. static char dest_dir[MAX_PATH];
  27. BOOL explode_cab(const char *cabinet_fullpath, const char *destination)
  28. {
  29. char cab_path[MAX_PATH];
  30. strcpy(dest_dir, destination);
  31. strcpy(cab_path, cabinet_fullpath);
  32. return test_fdi(cabinet_fullpath);
  33. }
  34. //---------------------------------------------------------------------------
  35. // The following definitions are pulled from stat.h and types.h. I was having
  36. // trouble getting the build tree make to pull them in, so I just copied the
  37. // relevant stuff. This may very well need to be changed if those include
  38. // files change.
  39. //---------------------------------------------------------------------------
  40. #define _S_IREAD 0000400 /* read permission, owner */
  41. #define _S_IWRITE 0000200 /* write permission, owner */
  42. //---------------------------------------------------------------------------
  43. // All of these functions may be called by the unCAB library.
  44. //---------------------------------------------------------------------------
  45. FNALLOC(mem_alloc) { return malloc(cb); }
  46. FNFREE(mem_free) { free(pv); }
  47. FNOPEN(file_open) { return _open(pszFile, oflag, pmode); }
  48. FNREAD(file_read) { return _read((HFILE)hf, pv, cb); }
  49. FNWRITE(file_write) { return _write((HFILE)hf, pv, cb); }
  50. FNCLOSE(file_close) { return _close((HFILE)hf); }
  51. FNSEEK(file_seek) { return _lseek((HFILE)hf, dist, seektype); }
  52. BOOL DoesFileExist(const char *szFile)
  53. {
  54. HANDLE handle;
  55. handle = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  56. if (handle != INVALID_HANDLE_VALUE)
  57. {
  58. CloseHandle(handle);
  59. return TRUE;
  60. }
  61. return FALSE;
  62. }
  63. //---------------------------------------------------------------------------
  64. // This callback will be called by the unCAB library.
  65. //---------------------------------------------------------------------------
  66. FNFDINOTIFY(notification_function)
  67. {
  68. switch (fdint)
  69. {
  70. case fdintCABINET_INFO: // general information about the cabinet
  71. return 0;
  72. case fdintPARTIAL_FILE: // first file in cabinet is continuation
  73. return 0;
  74. case fdintCOPY_FILE: // file to be copied
  75. {
  76. int handle = -1;
  77. char destination[MAX_PATH];
  78. char szBuffer[MAX_PATH], *szFile;
  79. // We no longer want to create a directory tree as we expand the files.
  80. // TSHOOT.EXE, which is used to open some of the files in the CAB, likes
  81. // to find the files in a nice flat directory. Now we will need to handle
  82. // name collisions (although there probably won't be many). If we are
  83. // asked to create a second file with the same name as an existing file,
  84. // we'll prefix the subdirectory name and an underscore to the new file.
  85. if (pfdin->psz1 == NULL)
  86. return 0;
  87. strcpy(szBuffer, pfdin->psz1);
  88. szFile = strrchr(szBuffer, '\\');
  89. while (handle == -1 && szFile != NULL)
  90. {
  91. sprintf(destination, "%s\\%s", dest_dir, szFile + 1);
  92. if (!DoesFileExist(destination))
  93. handle = (HFILE)file_open(destination, _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
  94. else
  95. {
  96. *szFile = '_';
  97. szFile = strrchr(szBuffer, '\\');
  98. }
  99. }
  100. if (handle == -1)
  101. {
  102. sprintf(destination, "%s\\%s", dest_dir, szBuffer);
  103. handle = (HFILE)file_open(destination, _O_BINARY | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL, _S_IREAD | _S_IWRITE);
  104. }
  105. return handle;
  106. // Old code which created the directory structure:
  107. #if FALSE
  108. // If the file we are supposed to create contains path information,
  109. // we may need to create the directories before create the file.
  110. char szDir[MAX_PATH], szSubDir[MAX_PATH], *p;
  111. p = strrchr(pfdin->psz1, '\\');
  112. if (p)
  113. {
  114. strncpy(szSubDir, pfdin->psz1, MAX_PATH);
  115. p = strchr(szSubDir, '\\');
  116. while (p != NULL)
  117. {
  118. *p = '\0';
  119. sprintf(szDir, "%s\\%s", dest_dir, szSubDir);
  120. CreateDirectory(szDir, NULL);
  121. *p = '\\';
  122. p = strchr(p+1, '\\');
  123. }
  124. }
  125. sprintf(destination, "%s\\%s", dest_dir, pfdin->psz1);
  126. #endif
  127. }
  128. case fdintCLOSE_FILE_INFO: // close the file, set relevant info
  129. {
  130. HANDLE handle;
  131. DWORD attrs;
  132. char destination[MAX_PATH];
  133. sprintf(destination, "%s\\%s", dest_dir, pfdin->psz1);
  134. file_close(pfdin->hf);
  135. // Need to use Win32 type handle to set date/time
  136. handle = CreateFileA(destination, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  137. if (handle != INVALID_HANDLE_VALUE)
  138. {
  139. FILETIME datetime;
  140. if (TRUE == DosDateTimeToFileTime(pfdin->date, pfdin->time, &datetime))
  141. {
  142. FILETIME local_filetime;
  143. if (TRUE == LocalFileTimeToFileTime(&datetime, &local_filetime))
  144. {
  145. (void) SetFileTime(handle, &local_filetime, NULL, &local_filetime);
  146. }
  147. }
  148. CloseHandle(handle);
  149. }
  150. // Mask out attribute bits other than readonly,
  151. // hidden, system, and archive, since the other
  152. // attribute bits are reserved for use by
  153. // the cabinet format.
  154. attrs = pfdin->attribs;
  155. // Actually, let's mask out hidden as well.
  156. // attrs &= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
  157. attrs &= (_A_RDONLY | _A_SYSTEM | _A_ARCH);
  158. (void) SetFileAttributesA(destination, attrs);
  159. return TRUE;
  160. }
  161. case fdintNEXT_CABINET: // file continued to next cabinet
  162. return 0;
  163. default:
  164. return 0;
  165. }
  166. }
  167. /*
  168. * isCabFile - Returns TRUE if the file descriptor in hf references a cab file,
  169. * FALSE if not.
  170. *
  171. * History: a-jsari 2/17/98 Initial version
  172. */
  173. BOOL isCabFile(int hf, void **phfdi)
  174. {
  175. ERF erf;
  176. FDICABINETINFO fdici;
  177. BOOL fReturn;
  178. HFDI hfdi = FDICreate(mem_alloc, mem_free, file_open, file_read, file_write,
  179. file_close, file_seek, cpu80386, &erf);
  180. if (hfdi == NULL)
  181. {
  182. return FALSE;
  183. }
  184. fReturn = FDIIsCabinet(hfdi, hf, &fdici);
  185. if (phfdi == NULL)
  186. {
  187. (void) FDIDestroy(hfdi);
  188. }
  189. else
  190. {
  191. *phfdi = (void *)hfdi;
  192. }
  193. return fReturn;
  194. }
  195. //---------------------------------------------------------------------------
  196. // This function is used to actually expand the files in a CAB.
  197. //---------------------------------------------------------------------------
  198. BOOL test_fdi(const char *cabinet_fullpath)
  199. {
  200. HFDI hfdi = NULL;
  201. #if 0
  202. ERF erf;
  203. FDICABINETINFO fdici;
  204. #endif
  205. int hf;
  206. char *p;
  207. char cabinet_name[256];
  208. char cabinet_path[256];
  209. #if 0
  210. hfdi = FDICreate(mem_alloc, mem_free, file_open, file_read, file_write, file_close, file_seek, cpu80386, &erf);
  211. if (hfdi == NULL)
  212. {
  213. return FALSE;
  214. }
  215. #endif
  216. hf = (HFILE)file_open((char *)cabinet_fullpath, _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0);
  217. if (hf == -1)
  218. {
  219. #if 0
  220. (void) FDIDestroy(hfdi);
  221. #endif
  222. // printf("Unable to open '%s' for input\n", cabinet_fullpath);
  223. return FALSE;
  224. }
  225. #if 0
  226. if (FALSE == FDIIsCabinet(hfdi, hf, &fdici))
  227. {
  228. _close(hf);
  229. (void) FDIDestroy(hfdi);
  230. return FALSE;
  231. }
  232. else
  233. {
  234. _close(hf);
  235. }
  236. #else
  237. if (FALSE == isCabFile(hf, &hfdi))
  238. {
  239. _close(hf);
  240. if(hfdi)
  241. (void) FDIDestroy(hfdi);
  242. return FALSE;
  243. }
  244. else
  245. {
  246. _close(hf);
  247. }
  248. #endif
  249. p = strrchr(cabinet_fullpath, '\\');
  250. if (p == NULL)
  251. {
  252. strcpy(cabinet_name, cabinet_fullpath);
  253. strcpy(cabinet_path, "");
  254. }
  255. else
  256. {
  257. strcpy(cabinet_name, p+1);
  258. strncpy(cabinet_path, cabinet_fullpath, (int) (p-cabinet_fullpath)+1);
  259. cabinet_path[ (int) (p-cabinet_fullpath)+1 ] = 0;
  260. }
  261. if (TRUE != FDICopy(hfdi, cabinet_name, cabinet_path, 0, notification_function, NULL, NULL))
  262. {
  263. (void) FDIDestroy(hfdi);
  264. return FALSE;
  265. }
  266. if (FDIDestroy(hfdi) != TRUE)
  267. return FALSE;
  268. return TRUE;
  269. }