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.

3275 lines
82 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. strucsup.c
  5. Abstract:
  6. This module implements the Netware Redirector structure support routines.
  7. Author:
  8. Manny Weiser (mannyw) 10-Feb-1993
  9. Revision History:
  10. --*/
  11. #include "procs.h"
  12. BOOLEAN
  13. GetLongNameSpaceForVolume(
  14. IN PIRP_CONTEXT IrpContext,
  15. IN UNICODE_STRING ShareName,
  16. OUT PCHAR VolumeLongNameSpace,
  17. OUT PCHAR VolumeNumber
  18. );
  19. CHAR
  20. GetNewDriveNumber (
  21. IN PSCB Scb
  22. );
  23. VOID
  24. FreeDriveNumber(
  25. IN PSCB Scb,
  26. IN CHAR DriveNumber
  27. );
  28. #define Dbg (DEBUG_TRACE_STRUCSUP)
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text( PAGE, NwInitializeRcb )
  31. #pragma alloc_text( PAGE, NwDeleteRcb )
  32. #pragma alloc_text( PAGE, NwCreateIcb )
  33. #pragma alloc_text( PAGE, NwDeleteIcb )
  34. #pragma alloc_text( PAGE, NwVerifyIcb )
  35. #pragma alloc_text( PAGE, NwVerifyIcbSpecial )
  36. #pragma alloc_text( PAGE, NwInvalidateAllHandlesForScb )
  37. #pragma alloc_text( PAGE, NwVerifyScb )
  38. #pragma alloc_text( PAGE, NwCreateFcb )
  39. #pragma alloc_text( PAGE, NwFindFcb )
  40. #pragma alloc_text( PAGE, NwDereferenceFcb )
  41. #pragma alloc_text( PAGE, NwFindVcb )
  42. #pragma alloc_text( PAGE, NwCreateVcb )
  43. #pragma alloc_text( PAGE, NwReopenVcbHandlesForScb )
  44. #pragma alloc_text( PAGE, NwReopenVcbHandle )
  45. #ifdef NWDBG
  46. #pragma alloc_text( PAGE, NwReferenceVcb )
  47. #endif
  48. #pragma alloc_text( PAGE, NwDereferenceVcb )
  49. #pragma alloc_text( PAGE, NwCleanupVcb )
  50. #pragma alloc_text( PAGE, GetLongNameSpaceForVolume )
  51. #pragma alloc_text( PAGE, IsFatNameValid )
  52. #pragma alloc_text( PAGE, GetNewDriveNumber )
  53. #pragma alloc_text( PAGE, FreeDriveNumber )
  54. #pragma alloc_text( PAGE, NwFreeDirCacheForIcb )
  55. #ifndef QFE_BUILD
  56. #pragma alloc_text( PAGE1, NwInvalidateAllHandles )
  57. #pragma alloc_text( PAGE1, NwCloseAllVcbs )
  58. #endif
  59. #endif
  60. #if 0 // Not pageable
  61. // see ifndef QFE_BUILD above
  62. #endif
  63. VOID
  64. NwInitializeRcb (
  65. IN PRCB Rcb
  66. )
  67. /*++
  68. Routine Description:
  69. This routine initializes new Rcb record.
  70. Arguments:
  71. Rcb - Supplies the address of the Rcb record being initialized.
  72. Return Value:
  73. None.
  74. --*/
  75. {
  76. PAGED_CODE();
  77. DebugTrace(+1, Dbg, "NwInitializeRcb, Rcb = %08lx\n", (ULONG_PTR)Rcb);
  78. //
  79. // We start by first zeroing out all of the RCB, this will guarantee
  80. // that any stale data is wiped clean.
  81. //
  82. RtlZeroMemory( Rcb, sizeof(RCB) );
  83. //
  84. // Set the node type code, node byte size, and reference count.
  85. //
  86. Rcb->NodeTypeCode = NW_NTC_RCB;
  87. Rcb->NodeByteSize = sizeof(RCB);
  88. Rcb->OpenCount = 0;
  89. //
  90. // Initialize the resource variable for the RCB.
  91. //
  92. ExInitializeResourceLite( &Rcb->Resource );
  93. //
  94. // Initialize the server name and file name tables.
  95. //
  96. RtlInitializeUnicodePrefix( &Rcb->ServerNameTable );
  97. RtlInitializeUnicodePrefix( &Rcb->VolumeNameTable );
  98. RtlInitializeUnicodePrefix( &Rcb->FileNameTable );
  99. //
  100. // Return to the caller.
  101. //
  102. DebugTrace(-1, Dbg, "NwInitializeRcb -> VOID\n", 0);
  103. return;
  104. }
  105. VOID
  106. NwDeleteRcb (
  107. IN PRCB Rcb
  108. )
  109. /*++
  110. Routine Description:
  111. This routine removes the RCB record from our in-memory data
  112. structures. It also will remove all associated underlings
  113. (i.e., FCB records).
  114. Arguments:
  115. Rcb - Supplies the Rcb to be removed
  116. Return Value:
  117. None
  118. --*/
  119. {
  120. PAGED_CODE();
  121. DebugTrace(+1, Dbg, "NwDeleteRcb, Rcb = %08lx\n", (ULONG_PTR)Rcb);
  122. //
  123. // Uninitialize the resource variable for the RCB.
  124. //
  125. ExDeleteResourceLite( &Rcb->Resource );
  126. //
  127. // Return to the caller.
  128. //
  129. DebugTrace(-1, Dbg, "NwDeleteRcb -> VOID\n", 0);
  130. return;
  131. }
  132. PICB
  133. NwCreateIcb (
  134. IN USHORT Type,
  135. IN PVOID Associate
  136. )
  137. /*++
  138. Routine Description:
  139. This routine allocates and initialize a new ICB. The ICB is
  140. inserted into the FCB's list.
  141. *** This routine must be called with the RCB held exclusively.
  142. Arguments:
  143. Type - The type of ICB this will be.
  144. Associate - A pointer to an associated data structure.
  145. It will be a FCB, DCB, or SCB.
  146. Return Value:
  147. ICB - A pointer to the newly created ICB.
  148. If memory allocation fails, this routine will raise an exception.
  149. --*/
  150. {
  151. PICB Icb;
  152. PSCB Scb;
  153. PAGED_CODE();
  154. Icb = ALLOCATE_POOL_EX( NonPagedPool, sizeof( ICB ) );
  155. RtlZeroMemory( Icb, sizeof( ICB ) );
  156. Icb->NodeTypeCode = Type;
  157. Icb->NodeByteSize = sizeof( ICB );
  158. Icb->State = ICB_STATE_OPEN_PENDING;
  159. Icb->Pid = (UCHAR)INVALID_PID;
  160. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  161. if ( Type == NW_NTC_ICB ) {
  162. PFCB Fcb = (PFCB)Associate;
  163. //
  164. // Insert this ICB on the list of ICBs for this FCB.
  165. //
  166. InsertTailList( &Fcb->IcbList, &Icb->ListEntry );
  167. ++Fcb->IcbCount;
  168. Icb->SuperType.Fcb = Fcb;
  169. Icb->NpFcb = Fcb->NonPagedFcb;
  170. Fcb->Vcb->OpenFileCount++;
  171. Scb = Fcb->Scb;
  172. Scb->OpenFileCount++;
  173. } else if ( Type == NW_NTC_ICB_SCB ) {
  174. Scb = (PSCB)Associate;
  175. //
  176. // Insert this ICB on the list of ICBs for this SCB.
  177. //
  178. InsertTailList( &Scb->IcbList, &Icb->ListEntry );
  179. ++Scb->IcbCount;
  180. Icb->SuperType.Scb = Scb;
  181. } else {
  182. KeBugCheck( RDR_FILE_SYSTEM );
  183. }
  184. InitializeListHead( &(Icb->DirCache) );
  185. NwReleaseRcb( &NwRcb );
  186. NwReferenceScb( Scb->pNpScb );
  187. return( Icb );
  188. }
  189. VOID
  190. NwDeleteIcb (
  191. IN PIRP_CONTEXT IrpContext OPTIONAL,
  192. IN PICB Icb
  193. )
  194. /*++
  195. Routine Description:
  196. This routine deletes an ICB in the OPEN_PENDING state.
  197. *** The IRP context must be at the head of the SCB queue when
  198. this routine is called.
  199. Arguments:
  200. Icb - A pointer the ICB to delete.
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. PFCB Fcb;
  206. PSCB Scb;
  207. PAGED_CODE();
  208. //
  209. // Acquire the lock to protect the ICB list.
  210. //
  211. DebugTrace( 0, DEBUG_TRACE_ICBS, "NwDeleteIcb, Icb = %08lx\n", (ULONG_PTR)Icb);
  212. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  213. RemoveEntryList( &Icb->ListEntry );
  214. if ( Icb->NodeTypeCode == NW_NTC_ICB ) {
  215. Fcb = Icb->SuperType.Fcb;
  216. Scb = Fcb->Scb;
  217. //
  218. // Decrement the open file count for the VCB. Note that the ICB
  219. // only reference the VCB indirectly via the FCB, so that we do
  220. // not dereference the VCB here.
  221. //
  222. --Fcb->Vcb->OpenFileCount;
  223. --Scb->OpenFileCount;
  224. //
  225. // Dereference the FCB. This frees the FCB if
  226. // this was the last ICB for the FCB.
  227. //
  228. NwDereferenceFcb( IrpContext, Fcb );
  229. } else if ( Icb->NodeTypeCode == NW_NTC_ICB_SCB ) {
  230. Scb = Icb->SuperType.Scb;
  231. //
  232. // Decrement of OpenIcb count on the SCB.
  233. //
  234. Scb->IcbCount--;
  235. } else {
  236. KeBugCheck( RDR_FILE_SYSTEM );
  237. }
  238. //
  239. // Free the query template buffers.
  240. //
  241. RtlFreeOemString( &Icb->NwQueryTemplate );
  242. if ( Icb->UQueryTemplate.Buffer != NULL ) {
  243. FREE_POOL( Icb->UQueryTemplate.Buffer );
  244. }
  245. //
  246. // Try and gracefully catch a 16 bit app closing a
  247. // handle to the server and wipe the connection as
  248. // soon as possible. This only applies to bindery
  249. // authenticated connections because in NDS land,
  250. // we handle the licensing of the connection
  251. // dynamically.
  252. //
  253. if ( ( Scb->pNpScb->Reference == 1 ) &&
  254. ( Icb->NodeTypeCode == NW_NTC_ICB_SCB ) &&
  255. ( !Icb->IsTreeHandle ) &&
  256. ( IrpContext != NULL ) &&
  257. ( Scb->UserName.Length != 0 ) )
  258. {
  259. LARGE_INTEGER Now;
  260. KeQuerySystemTime( &Now );
  261. DebugTrace( 0, Dbg, "Quick disconnecting 16-bit app.\n", 0 );
  262. NwAppendToQueueAndWait( IrpContext );
  263. if ( Scb->OpenFileCount == 0 &&
  264. Scb->pNpScb->State != SCB_STATE_RECONNECT_REQUIRED &&
  265. !Scb->PreferredServer ) {
  266. NwLogoffAndDisconnect( IrpContext, Scb->pNpScb);
  267. }
  268. Now.QuadPart += ( NwOneSecond * DORMANT_SCB_KEEP_TIME );
  269. NwDequeueIrpContext( IrpContext, FALSE );
  270. NwDereferenceScb( Scb->pNpScb );
  271. DisconnectTimedOutScbs(Now) ;
  272. CleanupScbs(Now);
  273. } else {
  274. NwDereferenceScb( Scb->pNpScb );
  275. }
  276. NwFreeDirCacheForIcb( Icb );
  277. FREE_POOL( Icb );
  278. NwReleaseRcb( &NwRcb );
  279. }
  280. VOID
  281. NwVerifyIcb (
  282. IN PICB Icb
  283. )
  284. /*++
  285. Routine Description:
  286. This routine verifies that an ICB is in the opened state.
  287. If it is not, the routine raises an exception.
  288. Arguments:
  289. Icb - A pointer the ICB to verify.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. PAGED_CODE();
  295. if ( Icb->State != ICB_STATE_OPENED ) {
  296. ExRaiseStatus( STATUS_INVALID_HANDLE );
  297. }
  298. }
  299. VOID
  300. NwVerifyIcbSpecial (
  301. IN PICB Icb
  302. )
  303. /*++
  304. Routine Description:
  305. This routine verifies that an ICB is in the opened state.
  306. If it is not, the routine raises an exception.
  307. Arguments:
  308. Icb - A pointer the ICB to verify.
  309. Return Value:
  310. None.
  311. --*/
  312. {
  313. PAGED_CODE();
  314. if ( (Icb->State != ICB_STATE_OPENED &&
  315. Icb->State != ICB_STATE_CLEANED_UP) ) {
  316. ExRaiseStatus( STATUS_INVALID_HANDLE );
  317. }
  318. }
  319. ULONG
  320. NwInvalidateAllHandles (
  321. PLARGE_INTEGER Uid OPTIONAL,
  322. PIRP_CONTEXT IrpContext OPTIONAL
  323. )
  324. /*++
  325. Routine Description:
  326. This routine finds all of the ICB in the system that were created
  327. by the user specified by the Logon credentials and marks them
  328. invalid.
  329. Arguments:
  330. Uid - Supplies the userid of the handles to close or NULL if all
  331. handles to be invalidated.
  332. IrpContext - The Irpcontext to be used for the NwLogoffAndDisconnect
  333. call, if appropriate. If this is NULL, it indicates a RAS
  334. transition.
  335. Return Value:
  336. The number of active handles that were closed.
  337. --*/
  338. {
  339. KIRQL OldIrql;
  340. PLIST_ENTRY ScbQueueEntry, NextScbQueueEntry;
  341. PNONPAGED_SCB pNpScb;
  342. PSCB pScb;
  343. ULONG FilesClosed = 0;
  344. PAGED_CODE();
  345. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  346. for (ScbQueueEntry = ScbQueue.Flink ;
  347. ScbQueueEntry != &ScbQueue ;
  348. ScbQueueEntry = NextScbQueueEntry ) {
  349. pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
  350. pScb = pNpScb->pScb;
  351. if ( pScb != NULL ) {
  352. NwReferenceScb( pNpScb );
  353. //
  354. // Release the SCB spin lock as we are about to touch nonpaged pool.
  355. //
  356. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  357. if ((Uid == NULL) ||
  358. ( pScb->UserUid.QuadPart == (*Uid).QuadPart)) {
  359. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  360. FilesClosed += NwInvalidateAllHandlesForScb( pScb );
  361. NwReleaseRcb( &NwRcb );
  362. if ( IrpContext ) {
  363. IrpContext->pNpScb = pNpScb;
  364. NwLogoffAndDisconnect( IrpContext , pNpScb);
  365. NwDequeueIrpContext( IrpContext, FALSE );
  366. } else {
  367. //
  368. // No IrpContext means that a RAS transition has occurred.
  369. // Let's try to keep our Netware servers happy if the net
  370. // is still attached.
  371. //
  372. PIRP_CONTEXT LocalIrpContext;
  373. if (NwAllocateExtraIrpContext(&LocalIrpContext, pNpScb)) {
  374. // Lock down so that we can send a packet.
  375. NwReferenceUnlockableCodeSection();
  376. LocalIrpContext->pNpScb = pNpScb;
  377. NwLogoffAndDisconnect( LocalIrpContext, pNpScb);
  378. NwAppendToQueueAndWait( LocalIrpContext );
  379. NwDequeueIrpContext( LocalIrpContext, FALSE );
  380. NwDereferenceUnlockableCodeSection ();
  381. NwFreeExtraIrpContext( LocalIrpContext );
  382. }
  383. //
  384. // Clear the LIP data speed.
  385. //
  386. pNpScb->LipDataSpeed = 0;
  387. pNpScb->State = SCB_STATE_ATTACHING;
  388. }
  389. }
  390. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  391. NwDereferenceScb( pNpScb );
  392. }
  393. NextScbQueueEntry = pNpScb->ScbLinks.Flink;
  394. }
  395. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  396. return( FilesClosed );
  397. }
  398. ULONG
  399. NwInvalidateAllHandlesForScb (
  400. PSCB Scb
  401. )
  402. /*++
  403. Routine Description:
  404. This routine finds all of the ICB in for an SCB and marks them
  405. invalid.
  406. *** The caller must own the RCB shared or exclusive.
  407. Arguments:
  408. SCB - A pointer to the SCB whose files are closed.
  409. Return Value:
  410. The number of files that were closed.
  411. --*/
  412. {
  413. PLIST_ENTRY VcbQueueEntry;
  414. PLIST_ENTRY FcbQueueEntry;
  415. PLIST_ENTRY IcbQueueEntry;
  416. PVCB pVcb;
  417. PFCB pFcb;
  418. PICB pIcb;
  419. ULONG FilesClosed = 0;
  420. PAGED_CODE();
  421. //
  422. // Walk the list of VCBs for this SCB
  423. //
  424. for ( VcbQueueEntry = Scb->ScbSpecificVcbQueue.Flink;
  425. VcbQueueEntry != &Scb->ScbSpecificVcbQueue;
  426. VcbQueueEntry = VcbQueueEntry->Flink ) {
  427. pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
  428. if ( !BooleanFlagOn( pVcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
  429. pVcb->Specific.Disk.Handle = (CHAR)-1;
  430. }
  431. //
  432. // Walk the list of FCBs and DCSs for this VCB
  433. //
  434. for ( FcbQueueEntry = pVcb->FcbList.Flink;
  435. FcbQueueEntry != &pVcb->FcbList;
  436. FcbQueueEntry = FcbQueueEntry->Flink ) {
  437. pFcb = CONTAINING_RECORD( FcbQueueEntry, FCB, FcbListEntry );
  438. //
  439. // Walk the list of ICBs for this FCB or DCB
  440. //
  441. for ( IcbQueueEntry = pFcb->IcbList.Flink;
  442. IcbQueueEntry != &pFcb->IcbList;
  443. IcbQueueEntry = IcbQueueEntry->Flink ) {
  444. pIcb = CONTAINING_RECORD( IcbQueueEntry, ICB, ListEntry );
  445. //
  446. // Mark the ICB handle invalid.
  447. //
  448. pIcb->State = ICB_STATE_CLOSE_PENDING;
  449. pIcb->HasRemoteHandle = FALSE;
  450. FilesClosed++;
  451. }
  452. }
  453. }
  454. return( FilesClosed );
  455. }
  456. VOID
  457. NwVerifyScb (
  458. IN PSCB Scb
  459. )
  460. /*++
  461. Routine Description:
  462. This routine verifies that an SCB is in the opened state.
  463. If it is not, the routine raises an exception.
  464. Arguments:
  465. Scb - A pointer the SCB to verify.
  466. Return Value:
  467. None.
  468. --*/
  469. {
  470. PAGED_CODE();
  471. if ( Scb->pNpScb->State == SCB_STATE_FLAG_SHUTDOWN ) {
  472. ExRaiseStatus( STATUS_INVALID_HANDLE );
  473. }
  474. }
  475. PFCB
  476. NwCreateFcb (
  477. IN PUNICODE_STRING FileName,
  478. IN PSCB Scb,
  479. IN PVCB Vcb
  480. )
  481. /*++
  482. Routine Description:
  483. This routine allocates and initialize a new FCB. The FCB is
  484. inserted into the RCB prefix table.
  485. *** This routine must be called with the RCB held exclusively.
  486. Arguments:
  487. FileName - The name of the file to create.
  488. Scb - A pointer to the SCB for this file.
  489. Vcb - A pointer to the VCB for the file.
  490. Return Value:
  491. FCB - A pointer to the newly created DCB.
  492. If memory allocation fails, this routine will raise an exception.
  493. --*/
  494. {
  495. PFCB Fcb;
  496. PNONPAGED_FCB NpFcb;
  497. PWCH FileNameBuffer;
  498. SHORT Length;
  499. PAGED_CODE();
  500. Fcb = NULL;
  501. NpFcb = NULL;
  502. try {
  503. //
  504. // Allocate and initialize structures.
  505. //
  506. Fcb = ALLOCATE_POOL_EX(
  507. PagedPool,
  508. sizeof( FCB ) + FileName->Length + sizeof(WCHAR));
  509. RtlZeroMemory( Fcb, sizeof( FCB ) );
  510. Fcb->NodeTypeCode = NW_NTC_FCB;
  511. Fcb->NodeByteSize = sizeof( FCB ) + FileName->Length;
  512. Fcb->State = FCB_STATE_OPEN_PENDING;
  513. InitializeListHead( &Fcb->IcbList );
  514. Fcb->Vcb = Vcb;
  515. Fcb->Scb = Scb;
  516. FileNameBuffer = (PWCH)(Fcb + 1);
  517. NpFcb = ALLOCATE_POOL_EX( NonPagedPool, sizeof( NONPAGED_FCB ) );
  518. RtlZeroMemory( NpFcb, sizeof( NONPAGED_FCB ) );
  519. NpFcb->Header.NodeTypeCode = NW_NTC_NONPAGED_FCB;
  520. NpFcb->Header.NodeByteSize = sizeof( NONPAGED_FCB );
  521. NpFcb->Fcb = Fcb;
  522. Fcb->NonPagedFcb = NpFcb;
  523. //
  524. // Initialize the resource variable for the FCB.
  525. //
  526. ExInitializeResourceLite( &NpFcb->Resource );
  527. //
  528. // Copy the file name
  529. //
  530. RtlCopyMemory( FileNameBuffer, FileName->Buffer, FileName->Length );
  531. Fcb->FullFileName.MaximumLength = FileName->Length;
  532. Fcb->FullFileName.Length = FileName->Length;
  533. Fcb->FullFileName.Buffer = FileNameBuffer;
  534. // Mapping for Novell's handling of Euro char in file names
  535. {
  536. int i = 0;
  537. WCHAR * pCurrChar = FileNameBuffer;
  538. for (i = 0; i < (FileName->Length / 2); i++)
  539. {
  540. if (*(pCurrChar + i) == (WCHAR) 0x20AC) // Its a Euro
  541. *(pCurrChar + i) = (WCHAR) 0x2560; // set it to Novell's mapping for Euro
  542. }
  543. }
  544. //
  545. // The Relative name is normally the full name without the
  546. // server and volume name. Also strip the leading backslash.
  547. //
  548. Length = FileName->Length - Vcb->Name.Length - sizeof(L'\\');
  549. if ( Length < 0 ) {
  550. Length = 0;
  551. }
  552. Fcb->RelativeFileName.Buffer = (PWCH)
  553. ((PCHAR)FileNameBuffer + Vcb->Name.Length + sizeof(L'\\'));
  554. Fcb->RelativeFileName.MaximumLength = Length;
  555. Fcb->RelativeFileName.Length = Length;
  556. //
  557. // Insert this file in the prefix table.
  558. //
  559. RtlInsertUnicodePrefix(
  560. &NwRcb.FileNameTable,
  561. &Fcb->FullFileName,
  562. &Fcb->PrefixEntry );
  563. //
  564. // Insert this file into the VCB list, and increment the
  565. // file open count.
  566. //
  567. NwReferenceVcb( Vcb );
  568. InsertTailList(
  569. &Vcb->FcbList,
  570. &Fcb->FcbListEntry );
  571. //
  572. // Initialize the list of file locks for this FCB.
  573. //
  574. InitializeListHead( &NpFcb->FileLockList );
  575. InitializeListHead( &NpFcb->PendingLockList );
  576. //
  577. // Set the long name bit if necessary
  578. //
  579. if ( Fcb->Vcb->Specific.Disk.LongNameSpace != LFN_NO_OS2_NAME_SPACE ) {
  580. //
  581. // OBSCURE CODE POINT
  582. //
  583. // By default FavourLongNames is not set and we use DOS name
  584. // space unless we know we have to use LFN. Reason is if we
  585. // start using LFN then DOS apps that dont handle longnames
  586. // will give us short names and we are hosed because we are
  587. // using LFN NCPs that dont see the short names. Eg. without
  588. // the check below, the following will fail (assume mv.exe is
  589. // DOS app).
  590. //
  591. // cd public\longnamedir
  592. // mv foo bar
  593. //
  594. // This is because we will get call with public\longname\foo
  595. // and the truncated dir name is not accepted. If user values
  596. // case sensitivity, they can set this reg value and we will
  597. // use LFN even for short names. They sacrifice the scenario
  598. // above.
  599. //
  600. if ( FavourLongNames || !IsFatNameValid( &Fcb->RelativeFileName ) ) {
  601. SetFlag( Fcb->Flags, FCB_FLAGS_LONG_NAME );
  602. }
  603. }
  604. } finally {
  605. if ( AbnormalTermination() ) {
  606. if ( Fcb != NULL ) FREE_POOL( Fcb );
  607. if ( NpFcb != NULL ) FREE_POOL( NpFcb );
  608. }
  609. }
  610. return( Fcb );
  611. }
  612. PFCB
  613. NwFindFcb (
  614. IN PSCB Scb,
  615. IN PVCB Vcb,
  616. IN PUNICODE_STRING FileName,
  617. IN PDCB Dcb OPTIONAL
  618. )
  619. /*++
  620. Routine Description:
  621. This routine find an existing FCB by matching the file name.
  622. If a match is find the FCB reference count is incremented.
  623. If no match is found an FCB is created.
  624. Arguments:
  625. Scb - A pointer to the server for this open.
  626. FileName - The name of the file to find.
  627. Dcb - A pointer to the DCB for relative opens. If NULL the FileName
  628. is an full path name. If non NUL the FileName is relative to
  629. this directory.
  630. Return Value:
  631. FCB - A pointer to the found or newly created DCB.
  632. If memory allocation fails, this routine will raise an exception.
  633. --*/
  634. {
  635. PFCB Fcb;
  636. PUNICODE_PREFIX_TABLE_ENTRY Prefix;
  637. UNICODE_STRING FullName;
  638. PAGED_CODE();
  639. DebugTrace(+1, Dbg, "NwFindFcb\n", 0);
  640. ASSERT( Scb->NodeTypeCode == NW_NTC_SCB );
  641. if ( Dcb == NULL ) {
  642. MergeStrings( &FullName,
  643. &Scb->UnicodeUid,
  644. FileName,
  645. PagedPool );
  646. } else {
  647. //
  648. // Construct full name, ensuring we don't cause overflow
  649. //
  650. if ((ULONG)(Dcb->FullFileName.Length + FileName->Length) > (0xFFFF - 2)) {
  651. return NULL;
  652. }
  653. FullName.Length = Dcb->FullFileName.Length + FileName->Length + 2;
  654. FullName.MaximumLength = FullName.Length;
  655. FullName.Buffer = ALLOCATE_POOL_EX( PagedPool, FullName.Length );
  656. RtlCopyMemory(
  657. FullName.Buffer,
  658. Dcb->FullFileName.Buffer,
  659. Dcb->FullFileName.Length );
  660. FullName.Buffer[ Dcb->FullFileName.Length / sizeof(WCHAR) ] = L'\\';
  661. RtlCopyMemory(
  662. FullName.Buffer + Dcb->FullFileName.Length / sizeof(WCHAR) + 1,
  663. FileName->Buffer,
  664. FileName->Length );
  665. }
  666. DebugTrace( 0, Dbg, " ->FullName = ""%wZ""\n", &FullName);
  667. //
  668. // Strip the trailing '\' if there is one.
  669. //
  670. if ( FullName.Buffer[ FullName.Length/sizeof(WCHAR) - 1] == L'\\' ) {
  671. FullName.Length -= sizeof(WCHAR);
  672. }
  673. Fcb = NULL;
  674. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  675. Prefix = RtlFindUnicodePrefix( &NwRcb.FileNameTable, &FullName, 0 );
  676. if ( Prefix != NULL ) {
  677. Fcb = CONTAINING_RECORD( Prefix, FCB, PrefixEntry );
  678. if ( Fcb->FullFileName.Length != FullName.Length ) {
  679. //
  680. // This was not an exact match. Ignore it.
  681. // or
  682. // This Fcb is for a share owned by another LogonId.
  683. //
  684. Fcb = NULL;
  685. }
  686. }
  687. try {
  688. if ( Fcb != NULL ) {
  689. DebugTrace(0, Dbg, "Found existing FCB = %08lx\n", Fcb);
  690. } else {
  691. Fcb = NwCreateFcb( &FullName, Scb, Vcb );
  692. DebugTrace(0, Dbg, "Created new FCB = %08lx\n", Fcb);
  693. }
  694. } finally {
  695. if ( FullName.Buffer != NULL ) {
  696. FREE_POOL( FullName.Buffer );
  697. }
  698. NwReleaseRcb( &NwRcb );
  699. }
  700. ASSERT( Fcb == NULL || Fcb->Scb == Scb );
  701. DebugTrace(-1, Dbg, "NwFindFcb\n", 0);
  702. return( Fcb );
  703. }
  704. VOID
  705. NwDereferenceFcb(
  706. IN PIRP_CONTEXT IrpContext OPTIONAL,
  707. IN PFCB Fcb
  708. )
  709. /*++
  710. Routine Description:
  711. This routine decrement the ICB count for an FCB. If the count
  712. goes to zero, cleanup the FCB.
  713. *** This routine must be called with the RCB held exclusively.
  714. Arguments:
  715. FCB - A pointer to an FCB.
  716. Return Value:
  717. None.
  718. --*/
  719. {
  720. PNONPAGED_FCB NpFcb;
  721. PLIST_ENTRY listEntry, nextListEntry;
  722. PNW_FILE_LOCK pFileLock;
  723. PAGED_CODE();
  724. DebugTrace(+1, Dbg, "NwDereferenceFcb\n", 0);
  725. DebugTrace(0, Dbg, "New ICB count = %d\n", Fcb->IcbCount-1 );
  726. ASSERT( NodeType( Fcb ) == NW_NTC_FCB ||
  727. NodeType( Fcb ) == NW_NTC_DCB );
  728. if ( --Fcb->IcbCount == 0 ) {
  729. NpFcb = Fcb->NonPagedFcb;
  730. ASSERT( IsListEmpty( &Fcb->IcbList ) );
  731. //
  732. // If there are outstanding locks, clean them up. This
  733. // happens when something causes a remote handle to get
  734. // closed before the cleanup routine is called by the
  735. // ios on the regular close path.
  736. //
  737. if ( !IsListEmpty( &NpFcb->FileLockList ) ) {
  738. DebugTrace( 0, Dbg, "Freeing stray locks on FCB %08lx\n", NpFcb );
  739. for ( listEntry = NpFcb->FileLockList.Flink;
  740. listEntry != &NpFcb->FileLockList;
  741. listEntry = nextListEntry ) {
  742. nextListEntry = listEntry->Flink;
  743. pFileLock = CONTAINING_RECORD( listEntry,
  744. NW_FILE_LOCK,
  745. ListEntry );
  746. RemoveEntryList( listEntry );
  747. FREE_POOL( pFileLock );
  748. }
  749. }
  750. if ( !IsListEmpty( &NpFcb->PendingLockList ) ) {
  751. DebugTrace( 0, Dbg, "Freeing stray pending locks on FCB %08lx\n", NpFcb );
  752. for ( listEntry = NpFcb->PendingLockList.Flink;
  753. listEntry != &NpFcb->PendingLockList;
  754. listEntry = nextListEntry ) {
  755. nextListEntry = listEntry->Flink;
  756. pFileLock = CONTAINING_RECORD( listEntry,
  757. NW_FILE_LOCK,
  758. ListEntry );
  759. RemoveEntryList( listEntry );
  760. FREE_POOL( pFileLock );
  761. }
  762. }
  763. //
  764. // Delete the file now, if it is delete pending.
  765. //
  766. if ( BooleanFlagOn( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE ) ) {
  767. NwDeleteFile( IrpContext );
  768. }
  769. //
  770. // Remove this file in the prefix table.
  771. //
  772. RtlRemoveUnicodePrefix(
  773. &NwRcb.FileNameTable,
  774. &Fcb->PrefixEntry );
  775. //
  776. // Remove this file from the SCB list, and decrement the
  777. // file open count.
  778. //
  779. RemoveEntryList( &Fcb->FcbListEntry );
  780. NwDereferenceVcb( Fcb->Vcb, IrpContext, TRUE );
  781. //
  782. // Delete the resource variable for the FCB.
  783. //
  784. ExDeleteResourceLite( &NpFcb->Resource );
  785. //
  786. // Delete the cache buffer and MDL.
  787. //
  788. if ( NpFcb->CacheBuffer != NULL ) {
  789. FREE_POOL( NpFcb->CacheBuffer );
  790. FREE_MDL( NpFcb->CacheMdl );
  791. }
  792. //
  793. // Finally free the paged and non-paged memory
  794. //
  795. FREE_POOL( Fcb );
  796. FREE_POOL( NpFcb );
  797. }
  798. DebugTrace(-1, Dbg, "NwDereferenceFcb\n", 0);
  799. }
  800. PVCB
  801. NwFindVcb (
  802. IN PIRP_CONTEXT IrpContext,
  803. IN PUNICODE_STRING VolumeName,
  804. IN ULONG ShareType,
  805. IN WCHAR DriveLetter,
  806. IN BOOLEAN ExplicitConnection,
  807. IN BOOLEAN FindExisting
  808. )
  809. /*++
  810. Routine Description:
  811. This routine looks for a VCB structure. If one is found, it
  812. is referenced and a pointer is returned. If no VCB is found, an
  813. attempt is made to connect to the named volume and to create a VCB.
  814. Arguments:
  815. IrpContext - A pointer to the IRP context block for this request.
  816. VolumeName - The minimum name of the volume. This will be in one of
  817. the following forms:
  818. \SERVER\SHARE UNC open server volume
  819. \TREE\VOLUME UNC open tree volume in current context
  820. \TREE\PATH.TO.VOLUME UNC open distinguished tree volume
  821. \X:\SERVER\SHARE tree connect server volume
  822. \X:\TREE\VOLUME tree connect tree volume in current context
  823. \X:\TREE\PATH.TO.VOLUME tree connect distinguished tree volume
  824. ShareType - The type of the share to find.
  825. DriveLetter - The drive letter to find. A - Z for drive letter, 1 - 9
  826. for LPT ports or 0 if none.
  827. ExplicitConnection - If TRUE, the caller is make an explicit connection
  828. to this Volume. If FALSE, this is an implicit connection made by
  829. a UNC operation.
  830. Return Value:
  831. VCB - Pointer to a found or newly created VCB.
  832. --*/
  833. {
  834. PVCB Vcb = NULL;
  835. BOOLEAN OwnRcb = TRUE;
  836. PUNICODE_PREFIX_TABLE_ENTRY Prefix;
  837. UNICODE_STRING UidVolumeName;
  838. PNONPAGED_SCB pNpScb = IrpContext->pScb->pNpScb;
  839. PAGED_CODE();
  840. UidVolumeName.Buffer = NULL;
  841. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  842. try {
  843. MergeStrings( &UidVolumeName,
  844. &IrpContext->pScb->UnicodeUid,
  845. VolumeName,
  846. PagedPool );
  847. DebugTrace(+1, Dbg, "NwFindVcb %wZ\n", &UidVolumeName );
  848. if ( DriveLetter != 0 ) {
  849. //
  850. // This is a drive relative path. Look up the drive letter.
  851. //
  852. ASSERT( ( DriveLetter >= L'A' && DriveLetter <= L'Z' ) ||
  853. ( DriveLetter >= L'1' && DriveLetter <= L'9' ) );
  854. if ( DriveLetter >= L'A' && DriveLetter <= L'Z' ) {
  855. PVCB * DriveMapTable = GetDriveMapTable( IrpContext->Specific.Create.UserUid );
  856. Vcb = DriveMapTable[DriveLetter - L'A'];
  857. } else {
  858. PVCB * DriveMapTable = GetDriveMapTable( IrpContext->Specific.Create.UserUid );
  859. Vcb = DriveMapTable[MAX_DISK_REDIRECTIONS + DriveLetter - L'1'];
  860. }
  861. //
  862. // Was the Vcb created for this user?
  863. //
  864. if ((Vcb != NULL) &&
  865. (IrpContext->Specific.Create.UserUid.QuadPart != Vcb->Scb->UserUid.QuadPart )) {
  866. ExRaiseStatus( STATUS_ACCESS_DENIED );
  867. }
  868. } else {
  869. //
  870. // This is a UNC path. Look up the path name.
  871. //
  872. Prefix = RtlFindUnicodePrefix( &NwRcb.VolumeNameTable, &UidVolumeName, 0 );
  873. if ( Prefix != NULL ) {
  874. Vcb = CONTAINING_RECORD( Prefix, VCB, PrefixEntry );
  875. if ( Vcb->Name.Length != UidVolumeName.Length ) {
  876. //
  877. // This was not an exact match. Ignore it.
  878. //
  879. Vcb = NULL;
  880. }
  881. }
  882. }
  883. if ( Vcb != NULL ) {
  884. //
  885. // If this is an explicit use to a UNC path, we may find an
  886. // existing VCB structure. Mark this structure, and reference it.
  887. //
  888. if ( !BooleanFlagOn( Vcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION ) &&
  889. ExplicitConnection ) {
  890. NwReferenceVcb( Vcb );
  891. SetFlag( Vcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION );
  892. SetFlag( Vcb->Flags, VCB_FLAG_DELETE_IMMEDIATELY );
  893. //
  894. // Count this as an open file on the SCB.
  895. //
  896. ++Vcb->Scb->OpenFileCount;
  897. }
  898. NwReferenceVcb( Vcb );
  899. DebugTrace(0, Dbg, "Found existing VCB = %08lx\n", Vcb);
  900. //
  901. // If this VCB is queued to a different SCB as may
  902. // happen when we are resolving NDS UNC names, we
  903. // need to re-point the irpcontext at the correct SCB.
  904. // We can't hold the RCB or the open lock while we do
  905. // this!
  906. //
  907. // It is ok to release the open lock since we know
  908. // that we have an already created VCB and that we're
  909. // not creating a new vcb.
  910. //
  911. if ( Vcb->Scb != IrpContext->pScb ) {
  912. NwReferenceScb( Vcb->Scb->pNpScb );
  913. NwReleaseOpenLock( );
  914. NwReleaseRcb( &NwRcb );
  915. OwnRcb = FALSE;
  916. NwDequeueIrpContext( IrpContext, FALSE );
  917. NwDereferenceScb( IrpContext->pNpScb );
  918. IrpContext->pScb = Vcb->Scb;
  919. IrpContext->pNpScb = Vcb->Scb->pNpScb;
  920. NwAppendToQueueAndWait( IrpContext );
  921. NwAcquireOpenLock( );
  922. }
  923. } else if ( !FindExisting ) {
  924. //
  925. // Can't hold the RCB while creating a new VCB.
  926. //
  927. NwReleaseRcb( &NwRcb );
  928. OwnRcb = FALSE;
  929. Vcb = NwCreateVcb(
  930. IrpContext,
  931. IrpContext->pScb,
  932. &UidVolumeName,
  933. ShareType,
  934. DriveLetter,
  935. ExplicitConnection );
  936. if ( Vcb ) {
  937. DebugTrace(0, Dbg, "Created new VCB = %08lx\n", Vcb);
  938. }
  939. } else {
  940. //
  941. // If we didn't find anything and don't want
  942. // to do a create, make sure the caller doesn't
  943. // try to process the nds path.
  944. //
  945. IrpContext->Specific.Create.NeedNdsData = FALSE;
  946. }
  947. } finally {
  948. if ( OwnRcb ) {
  949. NwReleaseRcb( &NwRcb );
  950. }
  951. if (UidVolumeName.Buffer != NULL) {
  952. FREE_POOL( UidVolumeName.Buffer );
  953. }
  954. }
  955. DebugTrace(-1, Dbg, "NwFindVcb\n", 0);
  956. return( Vcb );
  957. }
  958. PVCB
  959. NwCreateVcb (
  960. IN PIRP_CONTEXT IrpContext,
  961. IN PSCB Scb,
  962. IN PUNICODE_STRING VolumeName,
  963. IN ULONG ShareType,
  964. IN WCHAR DriveLetter,
  965. IN BOOLEAN ExplicitConnection
  966. )
  967. /*++
  968. Routine Description:
  969. This routine allocates and initialize a new VCB. The
  970. workstation tries to connect to the Volume. If successful
  971. it creates a VCB and it is inserted into the volume
  972. prefix table.
  973. Arguments:
  974. IrpContext - A pointer to IRP context information.
  975. Scb - A pointer to the SCB for this volume.
  976. VolumeName - The name of the volume to create.
  977. ShareType - The type of share to create.
  978. DriveLetter - The drive letter assigned to this volume, or 0 if none.
  979. ExplicitConnection - TRUE if we are creating this VCB due to an
  980. add connection request. FALSE if we are creating the VCB to
  981. service a UNC request.
  982. Return Value:
  983. VCB - A pointer to the newly created DCB.
  984. NULL - Could not create a DCB, or failed to connect to the volume.
  985. --*/
  986. {
  987. PVCB Vcb;
  988. PWCH VolumeNameBuffer;
  989. PWCH ShareNameBuffer;
  990. PWCH ConnectNameBuffer;
  991. UCHAR DirectoryHandle;
  992. ULONG QueueId;
  993. BYTE *pbQueue, *pbRQueue;
  994. BOOLEAN PrintQueue = FALSE;
  995. NTSTATUS Status;
  996. CHAR LongNameSpace = LFN_NO_OS2_NAME_SPACE;
  997. CHAR VolumeNumber = -1;
  998. CHAR DriveNumber = 0;
  999. USHORT PreludeLength, ConnectNameLength;
  1000. PNONPAGED_SCB NpScb = Scb->pNpScb;
  1001. UNICODE_STRING ShareName;
  1002. UNICODE_STRING LongShareName;
  1003. PWCH p;
  1004. BOOLEAN InsertedColon;
  1005. BOOLEAN LongName = FALSE;
  1006. BOOLEAN LicensedConnection = FALSE;
  1007. PUNICODE_STRING puConnectName;
  1008. PAGED_CODE();
  1009. DebugTrace(+1, Dbg, "NwCreateVcb\n", 0);
  1010. DebugTrace( 0, Dbg, " ->Server = %wZ\n", &NpScb->ServerName );
  1011. DebugTrace( 0, Dbg, " ->VolumeName = %wZ\n", VolumeName );
  1012. DebugTrace( 0, Dbg, " ->DriveLetter = %x\n", DriveLetter );
  1013. Vcb = NULL;
  1014. ShareName.Buffer = NULL;
  1015. if ( IrpContext != NULL &&
  1016. IrpContext->Specific.Create.NdsCreate ) {
  1017. //
  1018. // If we don't have the NDS data for this create, bail out
  1019. // and have the create thread get the data before re-attempting
  1020. // the create. This is kind of weird, but we have to do it
  1021. // so that we handle the open lock correctly and prevent
  1022. // duplicate creates.
  1023. //
  1024. if ( IrpContext->Specific.Create.NeedNdsData ) {
  1025. DebugTrace( -1, Dbg, "NwCreateVcb: Need NDS data to continue.\n", 0 );
  1026. return NULL;
  1027. }
  1028. ConnectNameLength = IrpContext->Specific.Create.UidConnectName.Length;
  1029. puConnectName = &IrpContext->Specific.Create.UidConnectName;
  1030. } else {
  1031. puConnectName = VolumeName;
  1032. ConnectNameLength = 0;
  1033. }
  1034. DebugTrace( 0, Dbg, " ->ConnectName = %wZ\n", puConnectName );
  1035. if ( IrpContext != NULL) {
  1036. //
  1037. // Build the share name from the volume name.
  1038. //
  1039. // The share name will either be 'volume:' or 'volume:path\path'
  1040. //
  1041. //
  1042. // Allocate space for the share name buffer, and copy the volume
  1043. // name to the share name buffer, skipping the server name and
  1044. // the leading backslash.
  1045. //
  1046. if ( DriveLetter >= L'A' && DriveLetter <= L'Z' ) {
  1047. if ( ShareType == RESOURCETYPE_PRINT ) {
  1048. ExRaiseStatus( STATUS_BAD_NETWORK_PATH );
  1049. } else if ( ShareType == RESOURCETYPE_ANY) {
  1050. ShareType = RESOURCETYPE_DISK;
  1051. }
  1052. PreludeLength = Scb->UidServerName.Length +
  1053. sizeof( L"X:") + sizeof(WCHAR);
  1054. } else if ( DriveLetter >= L'1' && DriveLetter <= L'9' ) {
  1055. if ( ShareType == RESOURCETYPE_DISK ) {
  1056. ExRaiseStatus( STATUS_BAD_NETWORK_PATH );
  1057. } else if ( ShareType == RESOURCETYPE_ANY) {
  1058. ShareType = RESOURCETYPE_PRINT;
  1059. }
  1060. PreludeLength = Scb->UidServerName.Length +
  1061. sizeof( L"LPTX") + sizeof(WCHAR);
  1062. } else {
  1063. PreludeLength = Scb->UidServerName.Length + sizeof(WCHAR);
  1064. }
  1065. //
  1066. // Quick check for bogus volume name.
  1067. //
  1068. if ( puConnectName->Length <= PreludeLength ) {
  1069. ExRaiseStatus( STATUS_BAD_NETWORK_PATH );
  1070. }
  1071. //
  1072. // Clip the NDS share name at the appropriate spot.
  1073. //
  1074. if ( IrpContext->Specific.Create.NdsCreate ) {
  1075. ShareName.Length = (USHORT)IrpContext->Specific.Create.dwNdsShareLength;
  1076. } else {
  1077. ShareName.Length = puConnectName->Length - PreludeLength;
  1078. }
  1079. ShareName.Buffer = ALLOCATE_POOL_EX( PagedPool, ShareName.Length + sizeof(WCHAR) );
  1080. RtlMoveMemory(
  1081. ShareName.Buffer,
  1082. puConnectName->Buffer + PreludeLength / sizeof(WCHAR),
  1083. ShareName.Length );
  1084. ShareName.MaximumLength = ShareName.Length;
  1085. DebugTrace( 0, Dbg, " ->ServerShare = %wZ\n", &ShareName );
  1086. //
  1087. // Create a long share name.
  1088. //
  1089. LongShareName.Length = ShareName.Length;
  1090. LongShareName.Buffer = puConnectName->Buffer + PreludeLength / sizeof(WCHAR);
  1091. //
  1092. // Now scan the share name for the 1st slash.
  1093. //
  1094. InsertedColon = FALSE;
  1095. for ( p = ShareName.Buffer; p < ShareName.Buffer + ShareName.Length/sizeof(WCHAR); p++ ) {
  1096. if ( *p == L'\\') {
  1097. *p = L':';
  1098. InsertedColon = TRUE;
  1099. break;
  1100. }
  1101. }
  1102. if ( !InsertedColon ) {
  1103. //
  1104. // We need to append a column to generate the share name.
  1105. // Since we already allocated an extra WCHAR of buffer space,
  1106. // just append the ':' to the share name.
  1107. //
  1108. ShareName.Buffer[ShareName.Length / sizeof(WCHAR)] = L':';
  1109. ShareName.Length += 2;
  1110. }
  1111. ASSERT( ShareType == RESOURCETYPE_ANY ||
  1112. ShareType == RESOURCETYPE_DISK ||
  1113. ShareType == RESOURCETYPE_PRINT );
  1114. //
  1115. // If there are no vcb's and no nds streams connected to this scb and
  1116. // this is a Netware 4.x server that is NDS authenticated, then we
  1117. // haven't yet licensed this connection and we should do so.
  1118. //
  1119. if ( ( IrpContext->pScb->MajorVersion > 3 ) &&
  1120. ( IrpContext->pScb->UserName.Length == 0 ) &&
  1121. ( IrpContext->pScb->VcbCount == 0 ) &&
  1122. ( IrpContext->pScb->OpenNdsStreams == 0 ) ) {
  1123. Status = NdsLicenseConnection( IrpContext );
  1124. if ( !NT_SUCCESS( Status ) ) {
  1125. ExRaiseStatus( STATUS_REMOTE_SESSION_LIMIT );
  1126. }
  1127. LicensedConnection = TRUE;
  1128. }
  1129. if ( ShareType == RESOURCETYPE_ANY ||
  1130. ShareType == RESOURCETYPE_DISK ) {
  1131. GetLongNameSpaceForVolume(
  1132. IrpContext,
  1133. ShareName,
  1134. &LongNameSpace,
  1135. &VolumeNumber );
  1136. //
  1137. // TRACKING: If this is the deref of a directory map, the path we have
  1138. // been provided may be the short name space path. We don't know
  1139. // how to get the long name path to connect up the long name space
  1140. // for the user, which could cause problems...
  1141. //
  1142. if ( ( IrpContext->Specific.Create.NdsCreate ) &&
  1143. ( IrpContext->Specific.Create.dwNdsObjectType == NDS_OBJECTTYPE_DIRMAP ) ) {
  1144. if ( ( LongNameSpace == LONG_NAME_SPACE_ORDINAL ) &&
  1145. ( IsFatNameValid( &LongShareName ) ) &&
  1146. ( !FavourLongNames ) ) {
  1147. LongNameSpace = LFN_NO_OS2_NAME_SPACE;
  1148. }
  1149. }
  1150. //
  1151. // Check to see if long names have been completely
  1152. // disabled in the registry...
  1153. //
  1154. if ( LongNameFlags & LFN_FLAG_DISABLE_LONG_NAMES ) {
  1155. LongNameSpace = LFN_NO_OS2_NAME_SPACE;
  1156. }
  1157. //
  1158. // Try to get a permanent handle to the volume.
  1159. //
  1160. if ( LongNameSpace == LFN_NO_OS2_NAME_SPACE ) {
  1161. DriveNumber = GetNewDriveNumber(Scb);
  1162. Status = ExchangeWithWait (
  1163. IrpContext,
  1164. SynchronousResponseCallback,
  1165. "SbbJ",
  1166. NCP_DIR_FUNCTION, NCP_ALLOCATE_DIR_HANDLE,
  1167. 0,
  1168. DriveNumber,
  1169. &ShareName );
  1170. if ( NT_SUCCESS( Status ) ) {
  1171. Status = ParseResponse(
  1172. IrpContext,
  1173. IrpContext->rsp,
  1174. IrpContext->ResponseLength,
  1175. "Nb",
  1176. &DirectoryHandle );
  1177. }
  1178. if ( !NT_SUCCESS( Status ) ) {
  1179. FreeDriveNumber( Scb, DriveNumber );
  1180. }
  1181. } else {
  1182. Status = ExchangeWithWait (
  1183. IrpContext,
  1184. SynchronousResponseCallback,
  1185. "LbbWbDbC",
  1186. NCP_LFN_ALLOCATE_DIR_HANDLE,
  1187. LongNameSpace,
  1188. 0,
  1189. 0, // Mode = permanent
  1190. VolumeNumber,
  1191. LFN_FLAG_SHORT_DIRECTORY,
  1192. 0xFF, // Flag
  1193. &LongShareName );
  1194. if ( NT_SUCCESS( Status ) ) {
  1195. Status = ParseResponse(
  1196. IrpContext,
  1197. IrpContext->rsp,
  1198. IrpContext->ResponseLength,
  1199. "Nb",
  1200. &DirectoryHandle );
  1201. }
  1202. //
  1203. // WARNING. See comment towards end of NwCreateFcb() !!!
  1204. //
  1205. if ( FavourLongNames || !IsFatNameValid( &LongShareName ) ) {
  1206. LongName = TRUE;
  1207. }
  1208. }
  1209. if ( ( Status == STATUS_NO_SUCH_DEVICE ) &&
  1210. ( ShareType != RESOURCETYPE_ANY ) ) {
  1211. //
  1212. // Asked for disk and it failed. If its ANY, then try print.
  1213. //
  1214. if (DriveNumber) {
  1215. FreeDriveNumber( Scb, DriveNumber );
  1216. }
  1217. FREE_POOL( ShareName.Buffer );
  1218. if ( LicensedConnection ) {
  1219. NdsUnlicenseConnection( IrpContext );
  1220. }
  1221. ExRaiseStatus( STATUS_BAD_NETWORK_NAME );
  1222. return( NULL );
  1223. }
  1224. }
  1225. if ( ShareType == RESOURCETYPE_PRINT ||
  1226. ( ShareType == RESOURCETYPE_ANY && !NT_SUCCESS( Status ) ) ) {
  1227. //
  1228. // Try to connect to a print queue. If this is a bindery
  1229. // server or an nds server with bindery emulation, we scan
  1230. // the bindery for the QueueId. Otherwise, the QueueId is
  1231. // simply the ds object id with the byte ordering reversed.
  1232. //
  1233. ShareName.Length -= sizeof(WCHAR);
  1234. if ( ( Scb->MajorVersion < 4 ) ||
  1235. ( !( IrpContext->Specific.Create.NdsCreate ) ) ) {
  1236. Status = ExchangeWithWait(
  1237. IrpContext,
  1238. SynchronousResponseCallback,
  1239. "SdwJ", // Format string
  1240. NCP_ADMIN_FUNCTION, NCP_SCAN_BINDERY_OBJECT,
  1241. -1, // Previous ID
  1242. OT_PRINT_QUEUE,
  1243. &ShareName ); // Queue Name
  1244. if ( !NT_SUCCESS( Status ) ) {
  1245. Status = ExchangeWithWait(
  1246. IrpContext,
  1247. SynchronousResponseCallback,
  1248. "SdwJ", // Format string
  1249. NCP_ADMIN_FUNCTION, NCP_SCAN_BINDERY_OBJECT,
  1250. -1, // Previous ID
  1251. OT_JOBQUEUE,
  1252. &ShareName ); // Queue Name
  1253. }
  1254. if ( NT_SUCCESS( Status ) ) {
  1255. Status = ParseResponse(
  1256. IrpContext,
  1257. IrpContext->rsp,
  1258. IrpContext->ResponseLength,
  1259. "Nd",
  1260. &QueueId );
  1261. }
  1262. } else {
  1263. if ( IrpContext->Specific.Create.dwNdsObjectType == NDS_OBJECTTYPE_QUEUE ) {
  1264. DebugTrace( 0, Dbg, "Mapping NDS print queue %08lx\n",
  1265. IrpContext->Specific.Create.dwNdsOid );
  1266. pbQueue = (BYTE *)&IrpContext->Specific.Create.dwNdsOid;
  1267. pbRQueue = (BYTE *)&QueueId;
  1268. pbRQueue[0] = pbQueue[3];
  1269. pbRQueue[1] = pbQueue[2];
  1270. pbRQueue[2] = pbQueue[1];
  1271. pbRQueue[3] = pbQueue[0];
  1272. Status = STATUS_SUCCESS;
  1273. } else {
  1274. DebugTrace( 0, Dbg, "Nds object is not a print queue.\n", 0 );
  1275. Status = STATUS_UNSUCCESSFUL;
  1276. }
  1277. }
  1278. PrintQueue = TRUE;
  1279. }
  1280. if ( !NT_SUCCESS( Status ) ) {
  1281. if (DriveNumber) {
  1282. FreeDriveNumber( Scb, DriveNumber );
  1283. }
  1284. FREE_POOL( ShareName.Buffer );
  1285. if ( LicensedConnection ) {
  1286. NdsUnlicenseConnection( IrpContext );
  1287. }
  1288. ExRaiseStatus( STATUS_BAD_NETWORK_PATH );
  1289. return( NULL );
  1290. }
  1291. } else {
  1292. DirectoryHandle = 1;
  1293. }
  1294. //
  1295. // Allocate and initialize structures.
  1296. //
  1297. try {
  1298. Vcb = ALLOCATE_POOL_EX( PagedPool, sizeof( VCB ) + // vcb
  1299. VolumeName->Length + // volume name
  1300. ShareName.Length + // share name
  1301. ConnectNameLength ); // connect name
  1302. RtlZeroMemory( Vcb, sizeof( VCB ) );
  1303. Vcb->NodeTypeCode = NW_NTC_VCB;
  1304. Vcb->NodeByteSize = sizeof( VCB ) +
  1305. VolumeName->Length +
  1306. ShareName.Length +
  1307. ConnectNameLength;
  1308. InitializeListHead( &Vcb->FcbList );
  1309. VolumeNameBuffer = (PWCH)(Vcb + 1);
  1310. ShareNameBuffer = (PWCH)((PCHAR)VolumeNameBuffer + VolumeName->Length);
  1311. ConnectNameBuffer = (PWCH)((PCHAR)ShareNameBuffer + ShareName.Length);
  1312. Vcb->Reference = 1;
  1313. //
  1314. // Copy the volume name
  1315. //
  1316. RtlCopyMemory( VolumeNameBuffer, VolumeName->Buffer, VolumeName->Length );
  1317. Vcb->Name.MaximumLength = VolumeName->Length;
  1318. Vcb->Name.Length = VolumeName->Length;
  1319. Vcb->Name.Buffer = VolumeNameBuffer;
  1320. //
  1321. // Copy the share name
  1322. //
  1323. if ( IrpContext != NULL) {
  1324. RtlCopyMemory( ShareNameBuffer, ShareName.Buffer, ShareName.Length );
  1325. Vcb->ShareName.MaximumLength = ShareName.Length;
  1326. Vcb->ShareName.Length = ShareName.Length;
  1327. Vcb->ShareName.Buffer = ShareNameBuffer;
  1328. }
  1329. //
  1330. // Copy the connect name
  1331. //
  1332. if ( ConnectNameLength ) {
  1333. RtlCopyMemory( ConnectNameBuffer,
  1334. IrpContext->Specific.Create.UidConnectName.Buffer,
  1335. IrpContext->Specific.Create.UidConnectName.Length );
  1336. Vcb->ConnectName.MaximumLength = IrpContext->Specific.Create.UidConnectName.Length;
  1337. Vcb->ConnectName.Length = IrpContext->Specific.Create.UidConnectName.Length;
  1338. Vcb->ConnectName.Buffer = ConnectNameBuffer;
  1339. }
  1340. if ( ExplicitConnection ) {
  1341. //
  1342. // Bump the reference count to account for this drive being
  1343. // mapped via an explicit connection.
  1344. //
  1345. NwReferenceVcb( Vcb );
  1346. SetFlag( Vcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION );
  1347. SetFlag( Vcb->Flags, VCB_FLAG_DELETE_IMMEDIATELY );
  1348. }
  1349. if ( LongName ) {
  1350. SetFlag( Vcb->Flags, VCB_FLAG_LONG_NAME );
  1351. }
  1352. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1353. if ( DriveLetter != 0) {
  1354. //
  1355. // Insert this VCB in the drive map table.
  1356. //
  1357. if ( DriveLetter >= 'A' && DriveLetter <= 'Z' ) {
  1358. PVCB * DriveMapTable = GetDriveMapTable( Scb->UserUid );
  1359. DriveMapTable[DriveLetter - 'A'] = Vcb;
  1360. } else {
  1361. PVCB * DriveMapTable = GetDriveMapTable( Scb->UserUid );
  1362. DriveMapTable[MAX_DISK_REDIRECTIONS + DriveLetter - '1'] = Vcb;
  1363. }
  1364. Vcb->DriveLetter = DriveLetter;
  1365. } else {
  1366. //
  1367. // Insert this VCB in the prefix table.
  1368. //
  1369. RtlInsertUnicodePrefix(
  1370. &NwRcb.VolumeNameTable,
  1371. &Vcb->Name,
  1372. &Vcb->PrefixEntry );
  1373. }
  1374. //
  1375. // Add this VCB to the global list.
  1376. //
  1377. InsertTailList( &GlobalVcbList, &Vcb->GlobalVcbListEntry );
  1378. Vcb->SequenceNumber = CurrentVcbEntry++;
  1379. //
  1380. // Insert this VCB in the per SCB list
  1381. //
  1382. Vcb->Scb = Scb;
  1383. InsertTailList( &Scb->ScbSpecificVcbQueue, &Vcb->VcbListEntry );
  1384. ++Scb->VcbCount;
  1385. NwReferenceScb( Scb->pNpScb );
  1386. if ( ExplicitConnection ) {
  1387. //
  1388. // Count this as an open file on the SCB.
  1389. //
  1390. ++Vcb->Scb->OpenFileCount;
  1391. }
  1392. //
  1393. // tommye - MS bug 71690- Calculate the path
  1394. //
  1395. if ( Vcb->DriveLetter >= L'A' && Vcb->DriveLetter <= L'Z' ) {
  1396. Vcb->Path.Buffer = Vcb->Name.Buffer + 3;
  1397. Vcb->Path.Length = Vcb->Name.Length - 6;
  1398. } else if ( Vcb->DriveLetter >= L'1' && Vcb->DriveLetter <= L'9' ) {
  1399. Vcb->Path.Buffer = Vcb->Name.Buffer + 5;
  1400. Vcb->Path.Length = Vcb->Name.Length - 10;
  1401. } else {
  1402. Vcb->Path = Vcb->Name;
  1403. }
  1404. // Strip off the unicode prefix
  1405. Vcb->Path.Buffer += Vcb->Scb->UnicodeUid.Length/sizeof(WCHAR);
  1406. Vcb->Path.Length -= Vcb->Scb->UnicodeUid.Length;
  1407. Vcb->Path.MaximumLength -= Vcb->Scb->UnicodeUid.Length;
  1408. if ( !PrintQueue) {
  1409. PLIST_ENTRY VcbQueueEntry;
  1410. PVCB pVcb;
  1411. Vcb->Specific.Disk.Handle = DirectoryHandle;
  1412. Vcb->Specific.Disk.LongNameSpace = LongNameSpace;
  1413. Vcb->Specific.Disk.VolumeNumber = VolumeNumber;
  1414. Vcb->Specific.Disk.DriveNumber = DriveNumber;
  1415. //
  1416. // Appears that some servers can reuse the same permanent drive handle.
  1417. // if this happens we want to make the old handle invalid otherwise
  1418. // we will keep on using the new volume as if its the old one.
  1419. //
  1420. for ( VcbQueueEntry = Scb->ScbSpecificVcbQueue.Flink;
  1421. VcbQueueEntry != &Scb->ScbSpecificVcbQueue;
  1422. VcbQueueEntry = pVcb->VcbListEntry.Flink ) {
  1423. pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
  1424. if ( !BooleanFlagOn( pVcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
  1425. if (( pVcb->Specific.Disk.Handle == DirectoryHandle ) &&
  1426. ( pVcb->Specific.Disk.VolumeNumber != VolumeNumber )) {
  1427. // Invalidate the old handle
  1428. pVcb->Specific.Disk.Handle = (CHAR)-1;
  1429. // We could assume that the new one is correct but I don't think we will....
  1430. Vcb->Specific.Disk.Handle = (CHAR)-1;
  1431. break;
  1432. }
  1433. }
  1434. }
  1435. } else {
  1436. SetFlag( Vcb->Flags, VCB_FLAG_PRINT_QUEUE );
  1437. Vcb->Specific.Print.QueueId = QueueId;
  1438. }
  1439. NwReleaseRcb( &NwRcb );
  1440. } finally {
  1441. if ( AbnormalTermination() ) {
  1442. if ( Vcb != NULL ) FREE_POOL( Vcb );
  1443. if ( LicensedConnection ) {
  1444. NdsUnlicenseConnection( IrpContext );
  1445. }
  1446. }
  1447. if ( ShareName.Buffer != NULL ) {
  1448. FREE_POOL( ShareName.Buffer );
  1449. }
  1450. DebugTrace(-1, Dbg, "NwCreateVcb %lx\n", Vcb);
  1451. }
  1452. return( Vcb );
  1453. }
  1454. VOID
  1455. NwReopenVcbHandlesForScb (
  1456. IN PIRP_CONTEXT IrpContext,
  1457. IN PSCB Scb
  1458. )
  1459. /*++
  1460. Routine Description:
  1461. This routine reopens VCB handles after the autoreconnects to a server.
  1462. *** This IrpContext must already be at the head of the SCB queue.
  1463. Arguments:
  1464. IrpContext - A pointer to IRP context information.
  1465. Scb - A pointer to the SCB for this volume.
  1466. Return Value:
  1467. None.
  1468. --*/
  1469. {
  1470. PLIST_ENTRY VcbQueueEntry, NextVcbQueueEntry;
  1471. PVCB pVcb;
  1472. PLIST_ENTRY FcbQueueEntry;
  1473. PLIST_ENTRY IcbQueueEntry;
  1474. PFCB pFcb;
  1475. PICB pIcb;
  1476. NTSTATUS Status;
  1477. PAGED_CODE();
  1478. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1479. //
  1480. // Walk the list of VCBs for this SCB
  1481. //
  1482. for ( VcbQueueEntry = Scb->ScbSpecificVcbQueue.Flink;
  1483. VcbQueueEntry != &Scb->ScbSpecificVcbQueue;
  1484. VcbQueueEntry = NextVcbQueueEntry ) {
  1485. pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
  1486. if ( pVcb->Specific.Disk.Handle != 1 ) {
  1487. //
  1488. // Skip reconnecting SYS:LOGIN, since we get it for free.
  1489. //
  1490. //
  1491. // Reference the VCB so it can't disappear on us, then release
  1492. // the RCB.
  1493. //
  1494. NwReferenceVcb( pVcb );
  1495. NwReleaseRcb( &NwRcb );
  1496. //
  1497. // Try to get a permanent handle to the volume.
  1498. //
  1499. if ( BooleanFlagOn( pVcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
  1500. Status = ExchangeWithWait(
  1501. IrpContext,
  1502. SynchronousResponseCallback,
  1503. "SdwU", // Format string
  1504. NCP_ADMIN_FUNCTION, NCP_SCAN_BINDERY_OBJECT,
  1505. -1, // Previous ID
  1506. OT_PRINT_QUEUE,
  1507. &pVcb->ShareName ); // Queue Name
  1508. if ( NT_SUCCESS( Status ) ) {
  1509. Status = ParseResponse(
  1510. IrpContext,
  1511. IrpContext->rsp,
  1512. IrpContext->ResponseLength,
  1513. "Nd",
  1514. &pVcb->Specific.Print.QueueId );
  1515. }
  1516. } else {
  1517. NwReopenVcbHandle( IrpContext, pVcb);
  1518. }
  1519. //
  1520. // Setup for the next loop iteration.
  1521. //
  1522. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1523. //
  1524. // Walk the list of DCSs for this VCB and make them all valid.
  1525. //
  1526. for ( FcbQueueEntry = pVcb->FcbList.Flink;
  1527. FcbQueueEntry != &pVcb->FcbList;
  1528. FcbQueueEntry = FcbQueueEntry->Flink ) {
  1529. pFcb = CONTAINING_RECORD( FcbQueueEntry, FCB, FcbListEntry );
  1530. if ( pFcb->NodeTypeCode == NW_NTC_DCB ) {
  1531. //
  1532. // Walk the list of ICBs for this FCB or DCB
  1533. //
  1534. for ( IcbQueueEntry = pFcb->IcbList.Flink;
  1535. IcbQueueEntry != &pFcb->IcbList;
  1536. IcbQueueEntry = IcbQueueEntry->Flink ) {
  1537. pIcb = CONTAINING_RECORD( IcbQueueEntry, ICB, ListEntry );
  1538. //
  1539. // Mark the ICB handle invalid.
  1540. //
  1541. pIcb->State = ICB_STATE_OPENED;
  1542. }
  1543. }
  1544. }
  1545. }
  1546. NextVcbQueueEntry = VcbQueueEntry->Flink;
  1547. if ( pVcb->Specific.Disk.Handle != 1 ) {
  1548. NwDereferenceVcb( pVcb, NULL, TRUE );
  1549. }
  1550. }
  1551. NwReleaseRcb( &NwRcb );
  1552. }
  1553. VOID
  1554. NwReopenVcbHandle(
  1555. IN PIRP_CONTEXT IrpContext,
  1556. IN PVCB Vcb
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. This routine reopens a VCB handle after it appears that the server
  1561. may have dismounted and remounted the volume.
  1562. *** This IrpContext must already be at the head of the SCB queue.
  1563. Arguments:
  1564. IrpContext - A pointer to IRP context information.
  1565. Vcb - A pointer to the VCB for this volume.
  1566. Return Value:
  1567. None.
  1568. --*/
  1569. {
  1570. NTSTATUS Status;
  1571. PAGED_CODE();
  1572. ASSERT( Vcb->Scb->pNpScb->Requests.Flink == &IrpContext->NextRequest );
  1573. if ( Vcb->Specific.Disk.LongNameSpace == LFN_NO_OS2_NAME_SPACE ) {
  1574. Status = ExchangeWithWait (
  1575. IrpContext,
  1576. SynchronousResponseCallback,
  1577. "SbbJ",
  1578. NCP_DIR_FUNCTION, NCP_ALLOCATE_DIR_HANDLE,
  1579. 0,
  1580. Vcb->Specific.Disk.DriveNumber,
  1581. &Vcb->ShareName );
  1582. } else {
  1583. UNICODE_STRING Name;
  1584. PWCH thisChar, lastChar;
  1585. Status = DuplicateUnicodeStringWithString (
  1586. &Name,
  1587. &Vcb->ShareName,
  1588. PagedPool);
  1589. if ( !NT_SUCCESS( Status ) ) {
  1590. // Not much we can do now.
  1591. return;
  1592. }
  1593. thisChar = Name.Buffer;
  1594. lastChar = &Name.Buffer[ Name.Length / sizeof(WCHAR) ];
  1595. //
  1596. // Change the : to a backslash so that FormatMessage works
  1597. //
  1598. while ( thisChar < lastChar ) {
  1599. if (*thisChar == L':' ) {
  1600. *thisChar = L'\\';
  1601. break;
  1602. }
  1603. thisChar++;
  1604. }
  1605. Status = ExchangeWithWait (
  1606. IrpContext,
  1607. SynchronousResponseCallback,
  1608. "LbbWbDbC",
  1609. NCP_LFN_ALLOCATE_DIR_HANDLE,
  1610. Vcb->Specific.Disk.LongNameSpace,
  1611. 0,
  1612. 0, // Mode = permanent
  1613. Vcb->Specific.Disk.VolumeNumber,
  1614. LFN_FLAG_SHORT_DIRECTORY,
  1615. 0xFF, // Flag
  1616. &Name );
  1617. if ( Name.Buffer != NULL ) {
  1618. FREE_POOL( Name.Buffer );
  1619. }
  1620. }
  1621. if ( NT_SUCCESS( Status ) ) {
  1622. Status = ParseResponse(
  1623. IrpContext,
  1624. IrpContext->rsp,
  1625. IrpContext->ResponseLength,
  1626. "Nb",
  1627. &Vcb->Specific.Disk.Handle );
  1628. }
  1629. if ( !NT_SUCCESS( Status ) ) {
  1630. Vcb->Specific.Disk.Handle = (CHAR)-1;
  1631. } else {
  1632. PLIST_ENTRY VcbQueueEntry;
  1633. PVCB pVcb;
  1634. //
  1635. // Appears that some servers can reuse the same permanent drive handle.
  1636. // if this happens we want to make the old handle invalid otherwise
  1637. // we will keep on using the new volume as if its the old one.
  1638. //
  1639. // Note that we reach the scb pointer from the npscb pointer because
  1640. // the scb pointer isn't always valid. These few cases where only one
  1641. // pointer is set should be found and fixed.
  1642. //
  1643. for ( VcbQueueEntry = IrpContext->pNpScb->pScb->ScbSpecificVcbQueue.Flink;
  1644. VcbQueueEntry != &IrpContext->pNpScb->pScb->ScbSpecificVcbQueue;
  1645. VcbQueueEntry = pVcb->VcbListEntry.Flink ) {
  1646. pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
  1647. if ( !BooleanFlagOn( pVcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
  1648. if (( pVcb->Specific.Disk.Handle == Vcb->Specific.Disk.Handle ) &&
  1649. ( pVcb->Specific.Disk.VolumeNumber != Vcb->Specific.Disk.VolumeNumber )) {
  1650. // Invalidate the old handle
  1651. pVcb->Specific.Disk.Handle = (CHAR)-1;
  1652. // We could assume that the new one is correct but I don't think we will....
  1653. Vcb->Specific.Disk.Handle = (CHAR)-1;
  1654. break;
  1655. }
  1656. }
  1657. }
  1658. }
  1659. }
  1660. #ifdef NWDBG
  1661. VOID
  1662. NwReferenceVcb (
  1663. IN PVCB Vcb
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. This routine increments the FCB count for a VCB.
  1668. Arguments:
  1669. VCB - A pointer to an VCB.
  1670. Return Value:
  1671. None.
  1672. --*/
  1673. {
  1674. PAGED_CODE();
  1675. DebugTrace(+1, Dbg, "NwReferenceVcb %08lx\n", Vcb);
  1676. DebugTrace(0, Dbg, "Current Reference count = %d\n", Vcb->Reference );
  1677. ASSERT( NodeType( Vcb ) == NW_NTC_VCB );
  1678. ++Vcb->Reference;
  1679. }
  1680. #endif
  1681. VOID
  1682. NwDereferenceVcb (
  1683. IN PVCB Vcb,
  1684. IN PIRP_CONTEXT IrpContext OPTIONAL,
  1685. IN BOOLEAN OwnRcb
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. This routine decrement the FCB count for a VCB.
  1690. If the count goes to zero, we record the time. The scavenger
  1691. thread will cleanup delete the VCB if it remains idle.
  1692. This routine may be called with the RCB owned and the irpcontext
  1693. at the head of the queue. Be careful when dequeueing the irp
  1694. context or acquiring any resources!
  1695. Arguments:
  1696. VCB - A pointer to an VCB.
  1697. Return Value:
  1698. None.
  1699. --*/
  1700. {
  1701. PSCB Scb = Vcb->Scb;
  1702. PNONPAGED_SCB pOrigNpScb = NULL;
  1703. #ifdef NWDBG
  1704. BOOLEAN OwnRcbExclusive = FALSE;
  1705. #endif
  1706. PAGED_CODE();
  1707. DebugTrace(+1, Dbg, "NwDereferenceVcb %08lx\n", Vcb);
  1708. ASSERT( NodeType( Vcb ) == NW_NTC_VCB );
  1709. #ifdef NWDBG
  1710. //
  1711. // A little extra lock checking.
  1712. //
  1713. OwnRcbExclusive = ExIsResourceAcquiredExclusiveLite( &(NwRcb.Resource) );
  1714. if ( OwnRcb ) {
  1715. ASSERT( OwnRcbExclusive );
  1716. } else {
  1717. ASSERT( !OwnRcbExclusive );
  1718. }
  1719. #endif
  1720. //
  1721. // We have to get to the right scb queue before doing this
  1722. // so that CleanupVcb unlicenses the correct connection.
  1723. //
  1724. if ( ( IrpContext ) &&
  1725. ( IrpContext->pNpScb->pScb->MajorVersion > 3 ) &&
  1726. ( IrpContext->pNpScb != Scb->pNpScb ) ) {
  1727. if ( OwnRcb ) {
  1728. NwReleaseRcb( &NwRcb );
  1729. }
  1730. pOrigNpScb = IrpContext->pNpScb;
  1731. ASSERT( pOrigNpScb != NULL );
  1732. NwDequeueIrpContext( IrpContext, FALSE );
  1733. IrpContext->pScb = Scb;
  1734. IrpContext->pNpScb = Scb->pNpScb;
  1735. NwAppendToQueueAndWait( IrpContext );
  1736. //
  1737. // If the caller owned the RCB, we have to make sure
  1738. // we re-acquire the RCB reference that we freed for
  1739. // them so that they don't lose access to the resource
  1740. // too early.
  1741. //
  1742. if ( OwnRcb ) {
  1743. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1744. }
  1745. }
  1746. //
  1747. // Acquire the lock to protect the Reference count.
  1748. //
  1749. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1750. DebugTrace(0, Dbg, "Current Reference count = %d\n", Vcb->Reference );
  1751. --Vcb->Reference;
  1752. if ( Vcb->Reference == 0 ) {
  1753. if ( !BooleanFlagOn( Vcb->Flags, VCB_FLAG_DELETE_IMMEDIATELY ) ||
  1754. IrpContext == NULL ) {
  1755. //
  1756. // Either this is a UNC path, or we don't have an IRP context
  1757. // to do the VCB cleanup. Simply timestamp the VCB and the
  1758. // scavenger will cleanup if the VCB remains idle.
  1759. //
  1760. KeQuerySystemTime( &Vcb->LastUsedTime );
  1761. NwReleaseRcb( &NwRcb );
  1762. } else {
  1763. //
  1764. // This VCB is being explicitly deleted by the user.
  1765. // Make it go away now. This will release the RCB.
  1766. //
  1767. NwCleanupVcb( Vcb, IrpContext );
  1768. }
  1769. } else {
  1770. NwReleaseRcb( &NwRcb );
  1771. }
  1772. //
  1773. // At this point, we've released our acquisition of the RCB, but
  1774. // the caller may still own the RCB. To prevent a deadlock, we
  1775. // have to be careful when we put this irpcontext back on the
  1776. // original server.
  1777. //
  1778. if ( pOrigNpScb ) {
  1779. if ( OwnRcb ) {
  1780. NwReleaseRcb( &NwRcb );
  1781. }
  1782. NwDequeueIrpContext( IrpContext, FALSE );
  1783. IrpContext->pNpScb = pOrigNpScb;
  1784. IrpContext->pScb = pOrigNpScb->pScb;
  1785. NwAppendToQueueAndWait( IrpContext );
  1786. //
  1787. // Re-acquire for the caller.
  1788. //
  1789. if ( OwnRcb ) {
  1790. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1791. }
  1792. }
  1793. DebugTrace(-1, Dbg, "NwDereferenceVcb\n", 0);
  1794. }
  1795. VOID
  1796. NwCleanupVcb(
  1797. IN PVCB pVcb,
  1798. IN PIRP_CONTEXT IrpContext
  1799. )
  1800. /*++
  1801. Routine Description:
  1802. This routine cleans up and frees a VCB.
  1803. This routine must be called with the RCB held to
  1804. protect the drive map tables and unicode prefix
  1805. tables. The caller must own the IRP context at
  1806. the head of the SCB queue. This routine will
  1807. free the RCB and dequeue the irp context.
  1808. Arguments:
  1809. pVcb - A pointer to the VCB to free.
  1810. Return Value:
  1811. None.
  1812. --*/
  1813. {
  1814. NTSTATUS Status;
  1815. CHAR Handle;
  1816. BOOLEAN CallDeleteScb = FALSE;
  1817. PSCB pScb = pVcb->Scb;
  1818. PNONPAGED_SCB pNpScb = pScb->pNpScb;
  1819. PAGED_CODE();
  1820. DebugTrace(+1, Dbg, "NwCleanupVcb...\n", 0);
  1821. ASSERT( pVcb->NodeTypeCode == NW_NTC_VCB );
  1822. ASSERT( IsListEmpty( &pVcb->FcbList ) );
  1823. ASSERT( pVcb->OpenFileCount == 0 );
  1824. DebugTrace(0, Dbg, "Cleaning Vcb %08lx\n", pVcb);
  1825. //
  1826. // Remove the VCB from the drive map table. The RCB is owned, so
  1827. // the drive map table and vcb lists are protected.
  1828. //
  1829. if ( pVcb->DriveLetter != 0 ) {
  1830. PVCB * DriveMapTable = GetDriveMapTable( pScb->UserUid );
  1831. if ( pVcb->DriveLetter >= L'A' && pVcb->DriveLetter <= L'Z' ) {
  1832. DriveMapTable[pVcb->DriveLetter - L'A'] = NULL;
  1833. } else {
  1834. DriveMapTable[MAX_DISK_REDIRECTIONS + pVcb->DriveLetter - L'1'] = NULL;
  1835. }
  1836. if ( !BooleanFlagOn( pVcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
  1837. FreeDriveNumber( pVcb->Scb, pVcb->Specific.Disk.DriveNumber );
  1838. }
  1839. }
  1840. //
  1841. // Remove the VCB from the Volume Name table.
  1842. //
  1843. RtlRemoveUnicodePrefix ( &NwRcb.VolumeNameTable, &pVcb->PrefixEntry );
  1844. //
  1845. // Remove the VCB from the global list
  1846. //
  1847. RemoveEntryList( &pVcb->GlobalVcbListEntry );
  1848. //
  1849. // Remove the VCB from our SCB's VCB list.
  1850. //
  1851. RemoveEntryList( &pVcb->VcbListEntry );
  1852. --pScb->VcbCount;
  1853. //
  1854. // There is no server jumping allowed!! We should have
  1855. // pre-located the correct server to avoid deadlock problems.
  1856. //
  1857. ASSERT( IrpContext->pNpScb == pNpScb );
  1858. //
  1859. // If we are cleaning up the last vcb on an NDS server and
  1860. // there are no open streams, we can unlicense the connection.
  1861. //
  1862. if ( ( pScb->MajorVersion > 3 ) &&
  1863. ( pScb->UserName.Length == 0 ) &&
  1864. ( pScb->VcbCount == 0 ) &&
  1865. ( pScb->OpenNdsStreams == 0 ) ) {
  1866. NdsUnlicenseConnection( IrpContext );
  1867. }
  1868. //
  1869. // If this is a VCB for a share, remove the volume handle.
  1870. //
  1871. if ( !BooleanFlagOn( pVcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
  1872. Handle = pVcb->Specific.Disk.Handle;
  1873. Status = ExchangeWithWait (
  1874. IrpContext,
  1875. SynchronousResponseCallback,
  1876. "Sb",
  1877. NCP_DIR_FUNCTION, NCP_DEALLOCATE_DIR_HANDLE,
  1878. Handle );
  1879. if ( NT_SUCCESS( Status )) {
  1880. Status = ParseResponse(
  1881. IrpContext,
  1882. IrpContext->rsp,
  1883. IrpContext->ResponseLength,
  1884. "N" );
  1885. }
  1886. }
  1887. //
  1888. // We can now free the VCB memory.
  1889. //
  1890. FREE_POOL( pVcb );
  1891. //
  1892. // If there are no handles open (and hence no explicit connections)
  1893. // and this is a bindery login, then we should logout and disconnect
  1894. // from this server. This is most important when a user has a
  1895. // login count on a server set to 1 and wants to access the server
  1896. // from another machine.
  1897. //
  1898. // Release the RCB in case we get off the head of the queue in
  1899. // NwLogoffAndDisconnect.
  1900. //
  1901. NwReleaseRcb( &NwRcb );
  1902. if ( ( pScb->IcbCount == 0 ) &&
  1903. ( pScb->OpenFileCount == 0 ) &&
  1904. ( pNpScb->State == SCB_STATE_IN_USE ) &&
  1905. ( pScb->UserName.Length != 0 ) ) {
  1906. NwLogoffAndDisconnect( IrpContext, pNpScb );
  1907. }
  1908. //
  1909. // We might need to restore the server pointers.
  1910. //
  1911. NwDequeueIrpContext( IrpContext, FALSE );
  1912. NwDereferenceScb( pScb->pNpScb );
  1913. DebugTrace(-1, Dbg, "NwCleanupVcb exit\n", 0);
  1914. return;
  1915. }
  1916. VOID
  1917. NwCloseAllVcbs(
  1918. PIRP_CONTEXT pIrpContext
  1919. )
  1920. /*++
  1921. Routine Description:
  1922. This routine sends closes all open VCB handles.
  1923. Arguments:
  1924. pIrpContext - The IRP context for this request.
  1925. Return Value:
  1926. none.
  1927. --*/
  1928. {
  1929. KIRQL OldIrql;
  1930. PLIST_ENTRY ScbQueueEntry, NextScbQueueEntry;
  1931. PLIST_ENTRY VcbQueueEntry, NextVcbQueueEntry;
  1932. PNONPAGED_SCB pNpScb;
  1933. PSCB pScb;
  1934. PVCB pVcb;
  1935. BOOLEAN VcbDeleted;
  1936. PAGED_CODE();
  1937. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  1938. ScbQueueEntry = ScbQueue.Flink;
  1939. if (ScbQueueEntry != &ScbQueue) {
  1940. PNONPAGED_SCB pNpScb = CONTAINING_RECORD(ScbQueueEntry,
  1941. NONPAGED_SCB,
  1942. ScbLinks);
  1943. NwReferenceScb( pNpScb );
  1944. }
  1945. for (;
  1946. ScbQueueEntry != &ScbQueue ;
  1947. ScbQueueEntry = NextScbQueueEntry ) {
  1948. pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
  1949. NextScbQueueEntry = pNpScb->ScbLinks.Flink;
  1950. //
  1951. // Reference the next entry in the list before letting go of the ScbSpinLock
  1952. // to ensure that the scavenger doesn't destroy it.
  1953. //
  1954. if (NextScbQueueEntry != &ScbQueue) {
  1955. PNONPAGED_SCB pNextNpScb = CONTAINING_RECORD(NextScbQueueEntry,
  1956. NONPAGED_SCB,
  1957. ScbLinks);
  1958. NwReferenceScb( pNextNpScb );
  1959. }
  1960. pScb = pNpScb->pScb;
  1961. if ( pScb == NULL ) {
  1962. NwDereferenceScb( pNpScb );
  1963. continue;
  1964. }
  1965. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  1966. //
  1967. // Get to the head of the SCB queue so that we don't deadlock
  1968. // if we need to send packets in NwCleanupVcb().
  1969. //
  1970. pIrpContext->pNpScb = pNpScb;
  1971. pIrpContext->pScb = pNpScb->pScb;
  1972. NwAppendToQueueAndWait( pIrpContext );
  1973. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  1974. //
  1975. // NwCleanupVcb releases the RCB, but we can't be guaranteed
  1976. // the state of the Vcb list when we release the RCB.
  1977. //
  1978. // If we need to cleanup a VCB, release the lock, and start
  1979. // processing the list again.
  1980. //
  1981. VcbDeleted = TRUE;
  1982. while ( VcbDeleted ) {
  1983. VcbDeleted = FALSE;
  1984. //
  1985. // Walk the list of VCBs for this SCB
  1986. //
  1987. for ( VcbQueueEntry = pScb->ScbSpecificVcbQueue.Flink;
  1988. VcbQueueEntry != &pScb->ScbSpecificVcbQueue;
  1989. VcbQueueEntry = NextVcbQueueEntry ) {
  1990. pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
  1991. NextVcbQueueEntry = VcbQueueEntry->Flink;
  1992. //
  1993. // If this VCB is mapped to a drive letter, delete the mapping
  1994. // now.
  1995. //
  1996. if ( BooleanFlagOn( pVcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION )) {
  1997. //
  1998. // Remove the VCB from the global list.
  1999. //
  2000. ClearFlag( pVcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION );
  2001. --pVcb->Reference;
  2002. --pVcb->Scb->OpenFileCount;
  2003. }
  2004. if ( pVcb->DriveLetter >= L'A' && pVcb->DriveLetter <= L'Z' ) {
  2005. PVCB * DriveMapTable = GetDriveMapTable( pScb->UserUid );
  2006. DriveMapTable[ pVcb->DriveLetter - 'A' ] = NULL;
  2007. } else if ( pVcb->DriveLetter >= L'1' && pVcb->DriveLetter <= L'9' ) {
  2008. PVCB * DriveMapTable = GetDriveMapTable( pScb->UserUid );
  2009. DriveMapTable[ MAX_DISK_REDIRECTIONS + pVcb->DriveLetter - '1' ] = NULL;
  2010. } else {
  2011. ASSERT( pVcb->DriveLetter == 0 );
  2012. }
  2013. if ( pVcb->Reference == 0 ) {
  2014. NwCleanupVcb( pVcb, pIrpContext );
  2015. //
  2016. // Get back to the head of the queue.
  2017. //
  2018. NwAppendToQueueAndWait( pIrpContext );
  2019. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  2020. VcbDeleted = TRUE;
  2021. break;
  2022. } else {
  2023. SetFlag( pVcb->Flags, VCB_FLAG_DELETE_IMMEDIATELY );
  2024. }
  2025. }
  2026. }
  2027. //
  2028. // Get off the head of this SCB and move on.
  2029. //
  2030. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  2031. NwDequeueIrpContext( pIrpContext, TRUE );
  2032. NwReleaseRcb( &NwRcb );
  2033. NwDereferenceScb( pNpScb );
  2034. }
  2035. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  2036. }
  2037. BOOLEAN
  2038. GetLongNameSpaceForVolume(
  2039. IN PIRP_CONTEXT IrpContext,
  2040. IN UNICODE_STRING ShareName,
  2041. OUT PCHAR VolumeLongNameSpace,
  2042. OUT PCHAR VolumeNumber
  2043. )
  2044. /*++
  2045. Routine Description:
  2046. This routine determines the name space index for long name support.
  2047. This is accomplished by looking for the OS2 name space.
  2048. Arguments:
  2049. pIrpContext - The IRP context for this request.
  2050. ShareName - The name of the interesting volume.
  2051. VolumeLongNameSpace - Returns the name space id of the OS/2 name space.
  2052. VolumeNumber - Returns the volume number.
  2053. Return Value:
  2054. TRUE - The volume support long names.
  2055. FALSE - The volume does not support long names.
  2056. --*/
  2057. {
  2058. NTSTATUS Status;
  2059. char *ptr;
  2060. USHORT i;
  2061. char length;
  2062. BOOLEAN LongNameSpace;
  2063. CHAR NumberOfNameSpaces, NumberOfInfoRecords;
  2064. PAGED_CODE();
  2065. DebugTrace(+1, Dbg, "GetLongNameSpaceForVolume...\n", 0);
  2066. *VolumeLongNameSpace = LFN_NO_OS2_NAME_SPACE;
  2067. //
  2068. // Get the ordinal number of this volume.
  2069. //
  2070. for ( i = 0; ShareName.Buffer[i] != ':'; i++);
  2071. ShareName.Length = i * sizeof( WCHAR );
  2072. DebugTrace( 0, Dbg, "Volume name %wZ\n", &ShareName );
  2073. Status = ExchangeWithWait (
  2074. IrpContext,
  2075. SynchronousResponseCallback,
  2076. "SU",
  2077. NCP_DIR_FUNCTION, NCP_GET_VOLUME_NUMBER,
  2078. &ShareName );
  2079. if ( NT_SUCCESS( Status ) ) {
  2080. Status = ParseResponse(
  2081. IrpContext,
  2082. IrpContext->rsp,
  2083. IrpContext->ResponseLength,
  2084. "Nb",
  2085. VolumeNumber );
  2086. }
  2087. if ( !NT_SUCCESS( Status )) {
  2088. DebugTrace( 0, Dbg, "Couldn't get volume number\n", 0);
  2089. DebugTrace(-1, Dbg, "GetLongNameSpaceForVolume -> -1\n", 0);
  2090. return( FALSE );
  2091. }
  2092. //
  2093. // Send a get name space info request, and wait for the response.
  2094. //
  2095. DebugTrace( 0, Dbg, "Querying volume number %d\n", *VolumeNumber );
  2096. Status = ExchangeWithWait (
  2097. IrpContext,
  2098. SynchronousResponseCallback,
  2099. "Sb",
  2100. NCP_DIR_FUNCTION, NCP_GET_NAME_SPACE_INFO,
  2101. *VolumeNumber );
  2102. if ( NT_SUCCESS( Status )) {
  2103. Status = ParseResponse(
  2104. IrpContext,
  2105. IrpContext->rsp,
  2106. IrpContext->ResponseLength,
  2107. "Nb",
  2108. &NumberOfNameSpaces );
  2109. }
  2110. if ( !NT_SUCCESS( Status )) {
  2111. DebugTrace( 0, Dbg, "Couldn't get name space info\n", 0);
  2112. DebugTrace(-1, Dbg, "GetLongNameSpaceForVolume -> -1\n", 0);
  2113. return( FALSE );
  2114. }
  2115. //
  2116. // Parse the response, it has the following format:
  2117. //
  2118. // NCP Header
  2119. //
  2120. // Number of Name Space Records (n1, byte)
  2121. //
  2122. // n1 Name Space Records
  2123. // Length (l1, byte)
  2124. // Value (l1 bytes, non-NUL-terminated ASCII string)
  2125. //
  2126. // Number of Name Space Info Records (n2, byte)
  2127. //
  2128. // n2 Name Space Info Records
  2129. // Record number (byte)
  2130. // Length (l2, byte)
  2131. // Value (l2 bytes, non-NUL-terminated ASCII string)
  2132. //
  2133. // Loaded name spaces (n3, byte)
  2134. // Loaded name space list (n3 bytes, each byte refers to the ordinal
  2135. // number of a name space record )
  2136. //
  2137. // Volume name spaces (n3, byte)
  2138. // Volume name space list (n3 bytes, as above)
  2139. //
  2140. // Volume Data Streams (n3, byte)
  2141. // Volume Data Streams (n3 bytes, each byte refers to the ordinal
  2142. // number of a name space info record )
  2143. //
  2144. DebugTrace( 0, Dbg, "Number of name spaces = %d\n", NumberOfNameSpaces );
  2145. ptr = &IrpContext->rsp[ 9 ];
  2146. LongNameSpace = FALSE;
  2147. //
  2148. // Skip the loaded name space list.
  2149. //
  2150. for ( i = 0 ; i < NumberOfNameSpaces ; i++ ) {
  2151. length = *ptr++;
  2152. ptr += length;
  2153. }
  2154. //
  2155. // Skip the supported data streams list.
  2156. //
  2157. NumberOfInfoRecords = *ptr++;
  2158. for ( i = 0 ; i < NumberOfInfoRecords ; i++ ) {
  2159. ptr++; // Skip record number
  2160. length = *ptr;
  2161. ptr += length + 1;
  2162. }
  2163. //
  2164. // Skip the supported data streams ordinal list.
  2165. //
  2166. length = *ptr;
  2167. ptr += length + 1;
  2168. //
  2169. // See if this volume supports long names.
  2170. //
  2171. length = *ptr++;
  2172. for ( i = 0; i < length ; i++ ) {
  2173. if ( *ptr++ == LONG_NAME_SPACE_ORDINAL ) {
  2174. LongNameSpace = TRUE;
  2175. *VolumeLongNameSpace = LONG_NAME_SPACE_ORDINAL;
  2176. }
  2177. }
  2178. if ( LongNameSpace ) {
  2179. DebugTrace(-1, Dbg, "GetLongNameSpaceForVolume -> STATUS_SUCCESS\n", 0 );
  2180. } else {
  2181. DebugTrace(-1, Dbg, "No long name space for volume.\n", 0 );
  2182. }
  2183. return( LongNameSpace );
  2184. }
  2185. BOOLEAN
  2186. IsFatNameValid (
  2187. IN PUNICODE_STRING FileName
  2188. )
  2189. /*++
  2190. Routine Description:
  2191. This routine checks if the specified file name is conformant to the
  2192. Fat 8.3 file naming rules.
  2193. Arguments:
  2194. FileName - Supplies the name to check.
  2195. Return Value:
  2196. BOOLEAN - TRUE if the name is valid, FALSE otherwise.
  2197. --*/
  2198. {
  2199. STRING DbcsName;
  2200. int i;
  2201. PAGED_CODE();
  2202. //
  2203. // Build up the dbcs string to call the fsrtl routine to check
  2204. // for legal 8.3 formation
  2205. //
  2206. if (NT_SUCCESS(RtlUnicodeStringToCountedOemString( &DbcsName, FileName, TRUE))) {
  2207. for ( i = 0; i < DbcsName.Length; i++ ) {
  2208. if ( FsRtlIsLeadDbcsCharacter( DbcsName.Buffer[i] ) ) {
  2209. if (Korean){
  2210. //
  2211. // Korean NT supports a large DBCS code-range than Korean
  2212. // Netware. We block the extra code-range to avoid
  2213. // code conversion problems.
  2214. //
  2215. if ( (UCHAR) DbcsName.Buffer[i] >=0x81 && (UCHAR) DbcsName.Buffer[i] <=0xA0){
  2216. RtlFreeOemString( &DbcsName );
  2217. return FALSE;
  2218. }else if((UCHAR) DbcsName.Buffer[i+1] <=0xA0){
  2219. RtlFreeOemString( &DbcsName );
  2220. return FALSE;
  2221. }
  2222. }
  2223. //
  2224. // Ignore lead bytes and trailing bytes
  2225. //
  2226. i++;
  2227. } else {
  2228. //
  2229. // disallow:
  2230. // '*' + 0x80 alt-170 (0xAA)
  2231. // '.' + 0x80 alt-174 (0xAE),
  2232. // '?' + 0x80 alt-191 (0xBF) the same as Dos clients.
  2233. //
  2234. // May need to add 229(0xE5) too.
  2235. //
  2236. // We also disallow spaces as valid FAT chars since
  2237. // NetWare treats them as part of the OS2 name space.
  2238. //
  2239. if ((DbcsName.Buffer[i] == 0xAA) ||
  2240. (DbcsName.Buffer[i] == 0xAE) ||
  2241. (DbcsName.Buffer[i] == 0xBF) ||
  2242. (DbcsName.Buffer[i] == ' ')) {
  2243. RtlFreeOemString( &DbcsName );
  2244. return FALSE;
  2245. }
  2246. }
  2247. }
  2248. if (FsRtlIsFatDbcsLegal( DbcsName, FALSE, TRUE, TRUE )) {
  2249. RtlFreeOemString( &DbcsName );
  2250. return TRUE;
  2251. }
  2252. RtlFreeOemString( &DbcsName );
  2253. }
  2254. //
  2255. // And return to our caller
  2256. //
  2257. return FALSE;
  2258. }
  2259. CHAR
  2260. GetNewDriveNumber (
  2261. IN PSCB Scb
  2262. )
  2263. /*++
  2264. Routine Description:
  2265. Portable NetWare needs us to give a different drive letter each time
  2266. we ask for a permanent handle. If we use the same one then:
  2267. net use s: \\port\sys
  2268. net use v: \\port\vol1
  2269. dir s:
  2270. <get contents of \\port\vol1 !!!!>
  2271. Arguments:
  2272. Scb
  2273. Return Value:
  2274. Letter assigned.
  2275. --*/
  2276. {
  2277. ULONG result = RtlFindClearBitsAndSet( &Scb->DriveMapHeader, 1, 0 );
  2278. PAGED_CODE();
  2279. if (result == 0xffffffff) {
  2280. return(0); // All used!
  2281. } else {
  2282. return('A' + (CHAR)(result & 0x00ff) );
  2283. }
  2284. }
  2285. VOID
  2286. FreeDriveNumber(
  2287. IN PSCB Scb,
  2288. IN CHAR DriveNumber
  2289. )
  2290. /*++
  2291. Routine Description:
  2292. This routine releases the appropriate Drivehandles bit.
  2293. Arguments:
  2294. FileName - Supplies the name to check.
  2295. Return Value:
  2296. BOOLEAN - TRUE if the name is valid, FALSE otherwise.
  2297. --*/
  2298. {
  2299. PAGED_CODE();
  2300. if (DriveNumber) {
  2301. RtlClearBits( &Scb->DriveMapHeader, (DriveNumber - 'A') & 0x00ff, 1);
  2302. }
  2303. }
  2304. VOID
  2305. NwFreeDirCacheForIcb(
  2306. IN PICB Icb
  2307. )
  2308. /*++
  2309. Routine Description:
  2310. This routine frees the directory cache associated with an ICB.
  2311. Arguments:
  2312. Icb - Supplies the ICB to clear the dir cache on.
  2313. Return Value:
  2314. --*/
  2315. {
  2316. PAGED_CODE();
  2317. Icb->CacheHint = NULL;
  2318. InitializeListHead( &(Icb->DirCache) );
  2319. if( Icb->DirCacheBuffer ) {
  2320. FREE_POOL( Icb->DirCacheBuffer );
  2321. }
  2322. Icb->DirCacheBuffer = NULL;
  2323. }