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.

2337 lines
86 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. DownLvlI.c
  5. Abstract:
  6. This module implements downlevel fileinfo, volinfo, and dirctrl.
  7. Author:
  8. JoeLinn [JoeLi] 7-March-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, MRxSmbFabricateAttributesOnNetRoot)
  15. #pragma alloc_text(PAGE, MRxSmbCoreInformation)
  16. #pragma alloc_text(PAGE, MRxSmbLoadCoreFileSearchBuffer)
  17. #pragma alloc_text(PAGE, MRxSmbCoreFileSearch)
  18. #pragma alloc_text(PAGE, MrxSmbOemVolumeInfoToUnicode)
  19. #pragma alloc_text(PAGE, MrxSmbCoreQueryFsVolumeInfo)
  20. #pragma alloc_text(PAGE, MrxSmbQueryFsVolumeInfo)
  21. #pragma alloc_text(PAGE, MrxSmbCoreQueryDiskAttributes)
  22. #pragma alloc_text(PAGE, MrxSmbCoreQueryDiskAttributes)
  23. #pragma alloc_text(PAGE, SmbPseExchangeStart_CoreInfo)
  24. #pragma alloc_text(PAGE, MRxSmbFinishSearch)
  25. #pragma alloc_text(PAGE, MRxSmbFinishQueryDiskInfo)
  26. #pragma alloc_text(PAGE, MRxSmbExtendForCache)
  27. #pragma alloc_text(PAGE, MRxSmbExtendForNonCache)
  28. #pragma alloc_text(PAGE, MRxSmbGetNtAllocationInfo)
  29. #pragma alloc_text(PAGE, __MRxSmbSimpleSyncTransact2)
  30. #pragma alloc_text(PAGE, MRxSmbFinishTransaction2)
  31. #endif
  32. #define Dbg (DEBUG_TRACE_VOLINFO)
  33. //#define FORCE_CORE_GETATTRIBUTES
  34. #ifndef FORCE_CORE_GETATTRIBUTES
  35. #define MRxSmbForceCoreGetAttributes FALSE
  36. #else
  37. BOOLEAN MRxSmbForceCoreGetAttributes = TRUE;
  38. #endif
  39. NTSTATUS
  40. SmbPseExchangeStart_CoreInfo(
  41. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  42. );
  43. //these structures are used for t2_query_fs_info
  44. typedef
  45. struct _QFS_INFO {
  46. ULONG ulVSN;
  47. UCHAR cch;
  48. CHAR szVolLabel[12]; //not unicode
  49. } QFS_INFO, *PQFS_INFO;
  50. #define ACTUAL_QFS_INFO_LENGTH (FIELD_OFFSET(QFS_INFO,szVolLabel[12]))
  51. typedef
  52. struct _QFS_ALLOCATE {
  53. ULONG ulReserved;
  54. ULONG cSectorUnit;
  55. ULONG cUnit;
  56. ULONG cUnitAvail;
  57. USHORT cbSector;
  58. } QFS_ALLOCATE, *PQFS_ALLOCATE;
  59. #define ACTUAL_QFS_ALLOCATE_LENGTH (FIELD_OFFSET(QFS_ALLOCATE,cbSector)+sizeof(((PQFS_ALLOCATE)0)->cbSector))
  60. //++
  61. //
  62. // VOID
  63. // NAME_LENGTH(
  64. // OUT ULONG Length,
  65. // IN PUCHAR Ptr
  66. // )
  67. //
  68. // Routine Description:
  69. //
  70. // Determines the length of a Core filename returned by search. This
  71. // is normally a NULL terminated string less than MAXIMUM_COMPONENT_CORE.
  72. // In some cases this is Non-null teminated and space filled.
  73. //
  74. // Arguments:
  75. //
  76. // Length - Returns the string length
  77. // Ptr - The filename to be measured
  78. //
  79. // Return Value:
  80. //
  81. // None.
  82. //
  83. //--
  84. #define NAME_LENGTH( Length, Ptr, Max ) { \
  85. Length = 0; \
  86. while( ((PCHAR)Ptr)[Length] != '\0' ) { \
  87. Length++; \
  88. if ( Length == Max ) { \
  89. break; \
  90. } \
  91. } \
  92. while( ((PCHAR)Ptr)[Length-1] == ' ' && Length ) { \
  93. Length--; \
  94. } \
  95. }
  96. MRxSmbSetDeleteDisposition(
  97. IN PRX_CONTEXT RxContext
  98. );
  99. typedef struct __NativeFs_Name_Entry {
  100. UCHAR Last;
  101. UCHAR MaximumComponentNameLength;
  102. UCHAR FileSystemAttributes; //this may overflow someday.....
  103. UCHAR NameLength;
  104. PWCHAR Name;
  105. };
  106. struct __NativeFs_Name_Entry NativeFsNameTable[] = {
  107. {0,12,0,sizeof(L"FAT")-sizeof(WCHAR),L"FAT"},
  108. #ifdef MRXSMB_BUILD_FOR_CSC_DCON
  109. {0,255,
  110. FILE_CASE_SENSITIVE_SEARCH |
  111. FILE_CASE_PRESERVED_NAMES |
  112. FILE_UNICODE_ON_DISK |
  113. // FILE_FILE_COMPRESSION |
  114. // FILE_SUPPORTS_REPARSE_POINTS |
  115. // FILE_SUPPORTS_SPARSE_FILES |
  116. FILE_PERSISTENT_ACLS,
  117. sizeof(L"*NT5CSC")-sizeof(WCHAR),L"*NT5CSC"},
  118. #endif //#ifdef MRXSMB_BUILD_FOR_CSC_DCON
  119. {0,254,FILE_CASE_PRESERVED_NAMES,sizeof(L"HPFS")-sizeof(WCHAR),L"HPFS"},
  120. {1,254,FILE_CASE_PRESERVED_NAMES,sizeof(L"HPFS386")-sizeof(WCHAR),L"HPFS386"}
  121. };
  122. NTSTATUS
  123. MRxSmbFabricateAttributesOnNetRoot(
  124. IN OUT PSMBCE_NET_ROOT psmbNetRoot,
  125. IN PSMBCE_SERVER pServer
  126. )
  127. /*++
  128. Routine Description:
  129. This routine uses information stored in the netroot structure to hallucinate the attributes
  130. of the netroot. it may be that the ascii representation of the filesystem name has already been
  131. stored in the netroot. If so, expeand it out.....otherwise, it must be FAT.
  132. Arguments:
  133. Return Value:
  134. RXSTATUS - STATUS_SUCCESS
  135. --*/
  136. {
  137. NTSTATUS StringStatus;
  138. WCHAR FileSystemNameBuffer[SMB_MAXIMUM_SUPPORTED_VOLUME_LABEL+1]; //must leave room for the null
  139. UNICODE_STRING FileSystemNameU;
  140. OEM_STRING FileSystemNameA;
  141. UCHAR FileSystemNameALength;
  142. PAGED_CODE();
  143. // ASSERT (psmbNetRoot->MaximumComponentNameLength==0);
  144. FileSystemNameALength = psmbNetRoot->FileSystemNameALength;
  145. if (FileSystemNameALength == 0) {
  146. if (pServer->Dialect <= WFW10_DIALECT)
  147. {
  148. //must be Fat!
  149. FileSystemNameALength = 3;
  150. psmbNetRoot->FileSystemNameA[0] = 'F';
  151. psmbNetRoot->FileSystemNameA[1] = 'A';
  152. psmbNetRoot->FileSystemNameA[2] = 'T';
  153. }
  154. else
  155. {
  156. FileSystemNameALength = 7;
  157. psmbNetRoot->FileSystemNameA[0] = 'U';
  158. psmbNetRoot->FileSystemNameA[1] = 'N';
  159. psmbNetRoot->FileSystemNameA[2] = 'K';
  160. psmbNetRoot->FileSystemNameA[3] = 'N';
  161. psmbNetRoot->FileSystemNameA[4] = 'O';
  162. psmbNetRoot->FileSystemNameA[5] = 'W';
  163. psmbNetRoot->FileSystemNameA[6] = 'N';
  164. }
  165. }
  166. //now, translate the name to Unicode.......
  167. FileSystemNameA.Length = FileSystemNameALength;
  168. FileSystemNameA.MaximumLength = FileSystemNameALength;
  169. FileSystemNameA.Buffer = &psmbNetRoot->FileSystemNameA[0];
  170. FileSystemNameU.Length = 0;
  171. FileSystemNameU.MaximumLength = (USHORT)sizeof(FileSystemNameBuffer);
  172. FileSystemNameU.Buffer = &FileSystemNameBuffer[0];
  173. StringStatus = RtlOemStringToUnicodeString(&FileSystemNameU, &FileSystemNameA, FALSE);
  174. ASSERT(StringStatus==STATUS_SUCCESS);
  175. //copy back the name
  176. RtlCopyMemory(&psmbNetRoot->FileSystemName[0],FileSystemNameU.Buffer,FileSystemNameU.Length);
  177. psmbNetRoot->FileSystemNameLength = FileSystemNameU.Length;
  178. if (FALSE) DbgPrint("NativeFs in unicode %wZ (%d/%d) on netroot %08lx\n",
  179. &FileSystemNameU,FileSystemNameU.Length,FileSystemNameU.MaximumLength,psmbNetRoot);
  180. { struct __NativeFs_Name_Entry *i;
  181. for (i=NativeFsNameTable;;i++) {
  182. UCHAR NameLength = i->NameLength;
  183. if (RtlCompareMemory(&FileSystemNameBuffer[0],
  184. i->Name,
  185. NameLength) == NameLength) {
  186. psmbNetRoot->MaximumComponentNameLength = i->MaximumComponentNameLength;
  187. psmbNetRoot->FileSystemAttributes = i->FileSystemAttributes;
  188. if (FALSE) {
  189. UNICODE_STRING u;
  190. u.Buffer = i->Name;
  191. u.Length = i->NameLength;
  192. DbgPrint("FoundNativeFsStrng %wZ len %d for %d %d\n",&u,i->NameLength,
  193. i->MaximumComponentNameLength,i->FileSystemAttributes);
  194. }
  195. break;
  196. }
  197. if (i->Last) {
  198. //ASSERT(!"Valid Share Type returned in TREE COnnect And X response");
  199. psmbNetRoot->MaximumComponentNameLength = 255;
  200. psmbNetRoot->FileSystemAttributes = 0;
  201. break;
  202. }
  203. }
  204. }
  205. return(STATUS_SUCCESS); //could be a VOID routine.....
  206. }
  207. NTSTATUS
  208. MRxSmbGetFsAttributesFromNetRoot(
  209. IN OUT PRX_CONTEXT RxContext
  210. )
  211. /*++
  212. Routine Description:
  213. This routine uses information stored in the netroot structure to fill in a FILE
  214. FileFsAttributeInformation structure.
  215. Arguments:
  216. Return Value:
  217. RXSTATUS - STATUS_SUCCESS
  218. --*/
  219. {
  220. RxCaptureFcb;
  221. ULONG FileSystemNameLength,LengthNeeded;
  222. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  223. PSMBCE_NET_ROOT psmbNetRoot;
  224. //FILE_INFORMATION_CLASS FileInformationClass;
  225. PBYTE pBuffer;
  226. PULONG pBufferLength;
  227. //DbgPrint("yeppp!!\n");
  228. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(capFcb->pNetRoot);
  229. if (pNetRootEntry == NULL) {
  230. return (STATUS_INVALID_PARAMETER);
  231. }
  232. ASSERT(RxContext->MajorFunction==IRP_MJ_QUERY_VOLUME_INFORMATION);
  233. //FileInformationClass = RxContext->Info.FileInformationClass;
  234. ASSERT(RxContext->Info.FileInformationClass==FileFsAttributeInformation);
  235. pBuffer = RxContext->Info.Buffer;
  236. pBufferLength = &RxContext->Info.LengthRemaining;
  237. psmbNetRoot = &pNetRootEntry->NetRoot;
  238. if (psmbNetRoot->MaximumComponentNameLength==0) {
  239. MRxSmbFabricateAttributesOnNetRoot(psmbNetRoot, &pNetRootEntry->pServerEntry->Server);
  240. }
  241. FileSystemNameLength = psmbNetRoot->FileSystemNameLength;
  242. LengthNeeded = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)+FileSystemNameLength;
  243. if (*pBufferLength < LengthNeeded) {
  244. return (STATUS_BUFFER_OVERFLOW);
  245. }
  246. {
  247. PFILE_FS_ATTRIBUTE_INFORMATION pTypedBuffer = (PFILE_FS_ATTRIBUTE_INFORMATION)pBuffer;
  248. pTypedBuffer->MaximumComponentNameLength = psmbNetRoot->MaximumComponentNameLength;
  249. pTypedBuffer->FileSystemAttributes = psmbNetRoot->FileSystemAttributes;
  250. pTypedBuffer->FileSystemNameLength = FileSystemNameLength;
  251. RtlCopyMemory(pTypedBuffer->FileSystemName, psmbNetRoot->FileSystemName, FileSystemNameLength);
  252. *pBufferLength -= LengthNeeded;
  253. }
  254. return(STATUS_SUCCESS);
  255. }
  256. //CODE.IMPROVEMENT 3 args should NOT be passed
  257. NTSTATUS
  258. MRxSmbCoreInformation(
  259. IN OUT PRX_CONTEXT RxContext,
  260. IN ULONG InformationClass,
  261. IN OUT PVOID pBuffer,
  262. IN OUT PULONG pBufferLength,
  263. IN SMB_PSE_ORDINARY_EXCHANGE_ENTRYPOINTS EntryPoint
  264. )
  265. /*++
  266. Routine Description:
  267. This routine does a core level getinfo (vol or fileinfo) a file across the network
  268. Arguments:
  269. RxContext - the RDBSS context
  270. InformationClass - a class variable that is specific to the call. sometimes it's a SMB class; sometimes
  271. an NT class. CODE.IMPROVEMENT.ASHAMED we should always use the NT guy OR we should define
  272. some other enumeration that we like better. consideration of the latter has kept me from
  273. proceeding here..........
  274. pBuffer - pointer to the user's buffer
  275. pBufferLength - a pointer to a ulong containing the bufferlength that is updated as we go;
  276. if it's a setinfo then we deref and place the actual bufferlength in the OE.
  277. Return Value:
  278. RXSTATUS - The return status for the operation
  279. --*/
  280. {
  281. NTSTATUS Status = (STATUS_SUCCESS);
  282. PUNICODE_STRING RemainingName;
  283. RxCaptureFcb; RxCaptureFobx;
  284. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  285. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  286. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  287. PAGED_CODE();
  288. RxDbgTrace(0, Dbg, ("MRxSmbDownLevelQueryInformation\n", 0 )); //0 instead of +1.....the general entrypoint already inc'd
  289. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  290. //some stuff is early out............catch them here even before we initialize the stufferstate
  291. //CODE.IMPROVEMENT we should potentially find a way to flatten these switches....both here and in volinfo_start
  292. switch (EntryPoint) {
  293. case SMBPSE_OE_FROM_QUERYVOLUMEINFO:
  294. switch (InformationClass) {
  295. case FileFsVolumeInformation:
  296. case FileFsSizeInformation:
  297. break; //these are actually implemented on the wire
  298. case FileFsAttributeInformation: {
  299. Status = MRxSmbGetFsAttributesFromNetRoot(RxContext);
  300. goto FINALLY;
  301. }
  302. //no break needed because of gotofinally
  303. case FileFsDeviceInformation:
  304. ASSERT(!"this should have been turned away");
  305. //no break;
  306. default:
  307. Status = STATUS_NOT_IMPLEMENTED;
  308. goto FINALLY;
  309. }
  310. break;
  311. case SMBPSE_OE_FROM_QUERYFILEINFO:
  312. //notice that the designators are smb_query_info types
  313. switch (InformationClass) {
  314. case SMB_QUERY_FILE_BASIC_INFO:
  315. case SMB_QUERY_FILE_STANDARD_INFO:
  316. // go thru to the wire or get it from file information cache
  317. break;
  318. case SMB_QUERY_FILE_EA_INFO:
  319. //downlevel guys have no EAs....turn this backright here
  320. ((PFILE_EA_INFORMATION)pBuffer)->EaSize = 0;
  321. *pBufferLength -= sizeof(FILE_EA_INFORMATION);
  322. goto FINALLY;
  323. //case SMB_QUERY_FILE_ALLOCATION_INFO:
  324. //case SMB_QUERY_FILE_END_OF_FILEINFO:
  325. //case SMB_QUERY_FILE_ALT_NAME_INFO:
  326. //case SMB_QUERY_FILE_STREAM_INFO:
  327. //case SMB_QUERY_FILE_COMPRESSION_INFO:
  328. default:
  329. Status = STATUS_NOT_IMPLEMENTED;
  330. goto FINALLY;
  331. }
  332. break;
  333. case SMBPSE_OE_FROM_SETFILEINFO:
  334. switch (InformationClass) {
  335. case FileBasicInformation:
  336. case FileEndOfFileInformation:
  337. //these go thru to the wire
  338. break;
  339. case FileDispositionInformation:
  340. /*
  341. Send this through to the wire. We used to delay the delete until close time, but then if the caller does not have the
  342. rights to delete they will never get an error. This can result in various error cases. (Like in explorer, delete will
  343. remove it from the view, but than the file will come back on the next refresh)
  344. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_FILE_DELETED) ||
  345. !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  346. // if it is a pseudo open, we send the delete file request to get the result;
  347. // otherwise, we delay the delete until close.
  348. goto FINALLY;
  349. }
  350. */
  351. break;
  352. case FileRenameInformation:
  353. Status = MRxSmbRename(RxContext);
  354. goto FINALLY;
  355. case FileAllocationInformation:
  356. Status = STATUS_SUCCESS;
  357. goto FINALLY;
  358. default:
  359. Status = STATUS_NOT_IMPLEMENTED;
  360. goto FINALLY;
  361. }
  362. break;
  363. case SMBPSE_OE_FROM_EXTENDFILEFORCACHEING:
  364. case SMBPSE_OE_FROM_QUERYDIRECTORY:
  365. break;
  366. }
  367. Status = SmbPseCreateOrdinaryExchange(RxContext,
  368. SrvOpen->pVNetRoot,
  369. EntryPoint,
  370. SmbPseExchangeStart_CoreInfo,
  371. &OrdinaryExchange
  372. );
  373. if (Status != STATUS_SUCCESS) {
  374. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  375. goto FINALLY;
  376. }
  377. //this is redundant since this info is already stored in the rxcontext! CODE.IMPROVEMENT
  378. OrdinaryExchange->Info.Buffer = pBuffer;
  379. OrdinaryExchange->Info.pBufferLength = pBufferLength;
  380. OrdinaryExchange->Info.InfoClass = InformationClass;
  381. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  382. ASSERT (Status != (STATUS_PENDING)); //async was turned away at the top level
  383. //NTRAID-455630-2/2/2000 yunlin Possible reconnect point
  384. SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  385. FINALLY:
  386. RxDbgTrace(-1, Dbg, ("MRxSmbDownLevelQueryInformation exit with status=%08lx\n", Status ));
  387. return(Status);
  388. }
  389. UNICODE_STRING MRxSmbAll8dot3Files = {sizeof(L"????????.???")-sizeof(WCHAR),sizeof(L"????????.???"),L"????????.???"};
  390. #if DBG
  391. #include "stdarg.h"
  392. #include "stdio.h"
  393. #include "string.h"
  394. VOID
  395. MRxSmbDumpResumeKey(
  396. PSZ text,
  397. PSMB_RESUME_KEY ResumeKey
  398. )
  399. {
  400. PBYTE rk = (PBYTE)ResumeKey;
  401. CHAR Buffer[80];
  402. PCHAR b;
  403. ULONG i;
  404. PAGED_CODE();
  405. for (i=0,b=Buffer;i<sizeof(SMB_RESUME_KEY);i++,b+=2) {
  406. RxSprintf(b,"%02lx ",rk[i]);
  407. if (i==0) b+=2;
  408. if (i==11) b+=2;
  409. if (i==16) b+=2;
  410. }
  411. RxDbgTrace(0, Dbg, ("%s rk(%08lx)=%s\n", text, ResumeKey, Buffer));
  412. }
  413. #else
  414. #define MRxSmbDumpResumeKey(x,y)
  415. #endif
  416. NTSTATUS
  417. MRxSmbLoadCoreFileSearchBuffer(
  418. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  419. )
  420. /*++
  421. Routine Description:
  422. This routine does a CORE_SMB_SEARCH and leaves the result in the SMBbuf.
  423. Arguments:
  424. OrdinaryExchange - an exchange to be used for conducting this open.
  425. Return Value:
  426. RXSTATUS - The return status for the operation
  427. Notes:
  428. --*/
  429. {
  430. NTSTATUS Status = (STATUS_NOT_IMPLEMENTED);
  431. #ifndef WIN9X
  432. RxCaptureFcb; RxCaptureFobx;
  433. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  434. PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
  435. PSMBSTUFFER_BUFFER_STATE StufferState;
  436. PSMB_HEADER SmbHeader;
  437. //PUNICODE_STRING DirectoryName;
  438. //PUNICODE_STRING Template;
  439. BOOLEAN FindFirst;
  440. UNICODE_STRING FindFirstPattern;
  441. USHORT ResumeKeyLength;
  442. ULONG ReturnCount;
  443. BOOLEAN EndOfSearchReached;
  444. // SearchAttributes is hardcoded to the magic number 0x16 CODE.IMPROVEMENT.ASHAMED use a macro....
  445. ULONG SearchAttributes =
  446. (SMB_FILE_ATTRIBUTE_DIRECTORY
  447. | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN);
  448. PULONG pCountRemainingInSmbbuf = &OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf;
  449. PAGED_CODE();
  450. RxDbgTrace(+1, Dbg, ("MRxSmbLoadCoreFileSearchBuffer entering.......OE=%08lx\n",OrdinaryExchange));
  451. RxDbgTrace( 0, Dbg, (".......smbFobx/resumekey=%08lx/%08lx\n",smbFobx,smbFobx->Enumeration.CoreResumeKey));
  452. if (!FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST)) {
  453. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME(capFobx->pSrvOpen,capFcb);
  454. PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
  455. ULONG DirectoryNameLength,TemplateLength,AllocationLength;
  456. PBYTE SmbFileName;
  457. //this is the first time thru....the stuffer cannot handle the intricate logic here so we
  458. //will have to preallocate for the name
  459. if (smbFobx->Enumeration.WildCardsFound = FsRtlDoesNameContainWildCards(Template)){
  460. // we will need to have an upcased template for compares; we do this in place
  461. RtlUpcaseUnicodeString( Template, Template, FALSE );
  462. //CODE.IMPROVEMENT.ASHAMED we should see if we can translate the template; otherwise,
  463. // we beat the heck out of downlevel servers on an exe lookup
  464. // if we do that we should revisit the decision to get 10 entries
  465. // as an alternative....in addition, we could keep a sidebuffer the way
  466. // that we do for uplevel. don't know if this is worthwhile
  467. //CODE.IMPROVEMENT but we should specialcase *.* (altho the fsrtl routine also does it)
  468. Template = &MRxSmbAll8dot3Files; //we will have to filter on this side
  469. }
  470. DirectoryNameLength = DirectoryName->Length;
  471. TemplateLength = Template->Length;
  472. AllocationLength = sizeof(WCHAR) // backslash separator
  473. +DirectoryNameLength
  474. +TemplateLength;
  475. RxDbgTrace(0, Dbg, (" --> d/t/dl/tl/al <%wZ><%wZ>%08lx/%08lx/%08lx!\n",
  476. DirectoryName,Template,
  477. DirectoryNameLength,TemplateLength,AllocationLength));
  478. FindFirstPattern.Buffer = (PWCHAR)RxAllocatePoolWithTag( PagedPool,AllocationLength,'0SxR');
  479. if (FindFirstPattern.Buffer==NULL) {
  480. RxDbgTrace(0, Dbg, (" --> Couldn't get the findfind pattern buffer!\n"));
  481. Status = STATUS_INSUFFICIENT_RESOURCES;
  482. goto FINALLY;
  483. }
  484. SmbFileName = (PBYTE)FindFirstPattern.Buffer;
  485. RtlCopyMemory(SmbFileName,DirectoryName->Buffer,DirectoryNameLength);
  486. SmbFileName += DirectoryNameLength;
  487. if (*((PWCHAR)(SmbFileName-sizeof(WCHAR))) != L'\\') {
  488. *((PWCHAR)SmbFileName) = L'\\'; SmbFileName+= sizeof(WCHAR);
  489. }
  490. RtlCopyMemory(SmbFileName,Template->Buffer,TemplateLength);
  491. SmbFileName += TemplateLength;
  492. if ((TemplateLength == sizeof(WCHAR)) && (Template->Buffer[0]==DOS_STAR)) {
  493. ASSERT(FALSE); //this should never happen
  494. *((PWCHAR)SmbFileName) = L'.'; SmbFileName+= sizeof(WCHAR);
  495. *((PWCHAR)SmbFileName) = L'*'; SmbFileName+= sizeof(WCHAR);
  496. }
  497. //*((PWCHAR)SmbFileName) = 0; SmbFileName+= sizeof(WCHAR); //trailing NULL;
  498. //CODE.IMPROVEMENT we should potentially 8.3ize the string here
  499. FindFirstPattern.Length = (USHORT)(SmbFileName - (PBYTE)FindFirstPattern.Buffer);
  500. RxDbgTrace(0, Dbg, (" --> find1stpattern <%wZ>!\n",&FindFirstPattern));
  501. FindFirst = TRUE;
  502. ResumeKeyLength = 0;
  503. } else {
  504. RxDbgTrace(0, Dbg, ("-->FINDNEXT\n"));
  505. FindFirstPattern.Buffer = NULL;
  506. if (!FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_CORE_SEARCH_IN_PROGRESS)) {
  507. Status = smbFobx->Enumeration.ErrorStatus;
  508. RxDbgTrace(0, Dbg, ("-->ERROR EARLY OUT\n"));
  509. goto FINALLY;
  510. }
  511. FindFirst = FALSE;
  512. FindFirstPattern.Length = 0;
  513. ResumeKeyLength = sizeof(SMB_RESUME_KEY);
  514. MRxSmbDumpResumeKey("FindNext:",smbFobx->Enumeration.CoreResumeKey);
  515. }
  516. //get the correct return count. there are three factors: countremaining from the OE,
  517. // how many could fit the the user's buffer, and how many could fit in a negotiated buffer.
  518. // we pick the smallest of the three except that we never go for less than 10 unless 10 won't
  519. // fit in the smbbuf.
  520. ReturnCount = OrdinaryExchange->Info.CoreSearch.CountRemaining;
  521. { ULONG t = (*OrdinaryExchange->Info.pBufferLength) / smbFobx->Enumeration.FileNameOffset;
  522. if (t<ReturnCount) { ReturnCount = t; }
  523. }
  524. if (ReturnCount<10) { ReturnCount = 10; }
  525. {
  526. PSMBCE_SERVER pServer;
  527. ULONG AvailableBufferSize,t;
  528. pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  529. AvailableBufferSize = pServer->MaximumBufferSize -
  530. (sizeof(SMB_HEADER) +
  531. FIELD_OFFSET(RESP_SEARCH,Buffer[0])
  532. +sizeof(UCHAR)+sizeof(USHORT) //bufferformat,datalength fields
  533. );
  534. t = AvailableBufferSize / sizeof(SMB_DIRECTORY_INFORMATION);
  535. if (t<ReturnCount) { ReturnCount = t; }
  536. }
  537. RxDbgTrace( 0, Dbg, ("-------->count=%08lx\n",ReturnCount));
  538. if (ReturnCount==0) {
  539. Status = (STATUS_MORE_PROCESSING_REQUIRED);
  540. RxDbgTrace(0, Dbg, ("-->Count==0 EARLY OUT\n"));
  541. goto FINALLY;
  542. }
  543. StufferState = &OrdinaryExchange->AssociatedStufferState;
  544. ASSERT( StufferState );
  545. *pCountRemainingInSmbbuf = 0;
  546. OrdinaryExchange->Info.CoreSearch.NextDirInfo = NULL;
  547. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,
  548. SMB_COM_SEARCH, SMB_REQUEST_SIZE(SEARCH),
  549. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  550. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  551. );
  552. RxDbgTrace(0, Dbg,("core search command initial status = %lu\n",Status));
  553. MRxSmbDumpStufferState (1100,"SMB w/ core search before stuffing",StufferState);
  554. MRxSmbStuffSMB (StufferState,
  555. "0wwB4ywc!",
  556. // 0 UCHAR WordCount; // Count of parameter words = 2
  557. ReturnCount, // w _USHORT( MaxCount ); // Number of dir. entries to return
  558. SearchAttributes, // w _USHORT( SearchAttributes );
  559. SMB_WCT_CHECK(2) // B _USHORT( ByteCount ); // Count of data bytes; min = 5
  560. // UCHAR Buffer[1]; // Buffer containing:
  561. &FindFirstPattern, // 4 //UCHAR BufferFormat1; // 0x04 -- ASCII
  562. // //UCHAR FileName[]; // File name, may be null
  563. 0x05, // y //UCHAR BufferFormat2; // 0x05 -- Variable block
  564. ResumeKeyLength, // w //USHORT ResumeKeyLength; // Length of resume key, may be 0
  565. // c //UCHAR SearchStatus[]; // Resume key
  566. ResumeKeyLength,smbFobx->Enumeration.CoreResumeKey
  567. );
  568. MRxSmbDumpStufferState (700,"SMB w/ core search after stuffing",StufferState);
  569. //ASSERT(!"Now it's stuffed");
  570. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  571. SMBPSE_OETYPE_CORESEARCH
  572. );
  573. if (!NT_SUCCESS(Status)) goto FINALLY;
  574. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST|SMBFOBX_ENUMFLAG_CORE_SEARCH_IN_PROGRESS;
  575. //if (Status==RxStatus(SUCCESS) && FilesReturned==0) {
  576. // RxDbgTrace( 0, Dbg, ("MRxSmbQueryDirectory: no files returned...switch status\n"));
  577. // EndOfSearchReached = TRUE;
  578. // Status = RxStatus(NO_MORE_FILES);
  579. //}
  580. if (Status==(STATUS_SUCCESS) && *pCountRemainingInSmbbuf==0) {
  581. RxDbgTrace( 0, Dbg, ("MRxSmbLoadCoreFileSearchBuffer: no files returned...switch status\n"));
  582. EndOfSearchReached = TRUE;
  583. Status = (STATUS_NO_MORE_FILES);
  584. } else {
  585. //CODE.IMPROVEMENT a possible improvement here is to know that the search is closed
  586. // based on a "smaller-than-normal" return; we would key this off of the
  587. // operatingsystem return string i guess. for NT systems, we don't do this
  588. EndOfSearchReached = FALSE;
  589. }
  590. if (EndOfSearchReached) {
  591. RxDbgTrace( 0, Dbg, ("MRxSmbLoadCoreFileSearchBuffer: no longer in progress...EOS\n"));
  592. smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_CORE_SEARCH_IN_PROGRESS;
  593. smbFobx->Enumeration.ErrorStatus = (STATUS_NO_MORE_FILES);
  594. }
  595. //we dont save a resume key here since each individual copy operation will have to do that
  596. FINALLY:
  597. if (FindFirstPattern.Buffer != NULL) {
  598. RxFreePool(FindFirstPattern.Buffer);
  599. }
  600. if (!NT_SUCCESS(Status)&&(Status!=(STATUS_MORE_PROCESSING_REQUIRED))) {
  601. RxDbgTrace( 0, Dbg, ("MRxSmbCoreFileSearch: Failed .. returning %lx\n",Status));
  602. smbFobx->Enumeration.Flags &= ~SMBFOBX_ENUMFLAG_CORE_SEARCH_IN_PROGRESS;
  603. smbFobx->Enumeration.ErrorStatus = Status; //keep returning this
  604. }
  605. RxDbgTrace(-1, Dbg, ("MRxSmbLoadCoreFileSearchBuffer exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  606. #endif
  607. return(Status);
  608. }
  609. #define ASSERT_SAME_FIELD(__field,__t1,__t2) { \
  610. ASSERT(FIELD_OFFSET(__t1,__field)==FIELD_OFFSET(__t2,__field)); \
  611. }
  612. #define ASSERT_SAME_DIRINFO_FIELDS(__t1,__t2) {\
  613. ASSERT_SAME_FIELD(LastWriteTime,__t1,__t2); \
  614. ASSERT_SAME_FIELD(EndOfFile,__t1,__t2); \
  615. ASSERT_SAME_FIELD(AllocationSize,__t1,__t2); \
  616. ASSERT_SAME_FIELD(FileAttributes,__t1,__t2); \
  617. }
  618. #if DBG
  619. VOID MRxSmbCoreFileSeach_AssertFields(void){
  620. //just move this out of the main execution path so that we don't have to look at it while
  621. //we Uing the code
  622. ASSERT_SAME_DIRINFO_FIELDS(FILE_DIRECTORY_INFORMATION,FILE_FULL_DIR_INFORMATION);
  623. ASSERT_SAME_DIRINFO_FIELDS(FILE_DIRECTORY_INFORMATION,FILE_BOTH_DIR_INFORMATION);
  624. }
  625. #else
  626. #define MRxSmbCoreFileSeach_AssertFields()
  627. #endif
  628. NTSTATUS
  629. MRxSmbCoreFileSearch(
  630. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  631. )
  632. /*++
  633. Routine Description:
  634. This routine does a GetFileAttributes and remembers the reponse.
  635. Arguments:
  636. OrdinaryExchange - an exchange to be used for conducting this open.
  637. Return Value:
  638. RXSTATUS - The return status for the operation
  639. Notes:
  640. --*/
  641. {
  642. NTSTATUS Status = (STATUS_NOT_IMPLEMENTED);
  643. #ifndef WIN9X
  644. RxCaptureFcb; RxCaptureFobx;
  645. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  646. PBYTE pBuffer = OrdinaryExchange->Info.Buffer;
  647. PULONG pLengthRemaining = OrdinaryExchange->Info.pBufferLength;
  648. ULONG InformationClass = OrdinaryExchange->Info.InfoClass;
  649. PFILE_DIRECTORY_INFORMATION pPreviousBuffer = NULL;
  650. PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
  651. ULONG SuccessCount = 0;
  652. PAGED_CODE();
  653. RxDbgTrace(+1, Dbg, ("MRxSmbCoreFileSearch entering.......OE=%08lx\n",OrdinaryExchange));
  654. MRxSmbCoreFileSeach_AssertFields();
  655. OrdinaryExchange->Info.CoreSearch.CountRemaining =
  656. RxContext->QueryDirectory.ReturnSingleEntry?1:0x7ffffff;
  657. if ( (smbFobx->Enumeration.CoreResumeKey ==NULL )
  658. && ((smbFobx->Enumeration.CoreResumeKey = RxAllocatePoolWithTag(PagedPool,sizeof(SMB_RESUME_KEY),'rbms'))==NULL) ){
  659. RxDbgTrace(0, Dbg, ("...couldn't allocate resume key\n"));
  660. Status = (STATUS_INSUFFICIENT_RESOURCES);
  661. goto FINALLY;
  662. }
  663. RxDbgTrace( 0, Dbg, (".......smbFobx/resumekey=%08lx/%08lx\n",smbFobx,smbFobx->Enumeration.CoreResumeKey));
  664. Status = MRxSmbLoadCoreFileSearchBuffer( SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS );
  665. for (;;) {
  666. BOOLEAN BufferOverflow = FALSE;
  667. PSMB_DIRECTORY_INFORMATION NextDirInfo;
  668. UNICODE_STRING FileNameU;
  669. OEM_STRING FileNameA;
  670. WCHAR FileNameU_buffer[14];
  671. ULONG NameLength;
  672. PBYTE NextFileName;
  673. BOOLEAN Match,BufferOverFlow;
  674. if (!NT_SUCCESS(Status)) {
  675. if (Status == STATUS_NO_MORE_FILES) {
  676. if (SuccessCount > 0) {
  677. Status = (STATUS_SUCCESS);
  678. }
  679. } else if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  680. if (SuccessCount > 0) {
  681. Status = (STATUS_SUCCESS);
  682. } else {
  683. Status = (STATUS_BUFFER_OVERFLOW);
  684. }
  685. }
  686. goto FINALLY;
  687. }
  688. ASSERT ( OrdinaryExchange->Info.CoreSearch.CountRemaining>0 );
  689. ASSERT ( OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf>0 );
  690. RxDbgTrace(0, Dbg, ("MRxSmbCoreFileSearch looptopcheck counts=%08lx,%08lx\n",
  691. OrdinaryExchange->Info.CoreSearch.CountRemaining,
  692. OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf
  693. ));
  694. //next issue: does the next dirinfo match the criteria?!?
  695. NextDirInfo = OrdinaryExchange->Info.CoreSearch.NextDirInfo;
  696. NextFileName = &NextDirInfo->FileName[0];
  697. // According to colinw, some core servers do not remember to insert the null at the end of the name...
  698. // but the namelength macro handles this correctly. some servers (Xenix, apparently) pad the
  699. // names with spaces. again, the macro handles it....
  700. //
  701. NAME_LENGTH(NameLength, NextFileName,sizeof(NextDirInfo->FileName));
  702. FileNameA.Length = (USHORT)NameLength;
  703. FileNameA.MaximumLength = (USHORT)NameLength;
  704. FileNameA.Buffer = NextFileName;
  705. FileNameU.Length = sizeof(FileNameU_buffer);
  706. FileNameU.MaximumLength = sizeof(FileNameU_buffer);
  707. FileNameU.Buffer = &FileNameU_buffer[0];
  708. Status = RtlOemStringToUnicodeString(&FileNameU, &FileNameA, TRUE);
  709. RxDbgTrace(0, Dbg, ("MRxSmbCoreFileSearch considering.......filename=%wZ, template=%wZ\n",
  710. &FileNameU,&capFobx->UnicodeQueryTemplate));
  711. ASSERT(Status==(STATUS_SUCCESS));
  712. // we deal with a conversion failure by skipping this guy
  713. Match = (Status==(STATUS_SUCCESS));
  714. if (Match && smbFobx->Enumeration.WildCardsFound ) {
  715. //DbgBreakPoint();
  716. try
  717. {
  718. Match = FsRtlIsNameInExpression( &capFobx->UnicodeQueryTemplate,
  719. &FileNameU, TRUE, NULL );
  720. }
  721. except(EXCEPTION_EXECUTE_HANDLER)
  722. {
  723. Match = 0;
  724. }
  725. }
  726. //next issue: will the next dirinfo fit in the user's buffer?!?
  727. if (Match) {
  728. ULONG SpaceNeeded;
  729. PBYTE pRememberBuffer = pBuffer;
  730. //QuadAlign!! pBuffer = (PBYTE)LongAlign(pBuffer); //assume that this will fit
  731. if (SuccessCount != 0) {
  732. pBuffer = (PBYTE)QuadAlignPtr(pBuffer); //assume that this will fit
  733. }
  734. SpaceNeeded = smbFobx->Enumeration.FileNameOffset+FileNameU.Length;
  735. if (pBuffer+SpaceNeeded > pRememberBuffer+*pLengthRemaining) {
  736. BufferOverflow = TRUE;
  737. pBuffer = pRememberBuffer; //rollback
  738. } else {
  739. PSMBCEDB_SERVER_ENTRY pServerEntry;
  740. PFILE_DIRECTORY_INFORMATION pThisBuffer = (PFILE_DIRECTORY_INFORMATION)pBuffer;
  741. SMB_TIME Time;
  742. SMB_DATE Date;
  743. PSMBCE_SERVER Server;
  744. Server = SmbCeGetExchangeServer(Exchange);
  745. BufferOverflow = FALSE;
  746. if (pPreviousBuffer != NULL) {
  747. pPreviousBuffer->NextEntryOffset =
  748. (ULONG)(((PBYTE)pThisBuffer)-((PBYTE)pPreviousBuffer));
  749. }
  750. pPreviousBuffer = pThisBuffer;
  751. RtlZeroMemory(pBuffer,smbFobx->Enumeration.FileNameOffset);
  752. RtlCopyMemory(pBuffer+smbFobx->Enumeration.FileNameOffset, FileNameU.Buffer,FileNameU.Length);
  753. *((PULONG)(pBuffer+smbFobx->Enumeration.FileNameLengthOffset)) = FileNameU.Length;
  754. //hallucinate the record based on specific return type
  755. switch (InformationClass) {
  756. case SMB_FIND_FILE_NAMES_INFO:
  757. break;
  758. case SMB_FIND_FILE_DIRECTORY_INFO:
  759. case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
  760. case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
  761. //just fill what we have...we do not go to a lot of trouble on allocinfo as rdr1 did.
  762. // actually, rdr1 didn't do that here...only on getfielinfo.......
  763. SmbMoveTime (&Time, &NextDirInfo->LastWriteTime);
  764. SmbMoveDate (&Date, &NextDirInfo->LastWriteDate);
  765. pThisBuffer->LastWriteTime = MRxSmbConvertSmbTimeToTime(Server, Time, Date);
  766. pThisBuffer->EndOfFile.LowPart = SmbGetUlong(&NextDirInfo->FileSize);
  767. pThisBuffer->FileAttributes = MRxSmbMapSmbAttributes (NextDirInfo->FileAttributes);
  768. break;
  769. default:
  770. RxDbgTrace( 0, Dbg, ("MRxSmbCoreFileSearch: Invalid FS information class\n"));
  771. ASSERT(!"this can't happen");
  772. Status = STATUS_INVALID_PARAMETER;
  773. goto FINALLY;
  774. }
  775. pBuffer += SpaceNeeded;
  776. *pLengthRemaining -= (ULONG)(pBuffer-pRememberBuffer);
  777. OrdinaryExchange->Info.CoreSearch.CountRemaining--;
  778. SuccessCount++;
  779. }
  780. }
  781. //
  782. // if no match or no overflow, move up in the buffer. this means not only juggling the
  783. // pointers but also saving the resume key
  784. if (!Match || !BufferOverflow) {
  785. MRxSmbDumpResumeKey("BufferKey:",&NextDirInfo->ResumeKey);
  786. *(smbFobx->Enumeration.CoreResumeKey) = NextDirInfo->ResumeKey;
  787. MRxSmbDumpResumeKey("SaveKey: ",smbFobx->Enumeration.CoreResumeKey);
  788. OrdinaryExchange->Info.CoreSearch.NextDirInfo = NextDirInfo + 1;
  789. OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf--;
  790. }
  791. if (OrdinaryExchange->Info.CoreSearch.CountRemaining==0) {
  792. Status = (STATUS_SUCCESS);
  793. goto FINALLY;
  794. }
  795. //should we jam these together by smashing the countrem to 0 on bufferoverflow??? CODE.IMPROVEMENT
  796. if (BufferOverflow) {
  797. Status = (SuccessCount==0)?(STATUS_BUFFER_OVERFLOW):(STATUS_SUCCESS);
  798. goto FINALLY;
  799. }
  800. if (OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf==0) {
  801. Status = MRxSmbLoadCoreFileSearchBuffer( SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS );
  802. }
  803. }
  804. FINALLY:
  805. RxDbgTrace(-1, Dbg, ("MRxSmbCoreFileSearch exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  806. //CODE.IMPROVEMENT if we're done with the resume key we could free it!
  807. #endif
  808. return(Status);
  809. }
  810. NTSTATUS
  811. MrxSmbOemVolumeInfoToUnicode(
  812. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
  813. ULONG *VolumeLabelLengthReturned
  814. )
  815. /*++
  816. Routine Description:
  817. This routine does a GetFileAttributes and remembers the reponse.
  818. Arguments:
  819. Return Value:
  820. RXSTATUS - The return status for the operation
  821. also VolumeLabelLengthReturned is the number of bytes of the label that were stored, if any.
  822. Notes:
  823. --*/
  824. {
  825. NTSTATUS Status = STATUS_SUCCESS;
  826. UNICODE_STRING VolumeLabelU;
  827. OEM_STRING VolumeLabelA;
  828. SMB_DIRECTORY_INFORMATION Buffer;
  829. ULONG NameLength;
  830. ULONG BytesToCopy;
  831. PBYTE VolumeLabel = &OrdinaryExchange->Info.QFSVolInfo.CoreLabel[0];
  832. PAGED_CODE();
  833. NAME_LENGTH(NameLength, VolumeLabel,
  834. sizeof(OrdinaryExchange->Info.QFSVolInfo.CoreLabel));
  835. VolumeLabelA.Length = (USHORT)NameLength;
  836. VolumeLabelA.MaximumLength = (USHORT)NameLength;
  837. VolumeLabelA.Buffer = VolumeLabel;
  838. //some core servers put a '.' in the labelname.....if it's there then remove it
  839. if ((NameLength>8)&& (VolumeLabel[8]=='.') ) {
  840. ULONG i;
  841. for (i=8;i<NameLength;i++) {
  842. VolumeLabel[i] = VolumeLabel[i+1];
  843. }
  844. }
  845. Status = RtlOemStringToUnicodeString(&VolumeLabelU, &VolumeLabelA, TRUE);
  846. if (NT_SUCCESS(Status)) {
  847. PULONG pBufferLength = OrdinaryExchange->Info.pBufferLength;
  848. PFILE_FS_VOLUME_INFORMATION pBuffer = OrdinaryExchange->Info.Buffer;
  849. ULONG BytesToCopy = min((ULONG)VolumeLabelU.Length, (*pBufferLength-sizeof(FILE_FS_VOLUME_INFORMATION)));
  850. RtlCopyMemory(&pBuffer->VolumeLabel[0],
  851. VolumeLabelU.Buffer,
  852. BytesToCopy);
  853. *VolumeLabelLengthReturned = BytesToCopy;
  854. pBuffer->VolumeLabelLength = VolumeLabelU.Length;
  855. IF_DEBUG {
  856. UNICODE_STRING FinalLabel;
  857. FinalLabel.Buffer = &pBuffer->VolumeLabel[0];
  858. FinalLabel.Length = (USHORT)BytesToCopy;
  859. RxDbgTrace(0, Dbg, ("MrxSmbOemVolumeInfoToUnicode vollabel=%wZ\n",&FinalLabel));
  860. }
  861. RtlFreeUnicodeString(&VolumeLabelU);
  862. }
  863. return(Status);
  864. }
  865. MrxSmbCoreQueryFsVolumeInfo(
  866. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  867. )
  868. /*++
  869. Routine Description:
  870. This routine does a GetFileAttributes and remembers the reponse.
  871. Arguments:
  872. OrdinaryExchange - an exchange to be used for conducting this open.
  873. Return Value:
  874. RXSTATUS - The return status for the operation
  875. Notes:
  876. --*/
  877. {
  878. NTSTATUS Status = (STATUS_NOT_IMPLEMENTED);
  879. PSMBSTUFFER_BUFFER_STATE StufferState;
  880. PAGED_CODE();
  881. RxDbgTrace(+1, Dbg, ("MrxSmbCoreQueryFsVolumeInfo entering.......OE=%08lx\n",OrdinaryExchange));
  882. StufferState = &OrdinaryExchange->AssociatedStufferState;
  883. ASSERT( StufferState );
  884. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_SEARCH,
  885. SMB_REQUEST_SIZE(SEARCH),
  886. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  887. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  888. );
  889. MRxSmbDumpStufferState (1100,"SMB w/ searchvolumelabel before stuffing",StufferState);
  890. //CODE.IMPROVEMENT if this is truly core, we have to copy the name since its in UNICODE
  891. // otherwise, we don't need to copy the name here, we can just Mdl like in writes
  892. MRxSmbStuffSMB (StufferState,
  893. "0wwB4yw!",
  894. // 0 UCHAR WordCount; // Count of parameter words = 2
  895. 1, // w _USHORT( MaxCount ); // Number of dir. entries to return
  896. // w _USHORT( SearchAttributes );
  897. SMB_FILE_ATTRIBUTE_VOLUME,
  898. SMB_WCT_CHECK(2) // B _USHORT( ByteCount ); // Count of data bytes; min = 5
  899. // UCHAR Buffer[1]; // Buffer containing:
  900. &MRxSmbAll8dot3Files,// 4 //UCHAR BufferFormat1; // 0x04 -- ASCII
  901. // //UCHAR FileName[]; // File name, may be null
  902. 0x05, // y //UCHAR BufferFormat2; // 0x05 -- Variable block
  903. 0 // w //USHORT ResumeKeyLength; // Length of resume key, may be 0
  904. // //UCHAR SearchStatus[]; // Resume key
  905. );
  906. MRxSmbDumpStufferState (700,"SMB w/ searchvolumelabel after stuffing",StufferState);
  907. //ASSERT(!"Now it's stuffed");
  908. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  909. SMBPSE_OETYPE_COREQUERYLABEL
  910. );
  911. //Status = RxStatus(NOT_IMPLEMENTED);
  912. FINALLY:
  913. RxDbgTrace(-1, Dbg, ("MrxSmbCoreQueryFsVolumeInfo exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  914. return(Status);
  915. }
  916. NTSTATUS
  917. MrxSmbQueryFsVolumeInfo(
  918. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  919. )
  920. /*++
  921. Routine Description:
  922. This routine does a downlevel getvolumeinfo/FS_VOLUME_INFORMATION.
  923. Arguments:
  924. OrdinaryExchange - duh!
  925. Return Value:
  926. RXSTATUS - The return status for the operation
  927. Notes:
  928. --*/
  929. {
  930. NTSTATUS Status;
  931. RxCaptureFcb;
  932. RxCaptureFobx;
  933. PSMBCE_SERVER pServer;
  934. BOOLEAN UseTransactVersion;
  935. REQ_QUERY_FS_INFORMATION VolInfo;
  936. PFILE_FS_VOLUME_INFORMATION pBuffer = OrdinaryExchange->Info.Buffer;
  937. PULONG pBufferLength = OrdinaryExchange->Info.pBufferLength;
  938. ULONG VolumeLabelLengthReturned = 0;
  939. PAGED_CODE();
  940. ASSERT(pBuffer!=NULL);
  941. pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  942. UseTransactVersion = BooleanFlagOn(pServer->DialectFlags,DF_LANMAN20);
  943. RxDbgTrace(+1, Dbg, ("MrxSmbQueryFsVolumeInfo entering.......OE=%08lx\n",OrdinaryExchange));
  944. pBuffer->SupportsObjects = FALSE;
  945. pBuffer->VolumeCreationTime.LowPart = 0;
  946. pBuffer->VolumeCreationTime.HighPart = 0;
  947. pBuffer->VolumeSerialNumber = 0;
  948. pBuffer->VolumeLabelLength = 0;
  949. OrdinaryExchange->Info.QFSVolInfo.CoreLabel[0] = 0; //no label
  950. if (!UseTransactVersion) {
  951. Status = MrxSmbCoreQueryFsVolumeInfo(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  952. } else {
  953. VolInfo.InformationLevel = SMB_INFO_VOLUME;
  954. Status = MRxSmbSimpleSyncTransact2(
  955. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  956. SMBPSE_OETYPE_T2_FOR_LANMAN_VOLUMELABEL_INFO,
  957. TRANS2_QUERY_FS_INFORMATION,
  958. &VolInfo,sizeof(VolInfo),
  959. NULL,0
  960. );
  961. }
  962. ASSERT ( *pBufferLength>=sizeof(FILE_FS_VOLUME_INFORMATION));
  963. RxDbgTrace(0, Dbg, ("MrxSmbQueryFsVolumeInfo OEstatus=%08lx\n",Status));
  964. //DbgBreakPoint();
  965. if ( (Status==STATUS_SUCCESS) &&
  966. (OrdinaryExchange->Info.QFSVolInfo.CoreLabel[0] != 0) ) {
  967. Status = MrxSmbOemVolumeInfoToUnicode(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,&VolumeLabelLengthReturned);
  968. } else if ( (Status == STATUS_NO_SUCH_FILE)
  969. || (Status == STATUS_NO_MORE_FILES) ) {
  970. //
  971. // these statuses indicate that there's no volume label
  972. // the remote volume. Return success with no data.
  973. //
  974. Status = (STATUS_SUCCESS);
  975. }
  976. if (NT_SUCCESS(Status)) {
  977. *pBufferLength -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION,VolumeLabel);
  978. *pBufferLength -= VolumeLabelLengthReturned;
  979. }
  980. RxDbgTrace(-1, Dbg, ("MrxSmbQueryFsVolumeInfo exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  981. return(Status);
  982. }
  983. NTSTATUS
  984. MrxSmbCoreQueryDiskAttributes(
  985. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  986. )
  987. /*++
  988. Routine Description:
  989. This routine does a GetDiskAttributes and remembers the reponse in a buffer pointed to
  990. by the exchange. this is called from the downlevel queryvolumeinfo AND ALSO from
  991. extend-for-cached-write.
  992. Arguments:
  993. OrdinaryExchange - duh!
  994. Return Value:
  995. RXSTATUS - The return status for the operation
  996. Notes:
  997. --*/
  998. {
  999. NTSTATUS Status;
  1000. RxCaptureFcb; RxCaptureFobx;
  1001. PSMBSTUFFER_BUFFER_STATE StufferState;
  1002. PAGED_CODE();
  1003. ASSERT(OrdinaryExchange->Info.Buffer!=NULL);
  1004. RxDbgTrace(+1, Dbg, ("MrxSmbCoreQueryDiskAttributes entering.......OE=%08lx\n",OrdinaryExchange));
  1005. StufferState = &OrdinaryExchange->AssociatedStufferState;
  1006. ASSERT( StufferState );
  1007. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_QUERY_INFORMATION_DISK,
  1008. SMB_REQUEST_SIZE(QUERY_INFORMATION_DISK),
  1009. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  1010. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  1011. );
  1012. RxDbgTrace(0, Dbg,("querydiskattribs command initial status = %lu\n",Status));
  1013. MRxSmbDumpStufferState (1100,"SMB w/ querydiskattribs before stuffing",StufferState);
  1014. MRxSmbStuffSMB (StufferState,
  1015. "0B!",
  1016. // 0 UCHAR WordCount; // Count of parameter words = 0
  1017. SMB_WCT_CHECK(0) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
  1018. // UCHAR Buffer[1]; // empty
  1019. );
  1020. MRxSmbDumpStufferState (700,"SMB w/ querydiskattribs after stuffing",StufferState);
  1021. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1022. SMBPSE_OETYPE_COREQUERYDISKATTRIBUTES
  1023. );
  1024. FINALLY:
  1025. RxDbgTrace(-1, Dbg, ("MrxSmbCoreQueryDiskAttributes exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  1026. return(Status);
  1027. }
  1028. NTSTATUS
  1029. MrxSmbQueryDiskAttributes(
  1030. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This routine does a GetDiskAttributes and remembers the reponse in a buffer pointed to
  1035. by the exchange. this is called from the downlevel queryvolumeinfo AND ALSO from
  1036. extend-for-cached-write.
  1037. Arguments:
  1038. OrdinaryExchange - duh!
  1039. Return Value:
  1040. RXSTATUS - The return status for the operation
  1041. Notes:
  1042. NTRAID-455631-2/2/2000 yunlin NT transaction should be used
  1043. --*/
  1044. {
  1045. NTSTATUS Status;
  1046. RxCaptureFcb;
  1047. RxCaptureFobx;
  1048. PSMBCE_SERVER pServer;
  1049. BOOLEAN UseTransactVersion;
  1050. REQ_QUERY_FS_INFORMATION VolInfo;
  1051. PAGED_CODE();
  1052. ASSERT(OrdinaryExchange->Info.Buffer!=NULL);
  1053. pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  1054. UseTransactVersion = BooleanFlagOn(pServer->DialectFlags,DF_LANMAN20) &&
  1055. !MRxSmbForceCoreGetAttributes;
  1056. if (!UseTransactVersion) {
  1057. return MrxSmbCoreQueryDiskAttributes(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1058. }
  1059. RxDbgTrace(+1, Dbg, ("MrxSmbQueryDiskAttributes entering.......OE=%08lx\n",OrdinaryExchange));
  1060. VolInfo.InformationLevel = SMB_INFO_ALLOCATION;
  1061. Status = MRxSmbSimpleSyncTransact2(
  1062. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1063. SMBPSE_OETYPE_T2_FOR_LANMAN_DISKATTRIBUTES_INFO,
  1064. TRANS2_QUERY_FS_INFORMATION,
  1065. &VolInfo,sizeof(VolInfo),
  1066. NULL,0
  1067. );
  1068. RxDbgTrace(-1, Dbg, ("MrxSmbQueryDiskAttributes exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  1069. return(Status);
  1070. }
  1071. NTSTATUS
  1072. MRxSmbGetNtAllocationInfo (
  1073. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  1074. );
  1075. NTSTATUS
  1076. SmbPseExchangeStart_CoreInfo(
  1077. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. This is the start routine for VOLINFO.
  1082. Arguments:
  1083. pExchange - the exchange instance
  1084. Return Value:
  1085. RXSTATUS - The return status for the operation
  1086. --*/
  1087. {
  1088. NTSTATUS Status = (STATUS_NOT_IMPLEMENTED);
  1089. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  1090. ULONG InformationClass = OrdinaryExchange->Info.InfoClass;
  1091. PBYTE pBuffer = (PBYTE)OrdinaryExchange->Info.Buffer;
  1092. PULONG pBufferLength = OrdinaryExchange->Info.pBufferLength;
  1093. RxCaptureFcb; RxCaptureFobx;
  1094. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1095. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1096. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1097. PAGED_CODE();
  1098. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_CoreInfo\n", 0 ));
  1099. ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);
  1100. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  1101. //ASSERT (StufferState->CurrentCommand == SMB_COM_NO_ANDX_COMMAND);
  1102. switch (OrdinaryExchange->EntryPoint) {
  1103. case SMBPSE_OE_FROM_QUERYVOLUMEINFO:
  1104. switch (InformationClass) {
  1105. case FileFsVolumeInformation:
  1106. Status = MrxSmbQueryFsVolumeInfo(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1107. goto FINALLY;
  1108. case FileFsSizeInformation:
  1109. Status = MrxSmbQueryDiskAttributes(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1110. goto FINALLY;
  1111. default:
  1112. ASSERT(!"this should have been turned away");
  1113. goto FINALLY;
  1114. }
  1115. ASSERT(!"shouldn't get here1");
  1116. goto FINALLY;
  1117. case SMBPSE_OE_FROM_QUERYFILEINFO:
  1118. Status = MRxSmbGetFileAttributes(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1119. if (!NT_SUCCESS(Status)) goto FINALLY;
  1120. switch (InformationClass) {
  1121. case SMB_QUERY_FILE_BASIC_INFO:
  1122. *((PFILE_BASIC_INFORMATION)pBuffer) = OrdinaryExchange->Create.FileInfo.Basic;
  1123. *pBufferLength -= sizeof(FILE_BASIC_INFORMATION);
  1124. goto FINALLY;
  1125. case SMB_QUERY_FILE_STANDARD_INFO:
  1126. *((PFILE_STANDARD_INFORMATION)pBuffer) = OrdinaryExchange->Create.FileInfo.Standard;
  1127. *pBufferLength -= sizeof(FILE_STANDARD_INFORMATION);
  1128. goto FINALLY;
  1129. default:
  1130. ASSERT(!"this should have been turned away");
  1131. goto FINALLY;
  1132. }
  1133. ASSERT(!"shouldn't get here2");
  1134. goto FINALLY;
  1135. case SMBPSE_OE_FROM_SETFILEINFO:
  1136. switch (InformationClass) {
  1137. case FileBasicInformation:
  1138. {
  1139. ULONG SmbAttributes = MRxSmbMapFileAttributes(((PFILE_BASIC_INFORMATION)pBuffer)->FileAttributes);
  1140. PFILE_BASIC_INFORMATION BasicInfo = (PFILE_BASIC_INFORMATION)pBuffer;
  1141. if (SmbAttributes != 0 ||
  1142. (BasicInfo->CreationTime.QuadPart == 0 &&
  1143. BasicInfo->LastWriteTime.QuadPart == 0 &&
  1144. BasicInfo->LastAccessTime.QuadPart == 0)) {
  1145. Status = MRxSmbSetFileAttributes(
  1146. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1147. SmbAttributes);
  1148. }
  1149. if (BasicInfo->LastWriteTime.QuadPart == 0 &&
  1150. FlagOn(pServerEntry->Server.DialectFlags,DF_W95)) {
  1151. // Win9x server only takes last write time.
  1152. Status = STATUS_SUCCESS;
  1153. goto FINALLY;
  1154. }
  1155. if (BasicInfo->CreationTime.QuadPart != 0 ||
  1156. BasicInfo->LastWriteTime.QuadPart != 0 ||
  1157. BasicInfo->LastAccessTime.QuadPart != 0) {
  1158. Status = MRxSmbDeferredCreate(RxContext);
  1159. if (Status == STATUS_SUCCESS) {
  1160. Status = MRxSmbSetFileAttributes(
  1161. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1162. SmbAttributes);
  1163. }
  1164. }
  1165. }
  1166. goto FINALLY;
  1167. case FileEndOfFileInformation:
  1168. if (((PFILE_END_OF_FILE_INFORMATION)pBuffer)->EndOfFile.HighPart) {
  1169. Status = (STATUS_INVALID_PARAMETER);
  1170. } else {
  1171. Status = MRxSmbCoreTruncate(
  1172. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1173. smbSrvOpen->Fid,
  1174. ((PFILE_END_OF_FILE_INFORMATION)pBuffer)->EndOfFile.LowPart);
  1175. }
  1176. goto FINALLY;
  1177. case FileDispositionInformation:
  1178. OrdinaryExchange->pPathArgument1 = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
  1179. Status = MRxSmbCoreDeleteForSupercedeOrClose(
  1180. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1181. ((BOOLEAN)( NodeType(capFcb)==RDBSS_NTC_STORAGE_TYPE_DIRECTORY )));
  1182. goto FINALLY;
  1183. default:
  1184. ASSERT(!"this should have been turned away");
  1185. goto FINALLY;
  1186. }
  1187. ASSERT(!"shouldn't get here3");
  1188. goto FINALLY;
  1189. case SMBPSE_OE_FROM_QUERYDIRECTORY:
  1190. Status = MRxSmbCoreFileSearch(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1191. goto FINALLY;
  1192. case SMBPSE_OE_FROM_EXTENDFILEFORCACHEING:
  1193. {
  1194. PSMBCE_NET_ROOT psmbNetRoot = SmbCeGetExchangeNetRoot(OrdinaryExchange);
  1195. PMRX_V_NET_ROOT pVNetRoot = SmbCeGetExchangeVNetRoot(OrdinaryExchange);
  1196. PMRX_NET_ROOT pNetRoot = pVNetRoot->pNetRoot;
  1197. PSMBCE_SERVER psmbServer = SmbCeGetExchangeServer(OrdinaryExchange);
  1198. ULONG ClusterSize;
  1199. PLARGE_INTEGER pFileSize = (PLARGE_INTEGER)(OrdinaryExchange->Info.Buffer);
  1200. PLARGE_INTEGER pAllocationSize = (PLARGE_INTEGER)(OrdinaryExchange->Info.pBufferLength);
  1201. //we will need the cluster size
  1202. if (OrdinaryExchange->ServerVersion==pNetRoot->ParameterValidationStamp) {
  1203. ClusterSize=pNetRoot->DiskParameters.ClusterSize;
  1204. } else {
  1205. RxSynchronizeBlockingOperations(RxContext,&psmbNetRoot->ClusterSizeSerializationQueue);
  1206. if (OrdinaryExchange->ServerVersion!=pNetRoot->ParameterValidationStamp) {
  1207. //
  1208. //here we have to go find out the clustersize
  1209. NTSTATUS LocalStatus;
  1210. FILE_FS_SIZE_INFORMATION UsersBuffer;
  1211. ULONG BufferLength = sizeof(FILE_FS_SIZE_INFORMATION);
  1212. //fill in the exchange params so that we can get the params we need
  1213. OrdinaryExchange->Info.Buffer = &UsersBuffer;
  1214. OrdinaryExchange->Info.pBufferLength = &BufferLength;
  1215. LocalStatus = MrxSmbQueryDiskAttributes(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1216. if (LocalStatus == STATUS_SUCCESS) {
  1217. ClusterSize = UsersBuffer.BytesPerSector * UsersBuffer.SectorsPerAllocationUnit;
  1218. pNetRoot->ParameterValidationStamp =OrdinaryExchange->ServerVersion;
  1219. } else {
  1220. ClusterSize = 0;
  1221. }
  1222. if (ClusterSize==0) {
  1223. ClusterSize = 1;
  1224. }
  1225. pNetRoot->DiskParameters.ClusterSize = ClusterSize;
  1226. RxDbgTrace(0, Dbg, ("clustersize set to %08lx\n", ClusterSize ));
  1227. RxLog(("clustersize rx/n/cs %lx %lx %lx\n",
  1228. OrdinaryExchange->RxContext,pNetRoot,ClusterSize ));
  1229. SmbLog(LOG,
  1230. SmbPseExchangeStart_CoreInfo,
  1231. LOGPTR(OrdinaryExchange->RxContext)
  1232. LOGPTR(pNetRoot)
  1233. LOGULONG(ClusterSize));
  1234. } else {
  1235. // someone else went and got the value while i was asleep...just use it
  1236. ClusterSize=pNetRoot->DiskParameters.ClusterSize;
  1237. }
  1238. RxResumeBlockedOperations_Serially(RxContext,&psmbNetRoot->ClusterSizeSerializationQueue);
  1239. }
  1240. ASSERT (ClusterSize != 0);
  1241. if (FlagOn(psmbServer->DialectFlags,DF_NT_SMBS)) {
  1242. //i'm using this to identify a server that supports 64bit offsets
  1243. //for these guys, we write a zero at the eof....since the filesystems
  1244. //extend on writes this will be much better than a set-end-of-file
  1245. LARGE_INTEGER ByteOffset,AllocationSize,ClusterSizeAsLI;
  1246. ULONG Buffer = 0;
  1247. UCHAR WriteCommand;
  1248. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  1249. // We have to be smart about this. Ntfs sometimes gets configured
  1250. // with cluster sizes around 32K.
  1251. // There is no reason to believe that the
  1252. // Allocation size has changed if the new File size is less than
  1253. // previous Allocation size. So, skip the extend and the qfi for
  1254. // Allocation size.
  1255. ClusterSizeAsLI.QuadPart = ClusterSize;
  1256. AllocationSize.QuadPart = (pFileSize->QuadPart+ ClusterSizeAsLI.QuadPart) &
  1257. ~(ClusterSizeAsLI.QuadPart - 1);
  1258. if ((AllocationSize.QuadPart <= capFcb->Header.AllocationSize.QuadPart) ||
  1259. ((capFcb->Header.AllocationSize.QuadPart == 0) && (pFileSize->QuadPart < 0x1000))) {
  1260. // Return the old value.
  1261. pAllocationSize->QuadPart = AllocationSize.QuadPart;
  1262. RxDbgTrace(0, Dbg, ("alocatedsiz222e set to %08lx\n", pAllocationSize->LowPart ));
  1263. // At this point, we know that the written data hasn't been
  1264. // flushed. This is ok, since the client would have requested
  1265. // a flush if the data need to be sunk into the server's disk.
  1266. // Server file size is different from the client file size
  1267. // at this point, but allocation size is the same. We extend
  1268. // to make sure the server has space, if we know the extend isn't
  1269. // going to question space constraint, we won't even try!!
  1270. } else {
  1271. if (FlagOn(pServer->DialectFlags,DF_LARGE_FILES)) {
  1272. WriteCommand = SMB_COM_WRITE_ANDX;
  1273. } else {
  1274. WriteCommand = SMB_COM_WRITE;
  1275. }
  1276. ByteOffset.QuadPart = pFileSize->QuadPart - 1;
  1277. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,0));
  1278. COVERED_CALL(MRxSmbBuildWriteRequest(
  1279. OrdinaryExchange,
  1280. TRUE, // IsPagingIo
  1281. WriteCommand,
  1282. 1,
  1283. &ByteOffset,
  1284. (PBYTE)&Buffer,
  1285. NULL //BufferAsMdl,
  1286. ));
  1287. COVERED_CALL(SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1288. SMBPSE_OETYPE_EXTEND_WRITE
  1289. ));
  1290. //this is what you do if you can't do better
  1291. ClusterSizeAsLI.QuadPart = ClusterSize;
  1292. AllocationSize.QuadPart =
  1293. (pFileSize->QuadPart+ ClusterSizeAsLI.QuadPart) &
  1294. ~(ClusterSizeAsLI.QuadPart - 1);
  1295. if (Status == STATUS_SUCCESS) {
  1296. Status = MRxSmbGetNtAllocationInfo(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS);
  1297. }
  1298. if (NT_SUCCESS(Status)) {
  1299. pAllocationSize->QuadPart = OrdinaryExchange->Transact2.AllocationSize.QuadPart;
  1300. RxDbgTrace(0, Dbg, ("alocatedsiz222e set to %08lx\n", pAllocationSize->LowPart ));
  1301. }
  1302. }
  1303. }
  1304. if ( (!FlagOn(psmbServer->DialectFlags,DF_NT_SMBS)) ||
  1305. (!NT_SUCCESS(Status) && (Status != STATUS_DISK_FULL) && (Status != STATUS_RETRY)) ) {
  1306. ULONG FileSize,AllocationSize;
  1307. FileSize = pFileSize->LowPart;
  1308. COVERED_CALL(MRxSmbCoreTruncate(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1309. smbSrvOpen->Fid, FileSize
  1310. ));
  1311. //this is what you do if you can't do better
  1312. AllocationSize = (FileSize+ClusterSize)&~(ClusterSize-1);
  1313. pAllocationSize->QuadPart = AllocationSize; //64bit!
  1314. RxDbgTrace(0, Dbg, ("alocatedsize set to %08lx\n", pAllocationSize->LowPart ));
  1315. //if we care a lot about downlevel performance, we could do the same as ntgetallocation
  1316. //except that we would use a 32bit smb.........like query_information2
  1317. }
  1318. }
  1319. goto FINALLY;
  1320. }
  1321. FINALLY:
  1322. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_CoreInfo exit w %08lx\n", Status ));
  1323. return Status;
  1324. }
  1325. NTSTATUS
  1326. MRxSmbFinishSearch (
  1327. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  1328. PRESP_SEARCH Response
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. This routine actually gets the stuff out of the VolInfo response and finishes the close.
  1333. Arguments:
  1334. OrdinaryExchange - the exchange instance
  1335. Response - the response
  1336. Return Value:
  1337. RXSTATUS - The return status for the operation
  1338. --*/
  1339. {
  1340. NTSTATUS Status = (STATUS_SUCCESS);
  1341. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  1342. RxCaptureFobx;
  1343. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1344. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1345. PAGED_CODE();
  1346. RxDbgTrace(+1, Dbg, ("MRxSmbFinishSearch\n" ));
  1347. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishSearch:");
  1348. if (Response->WordCount != 1) {
  1349. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1350. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1351. goto FINALLY;
  1352. }
  1353. if (OrdinaryExchange->OEType == SMBPSE_OETYPE_COREQUERYLABEL) {
  1354. //here, all we do is to copy the label to wherever is pointed to by
  1355. if (SmbGetUshort(&Response->Count)>0) {
  1356. PBYTE smbDirInfotmp = &Response->Buffer[0]
  1357. +sizeof(UCHAR) //bufferformat
  1358. +sizeof(USHORT); //datalength
  1359. PSMB_DIRECTORY_INFORMATION smbDirInfo = (PSMB_DIRECTORY_INFORMATION)smbDirInfotmp;
  1360. RxDbgTrace(+1, Dbg, ("MRxSmbFinishSearch corelabl=%s,size=%d\n",
  1361. smbDirInfo->FileName, sizeof(smbDirInfo->FileName) ));
  1362. if (sizeof(smbDirInfo->FileName) != 13) { //straightfrom the spec
  1363. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1364. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1365. goto FINALLY;
  1366. }
  1367. RtlCopyMemory(OrdinaryExchange->Info.QFSVolInfo.CoreLabel,
  1368. smbDirInfo->FileName, sizeof(smbDirInfo->FileName)
  1369. );
  1370. } else {
  1371. OrdinaryExchange->Info.QFSVolInfo.CoreLabel[0] = 0; //no label
  1372. }
  1373. } else if (OrdinaryExchange->OEType == SMBPSE_OETYPE_CORESEARCHFORCHECKEMPTY) {
  1374. //here, we 're doing a search SMB to see if the directory is empty. we have to read thru the
  1375. // entries returned (if successful). if we encounter ones that are neither '.' or '..', set
  1376. // resumekey to null since that will tell the guy above that the directory is nonempty
  1377. ULONG Count = SmbGetUshort(&Response->Count);
  1378. PSMB_DIRECTORY_INFORMATION NextDirInfo =
  1379. (PSMB_DIRECTORY_INFORMATION)(&Response->Buffer[0]+sizeof(UCHAR)+sizeof(USHORT));
  1380. for (;Count>0;Count--,NextDirInfo++) {
  1381. RxDbgTrace(0, Dbg, ("--->emptydirchk: file=%s\n",&NextDirInfo->FileName[0]));
  1382. /*
  1383. // Since the DOS Server returns the file name ". " instead of ".", and so does the
  1384. // ".. ", the following if {...} statements are always past through with no action.
  1385. // But those statements make the RMDIR not working on OS2 Server since it returns the "."
  1386. // and ".." without following blanks. After the if {...} statements were removed, the RMDIR
  1387. // workes on OS2 Server and no impact has been found to access the DOS Server.
  1388. if (NextDirInfo->FileName[0]=='.') {
  1389. CHAR c1;
  1390. if ((c1=NextDirInfo->FileName[1])==0) {
  1391. continue; //skip past "."
  1392. } else if ((c1=='.')&&(NextDirInfo->FileName[2]==0)) {
  1393. continue; //skip past ".."
  1394. } else {
  1395. NOTHING;
  1396. }
  1397. }
  1398. */
  1399. // here we have found a bad one...make sure there's no resume key and change the status
  1400. Status = (STATUS_NO_MORE_FILES);
  1401. OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey = NULL;
  1402. }
  1403. //if we get here with success, set up the resume key and buffer
  1404. if (Status == (STATUS_SUCCESS)) {
  1405. NextDirInfo--;
  1406. OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKeyBuffer =
  1407. NextDirInfo->ResumeKey;
  1408. OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey =
  1409. &OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKeyBuffer;
  1410. }
  1411. } else {
  1412. //all that we do here is to setup the nextdirptr and the count in the OE
  1413. ASSERT(OrdinaryExchange->OEType == SMBPSE_OETYPE_CORESEARCH);
  1414. OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf = SmbGetUshort(&Response->Count);
  1415. OrdinaryExchange->Info.CoreSearch.NextDirInfo =
  1416. (PSMB_DIRECTORY_INFORMATION)(&Response->Buffer[0]+sizeof(UCHAR)+sizeof(USHORT));
  1417. IF_DEBUG {
  1418. ULONG tcount = OrdinaryExchange->Info.CoreSearch.CountRemainingInSmbbuf;
  1419. PSMB_DIRECTORY_INFORMATION ndi = OrdinaryExchange->Info.CoreSearch.NextDirInfo;
  1420. RxDbgTrace(0, Dbg, ("--->coresearch: count/ndi=%08lx/%08lx\n",tcount,ndi));
  1421. if (tcount) {
  1422. //DbgBreakPoint();
  1423. RxDbgTrace(0, Dbg, ("--->coresearch: firstfile=%s\n",&ndi->FileName[0]));
  1424. }
  1425. }
  1426. }
  1427. FINALLY:
  1428. RxDbgTrace(-1, Dbg, ("MRxSmbFinishSearch returning %08lx\n", Status ));
  1429. return Status;
  1430. }
  1431. NTSTATUS
  1432. MRxSmbFinishQueryDiskInfo (
  1433. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  1434. PRESP_QUERY_INFORMATION_DISK Response
  1435. )
  1436. /*++
  1437. Routine Description:
  1438. This routine actually gets the stuff out of the VolInfo response and finishes the close.
  1439. Arguments:
  1440. OrdinaryExchange - the exchange instance
  1441. Response - the response
  1442. Return Value:
  1443. RXSTATUS - The return status for the operation
  1444. --*/
  1445. {
  1446. NTSTATUS Status = (STATUS_SUCCESS);
  1447. PFILE_FS_SIZE_INFORMATION UsersBuffer = OrdinaryExchange->Info.Buffer;
  1448. PULONG BufferLength = OrdinaryExchange->Info.pBufferLength;
  1449. PAGED_CODE();
  1450. RxDbgTrace(+1, Dbg, ("MRxSmbFinishQueryDiskInfo\n" ));
  1451. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishQueryDiskInfo:");
  1452. //CODE.IMPROVEMENT this should be a macro.........
  1453. IF_DEBUG{
  1454. PRX_CONTEXT RxContext = OrdinaryExchange->RxContext;
  1455. RxCaptureFobx;
  1456. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1457. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1458. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  1459. }
  1460. if (Response->WordCount != 5 ||
  1461. SmbGetUshort(&Response->ByteCount) != 0) {
  1462. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1463. OrdinaryExchange->Status = STATUS_INVALID_NETWORK_RESPONSE;
  1464. goto FINALLY;
  1465. }
  1466. UsersBuffer->TotalAllocationUnits.QuadPart = SmbGetUshort(&Response->TotalUnits);
  1467. UsersBuffer->AvailableAllocationUnits.QuadPart = SmbGetUshort(&Response->FreeUnits);
  1468. UsersBuffer->SectorsPerAllocationUnit = SmbGetUshort(&Response->BlocksPerUnit);
  1469. UsersBuffer->BytesPerSector = SmbGetUshort(&Response->BlockSize);
  1470. *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION);
  1471. FINALLY:
  1472. RxDbgTrace(-1, Dbg, ("MRxSmbFinishQueryDiskInfo returning %08lx\n", Status ));
  1473. return Status;
  1474. }
  1475. NTSTATUS
  1476. MRxSmbExtendForCache (
  1477. IN OUT struct _RX_CONTEXT * RxContext,
  1478. IN PLARGE_INTEGER pNewFileSize,
  1479. OUT PLARGE_INTEGER pNewAllocationSize
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. This routine handles network requests to extend the file for cached IO. we just share the
  1484. core_info skeleton.
  1485. Arguments:
  1486. RxContext - the RDBSS context
  1487. Return Value:
  1488. RXSTATUS - The return status for the operation
  1489. --*/
  1490. {
  1491. NTSTATUS Status;
  1492. RxCaptureFcb; RxCaptureFobx;
  1493. PMRX_SRV_OPEN SrvOpen;
  1494. PMRX_SMB_SRV_OPEN smbSrvOpen;
  1495. PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
  1496. PSMB_EXCHANGE Exchange;
  1497. PAGED_CODE();
  1498. if (capFcb->Attributes & FILE_ATTRIBUTE_COMPRESSED) {
  1499. //here, we just get out since disk reservations don't do us any good....
  1500. pNewAllocationSize->QuadPart = (pNewFileSize->QuadPart)<<2;
  1501. return(STATUS_SUCCESS);
  1502. }
  1503. if (capFcb->pNetRoot->Type == NET_ROOT_PRINT) {
  1504. pNewAllocationSize->QuadPart = pNewFileSize->QuadPart;
  1505. // invalidate the name based file info cache since it is almost impossible
  1506. // to know the last write time of the file on the server.
  1507. MRxSmbInvalidateFileInfoCache(RxContext);
  1508. return(STATUS_SUCCESS);
  1509. }
  1510. RxDbgTrace(+1, Dbg, ("MRxSmbExtendForCache %08lx %08lx %08lx %08lx\n",
  1511. capFcb->Header.FileSize.LowPart,
  1512. capFcb->Header.AllocationSize.LowPart,
  1513. pNewFileSize->LowPart,
  1514. pNewAllocationSize->LowPart
  1515. ));
  1516. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  1517. SrvOpen = capFobx->pSrvOpen;
  1518. smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1519. if (FALSE) {
  1520. DbgPrint("Extend top %08lx %08lx %08lx %08lx\n",
  1521. capFcb->Header.FileSize.LowPart,
  1522. capFcb->Header.AllocationSize.LowPart,
  1523. pNewFileSize->LowPart,
  1524. pNewAllocationSize->LowPart);
  1525. }
  1526. IF_NOT_MRXSMB_BUILD_FOR_DISCONNECTED_CSC{
  1527. NOTHING;
  1528. } else {
  1529. if (smbSrvOpen->hfShadow != 0){
  1530. NTSTATUS ShadowExtendNtStatus;
  1531. ShadowExtendNtStatus = MRxSmbDCscExtendForCache(RxContext,
  1532. pNewFileSize,
  1533. pNewAllocationSize);
  1534. if (ShadowExtendNtStatus != STATUS_MORE_PROCESSING_REQUIRED) {
  1535. RxDbgTrace(-1, Dbg,
  1536. ("MRxSmbExtendForCache returningDCON with status=%08lx\n",
  1537. ShadowExtendNtStatus ));
  1538. return(ShadowExtendNtStatus);
  1539. } else {
  1540. RxDbgTrace(0, Dbg,
  1541. ("MRxSmbExtendForCache continueingDCON with status=%08lx\n",
  1542. ShadowExtendNtStatus ));
  1543. }
  1544. }
  1545. }
  1546. //we just pass in our info into MRxSmbCoreInformation thru the existing pointers....
  1547. //we have two pointers.....the first two params are ptrs......
  1548. do {
  1549. Status = MRxSmbCoreInformation(RxContext,0,
  1550. (PVOID)pNewFileSize,
  1551. (PULONG)pNewAllocationSize,
  1552. SMBPSE_OE_FROM_EXTENDFILEFORCACHEING
  1553. );
  1554. } while (Status == STATUS_RETRY);
  1555. if (FALSE) {
  1556. DbgPrint("Extend exit Status %lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
  1557. Status,
  1558. capFcb->Header.FileSize.HighPart,
  1559. capFcb->Header.FileSize.LowPart,
  1560. capFcb->Header.AllocationSize.HighPart,
  1561. capFcb->Header.AllocationSize.LowPart,
  1562. pNewFileSize->HighPart,
  1563. pNewFileSize->LowPart,
  1564. pNewAllocationSize->HighPart,
  1565. pNewAllocationSize->LowPart);
  1566. }
  1567. // Only invalidate if Allocation Size changed.
  1568. // Unless we close, the Last Access time or Last Written time is
  1569. // not guaranteed to change for Ntfs (one file system).
  1570. // If it is not guaranteed for one file system, we needn't guarantee for any.
  1571. // So, Don't have to Invalidate our FileInfo Cache.
  1572. if (capFcb->Header.AllocationSize.QuadPart < pNewAllocationSize->QuadPart) {
  1573. MRxSmbInvalidateFileInfoCache(RxContext);
  1574. }
  1575. RxLog(("Extend exit %lx %lx %lx %lx %lx\n",
  1576. RxContext,
  1577. capFcb->Header.FileSize.LowPart,
  1578. capFcb->Header.AllocationSize.LowPart,
  1579. pNewFileSize->LowPart,
  1580. pNewAllocationSize->LowPart));
  1581. SmbLog(LOG,
  1582. MRxSmbExtendForCache,
  1583. LOGPTR(RxContext)
  1584. LOGULONG(capFcb->Header.FileSize.LowPart)
  1585. LOGULONG(capFcb->Header.AllocationSize.LowPart)
  1586. LOGULONG(pNewFileSize->LowPart)
  1587. LOGULONG(pNewAllocationSize->LowPart));
  1588. RxDbgTrace(-1, Dbg, ("MRxSmbExtendForCache exit with status=%08lx %08lx %08lx\n",
  1589. Status, pNewFileSize->LowPart, pNewAllocationSize->LowPart));
  1590. return(Status);
  1591. }
  1592. NTSTATUS
  1593. MRxSmbExtendForNonCache(
  1594. IN OUT struct _RX_CONTEXT * RxContext,
  1595. IN PLARGE_INTEGER pNewFileSize,
  1596. OUT PLARGE_INTEGER pNewAllocationSize
  1597. )
  1598. /*++
  1599. Routine Description:
  1600. This routine handles network requests to extend the file for noncached IO. since the write
  1601. itself will extend the file, we can pretty much just get out quickly.
  1602. Arguments:
  1603. RxContext - the RDBSS context
  1604. Return Value:
  1605. RXSTATUS - The return status for the operation
  1606. --*/
  1607. {
  1608. NTSTATUS Status = STATUS_SUCCESS;
  1609. //RxCaptureFcb; RxCaptureFobx;
  1610. //PMRXSMB_RX_CONTEXT pMRxSmbContext = MRxSmbGetMinirdrContext(RxContext);
  1611. //PSMB_EXCHANGE Exchange;
  1612. PAGED_CODE();
  1613. pNewAllocationSize->QuadPart = pNewFileSize->QuadPart;
  1614. // invalidate the name based file info cache since it is almost impossible
  1615. // to know the last write time of the file on the server.
  1616. MRxSmbInvalidateFileInfoCache(RxContext);
  1617. return(Status);
  1618. }
  1619. NTSTATUS
  1620. MRxSmbGetNtAllocationInfo (
  1621. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  1622. )
  1623. /*++
  1624. Routine Description:
  1625. gets the nt allocation information by doing a simple transact........
  1626. Arguments:
  1627. OrdinaryExchange - an exchange to be used for conducting this open.
  1628. Return Value:
  1629. RXSTATUS - The return status for the operation
  1630. Notes:
  1631. --*/
  1632. {
  1633. NTSTATUS Status;
  1634. RxCaptureFcb; RxCaptureFobx;
  1635. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  1636. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1637. REQ_QUERY_FILE_INFORMATION FileInfo;
  1638. PAGED_CODE();
  1639. FileInfo.Fid = smbSrvOpen->Fid;
  1640. FileInfo.InformationLevel = SMB_QUERY_FILE_STANDARD_INFO;
  1641. Status = MRxSmbSimpleSyncTransact2(
  1642. SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1643. SMBPSE_OETYPE_T2_FOR_NT_FILE_ALLOCATION_INFO,
  1644. TRANS2_QUERY_FILE_INFORMATION,
  1645. &FileInfo,sizeof(FileInfo),
  1646. NULL,0
  1647. );
  1648. return(Status);
  1649. }
  1650. NTSTATUS
  1651. __MRxSmbSimpleSyncTransact2(
  1652. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE,
  1653. IN SMB_PSE_ORDINARY_EXCHANGE_TYPE OEType,
  1654. IN ULONG TransactSetupCode,
  1655. IN PVOID Params,
  1656. IN ULONG ParamsLength,
  1657. IN PVOID Data,
  1658. IN ULONG DataLength,
  1659. IN PSMB_PSE_OE_T2_FIXUP_ROUTINE FixupRoutine
  1660. )
  1661. /*++
  1662. Routine Description:
  1663. This routine does a simple 1-in-1out transact2
  1664. Arguments:
  1665. OrdinaryExchange - an exchange to be used for conducting this open.
  1666. Return Value:
  1667. RXSTATUS - The return status for the operation
  1668. Notes:
  1669. --*/
  1670. {
  1671. NTSTATUS Status;
  1672. RxCaptureFcb; RxCaptureFobx;
  1673. PSMB_EXCHANGE Exchange = (PSMB_EXCHANGE) OrdinaryExchange;
  1674. PSMBSTUFFER_BUFFER_STATE StufferState;
  1675. PAGED_CODE();
  1676. RxDbgTrace(+1, Dbg, ("MRxSmbSimpleSyncTransact2 entering.......OE=%08lx\n",OrdinaryExchange));
  1677. StufferState = &OrdinaryExchange->AssociatedStufferState;
  1678. ASSERT( StufferState );
  1679. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_TRANSACTION2,
  1680. SMB_REQUEST_SIZE(TRANSACTION),
  1681. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  1682. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  1683. );
  1684. MRxSmbDumpStufferState (1100,"SMB w/ pseT2 before stuffing",StufferState);
  1685. //the return sizes of 100 and 800 are chosen arbitrarily.
  1686. MRxSmbStuffSMB (StufferState,
  1687. "0wwwwdD",
  1688. // 0 UCHAR WordCount; // Count of parameter words; value = (14 + SetupCount)
  1689. ParamsLength, // w _USHORT( TotalParameterCount ); // Total parameter bytes being sent
  1690. DataLength, // w _USHORT( TotalDataCount ); // Total data bytes being sent
  1691. 100, // w _USHORT( MaxParameterCount ); // Max parameter bytes to return
  1692. 800, // w _USHORT( MaxDataCount ); // Max data bytes to return
  1693. 0, // d . UCHAR MaxSetupCount; // Max setup words to return
  1694. // . UCHAR Reserved;
  1695. // . _USHORT( Flags ); // Additional information:
  1696. // // bit 0 - also disconnect TID in Tid
  1697. // // bit 1 - one-way transacion (no resp)
  1698. // D _ULONG( Timeout );
  1699. SMB_OFFSET_CHECK(TRANSACTION,Timeout) 0,
  1700. STUFFER_CTL_NORMAL, "wwpwQyyw",
  1701. 0, // w _USHORT( Reserved2 );
  1702. ParamsLength, // w _USHORT( ParameterCount ); // Parameter bytes sent this buffer
  1703. // p _USHORT( ParameterOffset ); // Offset (from header start) to params
  1704. DataLength, // w _USHORT( DataCount ); // Data bytes sent this buffer
  1705. // Q _USHORT( DataOffset ); // Offset (from header start) to data
  1706. SMB_OFFSET_CHECK(TRANSACTION,DataOffset)
  1707. 1, // y UCHAR SetupCount; // Count of setup words
  1708. 0, // y UCHAR Reserved3; // Reserved (pad above to word)
  1709. // UCHAR Buffer[1]; // Buffer containing:
  1710. TransactSetupCode, // w //USHORT Setup[]; // Setup words (# = SetupWordCount)
  1711. STUFFER_CTL_NORMAL, "ByS6cS5c!",
  1712. SMB_WCT_CHECK(15) // B //USHORT ByteCount; // Count of data bytes
  1713. 0, // y //UCHAR Name[]; // Name of transaction (NULL if Transact2)
  1714. // S //UCHAR Pad[]; // Pad to SHORT or LONG
  1715. // 6c //UCHAR Parameters[]; // Parameter bytes (# = ParameterCount)
  1716. ParamsLength,Params,
  1717. //CODE.IMPROVEMENT altho every server seems to take it, this should
  1718. // be conditioned on datalength!=0
  1719. // S //UCHAR Pad1[]; // Pad to SHORT or LONG
  1720. // 5c //UCHAR Data[]; // Data bytes (# = DataCount)
  1721. DataLength,Data
  1722. );
  1723. MRxSmbDumpStufferState (700,"SMB w/ pseT2 after stuffing",StufferState);
  1724. //ASSERT(!"Now it's stuffed");
  1725. if (FixupRoutine) {
  1726. Status = FixupRoutine(OrdinaryExchange);
  1727. if (Status!=STATUS_SUCCESS) {
  1728. goto FINALLY;
  1729. }
  1730. }
  1731. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  1732. OEType
  1733. );
  1734. FINALLY:
  1735. RxDbgTrace(-1, Dbg, ("MRxSmbSimpleSyncTransact2 exiting.......OE=%08lx, st=%08lx\n",OrdinaryExchange,Status));
  1736. return(Status);
  1737. }
  1738. NTSTATUS
  1739. MRxSmbFinishTransaction2 (
  1740. IN OUT PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange,
  1741. IN PRESP_TRANSACTION Response
  1742. )
  1743. /*++
  1744. Routine Description:
  1745. This routine finishes a transact2. what it does depends on the OE_TYPE.
  1746. Arguments:
  1747. OrdinaryExchange - the exchange instance
  1748. Response - the response
  1749. Return Value:
  1750. RXSTATUS - The return status for the operation
  1751. --*/
  1752. {
  1753. NTSTATUS Status = (STATUS_SUCCESS);
  1754. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  1755. PAGED_CODE(); //could actually be nonpaged
  1756. RxDbgTrace(+1, Dbg, ("MRxSmbFinishTransaction2\n", 0 ));
  1757. SmbPseOEAssertConsistentLinkageFromOE("MRxSmbFinishTransaction2:");
  1758. switch (OrdinaryExchange->OEType) {
  1759. case SMBPSE_OETYPE_T2_FOR_NT_FILE_ALLOCATION_INFO:{
  1760. PFILE_STANDARD_INFORMATION StandardInfo;
  1761. if ( (Response->WordCount!=10)
  1762. || (SmbGetUshort(&Response->TotalParameterCount)!=2)
  1763. || (SmbGetUshort(&Response->ParameterCount)!=2)
  1764. || (SmbGetUshort(&Response->ParameterDisplacement)!=0)
  1765. || (SmbGetUshort(&Response->TotalDataCount)!=24)
  1766. || (SmbGetUshort(&Response->DataCount)!=24)
  1767. || (SmbGetUshort(&Response->DataDisplacement)!=0)) {
  1768. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1769. RxDbgTrace(+1, Dbg, ("Invalid parameter(s) received.\n", 0 ));
  1770. break;
  1771. }
  1772. StandardInfo = (PFILE_STANDARD_INFORMATION)
  1773. (StufferState->BufferBase+SmbGetUshort(&Response->DataOffset));
  1774. OrdinaryExchange->Transact2.AllocationSize.LowPart
  1775. = SmbGetUlong(&StandardInfo->AllocationSize.LowPart);
  1776. OrdinaryExchange->Transact2.AllocationSize.HighPart
  1777. = SmbGetUlong(&StandardInfo->AllocationSize.HighPart);
  1778. RxDbgTrace(0, Dbg, ("MRxSmbFinishTransaction2 nt allocation %08lx\n",
  1779. OrdinaryExchange->Transact2.AllocationSize.LowPart ));
  1780. }break;
  1781. case SMBPSE_OETYPE_T2_FOR_LANMAN_DISKATTRIBUTES_INFO:{
  1782. PFILE_FS_SIZE_INFORMATION UsersBuffer = OrdinaryExchange->Info.Buffer;
  1783. PULONG BufferLength = OrdinaryExchange->Info.pBufferLength;
  1784. PQFS_ALLOCATE QfsInfo;
  1785. if (Response->WordCount != 10 ||
  1786. SmbGetUshort(&Response->DataDisplacement) != 0 ||
  1787. SmbGetUshort(&Response->DataCount) != ACTUAL_QFS_ALLOCATE_LENGTH ||
  1788. SmbGetUshort(&Response->TotalDataCount) != ACTUAL_QFS_ALLOCATE_LENGTH ||
  1789. SmbGetUshort(&Response->TotalParameterCount) != SmbGetUshort(&Response->ParameterCount)) {
  1790. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1791. RxDbgTrace(+1, Dbg, ("Invalid parameter(s) received.\n", 0 ));
  1792. break;
  1793. }
  1794. QfsInfo = (PQFS_ALLOCATE)(StufferState->BufferBase+SmbGetUshort(&Response->DataOffset));
  1795. UsersBuffer->TotalAllocationUnits.QuadPart = SmbGetUlong(&QfsInfo->cUnit);
  1796. UsersBuffer->AvailableAllocationUnits.QuadPart = SmbGetUlong(&QfsInfo->cUnitAvail);
  1797. UsersBuffer->SectorsPerAllocationUnit = SmbGetUlong(&QfsInfo->cSectorUnit);
  1798. UsersBuffer->BytesPerSector = SmbGetUshort(&QfsInfo->cbSector);
  1799. *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION); //CODE.IMPROVEMENT shouldn't this be done above??
  1800. RxDbgTrace(0, Dbg, ("MRxSmbFinishTransaction2 allocation %08lx\n",
  1801. OrdinaryExchange->Transact2.AllocationSize.LowPart ));
  1802. }break;
  1803. case SMBPSE_OETYPE_T2_FOR_LANMAN_VOLUMELABEL_INFO:{
  1804. PFILE_FS_VOLUME_INFORMATION UsersBuffer = OrdinaryExchange->Info.Buffer;
  1805. PULONG BufferLength = OrdinaryExchange->Info.pBufferLength;
  1806. PQFS_INFO QfsInfo;
  1807. ULONG LabelLength;
  1808. PBYTE VolumeLabel = &OrdinaryExchange->Info.QFSVolInfo.CoreLabel[0];
  1809. if (Response->WordCount != 10 ||
  1810. SmbGetUshort(&Response->DataDisplacement) != 0 ||
  1811. SmbGetUshort(&Response->TotalParameterCount) != SmbGetUshort(&Response->ParameterCount)) {
  1812. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1813. RxDbgTrace(+1, Dbg, ("Invalid parameter(s) received.\n", 0 ));
  1814. break;
  1815. }
  1816. QfsInfo = (PQFS_INFO)(StufferState->BufferBase+SmbGetUshort(&Response->DataOffset));
  1817. UsersBuffer->VolumeSerialNumber = SmbGetUlong(&QfsInfo->ulVSN);
  1818. //copy the volumelabel to the right place in the OE where it can UNICODE-ized by the routine above
  1819. LabelLength = min(QfsInfo->cch,12);
  1820. RtlCopyMemory(VolumeLabel,&QfsInfo->szVolLabel[0],LabelLength);
  1821. VolumeLabel[LabelLength] = 0;
  1822. RxDbgTrace(0, Dbg, ("MRxSmbFinishTransaction2 volinfo serialnum= %08lx\n",
  1823. UsersBuffer->VolumeSerialNumber ));
  1824. }break;
  1825. case SMBPSE_OETYPE_T2_FOR_ONE_FILE_DIRCTRL:{
  1826. //do nothing here....everything is done back in the caller with the
  1827. //whole buffer having been copied.....
  1828. RxDbgTrace(0, Dbg, ("MRxSmbFinishTransaction2 one file \n"));
  1829. }break;
  1830. default:
  1831. Status = STATUS_INVALID_NETWORK_RESPONSE;
  1832. }
  1833. RxDbgTrace(-1, Dbg, ("MRxSmbFinishTransaction2 returning %08lx\n", Status ));
  1834. return Status;
  1835. }