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.

364 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. replace.c
  5. Abstract:
  6. This module contains the code to replace
  7. a file in the cab file.
  8. Author:
  9. Wesley Witt (wesw) 29-Sept-1998
  10. Revision History:
  11. --*/
  12. #include <ntcabp.h>
  13. #pragma hdrstop
  14. BOOL
  15. NtCabReplaceOneFile(
  16. IN PCAB_INSTANCE_DATA CabInst,
  17. IN PCWSTR FileName
  18. )
  19. {
  20. BOOL rVal;
  21. NTSTATUS Status;
  22. HANDLE hFileTmp;
  23. HANDLE hFile;
  24. PCAB_DIR_ENTRY CabDir;
  25. PCAB_DIR_ENTRY CabDirNew;
  26. WCHAR TempPath[MAX_PATH];
  27. WCHAR TempFileName[MAX_PATH];
  28. DWORD Bytes = 0;
  29. DWORD BytesRead;
  30. ULONG FileSize;
  31. ULONG i;
  32. DWORD BytesCompressed;
  33. LPWSTR s;
  34. //
  35. // file the file to replace
  36. //
  37. CabDir = FindFileInCab( CabInst, FileName );
  38. if (CabDir == NULL) {
  39. return FALSE;
  40. }
  41. //
  42. // open the new data file
  43. //
  44. hFile = CreateFile(
  45. FileName,
  46. GENERIC_READ,
  47. FILE_SHARE_READ,
  48. NULL,
  49. OPEN_EXISTING,
  50. FILE_ATTRIBUTE_NORMAL,
  51. NULL
  52. );
  53. if (hFile == INVALID_HANDLE_VALUE) {
  54. return FALSE;
  55. }
  56. FileSize = GetFileSize( hFile, NULL );
  57. if (FileSize < CabDir->FileSize) {
  58. //
  59. // do an inplace update - this is the fast code path
  60. //
  61. //
  62. // position the cabfile to the data for the old file
  63. //
  64. SetFilePointer( CabInst->hCab, CabDir->Offset, NULL, FILE_BEGIN );
  65. //
  66. // create a directory for the new cab file
  67. //
  68. BytesRead = sizeof(CAB_DIR_ENTRY) + (sizeof(ULONG)*64);
  69. CabDirNew = (PCAB_DIR_ENTRY) malloc( BytesRead );
  70. if (CabDirNew == NULL) {
  71. return FALSE;
  72. }
  73. ZeroMemory( CabDirNew, BytesRead );
  74. CabDirNew->Offset = SetFilePointer( CabInst->hCab, 0, NULL, FILE_CURRENT );
  75. wcscpy( CabDirNew->FileName, FileName );
  76. i = 0;
  77. Bytes = 0;
  78. FileSize = GetFileSize( hFile, NULL );
  79. //
  80. // copy the data from the new data file into
  81. // the new cab file, compressing it as we go
  82. //
  83. while (Bytes < FileSize) {
  84. BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
  85. Status = ReadFile(
  86. hFile,
  87. CabInst->ReadBuf,
  88. BytesRead,
  89. &BytesRead,
  90. NULL
  91. );
  92. Bytes += BytesRead;
  93. Status = RtlCompressBuffer(
  94. COMPRESSION_FLAGS,
  95. CabInst->ReadBuf,
  96. BytesRead,
  97. CabInst->CompressBuf,
  98. CabInst->CompressBufSize,
  99. 4096,
  100. &BytesCompressed,
  101. CabInst->WorkSpace
  102. );
  103. Status = WriteFile(
  104. CabInst->hCab,
  105. CabInst->CompressBuf,
  106. BytesCompressed,
  107. &BytesRead,
  108. NULL
  109. );
  110. CabDirNew->Segment[i++] = BytesRead;
  111. CabDirNew->CompressedFileSize += BytesRead;
  112. }
  113. CabDirNew->Segments = i;
  114. //
  115. // put the new file in the dir list and
  116. // remove the old file from the list
  117. //
  118. RemoveEntryList( &CabDir->Next );
  119. InsertTailList( &CabInst->CabDir, &CabDirNew->Next );
  120. //
  121. // truncate the dir entries
  122. //
  123. SetFilePointer( CabInst->hCab, CabInst->CabDirOffset, NULL, FILE_BEGIN );
  124. SetEndOfFile( CabInst->hCab );
  125. FlushFileBuffers( CabInst->hCab );
  126. //
  127. // trick the close function to rebuild the dirs
  128. //
  129. CabInst->NewCabFile = TRUE;
  130. return TRUE;
  131. }
  132. //
  133. // create a file name for the temporary cab file
  134. //
  135. GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath );
  136. GetTempFileName( TempPath, L"cab", 0, TempFileName );
  137. //
  138. // create the new temporary cab file
  139. //
  140. hFileTmp = CreateFile(
  141. TempFileName,
  142. GENERIC_WRITE,
  143. 0,
  144. NULL,
  145. CREATE_ALWAYS,
  146. FILE_ATTRIBUTE_NORMAL,
  147. NULL
  148. );
  149. if (hFileTmp == INVALID_HANDLE_VALUE) {
  150. return FALSE;
  151. }
  152. //
  153. // set the existing cab file pointer to the beginning
  154. //
  155. SetFilePointer( CabInst->hCab, 0, NULL, FILE_BEGIN );
  156. FileSize = CabDir->Offset;
  157. Bytes = 0;
  158. //
  159. // copy the data from the beginning of the cab file
  160. // to the first byte of the file that needs replacing
  161. //
  162. while(Bytes<FileSize) {
  163. BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
  164. rVal = ReadFile(
  165. CabInst->hCab,
  166. CabInst->ReadBuf,
  167. BytesRead,
  168. &BytesRead,
  169. NULL
  170. );
  171. Bytes += BytesRead;
  172. rVal = WriteFile(
  173. hFileTmp,
  174. CabInst->ReadBuf,
  175. BytesRead,
  176. &BytesRead,
  177. NULL
  178. );
  179. }
  180. //
  181. // create a directory for the new cab file
  182. //
  183. BytesRead = sizeof(CAB_DIR_ENTRY) + (sizeof(ULONG)*64);
  184. CabDirNew = (PCAB_DIR_ENTRY) malloc( BytesRead );
  185. if (CabDirNew == NULL) {
  186. return FALSE;
  187. }
  188. ZeroMemory( CabDirNew, BytesRead );
  189. CabDirNew->Offset = SetFilePointer( CabInst->hCab, 0, NULL, FILE_CURRENT );
  190. wcscpy( CabDirNew->FileName, FileName );
  191. i = 0;
  192. Bytes = 0;
  193. FileSize = GetFileSize( hFile, NULL );
  194. //
  195. // copy the data from the new data file into
  196. // the new cab file, compressing it as we go
  197. //
  198. while (Bytes < FileSize) {
  199. BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
  200. Status = ReadFile(
  201. hFile,
  202. CabInst->ReadBuf,
  203. BytesRead,
  204. &BytesRead,
  205. NULL
  206. );
  207. Bytes += BytesRead;
  208. Status = RtlCompressBuffer(
  209. COMPRESSION_FLAGS,
  210. CabInst->ReadBuf,
  211. BytesRead,
  212. CabInst->CompressBuf,
  213. CabInst->CompressBufSize,
  214. 4096,
  215. &BytesCompressed,
  216. CabInst->WorkSpace
  217. );
  218. Status = WriteFile(
  219. hFileTmp,
  220. CabInst->CompressBuf,
  221. BytesCompressed,
  222. &BytesRead,
  223. NULL
  224. );
  225. CabDirNew->Segment[i++] = BytesRead;
  226. CabDirNew->CompressedFileSize += BytesRead;
  227. }
  228. CabDirNew->Segments = i;
  229. //
  230. // skip the data for the original file
  231. //
  232. Bytes = SetFilePointer( CabInst->hCab, CabDir->CompressedFileSize, NULL, FILE_CURRENT );
  233. //
  234. // set up the file size for the remaining data minus the dir
  235. //
  236. FileSize = CabInst->CabDirOffset - Bytes;
  237. Bytes = 0;
  238. //
  239. // copy the remaining data
  240. //
  241. while(Bytes<FileSize) {
  242. BytesRead = min( CabInst->ReadBufSize, FileSize-Bytes );
  243. rVal = ReadFile(
  244. CabInst->hCab,
  245. CabInst->ReadBuf,
  246. BytesRead,
  247. &BytesRead,
  248. NULL
  249. );
  250. Bytes += BytesRead;
  251. rVal = WriteFile(
  252. hFileTmp,
  253. CabInst->ReadBuf,
  254. BytesRead,
  255. &BytesRead,
  256. NULL
  257. );
  258. }
  259. //
  260. // put the new file in the dir list and
  261. // remove the old file from the list
  262. //
  263. RemoveEntryList( &CabDir->Next );
  264. InsertTailList( &CabInst->CabDir, &CabDirNew->Next );
  265. //
  266. // close the new cab file and the new data file
  267. //
  268. CloseHandle( hFile );
  269. CloseHandle( hFileTmp );
  270. //
  271. // copy the new cab as the old cab file
  272. //
  273. CabInst->NewCabFile = TRUE;
  274. CloseHandle( CabInst->hCab );
  275. DeleteFile( CabInst->CabFileName );
  276. MoveFile( TempFileName, CabInst->CabFileName );
  277. //
  278. // reopen the cab file so we can re-write the
  279. // dir when it is closed
  280. //
  281. CabInst->hCab = CreateFile(
  282. CabInst->CabFileName,
  283. GENERIC_WRITE | GENERIC_READ,
  284. 0,
  285. NULL,
  286. OPEN_EXISTING,
  287. FILE_ATTRIBUTE_NORMAL,
  288. NULL
  289. );
  290. if (CabInst->hCab == INVALID_HANDLE_VALUE) {
  291. return FALSE;
  292. }
  293. return TRUE;
  294. }