Leaked source code of windows server 2003
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.

813 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. info.c
  6. Abstract:
  7. Handles marshalling support for notifications.
  8. Author:
  9. Environment:
  10. User Mode -Win32
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #include <ntfytab.h>
  16. #include <stddef.h>
  17. #define PRINTER_STRINGS
  18. #include <data.h>
  19. #define DEFINE(field, attrib, table, x, y) { attrib, table },
  20. NOTIFY_ATTRIB_TABLE NotifyAttribPrinter[] = {
  21. #include "ntfyprn.h"
  22. };
  23. NOTIFY_ATTRIB_TABLE NotifyAttribJob[] = {
  24. #include "ntfyjob.h"
  25. };
  26. #undef DEFINE
  27. PNOTIFY_ATTRIB_TABLE pNotifyAttribTable[] = {
  28. NotifyAttribPrinter,
  29. NotifyAttribJob
  30. };
  31. DWORD adwNotifyAttribMax[] = {
  32. COUNTOF(NotifyAttribPrinter),
  33. COUNTOF(NotifyAttribJob)
  34. };
  35. DWORD adwNotifyDatatypes[] = NOTIFY_DATATYPES;
  36. extern DWORD cDefaultPrinterNotifyInfoData;
  37. //
  38. // Forward prototypes.
  39. //
  40. PPRINTER_NOTIFY_INFO
  41. RouterAllocPrinterNotifyInfo(
  42. DWORD cPrinterNotifyInfoData)
  43. {
  44. PPRINTER_NOTIFY_INFO pPrinterNotifyInfo = NULL;
  45. if (!cPrinterNotifyInfoData)
  46. cPrinterNotifyInfoData = cDefaultPrinterNotifyInfoData;
  47. pPrinterNotifyInfo = MIDL_user_allocate(
  48. sizeof(PRINTER_NOTIFY_INFO) -
  49. sizeof(PRINTER_NOTIFY_INFO_DATA) +
  50. (cPrinterNotifyInfoData * sizeof(PRINTER_NOTIFY_INFO_DATA)));
  51. //
  52. // Must initialize version/count.
  53. //
  54. if (pPrinterNotifyInfo != NULL) {
  55. pPrinterNotifyInfo->Version = NOTIFICATION_VERSION;
  56. pPrinterNotifyInfo->Count = 0;
  57. if (pPrinterNotifyInfo) {
  58. ClearPrinterNotifyInfo(pPrinterNotifyInfo, NULL);
  59. }
  60. }
  61. return pPrinterNotifyInfo;
  62. }
  63. VOID
  64. SetupPrinterNotifyInfo(
  65. PPRINTER_NOTIFY_INFO pInfo,
  66. PCHANGE pChange)
  67. {
  68. //
  69. // Set the color flag.
  70. //
  71. pInfo->Flags |= PRINTER_NOTIFY_INFO_COLORSET;
  72. //
  73. // We should set the discard bit if there was a previous overflow
  74. // and we didn't or couldn't allocate a pInfo structure.
  75. // Do it now.
  76. //
  77. if (pChange && pChange->eStatus & STATUS_CHANGE_DISCARDED) {
  78. pInfo->Flags |= PRINTER_NOTIFY_INFO_DISCARDED;
  79. }
  80. }
  81. BOOL
  82. FreePrinterNotifyInfoData(
  83. PPRINTER_NOTIFY_INFO pInfo)
  84. {
  85. DWORD i;
  86. PPRINTER_NOTIFY_INFO_DATA pData;
  87. for(pData = pInfo->aData, i=pInfo->Count;
  88. i;
  89. pData++, i--) {
  90. if ((TABLE)pData->Reserved != TABLE_DWORD) {
  91. MIDL_user_free(pData->NotifyData.Data.pBuf);
  92. }
  93. }
  94. return TRUE;
  95. }
  96. BOOL
  97. RouterFreePrinterNotifyInfo(
  98. PPRINTER_NOTIFY_INFO pInfo)
  99. {
  100. if (!pInfo) {
  101. DBGMSG(DBG_WARNING, ("RFreePrinterNotifyInfo called with NULL!\n"));
  102. return FALSE;
  103. }
  104. FreePrinterNotifyInfoData(pInfo);
  105. MIDL_user_free(pInfo);
  106. return TRUE;
  107. }
  108. VOID
  109. ClearPrinterNotifyInfo(
  110. PPRINTER_NOTIFY_INFO pInfo,
  111. PCHANGE pChange)
  112. /*++
  113. Routine Description:
  114. Clears the PRINTER_NOTIFY structure for more notifications.
  115. Arguments:
  116. pInfo - Info to clear ( pInfo->aData must be valid if pInfo->Count != 0 )
  117. pChange - Associated pChange structure.
  118. Return Value:
  119. --*/
  120. {
  121. if (!pInfo)
  122. return;
  123. FreePrinterNotifyInfoData(pInfo);
  124. pInfo->Flags = 0;
  125. pInfo->Count = 0;
  126. if (pChange)
  127. SetupPrinterNotifyInfo(pInfo, pChange);
  128. }
  129. VOID
  130. SetDiscardPrinterNotifyInfo(
  131. PPRINTER_NOTIFY_INFO pInfo,
  132. PCHANGE pChange)
  133. {
  134. if (pInfo) {
  135. FreePrinterNotifyInfoData(pInfo);
  136. pInfo->Count = 0;
  137. pInfo->Flags |= PRINTER_NOTIFY_INFO_DISCARDED;
  138. }
  139. if (pChange)
  140. pChange->eStatus |= STATUS_CHANGE_DISCARDED;
  141. }
  142. DWORD
  143. AppendPrinterNotifyInfo(
  144. PPRINTHANDLE pPrintHandle,
  145. DWORD dwColor,
  146. PPRINTER_NOTIFY_INFO pInfoSrc)
  147. /*++
  148. Routine Description:
  149. Appends pInfoSrc to the pPrintHandle. We may get Src with zero
  150. notifications. This occurs when when the user requests a refresh
  151. and the client spooler synchronously replies back to clear out
  152. everything.
  153. Arguments:
  154. pPrintHandle -- handle to update
  155. pInfoSrc -- Source of info. NULL = no info.
  156. Return Value:
  157. Result of action.
  158. --*/
  159. {
  160. PPRINTER_NOTIFY_INFO pInfoDest;
  161. PCHANGE pChange;
  162. PPRINTER_NOTIFY_INFO_DATA pDataSrc;
  163. DWORD i;
  164. pChange = pPrintHandle->pChange;
  165. pInfoDest = pChange->ChangeInfo.pPrinterNotifyInfo;
  166. //
  167. // May be NULL if RPCing and the buffer is being used.
  168. // The worker thread will free the data.
  169. //
  170. if (!pInfoDest) {
  171. pInfoDest = RouterAllocPrinterNotifyInfo(0);
  172. if (!pInfoDest) {
  173. DBGMSG(DBG_WARNING,
  174. ("AppendPrinterNotifyInfo: Alloc fail, Can't set DISCARD\n"));
  175. goto Discard;
  176. }
  177. SetupPrinterNotifyInfo(pInfoDest, pChange);
  178. pChange->ChangeInfo.pPrinterNotifyInfo = pInfoDest;
  179. }
  180. if (!pInfoSrc) {
  181. return 0;
  182. }
  183. //
  184. // We must handle the case where the user requests and receives
  185. // a refresh, but the there was an outstanding RPC that is just
  186. // now being processed. In this case, we must drop this
  187. // notification. We determine this by maintaining a color value.
  188. //
  189. // Note that we can't return the DISCARDNOTED flag, since this can't
  190. // trigger an overflow.
  191. //
  192. // If (Color is set) AND (NOT color same) fail.
  193. //
  194. if (pInfoSrc->Flags & PRINTER_NOTIFY_INFO_COLORSET) {
  195. if (dwColor != pChange->dwColor) {
  196. DBGMSG(DBG_WARNING, ("AppendPrinterNotifyInfo: Color mismatch info %d != %d; discard\n",
  197. dwColor, pChange->dwColor));
  198. //
  199. // Clear it out, and we're done.
  200. //
  201. ClearPrinterNotifyInfo(pInfoDest,
  202. pChange);
  203. return PRINTER_NOTIFY_INFO_COLORMISMATCH;
  204. }
  205. }
  206. //
  207. // OR in the flags.
  208. //
  209. pInfoDest->Flags |= pInfoSrc->Flags;
  210. //
  211. // Check for overflow.
  212. //
  213. if (pInfoSrc->Count + pInfoDest->Count < cDefaultPrinterNotifyInfoData) {
  214. //
  215. // Now copy everything over.
  216. //
  217. for (pDataSrc = pInfoSrc->aData, i = pInfoSrc->Count;
  218. i;
  219. i--, pDataSrc++) {
  220. AppendPrinterNotifyInfoData(
  221. pInfoDest,
  222. pDataSrc,
  223. PRINTER_NOTIFY_INFO_DATA_COMPACT);
  224. }
  225. } else {
  226. Discard:
  227. SetDiscardPrinterNotifyInfo(pInfoDest, pChange);
  228. return PRINTER_NOTIFY_INFO_DISCARDED |
  229. PRINTER_NOTIFY_INFO_DISCARDNOTED;
  230. }
  231. return 0;
  232. }
  233. BOOL
  234. AppendPrinterNotifyInfoData(
  235. PPRINTER_NOTIFY_INFO pInfoDest,
  236. PPRINTER_NOTIFY_INFO_DATA pDataSrc,
  237. DWORD fdwFlags)
  238. /*++
  239. Routine Description:
  240. Append the data to the pInfoDest. If pDataSrc is NULL, set discard.
  241. Arguments:
  242. Return Value:
  243. --*/
  244. {
  245. PPRINTER_NOTIFY_INFO_DATA pDataDest;
  246. DWORD i;
  247. BOOL bCompact = FALSE;
  248. DWORD Count;
  249. PPRINTER_NOTIFY_INFO_DATA pDataNew;
  250. BOOL bNewSlot = TRUE;
  251. DWORD Type;
  252. DWORD Field;
  253. DWORD Table;
  254. DWORD Id;
  255. EnterRouterSem();
  256. if (!pDataSrc || (pInfoDest->Flags & PRINTER_NOTIFY_INFO_DISCARDED)) {
  257. SetLastError(ERROR_OUT_OF_STRUCTURES);
  258. goto DoDiscard;
  259. }
  260. Type = pDataSrc->Type;
  261. Field = pDataSrc->Field;
  262. Table = pDataSrc->Reserved;
  263. Id = pDataSrc->Id;
  264. //
  265. // Validate this is a correct type.
  266. //
  267. if (Type < NOTIFY_TYPE_MAX && Field < adwNotifyAttribMax[Type]) {
  268. //
  269. // If Table == 0, then the caller did not specify the type,
  270. // so we fill it in as appropriate.
  271. //
  272. // If it is non-zero and it's doesn't match our value, then
  273. // return an error.
  274. //
  275. if (Table != pNotifyAttribTable[Type][Field].Table) {
  276. if (Table) {
  277. //
  278. // The specified table type does not match our table
  279. // type. Punt, since we can't marshall.
  280. //
  281. DBGMSG(DBG_WARNING, ("Table = %d, != Type %d /Field %d!\n",
  282. Table, Field, Type));
  283. SetLastError(ERROR_INVALID_PARAMETER);
  284. goto DoDiscard;
  285. }
  286. //
  287. // Fix up the Table entry.
  288. //
  289. Table = pNotifyAttribTable[Type][Field].Table;
  290. pDataSrc->Reserved = (TABLE)Table;
  291. }
  292. bCompact = (fdwFlags & PRINTER_NOTIFY_INFO_DATA_COMPACT) &&
  293. (pNotifyAttribTable[Type][Field].Attrib &
  294. TABLE_ATTRIB_COMPACT);
  295. } else {
  296. //
  297. // This is not an error case, since we can still marshall fields
  298. // we don't know about as long as the Table is valid.
  299. //
  300. DBGMSG(DBG_WARNING, ("Unknown: Type= %d Field= %d!\n", Type, Field));
  301. }
  302. if (!Table || Table >= COUNTOF(adwNotifyDatatypes)) {
  303. DBGMSG(DBG_WARNING, ("Table %d unknown; can't marshall!\n",
  304. Table));
  305. SetLastError(ERROR_INVALID_PARAMETER);
  306. goto DoDiscard;
  307. }
  308. SPLASSERT(Table);
  309. //
  310. // Check if compactable.
  311. //
  312. if (bCompact) {
  313. //
  314. // We can compact, see if there is a match.
  315. //
  316. for (pDataDest = pInfoDest->aData, i = pInfoDest->Count;
  317. i;
  318. pDataDest++, i--) {
  319. if (Type == pDataDest->Type &&
  320. Field == pDataDest->Field &&
  321. Id == pDataDest->Id) {
  322. if (Table == TABLE_DWORD) {
  323. pDataDest->NotifyData.adwData[0] =
  324. pDataSrc->NotifyData.adwData[0];
  325. pDataDest->NotifyData.adwData[1] =
  326. pDataSrc->NotifyData.adwData[1];
  327. goto Done;
  328. }
  329. //
  330. // Must copy the data, so free the old one.
  331. //
  332. MIDL_user_free(pDataDest->NotifyData.Data.pBuf);
  333. bNewSlot = FALSE;
  334. break;
  335. }
  336. }
  337. //
  338. // pDataDest now points to the correct slot (either end or
  339. // somewhere in the middle if we are compacting.
  340. //
  341. } else {
  342. //
  343. // Slot defaults to the end.
  344. //
  345. pDataDest = &pInfoDest->aData[pInfoDest->Count];
  346. }
  347. //
  348. // Copy structure first
  349. //
  350. *pDataDest = *pDataSrc;
  351. //
  352. // The data may be either a pointer or the actual DWORD data.
  353. //
  354. if (adwNotifyDatatypes[Table] & TABLE_ATTRIB_DATA_PTR) {
  355. DWORD cbData = pDataSrc->NotifyData.Data.cbBuf;
  356. //
  357. // Now copy everything over.
  358. //
  359. pDataNew = (PPRINTER_NOTIFY_INFO_DATA)MIDL_user_allocate(cbData);
  360. if (!pDataNew) {
  361. pDataDest->NotifyData.Data.pBuf = NULL;
  362. DBGMSG( DBG_WARNING, ("Alloc %d bytes failed with %d\n",
  363. GetLastError()));
  364. goto DoDiscard;
  365. }
  366. CopyMemory(pDataNew, pDataSrc->NotifyData.Data.pBuf, cbData);
  367. pDataDest->NotifyData.Data.cbBuf = cbData;
  368. pDataDest->NotifyData.Data.pBuf = pDataNew;
  369. }
  370. //
  371. // Increment if necessary.
  372. //
  373. if (bNewSlot)
  374. pInfoDest->Count++;
  375. Done:
  376. LeaveRouterSem();
  377. return TRUE;
  378. DoDiscard:
  379. SetDiscardPrinterNotifyInfo(pInfoDest, NULL);
  380. LeaveRouterSem();
  381. return FALSE;
  382. }
  383. BOOL
  384. RouterRefreshPrinterChangeNotification(
  385. HANDLE hPrinter,
  386. DWORD dwColor,
  387. PVOID pPrinterNotifyRefresh,
  388. PPRINTER_NOTIFY_INFO* ppInfo)
  389. /*++
  390. Routine Description:
  391. Implements the refresh portion of FindNextPrinterChangeNotification.
  392. Arguments:
  393. Return Value:
  394. --*/
  395. {
  396. PPRINTHANDLE pPrintHandle = (PPRINTHANDLE)hPrinter;
  397. BOOL bReturn;
  398. EnterRouterSem();
  399. if (!pPrintHandle ||
  400. pPrintHandle->signature != PRINTHANDLE_SIGNATURE ||
  401. !pPrintHandle->pChange ||
  402. !(pPrintHandle->pChange->eStatus & (STATUS_CHANGE_VALID |
  403. STATUS_CHANGE_INFO))) {
  404. SetLastError(ERROR_INVALID_HANDLE);
  405. goto Fail;
  406. }
  407. if (!pPrintHandle->pProvidor->PrintProvidor.fpRefreshPrinterChangeNotification) {
  408. SetLastError(RPC_S_PROCNUM_OUT_OF_RANGE);
  409. goto Fail;
  410. }
  411. pPrintHandle->pChange->dwColor = dwColor;
  412. //
  413. // Allow notifications to begin again.
  414. //
  415. pPrintHandle->pChange->eStatus &= ~(STATUS_CHANGE_DISCARDED |
  416. STATUS_CHANGE_DISCARDNOTED);
  417. ClearPrinterNotifyInfo(pPrintHandle->pChange->ChangeInfo.pPrinterNotifyInfo,
  418. pPrintHandle->pChange);
  419. LeaveRouterSem();
  420. bReturn = (*pPrintHandle->pProvidor->PrintProvidor.fpRefreshPrinterChangeNotification)(
  421. pPrintHandle->hPrinter,
  422. pPrintHandle->pChange->dwColor,
  423. pPrinterNotifyRefresh,
  424. ppInfo);
  425. //
  426. // On failure, set discard.
  427. //
  428. if (!bReturn) {
  429. EnterRouterSem();
  430. //
  431. // The handle should be valid since RPC guarentees that context
  432. // handle access is serialized. However, a misbehaved
  433. // multithreaded spooler component could cause this to happen.
  434. //
  435. SPLASSERT(pPrintHandle->signature == PRINTHANDLE_SIGNATURE);
  436. if (pPrintHandle->pChange) {
  437. //
  438. // Disallow notifications since the refresh failed.
  439. //
  440. pPrintHandle->pChange->eStatus |= STATUS_CHANGE_DISCARDED;
  441. }
  442. LeaveRouterSem();
  443. }
  444. return bReturn;
  445. Fail:
  446. LeaveRouterSem();
  447. return FALSE;
  448. }
  449. BOOL
  450. NotifyNeeded(
  451. PCHANGE pChange)
  452. {
  453. register PPRINTER_NOTIFY_INFO pInfo;
  454. pInfo = pChange->ChangeInfo.pPrinterNotifyInfo;
  455. if (pChange->eStatus & STATUS_CHANGE_DISCARDNOTED) {
  456. return FALSE;
  457. }
  458. if (pChange->fdwChangeFlags || pChange->eStatus & STATUS_CHANGE_DISCARDED) {
  459. return TRUE;
  460. }
  461. if (!pInfo) {
  462. return FALSE;
  463. }
  464. if (pInfo->Flags & PRINTER_NOTIFY_INFO_DISCARDED || pInfo->Count) {
  465. return TRUE;
  466. }
  467. return FALSE;
  468. }
  469. /*------------------------------------------------------------------------
  470. Entry points for providors.
  471. ------------------------------------------------------------------------*/
  472. BOOL
  473. ReplyPrinterChangeNotification(
  474. HANDLE hPrinter,
  475. DWORD fdwChangeFlags,
  476. PDWORD pdwResult,
  477. PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
  478. )
  479. /*++
  480. Routine Description:
  481. Updates a notification with an entire pPrinterNotifyInfo packet.
  482. Providers can call PartialRPCN several times with small packets (the
  483. router won't send them until ReplyPrinterChangeNotification is sent).
  484. This allows batching and guarentees atmoic notifications.
  485. Arguments:
  486. hPrinter - Handle that is being watched.
  487. fdwChangeFlags - Flags that changed (WPC type flags for compatibility)
  488. pdwResult - Result of changes (OPTIONAL). Indicates whether changes
  489. were discarded, and if the discard was noted.
  490. pPrinterNotifyInfo - Information about change.
  491. Return Value:
  492. TRUE - success
  493. FALSE - failure, call GetLastError().
  494. --*/
  495. {
  496. return ReplyPrinterChangeNotificationWorker(
  497. hPrinter,
  498. 0,
  499. fdwChangeFlags,
  500. pdwResult,
  501. pPrinterNotifyInfo);
  502. }
  503. BOOL
  504. PartialReplyPrinterChangeNotification(
  505. HANDLE hPrinter,
  506. PPRINTER_NOTIFY_INFO_DATA pDataSrc
  507. )
  508. /*++
  509. Routine Description:
  510. Updates the notify info without triggering a notification. This is
  511. used to send multiple infos without rpcing on each one. Do a
  512. ReplyPrinterChangeNotificiation at the end.
  513. Arguments:
  514. hPrinter -- Printer handle that changed.
  515. pDataSrc -- Partial data to store. If NULL, indicates a discard
  516. should be stored, causing the client to refresh.
  517. Return Value:
  518. --*/
  519. {
  520. LPPRINTHANDLE pPrintHandle = (LPPRINTHANDLE)hPrinter;
  521. BOOL bReturn = FALSE;
  522. PPRINTER_NOTIFY_INFO* ppInfoDest;
  523. EnterRouterSem();
  524. if (!pPrintHandle ||
  525. pPrintHandle->signature != PRINTHANDLE_SIGNATURE ||
  526. !pPrintHandle->pChange) {
  527. DBGMSG(DBG_WARNING, ("PartialRPCN: Invalid handle 0x%x!\n",
  528. hPrinter));
  529. SetLastError(ERROR_INVALID_HANDLE);
  530. goto Fail;
  531. }
  532. if (!(pPrintHandle->pChange->eStatus &
  533. (STATUS_CHANGE_VALID|STATUS_CHANGE_INFO))) {
  534. DBGMSG(DBG_WARNING, ("PartialRPCN: Invalid handle 0x%x state = 0x%x!\n",
  535. hPrinter,
  536. pPrintHandle->pChange->eStatus));
  537. SetLastError(ERROR_INVALID_HANDLE);
  538. goto Fail;
  539. }
  540. ppInfoDest = &pPrintHandle->pChange->ChangeInfo.pPrinterNotifyInfo;
  541. if (!pDataSrc) {
  542. bReturn = TRUE;
  543. goto Discard;
  544. }
  545. //
  546. // May be NULL if RPCing and the buffer is being used.
  547. // The worker thread will free the data.
  548. //
  549. if (!*ppInfoDest) {
  550. *ppInfoDest = RouterAllocPrinterNotifyInfo(0);
  551. if (!*ppInfoDest) {
  552. DBGMSG(DBG_WARNING,
  553. ("PartialReplyPCN: Alloc failed, discarding\n"));
  554. //
  555. // We should set the discard flag here, but we can't,
  556. // so punt.
  557. //
  558. goto Discard;
  559. }
  560. SetupPrinterNotifyInfo(*ppInfoDest, pPrintHandle->pChange);
  561. }
  562. //
  563. // Check that we have enough space for the current data.
  564. //
  565. if ((*ppInfoDest)->Count < cDefaultPrinterNotifyInfoData) {
  566. bReturn = AppendPrinterNotifyInfoData(
  567. *ppInfoDest,
  568. pDataSrc,
  569. PRINTER_NOTIFY_INFO_DATA_COMPACT);
  570. } else {
  571. SetLastError(ERROR_OUT_OF_STRUCTURES);
  572. Discard:
  573. SetDiscardPrinterNotifyInfo(*ppInfoDest, pPrintHandle->pChange);
  574. }
  575. Fail:
  576. LeaveRouterSem();
  577. return bReturn;
  578. }