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.

815 lines
16 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. fdio.c
  5. Abstract:
  6. Implementation of PSX file descriptor io.
  7. Author:
  8. Mark Lucovsky (markl) 08-Mar-1989
  9. Revision History:
  10. --*/
  11. #include "psxsrv.h"
  12. //
  13. // This lock must be held while updating handle counts on system open file
  14. // descriptors.
  15. //
  16. RTL_CRITICAL_SECTION SystemOpenFileLock;
  17. //
  18. // This lock must be held while updating reference counts on IONODES, and
  19. // when scanning the IoNodeHashTable searching for an IoNode.
  20. //
  21. RTL_CRITICAL_SECTION IoNodeHashTableLock;
  22. //
  23. // IoNode Id Hash Table.
  24. //
  25. // Given a FileSerialNumber and DeviceSerialNumber, an IONODE can be located in
  26. // the IoNodeHashTable.
  27. //
  28. LIST_ENTRY IoNodeHashTable[IONODEHASHSIZE];
  29. BOOLEAN
  30. ReferenceOrCreateIoNode (
  31. IN dev_t DeviceSerialNumber,
  32. IN ULONG_PTR FileSerialNumber,
  33. IN BOOLEAN FindOnly,
  34. OUT PIONODE *IoNode
  35. )
  36. /*++
  37. Routine Description:
  38. This routine references an existing IoNode, or creates a new IoNode
  39. if one can not be found. It returns with the IoNode's reference count
  40. adjusted, and the IoNodes lock held.
  41. Arguments:
  42. DeviceSerialNumber - Supplies the device serial number of the IoNode.
  43. FileSerialNumber - Supplies the file serial number of the IoNode.
  44. FindOnly - If set, just return pointer to ionode; do not update ref count.
  45. IoNode - Returns the address of either the new or existing IoNode associated
  46. with the specified serial numbers.
  47. Return Value:
  48. TRUE - An existing IoNode was located.
  49. FALSE - A new IoNode was created.
  50. --*/
  51. {
  52. PIONODE ionode;
  53. PLIST_ENTRY head, next;
  54. NTSTATUS st;
  55. head = &IoNodeHashTable[
  56. SERIALNUMBERTOHASHINDEX(DeviceSerialNumber,FileSerialNumber)];
  57. //
  58. // Lock IoNodeHashTable
  59. //
  60. RtlEnterCriticalSection(&IoNodeHashTableLock);
  61. next = head->Flink;
  62. while (next != head) {
  63. ionode = CONTAINING_RECORD(next,IONODE,IoNodeHashLinks);
  64. if ( (ionode->DeviceSerialNumber == DeviceSerialNumber) &&
  65. (ionode->FileSerialNumber == FileSerialNumber) ) {
  66. RtlEnterCriticalSection(&ionode->IoNodeLock);
  67. if (!FindOnly) {
  68. // Increment the IoNode reference count
  69. ionode->ReferenceCount++;
  70. }
  71. RtlLeaveCriticalSection(&IoNodeHashTableLock);
  72. *IoNode = ionode;
  73. return TRUE;
  74. }
  75. next = next->Flink;
  76. }
  77. if (FindOnly) {
  78. RtlLeaveCriticalSection(&IoNodeHashTableLock);
  79. return FALSE;
  80. }
  81. //
  82. // Allocate a new IoNode
  83. //
  84. ionode = RtlAllocateHeap(PsxHeap, 0,sizeof(IONODE));
  85. if (! ionode) {
  86. RtlLeaveCriticalSection(&IoNodeHashTableLock);
  87. *IoNode = NULL;
  88. return FALSE;
  89. }
  90. //
  91. // Initialize the IoNode reference count
  92. // Initialize the IoNodeLock and insert the IoNode into the IoNodeHashTable
  93. // Initialize the device and file serial number fields
  94. // Initialize the list of flocks
  95. //
  96. ionode->ReferenceCount = 1;
  97. st = RtlInitializeCriticalSection(&ionode->IoNodeLock);
  98. ASSERT(NT_SUCCESS(st));
  99. InsertTailList(head, &ionode->IoNodeHashLinks);
  100. ionode->DeviceSerialNumber = DeviceSerialNumber;
  101. ionode->FileSerialNumber = FileSerialNumber;
  102. InitializeListHead(&ionode->Flocks);
  103. InitializeListHead(&ionode->Waiters);
  104. //
  105. // Lock the IoNode and release the IoNodeHashTableLock
  106. //
  107. RtlEnterCriticalSection(&ionode->IoNodeLock);
  108. RtlLeaveCriticalSection(&IoNodeHashTableLock);
  109. InitializeListHead(&ionode->Flocks);
  110. ionode->Junked = FALSE;
  111. *IoNode = ionode;
  112. return FALSE;
  113. }
  114. VOID
  115. DereferenceIoNode (
  116. IN PIONODE IoNode
  117. )
  118. /*++
  119. Routine Description:
  120. This routine dereferences and possibly deallocates the specified IoNode.
  121. Arguments:
  122. IoNode - Supplies the address of the IoNode to be dereferenced.
  123. Return Value:
  124. None.
  125. --*/
  126. {
  127. RtlEnterCriticalSection(&IoNodeHashTableLock);
  128. if (0 == --IoNode->ReferenceCount) {
  129. RemoveEntryList(&IoNode->IoNodeHashLinks);
  130. // Call close routine.
  131. RtlDeleteCriticalSection(&IoNode->IoNodeLock);
  132. if (IoNode->IoVectors->IoNodeCloseRoutine) {
  133. (IoNode->IoVectors->IoNodeCloseRoutine)(IoNode);
  134. }
  135. //
  136. // All flocks should have been freed by now.
  137. //
  138. ASSERT(IsListEmpty(&IoNode->Flocks));
  139. RtlFreeHeap(PsxHeap, 0,IoNode);
  140. }
  141. RtlLeaveCriticalSection(&IoNodeHashTableLock);
  142. }
  143. PFILEDESCRIPTOR
  144. AllocateFd(
  145. IN PPSX_PROCESS p,
  146. IN ULONG Start,
  147. OUT PULONG Index
  148. )
  149. /*++
  150. Routine Description:
  151. This function scans the specified process' open file table searching
  152. for the lowest free slot. Once a free slot is located, its address
  153. is returned. If no free slot is found, NULL is returned.
  154. Arguments:
  155. p - Supplies a pointer to the process whose open file table is to be
  156. scanned.
  157. Start - The file table is scanned starting from descriptor 'Start':
  158. Zero for the beginning of the table, and so forth.
  159. Index - If a file descriptor is located, this parameter returns the
  160. index of the allocated file descriptor.
  161. Return Value:
  162. NULL - No free file descriptor was located.
  163. NON-NULL - The address of the lowest free file descriptor greater than
  164. or equal to 'Start' is returned.
  165. --*/
  166. {
  167. ULONG i;
  168. PFILEDESCRIPTOR fd;
  169. fd = &p->ProcessFileTable[Start];
  170. for (i = Start; i < OPEN_MAX; i++, fd++) {
  171. //
  172. // XXX.mjb: CLIENT_OPEN: would also have to make sure not to
  173. // allocate an FD here that was obtained via clientopen.
  174. //
  175. if (NULL == fd->SystemOpenFileDesc) {
  176. *Index = i;
  177. fd->Flags = 0;
  178. return fd;
  179. }
  180. }
  181. return NULL;
  182. }
  183. BOOLEAN
  184. DeallocateFd(
  185. IN PPSX_PROCESS p,
  186. IN ULONG Index
  187. )
  188. /*++
  189. Routine Description:
  190. This function deallocates the file descriptor from the specified
  191. process' open file table. If the file is not allocated, then an
  192. error is returned.
  193. If the file descriptor was allocated, then the system open file that
  194. it refers to is dereferenced. This could cause the system open
  195. file, and possibly the associated IoNode, to be deallocated.
  196. Arguments:
  197. p - Supplies a pointer to the process whose open file table is being
  198. scanned.
  199. Index - Supplies the index of the file descriptor to be deallocated.
  200. Return Value:
  201. TRUE - The file descriptor was successfully deallocated.
  202. FALSE - The file descriptor did not refer to an allocated file descriptor.
  203. --*/
  204. {
  205. PFILEDESCRIPTOR Fd;
  206. PSYSTEMOPENFILE SystemOpenFile;
  207. Fd = &p->ProcessFileTable[Index];
  208. SystemOpenFile = Fd->SystemOpenFileDesc;
  209. if (NULL == SystemOpenFile) {
  210. return FALSE;
  211. }
  212. IoClose(p,Fd);
  213. Fd->SystemOpenFileDesc = (PSYSTEMOPENFILE)NULL;
  214. RtlEnterCriticalSection(&SystemOpenFileLock);
  215. if (--SystemOpenFile->HandleCount == 0) {
  216. DeallocateSystemOpenFile(p, SystemOpenFile);
  217. }
  218. RtlLeaveCriticalSection(&SystemOpenFileLock);
  219. return TRUE;
  220. }
  221. PFILEDESCRIPTOR
  222. FdIndexToFd(
  223. IN PPSX_PROCESS p,
  224. IN ULONG Index
  225. )
  226. /*++
  227. Routine Description:
  228. This function translates a file descriptor index into
  229. a pointer to a file descriptor.
  230. Arguments:
  231. p - Supplies the process whose file descriptor table is to be used
  232. Index - Supplies the file descriptor index to translate
  233. Return Value:
  234. NULL - the file descriptor index is not in range, or specifies a
  235. file descriptor that is not open.
  236. NON-NULL - Returns the address of the file descriptor associated with the
  237. index.
  238. --*/
  239. {
  240. PFILEDESCRIPTOR Fd;
  241. if ( !ISFILEDESINRANGE(Index) ) {
  242. return NULL;
  243. }
  244. Fd = &p->ProcessFileTable[Index];
  245. if ( !Fd->SystemOpenFileDesc ) {
  246. return NULL;
  247. }
  248. return Fd;
  249. }
  250. PSYSTEMOPENFILE
  251. AllocateSystemOpenFile(
  252. VOID
  253. )
  254. /*++
  255. Routine Description:
  256. This function allocates and references a system open file.
  257. Arguments:
  258. None.
  259. Return Value:
  260. NON-NULL - Returns the address of a system open file.
  261. --*/
  262. {
  263. PSYSTEMOPENFILE SystemOpenFile;
  264. //
  265. // Grab system open file lock
  266. //
  267. RtlEnterCriticalSection(&SystemOpenFileLock);
  268. SystemOpenFile = RtlAllocateHeap(PsxHeap, 0, sizeof(SYSTEMOPENFILE));
  269. if (NULL == SystemOpenFile) {
  270. RtlLeaveCriticalSection(&SystemOpenFileLock);
  271. return NULL;
  272. }
  273. SystemOpenFile->HandleCount = 1;
  274. SystemOpenFile->ReadHandleCount = 0;
  275. SystemOpenFile->WriteHandleCount = 0;
  276. SystemOpenFile->Flags = 0;
  277. //
  278. // Release system open file lock
  279. //
  280. RtlLeaveCriticalSection(&SystemOpenFileLock);
  281. return SystemOpenFile;
  282. }
  283. VOID
  284. DeallocateSystemOpenFile(
  285. IN PPSX_PROCESS p,
  286. IN PSYSTEMOPENFILE SystemOpenFile
  287. )
  288. /*++
  289. Routine Description:
  290. This function deallocates a system open file. If may cause the deallocation
  291. of the open file's associated IoNode.
  292. This function is called with the system open file lock held.
  293. Arguments:
  294. SystemOpenFile - Supplies the address of the system open file to deallocate.
  295. Return Value:
  296. None.
  297. --*/
  298. {
  299. PIONODE IoNode;
  300. IoNode = SystemOpenFile->IoNode;
  301. IoLastClose(p, SystemOpenFile);
  302. RtlFreeHeap(PsxHeap, 0,SystemOpenFile);
  303. DereferenceIoNode(IoNode);
  304. }
  305. VOID
  306. ForkProcessFileTable(
  307. IN PPSX_PROCESS ForkProcess,
  308. IN PPSX_PROCESS NewProcess
  309. )
  310. /*++
  311. Routine Description:
  312. This function forks the open file table of the calling process. It does
  313. this by copying each file descriptor in the fork process' table to a
  314. descriptor in the new process' table. For each descriptor that is opened
  315. (references a system open file descriptor), the reference count is
  316. incremented.
  317. Arguments:
  318. ForkProcess - Supplies a pointer to the process that is the parent in the
  319. fork operation.
  320. NewProcess - Supplies a pointer to the process that is the new process in
  321. the fork operation.
  322. Return Value:
  323. None.
  324. --*/
  325. {
  326. LONG i;
  327. PFILEDESCRIPTOR ForkFd, NewFd;
  328. ForkFd = ForkProcess->ProcessFileTable;
  329. NewFd = NewProcess->ProcessFileTable;
  330. //
  331. // Grab system open file lock
  332. //
  333. RtlEnterCriticalSection(&SystemOpenFileLock);
  334. for (i = 0; i < OPEN_MAX; i++, NewFd++, ForkFd++) {
  335. //
  336. // Copy the file descriptor, then up the reference
  337. // to the associated system open file descriptor
  338. //
  339. *NewFd = *ForkFd;
  340. if (NULL != ForkFd->SystemOpenFileDesc
  341. && (PSYSTEMOPENFILE)1 != ForkFd->SystemOpenFileDesc) {
  342. ForkFd->SystemOpenFileDesc->HandleCount++;
  343. IoNewHandle(NewProcess, NewFd);
  344. }
  345. }
  346. //
  347. // Release system open file lock
  348. //
  349. RtlLeaveCriticalSection(&SystemOpenFileLock);
  350. }
  351. VOID
  352. ExecProcessFileTable(
  353. IN PPSX_PROCESS p
  354. )
  355. /*++
  356. Routine Description:
  357. This function execs the open file table of the calling process.
  358. It does this by closing each file descriptor whose close on
  359. exec flag is set.
  360. Arguments:
  361. p - Supplies the process that is doing an exec.
  362. Return Value:
  363. None.
  364. --*/
  365. {
  366. LONG i;
  367. PFILEDESCRIPTOR Fd;
  368. Fd = p->ProcessFileTable;
  369. RtlEnterCriticalSection(&SystemOpenFileLock);
  370. for (i = 0; i < OPEN_MAX; i++, Fd++) {
  371. if (NULL != Fd->SystemOpenFileDesc &&
  372. Fd->Flags & PSX_FD_CLOSE_ON_EXEC) {
  373. IoClose(p,Fd);
  374. if (--(Fd->SystemOpenFileDesc->HandleCount) == 0) {
  375. DeallocateSystemOpenFile(p,
  376. Fd->SystemOpenFileDesc);
  377. }
  378. }
  379. }
  380. RtlLeaveCriticalSection(&SystemOpenFileLock);
  381. }
  382. VOID
  383. CloseProcessFileTable(
  384. IN PPSX_PROCESS p
  385. )
  386. /*++
  387. Routine Description:
  388. This function is called during process termination to close
  389. all open filehandles held by the process.
  390. Arguments:
  391. p - Supplies the address of the process whose open file table is
  392. being closed.
  393. Return Value:
  394. None.
  395. --*/
  396. {
  397. LONG i;
  398. PFILEDESCRIPTOR Fd;
  399. Fd = p->ProcessFileTable;
  400. // Grab system open file lock
  401. RtlEnterCriticalSection(&SystemOpenFileLock);
  402. for (i = 0; i < OPEN_MAX; i++, Fd++) {
  403. if (NULL != Fd->SystemOpenFileDesc) {
  404. (void)DeallocateFd(p, i);
  405. }
  406. }
  407. // Release system open file lock
  408. RtlLeaveCriticalSection(&SystemOpenFileLock);
  409. }
  410. BOOLEAN
  411. IoOpenNewHandle (
  412. IN PPSX_PROCESS p,
  413. IN PFILEDESCRIPTOR Fd,
  414. IN PPSX_API_MSG m
  415. )
  416. /*++
  417. Routine Description:
  418. This function is called after a new handle has been created and
  419. initialized. Its function is to adjust the read/write handle counts
  420. and then call the type specific open new handle routine.
  421. This function is only called from open.
  422. Arguments:
  423. p - Supplies the process creating a new handle
  424. Fd - Supplies the address of the initialized file descriptor
  425. m - Supplies the open message
  426. Return Value:
  427. TRUE - A reply to the open message should be generated.
  428. FALSE - No reply should be generated.
  429. --*/
  430. {
  431. RtlEnterCriticalSection(&SystemOpenFileLock);
  432. if (Fd->SystemOpenFileDesc->Flags & PSX_FD_READ) {
  433. Fd->SystemOpenFileDesc->ReadHandleCount++;
  434. }
  435. if (Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) {
  436. Fd->SystemOpenFileDesc->WriteHandleCount++;
  437. }
  438. RtlLeaveCriticalSection(&SystemOpenFileLock);
  439. if (Fd->SystemOpenFileDesc->IoNode->IoVectors->OpenNewHandleRoutine) {
  440. return (Fd->SystemOpenFileDesc->IoNode->IoVectors->OpenNewHandleRoutine)(p,Fd,m);
  441. }
  442. return TRUE;
  443. }
  444. VOID
  445. IoNewHandle (
  446. IN PPSX_PROCESS p,
  447. IN PFILEDESCRIPTOR Fd
  448. )
  449. /*++
  450. Routine Description:
  451. This function is called after a new handle has been created and
  452. initialized. Its function is to adjust the read/write handle counts
  453. and then call the type specific new handle routine.
  454. This function is not called in response to an open. Only handles
  455. created through pipe, dup, or fork get called in this way. Open
  456. is different because it might need to block so it
  457. can implement an open protocol (named pipe opens...);
  458. Arguments:
  459. p - Supplies the process creating a new handle
  460. Fd - Supplies the address of the initialized file descriptor
  461. Return Value:
  462. None.
  463. --*/
  464. {
  465. RtlEnterCriticalSection(&SystemOpenFileLock);
  466. if (Fd->SystemOpenFileDesc->Flags & PSX_FD_READ) {
  467. Fd->SystemOpenFileDesc->ReadHandleCount++;
  468. }
  469. if (Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) {
  470. Fd->SystemOpenFileDesc->WriteHandleCount++;
  471. }
  472. RtlLeaveCriticalSection(&SystemOpenFileLock);
  473. if (Fd->SystemOpenFileDesc->IoNode->IoVectors->NewHandleRoutine) {
  474. (Fd->SystemOpenFileDesc->IoNode->IoVectors->NewHandleRoutine)(p,Fd);
  475. }
  476. }
  477. VOID
  478. IoClose(
  479. IN PPSX_PROCESS p,
  480. IN PFILEDESCRIPTOR Fd
  481. )
  482. /*++
  483. Routine Description:
  484. This function is called whenever a handle is deleted.
  485. Its function is to adjust the read/write handle counts
  486. and then call the type specific close routine.
  487. Arguments:
  488. p - Supplies the process closing a handle
  489. Fd - Supplies the address of the initialized file descriptor
  490. Return Value:
  491. None.
  492. --*/
  493. {
  494. RtlEnterCriticalSection(&SystemOpenFileLock);
  495. if (Fd->SystemOpenFileDesc->Flags & PSX_FD_READ) {
  496. Fd->SystemOpenFileDesc->ReadHandleCount--;
  497. }
  498. if (Fd->SystemOpenFileDesc->Flags & PSX_FD_WRITE) {
  499. Fd->SystemOpenFileDesc->WriteHandleCount--;
  500. }
  501. RtlLeaveCriticalSection(&SystemOpenFileLock);
  502. ReleaseFlocksByPid(Fd->SystemOpenFileDesc->IoNode, p->Pid);
  503. if (Fd->SystemOpenFileDesc->IoNode->IoVectors->CloseRoutine) {
  504. (Fd->SystemOpenFileDesc->IoNode->IoVectors->CloseRoutine)(p,Fd);
  505. }
  506. }
  507. VOID
  508. IoLastClose (
  509. IN PPSX_PROCESS p,
  510. IN PSYSTEMOPENFILE SystemOpenFile
  511. )
  512. /*++
  513. Routine Description:
  514. This function is called whenever the last handle is deleted.
  515. Its function is to call the type specific close routine.
  516. Arguments:
  517. p - Supplies the process closing a handle
  518. Fd - Supplies the address of the initialized file descriptor
  519. Return Value:
  520. None.
  521. --*/
  522. {
  523. if (SystemOpenFile->IoNode->IoVectors->LastCloseRoutine) {
  524. (SystemOpenFile->IoNode->IoVectors->LastCloseRoutine)
  525. (p, SystemOpenFile);
  526. }
  527. }