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.

444 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. FileIo.c
  5. Abstract:
  6. This module implements various FileSystem routines used by
  7. the PGM Transport
  8. Author:
  9. Mohammad Shabbir Alam (MAlam) 3-30-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. //******************* Pageable Routine Declarations ****************
  14. #ifdef ALLOC_PRAGMA
  15. #endif
  16. //******************* Pageable Routine Declarations ****************
  17. //----------------------------------------------------------------------------
  18. NTSTATUS
  19. BuildPgmDataFileName(
  20. IN tSEND_SESSION *pSend
  21. )
  22. /*++
  23. Routine Description:
  24. This routine build the string for the file name used for buffering
  25. data packets.
  26. Arguments:
  27. IN pSend -- the Send object
  28. Return Value:
  29. NONE -- since we don't expect any error
  30. --*/
  31. {
  32. UNICODE_STRING ucPortNumber;
  33. WCHAR wcPortNumber[10];
  34. USHORT MaxFileLength;
  35. ULONG RandomNumber;
  36. PAGED_CODE();
  37. if (pPgmRegistryConfig->Flags & PGM_REGISTRY_SENDER_FILE_SPECIFIED)
  38. {
  39. MaxFileLength = pPgmRegistryConfig->ucSenderFileLocation.Length / sizeof(WCHAR);
  40. }
  41. else
  42. {
  43. MaxFileLength = sizeof (WS_DEFAULT_SENDER_FILE_LOCATION) / sizeof (WCHAR);
  44. }
  45. //
  46. // The file name is composed of the following:
  47. // "\\T" + 2DigitRandom# + UptoMAX_USHORTPort# + ".PGM" + "\0"
  48. //
  49. MaxFileLength += 2 + 2 + 5 + 4 + 1;
  50. if (!(pSend->pSender->DataFileName.Buffer = PgmAllocMem ((sizeof (WCHAR) * MaxFileLength), PGM_TAG('2'))))
  51. {
  52. PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "BuildPgmDataFileName",
  53. "STATUS_INSUFFICIENT_RESOURCES allocating <%d> bytes\n", MaxFileLength);
  54. return (STATUS_INSUFFICIENT_RESOURCES);
  55. }
  56. pSend->pSender->DataFileName.MaximumLength = sizeof (WCHAR) * MaxFileLength;
  57. pSend->pSender->DataFileName.Length = 0;
  58. //
  59. // First, set the root directory
  60. //
  61. if (pPgmRegistryConfig->Flags & PGM_REGISTRY_SENDER_FILE_SPECIFIED)
  62. {
  63. RtlAppendUnicodeToString (&pSend->pSender->DataFileName, pPgmRegistryConfig->ucSenderFileLocation.Buffer);
  64. }
  65. else
  66. {
  67. RtlAppendUnicodeToString (&pSend->pSender->DataFileName, WS_DEFAULT_SENDER_FILE_LOCATION);
  68. }
  69. RtlAppendUnicodeToString (&pSend->pSender->DataFileName, L"\\T");
  70. //
  71. // Now, Append a random 2 digit value
  72. //
  73. ucPortNumber.MaximumLength = sizeof (wcPortNumber);
  74. ucPortNumber.Buffer = wcPortNumber;
  75. RandomNumber = GetRandomInteger (0, 99);
  76. if (RandomNumber < 10)
  77. {
  78. RtlAppendUnicodeToString (&pSend->pSender->DataFileName, L"0");
  79. }
  80. RtlIntegerToUnicodeString (RandomNumber, 10, &ucPortNumber);
  81. RtlAppendUnicodeStringToString (&pSend->pSender->DataFileName, &ucPortNumber);
  82. //
  83. // Append the Port#
  84. //
  85. RtlIntegerToUnicodeString ((ULONG) pSend->TSIPort, 10, &ucPortNumber);
  86. RtlAppendUnicodeStringToString (&pSend->pSender->DataFileName, &ucPortNumber);
  87. //
  88. // Now, add the file name extension for id
  89. //
  90. RtlAppendUnicodeToString (&pSend->pSender->DataFileName, L".PGM");
  91. return (STATUS_SUCCESS);
  92. }
  93. //----------------------------------------------------------------------------
  94. NTSTATUS
  95. PgmCreateDataFileAndMapSection(
  96. IN tSEND_SESSION *pSend
  97. )
  98. /*++
  99. Routine Description:
  100. This routine creates the file and creates a section mapping for it.
  101. This file is used for buffering the data packets on behalf of the sender
  102. Arguments:
  103. IN pSend -- the Send object
  104. Return Value:
  105. NTSTATUS - Final status of the create operation
  106. --*/
  107. {
  108. OBJECT_ATTRIBUTES ObjectAttributes;
  109. IO_STATUS_BLOCK IoStatusBlock;
  110. LARGE_INTEGER lgMaxDataFileSize;
  111. NTSTATUS Status;
  112. ULONGLONG Size, BlockSize, PacketsInWindow;
  113. ULONG DesiredAccess;
  114. ULONG FileAttributes, AllocationAttributes;
  115. ULONG ShareAccess;
  116. ULONG CreateDisposition;
  117. ULONG CreateOptions;
  118. ULONG Protection;
  119. SIZE_T ViewSize;
  120. KAPC_STATE ApcState;
  121. BOOLEAN fAttached;
  122. PAGED_CODE();
  123. //
  124. // Make sure we are currently attached to the Application process
  125. //
  126. PgmAttachToProcessForVMAccess (pSend, &ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  127. //
  128. // First build the File name string
  129. //
  130. Status = BuildPgmDataFileName (pSend);
  131. if (!NT_SUCCESS (Status))
  132. {
  133. PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
  134. "BuildPgmDataFileName returned <%x>\n", Status);
  135. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  136. return (Status);
  137. }
  138. //
  139. // Compute the size of the Data file required to hold 2 * Window size
  140. // Also make it a multiple of the MTU and the FECGroupSize (if applicable)
  141. //
  142. PacketsInWindow = pSend->pAssociatedAddress->WindowSizeInBytes / pSend->pAssociatedAddress->OutIfMTU;
  143. PacketsInWindow += PacketsInWindow + pSend->FECGroupSize - 1;
  144. if (PacketsInWindow > SENDER_MAX_WINDOW_SIZE_PACKETS)
  145. {
  146. PacketsInWindow = SENDER_MAX_WINDOW_SIZE_PACKETS;
  147. if (pSend->pAssociatedAddress->WindowSizeInBytes > ((PacketsInWindow >> 1) *
  148. pSend->pAssociatedAddress->OutIfMTU))
  149. {
  150. pSend->pAssociatedAddress->WindowSizeInBytes = (PacketsInWindow >> 1) * pSend->pAssociatedAddress->OutIfMTU;
  151. pSend->pAssociatedAddress->WindowSizeInMSecs = (BITS_PER_BYTE *
  152. pSend->pAssociatedAddress->WindowSizeInBytes) /
  153. pSend->pAssociatedAddress->RateKbitsPerSec;
  154. }
  155. }
  156. BlockSize = pSend->FECGroupSize * pSend->pSender->PacketBufferSize;
  157. Size = PacketsInWindow * pSend->pSender->PacketBufferSize;
  158. Size = (Size / BlockSize) * BlockSize;
  159. pSend->pSender->MaxDataFileSize = Size;
  160. pSend->pSender->MaxPacketsInBuffer = Size / pSend->pSender->PacketBufferSize;
  161. lgMaxDataFileSize.QuadPart = Size;
  162. PgmZeroMemory (&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
  163. InitializeObjectAttributes (&ObjectAttributes,
  164. &pSend->pSender->DataFileName,
  165. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  166. NULL,
  167. NULL);
  168. //
  169. // We need to open the data file. This file contains data
  170. // and will be mapped into memory. Read and Write access
  171. // are requested.
  172. //
  173. DesiredAccess = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  174. FILE_GENERIC_READ | FILE_GENERIC_WRITE;
  175. // Using the FILE_ATTRIBUTE_TEMPORARY flag:
  176. // you let the system know that the file is likely to be short lived.
  177. // The temporary file is created as a normal file. The system needs to do
  178. // a minimal amount of lazy writes to the file system to keep the disk
  179. // structures (directories and so forth) consistent. This gives the
  180. // appearance that the file has been written to the disk. However, unless
  181. // the Memory Manager detects an inadequate supply of free pages and
  182. // starts writing modified pages to the disk, the Cache Manager's Lazy
  183. // Writer may never write the data pages of this file to the disk.
  184. // If the system has enough memory, the pages may remain in memory for
  185. // any arbitrary amount of time. Because temporary files are generally
  186. // short lived, there is a good chance the system will never write the pages to the disk.
  187. FileAttributes = FILE_ATTRIBUTE_TEMPORARY;
  188. ShareAccess = 0; // Gives the caller exclusive access to the open file
  189. CreateDisposition = FILE_CREATE; // If the file already exists, fail the request and do not create or
  190. // open the given file. If it does not, create the given file.
  191. // Delete the file when the last handle to it is is passed to ZwClose.
  192. CreateOptions = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE;
  193. PgmZeroMemory (&IoStatusBlock, sizeof(IO_STATUS_BLOCK));
  194. Status = ZwCreateFile (&pSend->pSender->FileHandle,
  195. DesiredAccess,
  196. &ObjectAttributes,
  197. &IoStatusBlock,
  198. &lgMaxDataFileSize, // AllocationSize
  199. FileAttributes,
  200. ShareAccess,
  201. CreateDisposition,
  202. CreateOptions,
  203. NULL, // EaBuffer
  204. 0); // EaLength
  205. if (!NT_SUCCESS (Status))
  206. {
  207. PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
  208. "ZwCreateFile for <%wZ> returned <%x>\n", &pSend->pSender->DataFileName, Status);
  209. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  210. pSend->pSender->FileHandle = NULL;
  211. return (Status);
  212. }
  213. //
  214. // Now we have a handle to our open test file. We now create a section
  215. // object with this handle.
  216. //
  217. DesiredAccess = STANDARD_RIGHTS_REQUIRED |
  218. SECTION_QUERY |
  219. SECTION_MAP_READ |
  220. SECTION_MAP_WRITE;
  221. Protection = PAGE_READWRITE;
  222. AllocationAttributes = SEC_COMMIT;
  223. PgmZeroMemory (&ObjectAttributes, sizeof (OBJECT_ATTRIBUTES));
  224. InitializeObjectAttributes (&ObjectAttributes,
  225. NULL,
  226. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  227. NULL,
  228. NULL);
  229. Status = ZwCreateSection (&pSend->pSender->SectionHandle,
  230. DesiredAccess,
  231. &ObjectAttributes, // NULL ?
  232. &lgMaxDataFileSize,
  233. Protection,
  234. AllocationAttributes,
  235. pSend->pSender->FileHandle);
  236. if (!NT_SUCCESS (Status))
  237. {
  238. PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
  239. "ZwCreateSection for <%wZ> returned <%x>\n", &pSend->pSender->DataFileName, Status);
  240. ZwClose (pSend->pSender->FileHandle);
  241. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  242. return (Status);
  243. }
  244. //
  245. // Reference the section object, if a view is mapped to the section
  246. // object, the object is not dereferenced as the virtual address
  247. // descriptor contains a pointer to the section object.
  248. //
  249. Status = ObReferenceObjectByHandle (pSend->pSender->SectionHandle,
  250. 0,
  251. 0,
  252. KernelMode,
  253. &pSend->pSender->pSectionObject,
  254. NULL );
  255. if (!NT_SUCCESS (Status))
  256. {
  257. PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
  258. "ObReferenceObjectByHandle for SectionHandle=<%x> returned <%x>\n",
  259. pSend->pSender->SectionHandle, Status);
  260. ZwClose (pSend->pSender->SectionHandle);
  261. ZwClose (pSend->pSender->FileHandle);
  262. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  263. return (Status);
  264. }
  265. //
  266. // Our section object has been created and linked to the file
  267. // object that was previous opened. Now we map a view on
  268. // this section.
  269. //
  270. ViewSize = 0;
  271. Protection = PAGE_READWRITE;
  272. Status = ZwMapViewOfSection (pSend->pSender->SectionHandle,
  273. NtCurrentProcess(),
  274. &pSend->pSender->SendDataBufferMapping,
  275. 0L, // ZeroBits
  276. 0L, // CommitSize (initially committed region)
  277. NULL, // &SectionOffset
  278. &ViewSize,
  279. ViewUnmap, // InheritDisposition: for child processes
  280. 0L, // AllocationType
  281. Protection);
  282. if (!NT_SUCCESS (Status))
  283. {
  284. PgmLog (PGM_LOG_ERROR, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
  285. "ZwMapViewOfSection for <%wZ> returned <%x>\n", &pSend->pSender->DataFileName, Status);
  286. ObDereferenceObject (pSend->pSender->pSectionObject);
  287. pSend->pSender->pSectionObject = NULL;
  288. ZwClose (pSend->pSender->SectionHandle);
  289. pSend->pSender->SectionHandle = NULL;
  290. ZwClose (pSend->pSender->FileHandle);
  291. pSend->pSender->FileHandle = NULL;
  292. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  293. return (Status);
  294. }
  295. PgmLog (PGM_LOG_INFORM_STATUS, DBG_FILEIO, "PgmCreateDataFileAndMapSection",
  296. "Mapped <%wZ> to address<%x>, Filelength=<%d>\n",
  297. &pSend->pSender->DataFileName, pSend->pSender->SendDataBufferMapping, Size);
  298. pSend->pSender->BufferSizeAvailable = pSend->pSender->MaxDataFileSize;
  299. pSend->pSender->LeadingWindowOffset = pSend->pSender->TrailingWindowOffset = 0;
  300. //
  301. // Now, reference the process
  302. //
  303. ObReferenceObject (pSend->Process);
  304. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CREATE_DATA_FILE);
  305. return (STATUS_SUCCESS);
  306. }
  307. //----------------------------------------------------------------------------
  308. NTSTATUS
  309. PgmUnmapAndCloseDataFile(
  310. IN tSEND_SESSION *pSend
  311. )
  312. /*++
  313. Routine Description:
  314. This routine cleansup the file mapping and closes the file
  315. handles. The file should automatically get deleted on closing
  316. the handle since we used the FILE_DELETE_ON_CLOSE option while
  317. creating the file.
  318. Arguments:
  319. IN pSend -- the Send object
  320. Return Value:
  321. NTSTATUS - Final status of the operation (STATUS_SUCCESS)
  322. --*/
  323. {
  324. NTSTATUS Status;
  325. KAPC_STATE ApcState;
  326. BOOLEAN fAttached;
  327. PgmAttachToProcessForVMAccess (pSend, &ApcState, &fAttached, REF_PROCESS_ATTACH_CLOSE_DATA_FILE);
  328. Status = ZwUnmapViewOfSection (NtCurrentProcess(), (PVOID) pSend->pSender->SendDataBufferMapping);
  329. ASSERT (NT_SUCCESS (Status));
  330. Status = ObDereferenceObject (pSend->pSender->pSectionObject);
  331. ASSERT (NT_SUCCESS (Status));
  332. pSend->pSender->pSectionObject = NULL;
  333. Status = ZwClose (pSend->pSender->SectionHandle);
  334. ASSERT (NT_SUCCESS (Status));
  335. pSend->pSender->SectionHandle = NULL;
  336. Status = ZwClose (pSend->pSender->FileHandle);
  337. ASSERT (NT_SUCCESS (Status));
  338. PgmDetachProcess (&ApcState, &fAttached, REF_PROCESS_ATTACH_CLOSE_DATA_FILE);
  339. ObDereferenceObject (pSend->Process); // Since we had referenced it when the file was created
  340. pSend->pSender->SendDataBufferMapping = NULL;
  341. pSend->pSender->pSectionObject = NULL;
  342. pSend->pSender->SectionHandle = NULL;
  343. pSend->pSender->FileHandle = NULL;
  344. PgmLog (PGM_LOG_INFORM_STATUS, DBG_SEND, "PgmUnmapAndCloseDataFile",
  345. "pSend = <%x>\n", pSend);
  346. return (STATUS_SUCCESS);
  347. }