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.

698 lines
20 KiB

  1. #include "brian.h"
  2. typedef struct _ASYNC_NOTIFY {
  3. USHORT FileIndex;
  4. BOOLEAN UseEvent;
  5. PIO_APC_ROUTINE ApcRoutine;
  6. PVOID ApcContext;
  7. PUSHORT BufferIndexPtr;
  8. USHORT BufferIndex;
  9. ULONG Length;
  10. ULONG CompletionFilter;
  11. BOOLEAN WatchTree;
  12. BOOLEAN DisplayParms;
  13. BOOLEAN VerboseResults;
  14. USHORT AsyncIndex;
  15. } ASYNC_NOTIFY, *PASYNC_NOTIFY;
  16. #define USE_EVENT_DEFAULT TRUE
  17. #define APC_ROUTINE_DEFAULT NULL
  18. #define APC_CONTEXT_DEFAULT NULL
  19. #define LENGTH_DEFAULT 0
  20. #define FILTER_DEFAULT FILE_NOTIFY_CHANGE_FILE_NAME
  21. #define WATCH_TREE_DEFAULT FALSE
  22. #define DISPLAY_PARMS_DEFAULT FALSE
  23. #define VERBOSE_RESULTS_DEFAULT FALSE
  24. VOID
  25. FullNotify(
  26. IN OUT PASYNC_NOTIFY AsyncNotify
  27. );
  28. VOID
  29. InputNotifyChange(
  30. IN PCHAR ParamBuffer
  31. )
  32. {
  33. ULONG FileIndex;
  34. BOOLEAN UseEvent;
  35. PIO_APC_ROUTINE ApcRoutine;
  36. PVOID ApcContext;
  37. PUSHORT BufferIndexPtr;
  38. USHORT BufferIndex;
  39. ULONG Length;
  40. ULONG CompletionFilter;
  41. BOOLEAN WatchTree;
  42. BOOLEAN DisplayParms;
  43. BOOLEAN VerboseResults;
  44. USHORT AsyncIndex;
  45. BOOLEAN ParamReceived;
  46. BOOLEAN LastInput;
  47. //
  48. // Set the defaults.
  49. //
  50. UseEvent = USE_EVENT_DEFAULT;
  51. ApcRoutine = APC_ROUTINE_DEFAULT;
  52. ApcContext = APC_CONTEXT_DEFAULT;
  53. BufferIndexPtr = NULL;
  54. BufferIndex = 0;
  55. Length = LENGTH_DEFAULT;
  56. CompletionFilter = FILTER_DEFAULT;
  57. WatchTree = WATCH_TREE_DEFAULT;
  58. DisplayParms = DISPLAY_PARMS_DEFAULT;
  59. VerboseResults = VERBOSE_RESULTS_DEFAULT;
  60. AsyncIndex = 0;
  61. ParamReceived = FALSE;
  62. LastInput = TRUE;
  63. //
  64. // While there is more input, analyze the parameter and update the
  65. // query flags.
  66. //
  67. while (TRUE) {
  68. ULONG DummyCount;
  69. ULONG TempIndex;
  70. //
  71. // Swallow leading white spaces.
  72. //
  73. ParamBuffer = SwallowWhite( ParamBuffer, &DummyCount );
  74. if (*ParamBuffer) {
  75. //
  76. // If the next parameter is legal then check the paramter value.
  77. // Update the parameter value.
  78. //
  79. if ((*ParamBuffer == '-'
  80. || *ParamBuffer == '/')
  81. && (ParamBuffer++, *ParamBuffer != '\0')) {
  82. BOOLEAN SwitchBool;
  83. //
  84. // Switch on the next character.
  85. //
  86. switch (*ParamBuffer) {
  87. //
  88. // Update the file handle index.
  89. //
  90. case 'i' :
  91. case 'I' :
  92. //
  93. // Move to the next character, as long as there
  94. // are no white spaces continue analyzing letters.
  95. // On the first bad letter, skip to the next
  96. // parameter.
  97. //
  98. ParamBuffer++;
  99. FileIndex = AsciiToInteger( ParamBuffer );
  100. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  101. ParamReceived = TRUE;
  102. break;
  103. //
  104. // Check whether we should use an event to signal
  105. // completion.
  106. //
  107. case 'e' :
  108. case 'E' :
  109. //
  110. // Legal values for use event are T/t or F/f.
  111. //
  112. ParamBuffer++;
  113. if (*ParamBuffer == 'T'
  114. || *ParamBuffer == 't') {
  115. UseEvent = TRUE;
  116. ParamBuffer++;
  117. } else if (*ParamBuffer == 'F'
  118. || *ParamBuffer == 'f') {
  119. UseEvent = FALSE;
  120. ParamBuffer++;
  121. }
  122. break;
  123. //
  124. // Check whether we should watch the tree.
  125. //
  126. case 'w' :
  127. case 'W' :
  128. //
  129. // Legal values for use event are T/t or F/f.
  130. //
  131. ParamBuffer++;
  132. if (*ParamBuffer == 'T'
  133. || *ParamBuffer == 't') {
  134. WatchTree = TRUE;
  135. ParamBuffer++;
  136. } else if (*ParamBuffer == 'F'
  137. || *ParamBuffer == 'f') {
  138. WatchTree = FALSE;
  139. ParamBuffer++;
  140. }
  141. break;
  142. //
  143. // Update the buffer index.
  144. //
  145. case 'b' :
  146. case 'B' :
  147. //
  148. // Move to the next character, as long as there
  149. // are no white spaces continue analyzing letters.
  150. // On the first bad letter, skip to the next
  151. // parameter.
  152. //
  153. ParamBuffer++;
  154. TempIndex = AsciiToInteger( ParamBuffer );
  155. BufferIndex = (USHORT) TempIndex;
  156. BufferIndexPtr = &BufferIndex;
  157. Length = Buffers[BufferIndex].Length;
  158. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  159. break;
  160. //
  161. // Update the byte count.
  162. //
  163. case 'l' :
  164. case 'L' :
  165. //
  166. // Move to the next character, as long as there
  167. // are no white spaces continue analyzing letters.
  168. // On the first bad letter, skip to the next
  169. // parameter.
  170. //
  171. ParamBuffer++;
  172. Length = AsciiToInteger( ParamBuffer );
  173. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  174. break;
  175. //
  176. // Update the completion filter.
  177. //
  178. case 'f' :
  179. case 'F' :
  180. //
  181. // Move to the next character, as long as there
  182. // are no white spaces continue analyzing letters.
  183. // On the first bad letter, skip to the next
  184. // parameter.
  185. //
  186. ParamBuffer++;
  187. SwitchBool = TRUE;
  188. while (*ParamBuffer
  189. && *ParamBuffer != ' '
  190. && *ParamBuffer != '\t') {
  191. //
  192. // Perform switch on character.
  193. //
  194. switch (*ParamBuffer) {
  195. case 'a' :
  196. case 'A' :
  197. CompletionFilter |= FILE_NOTIFY_CHANGE_FILE_NAME;
  198. break;
  199. case 'b' :
  200. case 'B' :
  201. CompletionFilter |= FILE_NOTIFY_CHANGE_DIR_NAME;
  202. break;
  203. case 'c' :
  204. case 'C' :
  205. CompletionFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
  206. break;
  207. case 'd' :
  208. case 'D' :
  209. CompletionFilter |= FILE_NOTIFY_CHANGE_SIZE;
  210. break;
  211. case 'e' :
  212. case 'E' :
  213. CompletionFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
  214. break;
  215. case 'f' :
  216. case 'F' :
  217. CompletionFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
  218. break;
  219. case 'g' :
  220. case 'G' :
  221. CompletionFilter |= FILE_NOTIFY_CHANGE_CREATION;
  222. break;
  223. case 'h' :
  224. case 'H' :
  225. CompletionFilter |= FILE_NOTIFY_CHANGE_EA;
  226. break;
  227. case 'i' :
  228. case 'I' :
  229. CompletionFilter |= FILE_NOTIFY_CHANGE_SECURITY;
  230. break;
  231. case 'j' :
  232. case 'J' :
  233. CompletionFilter |= FILE_NOTIFY_CHANGE_STREAM_NAME;
  234. break;
  235. case 'k' :
  236. case 'K' :
  237. CompletionFilter |= FILE_NOTIFY_CHANGE_STREAM_SIZE;
  238. break;
  239. case 'l' :
  240. case 'L' :
  241. CompletionFilter |= FILE_NOTIFY_CHANGE_STREAM_WRITE;
  242. break;
  243. case 'y' :
  244. case 'Y' :
  245. CompletionFilter = FILE_NOTIFY_VALID_MASK;
  246. break;
  247. case 'z' :
  248. case 'Z' :
  249. CompletionFilter = 0;
  250. break;
  251. default :
  252. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  253. SwitchBool = FALSE;
  254. }
  255. if (!SwitchBool) {
  256. break;
  257. }
  258. ParamBuffer++;
  259. }
  260. break;
  261. case 'v' :
  262. case 'V' :
  263. //
  264. // Legal values for params are T/t or F/f.
  265. //
  266. ParamBuffer++;
  267. if( *ParamBuffer == 'T'
  268. || *ParamBuffer == 't' ) {
  269. VerboseResults = TRUE;
  270. ParamBuffer++;
  271. } else if( *ParamBuffer == 'F'
  272. || *ParamBuffer == 'f' ) {
  273. VerboseResults = FALSE;
  274. ParamBuffer++;
  275. }
  276. break;
  277. case 'y' :
  278. case 'Y' :
  279. //
  280. // Set the display parms flag and jump over this
  281. // character.
  282. //
  283. DisplayParms = TRUE;
  284. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  285. break;
  286. case 'z' :
  287. case 'Z' :
  288. //
  289. // Set flag for more input and jump over this char.
  290. //
  291. LastInput = FALSE;
  292. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  293. break;
  294. default :
  295. //
  296. // Swallow to the next white space and continue the
  297. // loop.
  298. //
  299. ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
  300. }
  301. }
  302. //
  303. // Else the text is invalid, skip the entire block.
  304. //
  305. //
  306. //
  307. // Else if there is no input then exit.
  308. //
  309. } else if( LastInput ) {
  310. break;
  311. //
  312. // Else try to read another line for open parameters.
  313. //
  314. } else {
  315. }
  316. }
  317. //
  318. // If no parameters were received then display the syntax message.
  319. //
  320. if (!ParamReceived) {
  321. printf( "\n Usage: ncd [options]* -i<index> [options]*\n" );
  322. printf( "\n Options:" );
  323. printf( "\n -i<digits> File index" );
  324. printf( "\n -b<digits> Buffer to store results" );
  325. printf( "\n -l<digits> Stated length of buffer" );
  326. printf( "\n -f<chars> Completion filter" );
  327. printf( "\n -w[t|f] Watch directory tree" );
  328. printf( "\n -e[t|f] Use event on completion" );
  329. printf( "\n -v[t|f] Verbose results" );
  330. printf( "\n -y Display parameters to query" );
  331. printf( "\n -z Additional input line" );
  332. printf( "\n\n" );
  333. //
  334. // Else call our notify routine.
  335. //
  336. } else {
  337. NTSTATUS Status;
  338. SIZE_T RegionSize;
  339. ULONG TempIndex;
  340. PASYNC_NOTIFY AsyncNotify;
  341. HANDLE ThreadHandle;
  342. ULONG ThreadId;
  343. RegionSize = sizeof( ASYNC_NOTIFY );
  344. Status = AllocateBuffer( 0, &RegionSize, &TempIndex );
  345. AsyncIndex = (USHORT) TempIndex;
  346. if (!NT_SUCCESS( Status )) {
  347. printf("\n\tInputRead: Unable to allocate async structure" );
  348. } else {
  349. AsyncNotify = (PASYNC_NOTIFY) Buffers[AsyncIndex].Buffer;
  350. AsyncNotify->FileIndex = (USHORT) FileIndex;
  351. AsyncNotify->UseEvent = UseEvent;
  352. AsyncNotify->ApcRoutine = ApcRoutine;
  353. AsyncNotify->ApcContext = ApcContext;
  354. AsyncNotify->BufferIndex = BufferIndex;
  355. AsyncNotify->BufferIndexPtr = BufferIndexPtr
  356. ? &AsyncNotify->BufferIndex
  357. : BufferIndexPtr;
  358. AsyncNotify->Length = Length;
  359. AsyncNotify->CompletionFilter = CompletionFilter;
  360. AsyncNotify->WatchTree = WatchTree;
  361. AsyncNotify->DisplayParms = DisplayParms;
  362. AsyncNotify->VerboseResults = VerboseResults;
  363. AsyncNotify->AsyncIndex = AsyncIndex;
  364. if (!SynchronousCmds) {
  365. ThreadHandle = CreateThread( NULL,
  366. 0,
  367. FullNotify,
  368. AsyncNotify,
  369. 0,
  370. &ThreadId );
  371. if (ThreadHandle == 0) {
  372. printf( "\nInputNotify: Spawning thread fails -> %d\n", GetLastError() );
  373. return;
  374. }
  375. } else {
  376. FullNotify( AsyncNotify );
  377. }
  378. }
  379. }
  380. return;
  381. }
  382. VOID
  383. FullNotify(
  384. IN OUT PASYNC_NOTIFY AsyncNotify
  385. )
  386. {
  387. NTSTATUS Status;
  388. IO_STATUS_BLOCK Iosb;
  389. HANDLE ThisEvent;
  390. USHORT ThisEventIndex;
  391. USHORT ThisBufferIndex;
  392. BOOLEAN UnwindNotifyBuffer = FALSE;
  393. BOOLEAN UnwindEvent = FALSE;
  394. Status = STATUS_SUCCESS;
  395. if (AsyncNotify->DisplayParms) {
  396. bprint "\nNotify Parameters" );
  397. bprint "\n File Handle Index -> %d", AsyncNotify->FileIndex );
  398. bprint "\n Buffer Index Ptr -> %08lx", AsyncNotify->BufferIndexPtr );
  399. if (AsyncNotify->BufferIndexPtr) {
  400. bprint "\n BufferIndex value -> %04x", AsyncNotify->BufferIndex );
  401. }
  402. bprint "\n Length -> %08lx", AsyncNotify->Length );
  403. bprint "\n CompletionFilter -> %08lx", AsyncNotify->CompletionFilter );
  404. bprint "\n WatchTree -> %d", AsyncNotify->WatchTree );
  405. bprint "\n UseEvent -> %d", AsyncNotify->UseEvent );
  406. bprint "\n ApcRoutine -> %08lx", AsyncNotify->ApcRoutine );
  407. bprint "\n ApcContext -> %08lx", AsyncNotify->ApcContext );
  408. bprint "\n\n" );
  409. }
  410. try {
  411. SIZE_T ThisLength;
  412. //
  413. // If we need a buffer, allocate it now.
  414. //
  415. if (AsyncNotify->BufferIndexPtr == NULL ) {
  416. ULONG TempIndex;
  417. ThisLength = 4096;
  418. Status = AllocateBuffer( 0L, &ThisLength, &TempIndex );
  419. ThisBufferIndex = (USHORT) TempIndex;
  420. if (!NT_SUCCESS( Status )) {
  421. bprint "\n\tFullNotify: Unable to allocate a notify buffer" );
  422. try_return( Status );
  423. }
  424. bprint "\n\tFullNotify: Reading into buffer -> %04x\n", ThisBufferIndex );
  425. bprint "\n" );
  426. UnwindNotifyBuffer = TRUE;
  427. AsyncNotify->Length = (ULONG) ThisLength;
  428. } else {
  429. ThisBufferIndex = AsyncNotify->BufferIndex;
  430. }
  431. //
  432. // Check that the buffer index is valid.
  433. //
  434. if (ThisBufferIndex >= MAX_BUFFERS) {
  435. bprint "\n\tFullNotify: The read buffer index is invalid" );
  436. try_return( Status = STATUS_INVALID_HANDLE );
  437. }
  438. //
  439. // Check that the file index is valid.
  440. //
  441. if (AsyncNotify->FileIndex >= MAX_HANDLES) {
  442. bprint "\n\tFullNotify: The file index is invalid" );
  443. try_return( Status = STATUS_INVALID_HANDLE );
  444. }
  445. //
  446. // If we need an event, allocate and set it now.
  447. //
  448. if (AsyncNotify->UseEvent == TRUE) {
  449. Status = ObtainEvent( &ThisEventIndex );
  450. if (!NT_SUCCESS( Status )) {
  451. bprint "\n\tFullNotify: Unable to allocate an event" );
  452. try_return( Status );
  453. }
  454. UnwindEvent = TRUE;
  455. ThisEvent = Events[ThisEventIndex].Handle;
  456. } else {
  457. ThisEvent = 0;
  458. }
  459. //
  460. // Call the read routine.
  461. //
  462. Status = NtNotifyChangeDirectoryFile( Handles[AsyncNotify->FileIndex].Handle,
  463. ThisEvent,
  464. AsyncNotify->ApcRoutine,
  465. AsyncNotify->ApcContext,
  466. &Iosb,
  467. Buffers[ThisBufferIndex].Buffer,
  468. AsyncNotify->Length,
  469. AsyncNotify->CompletionFilter,
  470. AsyncNotify->WatchTree );
  471. if (AsyncNotify->VerboseResults) {
  472. bprint "\nNotifyChangeDir: Status -> %08lx\n", Status );
  473. if (AsyncNotify->UseEvent && NT_SUCCESS( Status )) {
  474. if ((Status = NtWaitForSingleObject( ThisEvent,
  475. FALSE,
  476. NULL )) != STATUS_SUCCESS) {
  477. bprint "\n\tNotifyChangeDir: Wait for event failed -> %08lx\n", Status );
  478. try_return( Status );
  479. }
  480. }
  481. if (NT_SUCCESS( Status )) {
  482. bprint "\nNotifyChangeDir: Iosb.Information -> %08lx", Iosb.Information );
  483. bprint "\nNotifyChangeDir: Iosb.Status -> %08lx", Iosb.Status );
  484. }
  485. bprint "\n" );
  486. }
  487. try_return( Status );
  488. try_exit: NOTHING;
  489. } finally {
  490. if (UnwindEvent) {
  491. FreeEvent( ThisEventIndex );
  492. }
  493. DeallocateBuffer( AsyncNotify->AsyncIndex );
  494. }
  495. if (!SynchronousCmds) {
  496. NtTerminateThread( 0, STATUS_SUCCESS );
  497. }
  498. }