Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

720 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. rename.c
  5. Abstract:
  6. This module implements rename in the smb minirdr.
  7. Revision History:
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #ifdef ALLOC_PRAGMA
  12. #pragma alloc_text(PAGE, MRxSmbRename)
  13. #pragma alloc_text(PAGE, MRxSmbBuildRename)
  14. #pragma alloc_text(PAGE, MRxSmbBuildDeleteForRename)
  15. #pragma alloc_text(PAGE, SmbPseExchangeStart_Rename)
  16. #pragma alloc_text(PAGE, MRxSmbFinishRename)
  17. #pragma alloc_text(PAGE, MRxSmbBuildCheckEmptyDirectory)
  18. #pragma alloc_text(PAGE, SmbPseExchangeStart_SetDeleteDisposition)
  19. #pragma alloc_text(PAGE, MRxSmbSetDeleteDisposition)
  20. #endif
  21. //
  22. // The debug trace level
  23. //
  24. #define Dbg (DEBUG_TRACE_FILEINFO)
  25. NTSTATUS
  26. SmbPseExchangeStart_Rename(
  27. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  28. );
  29. NTSTATUS
  30. SmbPseExchangeStart_SetDeleteDisposition(
  31. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  32. );
  33. MRxSmbRename(
  34. IN PRX_CONTEXT RxContext
  35. )
  36. /*++
  37. Routine Description:
  38. This routine does a rename by
  39. 1) purge and remove buffering rights....setup the FCB so that no more stuff can get thru.
  40. 2) closing its fid along with any deferred fids.
  41. 3) if replace...do a delete
  42. 4) do a downlevel smb_com_rename.
  43. there are many provisos but i think that this is the best balance. it is a real shame that the
  44. NT-->NT path was never implemented in nt4.0 or before.
  45. Arguments:
  46. RxContext - the RDBSS context
  47. Return Value:
  48. RXSTATUS - The return status for the operation
  49. --*/
  50. {
  51. NTSTATUS Status = STATUS_SUCCESS;
  52. RxCaptureFcb; RxCaptureFobx;
  53. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  54. PAGED_CODE();
  55. RxDbgTrace(0, Dbg, ("MRxSmbRename\n", 0 ));
  56. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  57. //ASSERT( RxContext->Info.FileInformationClass == FileRenameInformation); //later we'll do downlevel delete here as well
  58. Status = SmbPseCreateOrdinaryExchange(RxContext,
  59. capFobx->pSrvOpen->pVNetRoot,
  60. SMBPSE_OE_FROM_RENAME,
  61. SmbPseExchangeStart_Rename,
  62. &OrdinaryExchange);
  63. if (Status != STATUS_SUCCESS) {
  64. RxDbgTrace(0, Dbg, ("Couldn't get the smb buf!\n"));
  65. return(Status);
  66. }
  67. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  68. ASSERT (Status != STATUS_PENDING);
  69. SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  70. RxDbgTrace(0, Dbg, ("MRxSmbRename exit with status=%08lx\n", Status ));
  71. return(Status);
  72. }
  73. NTSTATUS
  74. MRxSmbBuildRename (
  75. PSMBSTUFFER_BUFFER_STATE StufferState
  76. )
  77. /*++
  78. Routine Description:
  79. This builds a Rename SMB. we don't have to worry about login id and such
  80. since that is done by the connection engine....pretty neat huh? all we have to do
  81. is to format up the bits.
  82. Arguments:
  83. StufferState - the state of the smbbuffer from the stuffer's point of view
  84. Return Value:
  85. RXSTATUS
  86. SUCCESS
  87. NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
  88. Notes:
  89. --*/
  90. {
  91. NTSTATUS Status;
  92. NTSTATUS StufferStatus;
  93. PRX_CONTEXT RxContext = StufferState->RxContext;
  94. RxCaptureFcb;RxCaptureFobx;
  95. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  96. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  97. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
  98. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
  99. PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
  100. UNICODE_STRING RenameName;
  101. USHORT SearchAttributes = SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_DIRECTORY;
  102. PAGED_CODE();
  103. RxDbgTrace(+1, Dbg, ("MRxSmbBuildRename\n", 0 ));
  104. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  105. RenameName.Buffer = &RenameInformation->FileName[0];
  106. RenameName.Length = (USHORT)RenameInformation->FileNameLength;
  107. if (RxContext->Info.FileInformationClass == FileRenameInformation) {
  108. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_RENAME,
  109. SMB_REQUEST_SIZE(RENAME),
  110. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  111. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  112. );
  113. MRxSmbDumpStufferState (1100,"SMB w/ RENAME before stuffing",StufferState);
  114. MRxSmbStuffSMB (StufferState,
  115. "0wB",
  116. // 0 UCHAR WordCount; // Count of parameter words = 1
  117. SearchAttributes, // w _USHORT( SearchAttributes );
  118. SMB_WCT_CHECK(1) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
  119. // UCHAR Buffer[1]; // Buffer containing:
  120. // //UCHAR BufferFormat1; // 0x04 -- ASCII
  121. // //UCHAR OldFileName[]; // Old file name
  122. // //UCHAR BufferFormat2; // 0x04 -- ASCII
  123. // //UCHAR NewFileName[]; // New file name
  124. );
  125. } else {
  126. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse, SMB_COM_NT_RENAME,
  127. SMB_REQUEST_SIZE(NTRENAME),
  128. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  129. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  130. );
  131. MRxSmbDumpStufferState (1100,"SMB w/ NTRENAME before stuffing",StufferState);
  132. MRxSmbStuffSMB (StufferState,
  133. "0wwdB",
  134. // 0 UCHAR WordCount; // Count of parameter words = 1
  135. SearchAttributes, // w _USHORT( SearchAttributes );
  136. SMB_NT_RENAME_SET_LINK_INFO, // w _USHORT( InformationLevel );
  137. 0, // d _ULONG( ClusterCount );
  138. SMB_WCT_CHECK(4) 0 // B _USHORT( ByteCount ); // Count of data bytes = 0
  139. // UCHAR Buffer[1]; // Buffer containing:
  140. // //UCHAR BufferFormat1; // 0x04 -- ASCII
  141. // //UCHAR OldFileName[]; // Old file name
  142. // //UCHAR BufferFormat2; // 0x04 -- ASCII
  143. // //UCHAR NewFileName[]; // New file name
  144. );
  145. }
  146. Status = MRxSmbStuffSMB (StufferState,
  147. "44!", RemainingName, &RenameName );
  148. MRxSmbDumpStufferState (700,"SMB w/ RENAME after stuffing",StufferState);
  149. //ASSERT(!"Now it's stuffed");
  150. FINALLY:
  151. RxDbgTraceUnIndent(-1,Dbg);
  152. return(Status);
  153. }
  154. NTSTATUS
  155. MRxSmbBuildDeleteForRename (
  156. PSMBSTUFFER_BUFFER_STATE StufferState
  157. )
  158. /*++
  159. Routine Description:
  160. This builds a Delete SMB. we don't have to worry about login id and such
  161. since that is done by the connection engine....pretty neat huh? all we have to do
  162. is to format up the bits.
  163. Arguments:
  164. StufferState - the state of the smbbuffer from the stuffer's point of view
  165. Return Value:
  166. RXSTATUS
  167. SUCCESS
  168. NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
  169. Notes:
  170. --*/
  171. {
  172. NTSTATUS Status;
  173. NTSTATUS StufferStatus;
  174. PRX_CONTEXT RxContext = StufferState->RxContext;
  175. RxCaptureFcb;RxCaptureFobx;
  176. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  177. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  178. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
  179. PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
  180. UNICODE_STRING RenameName;
  181. ULONG SearchAttributes = SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN; // a la rdr1
  182. PAGED_CODE();
  183. RxDbgTrace(+1, Dbg, ("MRxSmbBuild Delete 4RENAME\n", 0 ));
  184. ASSERT( NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN );
  185. RenameName.Buffer = &RenameInformation->FileName[0];
  186. RenameName.Length = (USHORT)RenameInformation->FileNameLength;
  187. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_ForReuse,SMB_COM_DELETE,
  188. SMB_REQUEST_SIZE(DELETE),
  189. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  190. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  191. );
  192. MRxSmbDumpStufferState (1100,"SMB Delete 4RENAME before stuffing",StufferState);
  193. MRxSmbStuffSMB (StufferState,
  194. "0wB4!",
  195. // 0 UCHAR WordCount; // Count of parameter words = 1
  196. SearchAttributes, // w _USHORT( SearchAttributes );
  197. SMB_WCT_CHECK(1) // B _USHORT( ByteCount ); // Count of data bytes; min = 2
  198. // UCHAR Buffer[1]; // Buffer containing:
  199. &RenameName // 4 //UCHAR BufferFormat; // 0x04 -- ASCII
  200. // //UCHAR FileName[]; // File name
  201. );
  202. MRxSmbDumpStufferState (700,"SMB w/ Delete 4RENAME after stuffing",StufferState);
  203. //ASSERT(!"Now it's stuffed");
  204. FINALLY:
  205. RxDbgTraceUnIndent(-1,Dbg);
  206. return(Status);
  207. }
  208. NTSTATUS
  209. SmbPseExchangeStart_Rename(
  210. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  211. )
  212. /*++
  213. Routine Description:
  214. This is the start routine for rename and downlevel delete.
  215. Arguments:
  216. pExchange - the exchange instance
  217. Return Value:
  218. RXSTATUS - The return status for the operation
  219. --*/
  220. {
  221. NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
  222. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  223. RxCaptureFcb; RxCaptureFobx;
  224. PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  225. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  226. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME(SrvOpen,capFcb);
  227. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  228. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  229. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  230. ULONG SmbLength;
  231. PAGED_CODE();
  232. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_Rename\n", 0 ));
  233. ASSERT(OrdinaryExchange->Type == ORDINARY_EXCHANGE);
  234. ASSERT(!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  235. //first we have to close the fid....if it's a directory, we close the search handle as well
  236. MRxSmbSetInitialSMB( StufferState STUFFERTRACE(Dbg,'FC') );
  237. ASSERT (StufferState->CurrentCommand == SMB_COM_NO_ANDX_COMMAND);
  238. if( (TypeOfOpen==RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
  239. && FlagOn(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN) ){
  240. // we have a search handle open.....close it
  241. NTSTATUS Status2 = MRxSmbBuildFindClose(StufferState);
  242. if (Status2 == STATUS_SUCCESS) {
  243. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  244. SMBPSE_OETYPE_FINDCLOSE
  245. );
  246. }
  247. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
  248. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST);
  249. if (smbFobx->Enumeration.ResumeInfo!=NULL) {
  250. RxFreePool(smbFobx->Enumeration.ResumeInfo);
  251. smbFobx->Enumeration.ResumeInfo = NULL;
  252. }
  253. }
  254. if (!FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  255. COVERED_CALL(MRxSmbBuildClose(StufferState));
  256. SetFlag(SrvOpen->Flags,SRVOPEN_FLAG_FILE_RENAMED);
  257. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  258. SMBPSE_OETYPE_CLOSE
  259. );
  260. }
  261. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  262. //
  263. // the fid is now closed and we are almost ready to do the rename. first, tho, we have
  264. // to check for ReplaceIfExists. our implementation here is the same as rdr1....we pop out
  265. // a smb_com_delete, which only works for a file. be like mike!! remember to ignore any errors....
  266. if (0) {
  267. DbgPrint("RxContext->Info.ReplaceIfExists %08lx %02lx\n",
  268. &RxContext->Info.ReplaceIfExists,
  269. RxContext->Info.ReplaceIfExists);
  270. if (0) {
  271. DbgBreakPoint();
  272. }
  273. }
  274. if (RxContext->Info.ReplaceIfExists) {
  275. NTSTATUS DeleteStatus;
  276. PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
  277. UNICODE_STRING RenameName;
  278. BOOLEAN CaseInsensitive;
  279. CaseInsensitive= BooleanFlagOn(capFcb->pNetRoot->pSrvCall->Flags,SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES);
  280. RenameName.Buffer = &RenameInformation->FileName[0];
  281. RenameName.Length = (USHORT)RenameInformation->FileNameLength;
  282. // We cannot delete the file that is renamed as its own.
  283. if (RtlCompareUnicodeString(RemainingName,
  284. &RenameName,
  285. CaseInsensitive)) {
  286. DeleteStatus = MRxSmbBuildDeleteForRename(StufferState);
  287. if (DeleteStatus==STATUS_SUCCESS) {
  288. DeleteStatus = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  289. SMBPSE_OETYPE_DELETE_FOR_RENAME);
  290. }
  291. } else {
  292. if ( !CaseInsensitive || (CaseInsensitive &&
  293. !RtlCompareUnicodeString(RemainingName,&RenameName,FALSE)) ) {
  294. Status = STATUS_SUCCESS;
  295. goto FINALLY;
  296. }
  297. }
  298. }
  299. //
  300. // now do the rename..........
  301. Status = MRxSmbBuildRename(StufferState);
  302. SmbLength = (ULONG)(StufferState->CurrentPosition - StufferState->BufferBase);
  303. if ( (Status == STATUS_BUFFER_OVERFLOW)
  304. || (SmbLength>pServer->MaximumBufferSize) ){
  305. RxDbgTrace(0, Dbg, ("MRxSmbRename - name too long\n", 0 ));
  306. Status = STATUS_OBJECT_NAME_INVALID;
  307. }
  308. if (Status!=STATUS_SUCCESS) {
  309. goto FINALLY;
  310. }
  311. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  312. SMBPSE_OETYPE_RENAME
  313. );
  314. FINALLY:
  315. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_Rename exit w %08lx\n", Status ));
  316. return Status;
  317. }
  318. extern UNICODE_STRING MRxSmbAll8dot3Files;
  319. NTSTATUS
  320. MRxSmbBuildCheckEmptyDirectory (
  321. PSMBSTUFFER_BUFFER_STATE StufferState
  322. )
  323. /*++
  324. Routine Description:
  325. This builds a FindFirst SMB.
  326. Arguments:
  327. StufferState - the state of the smbbuffer from the stuffer's point of view
  328. Return Value:
  329. RXSTATUS
  330. SUCCESS
  331. NOT_IMPLEMENTED something has appeared in the arguments that i can't handle
  332. Notes:
  333. --*/
  334. {
  335. NTSTATUS Status;
  336. PRX_CONTEXT RxContext = StufferState->RxContext;
  337. RxCaptureFcb;
  338. PUNICODE_STRING RemainingName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  339. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange = (PSMB_PSE_ORDINARY_EXCHANGE)StufferState->Exchange;
  340. ULONG ResumeKeyLength = 0;
  341. UNICODE_STRING FindFirstPattern;
  342. // SearchAttributes is hardcoded to the magic number 0x16
  343. ULONG SearchAttributes =
  344. (SMB_FILE_ATTRIBUTE_DIRECTORY
  345. | SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_HIDDEN);
  346. PAGED_CODE();
  347. RxDbgTrace(+1, Dbg, ("MRxSmbBuildCheckEmptyDirectory \n"));
  348. if (OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey == NULL) {
  349. PUNICODE_STRING DirectoryName = RemainingName;
  350. PUNICODE_STRING Template = &MRxSmbAll8dot3Files;
  351. ULONG DirectoryNameLength,TemplateLength,AllocationLength;
  352. PBYTE SmbFileName;
  353. //the stuffer cannot handle the intricate logic here so we
  354. //will have to preallocate for the name
  355. DirectoryNameLength = DirectoryName->Length;
  356. TemplateLength = Template->Length;
  357. AllocationLength = sizeof(WCHAR) // backslash separator
  358. +DirectoryNameLength
  359. +TemplateLength;
  360. RxDbgTrace(0, Dbg, (" --> d/t/dl/tl/al <%wZ><%wZ>%08lx/%08lx/%08lx!\n",
  361. DirectoryName,Template,
  362. DirectoryNameLength,TemplateLength,AllocationLength));
  363. FindFirstPattern.Buffer = (PWCHAR)RxAllocatePoolWithTag( PagedPool,AllocationLength,'0SxR');
  364. if (FindFirstPattern.Buffer==NULL) {
  365. RxDbgTrace(0, Dbg, (" --> Couldn't get the findfind pattern buffer!\n"));
  366. Status = STATUS_INSUFFICIENT_RESOURCES;
  367. DbgBreakPoint();
  368. goto FINALLY;
  369. }
  370. SmbFileName = (PBYTE)FindFirstPattern.Buffer;
  371. RtlCopyMemory(SmbFileName,DirectoryName->Buffer,DirectoryNameLength);
  372. SmbFileName += DirectoryNameLength;
  373. if (*((PWCHAR)(SmbFileName-sizeof(WCHAR))) != L'\\') {
  374. *((PWCHAR)SmbFileName) = L'\\'; SmbFileName+= sizeof(WCHAR);
  375. }
  376. RtlCopyMemory(SmbFileName,Template->Buffer,TemplateLength);
  377. SmbFileName += TemplateLength;
  378. if ((TemplateLength == sizeof(WCHAR)) && (Template->Buffer[0]==DOS_STAR)) {
  379. *((PWCHAR)SmbFileName) = L'.'; SmbFileName+= sizeof(WCHAR);
  380. *((PWCHAR)SmbFileName) = L'*'; SmbFileName+= sizeof(WCHAR);
  381. }
  382. FindFirstPattern.Length = (USHORT)(SmbFileName - (PBYTE)FindFirstPattern.Buffer);
  383. RxDbgTrace(0, Dbg, (" --> find1stpattern <%wZ>!\n",&FindFirstPattern));
  384. } else {
  385. ResumeKeyLength = sizeof(SMB_RESUME_KEY);
  386. FindFirstPattern.Buffer = NULL;
  387. FindFirstPattern.Length = 0;
  388. }
  389. ASSERT( StufferState );
  390. COVERED_CALL(MRxSmbStartSMBCommand (StufferState,SetInitialSMB_Never, SMB_COM_SEARCH,
  391. SMB_REQUEST_SIZE(SEARCH),
  392. NO_EXTRA_DATA,SMB_BEST_ALIGNMENT(1,0),RESPONSE_HEADER_SIZE_NOT_SPECIFIED,
  393. 0,0,0,0 STUFFERTRACE(Dbg,'FC'))
  394. );
  395. MRxSmbDumpStufferState (1100,"SMB w/ core search before stuffing",StufferState);
  396. MRxSmbStuffSMB (StufferState,
  397. "0wwB4ywc!",
  398. // 0 UCHAR WordCount; // Count of parameter words = 2
  399. 3, // w _USHORT( MaxCount ); // Number of dir. entries to return
  400. SearchAttributes, // w _USHORT( SearchAttributes );
  401. SMB_WCT_CHECK(2) // B _USHORT( ByteCount ); // Count of data bytes; min = 5
  402. // UCHAR Buffer[1]; // Buffer containing:
  403. &FindFirstPattern, // 4 //UCHAR BufferFormat1; // 0x04 -- ASCII
  404. // //UCHAR FileName[]; // File name, may be null
  405. 0x05, // y //UCHAR BufferFormat2; // 0x05 -- Variable block
  406. ResumeKeyLength, // w //USHORT ResumeKeyLength; // Length of resume key, may be 0
  407. // c
  408. ResumeKeyLength,OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey
  409. );
  410. MRxSmbDumpStufferState (700,"SMB w/ core search for checkempty after stuffing",StufferState);
  411. //ASSERT(!"Now it's stuffed");
  412. FINALLY:
  413. if (FindFirstPattern.Buffer != NULL) {
  414. RxFreePool(FindFirstPattern.Buffer);
  415. }
  416. RxDbgTrace(-1, Dbg, ("MRxSmbBuildCheckEmptyDirectory exiting.......st=%08lx\n",Status));
  417. return(Status);
  418. }
  419. NTSTATUS
  420. SmbPseExchangeStart_SetDeleteDisposition(
  421. SMBPSE_ORDINARY_EXCHANGE_ARGUMENT_SIGNATURE
  422. )
  423. /*++
  424. Routine Description:
  425. This is the start routine for SetDeleteDisposition and downlevel delete. This only thing that happens here
  426. is that we check for an empty directory. On core, this is harder than you think. what we do is to try to get three
  427. entries. if the directory is empty, we will get only two . and ..; since we do not know whether the server just terminated
  428. early or whether those are the only two, we go again. we do this until either we get a name that is not . or .. or until
  429. NO_MORE_FILES is returned. sigh..................
  430. Arguments:
  431. pExchange - the exchange instance
  432. Return Value:
  433. RXSTATUS - The return status for the operation
  434. --*/
  435. {
  436. NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
  437. PSMBSTUFFER_BUFFER_STATE StufferState = &OrdinaryExchange->AssociatedStufferState;
  438. RxCaptureFcb; RxCaptureFobx;
  439. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  440. PMRX_SMB_FOBX smbFobx = MRxSmbGetFileObjectExtension(capFobx);
  441. NODE_TYPE_CODE TypeOfOpen = NodeType(capFcb);
  442. PSMBCE_SERVER pServer = SmbCeGetExchangeServer(OrdinaryExchange);
  443. ULONG SmbLength;
  444. PAGED_CODE();
  445. RxDbgTrace(+1, Dbg, ("SmbPseExchangeStart_SetDeleteDisposition\n", 0 ));
  446. ASSERT_ORDINARY_EXCHANGE(OrdinaryExchange);
  447. ASSERT(!FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  448. ASSERT (OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey == NULL);
  449. for (;;) {
  450. MRxSmbSetInitialSMB(StufferState STUFFERTRACE(Dbg,'FC'));
  451. Status = MRxSmbBuildCheckEmptyDirectory(StufferState);
  452. SmbLength = (ULONG)(StufferState->CurrentPosition - StufferState->BufferBase);
  453. if ( (Status == STATUS_BUFFER_OVERFLOW)
  454. || (SmbLength>pServer->MaximumBufferSize) ){
  455. RxDbgTrace(-1, Dbg, ("MRxSmbSetDeleteDisposition - name too long\n", 0 ));
  456. return(STATUS_OBJECT_NAME_INVALID);
  457. } else if ( Status != STATUS_SUCCESS ){
  458. goto FINALLY;
  459. }
  460. Status = SmbPseOrdinaryExchange(SMBPSE_ORDINARY_EXCHANGE_ARGUMENTS,
  461. SMBPSE_OETYPE_CORESEARCHFORCHECKEMPTY
  462. );
  463. //
  464. // if success is returned with a resume key then we have to go again
  465. if ( (Status == STATUS_SUCCESS) && (OrdinaryExchange->Info.CoreSearch.EmptyCheckResumeKey != NULL) ) continue;
  466. break;
  467. }
  468. //
  469. // this is pretty strange. if it succeeds, then fail the empty check. similarly, if the search
  470. // fails with the right status...succeeed the check. otherwise fail
  471. FINALLY:
  472. if (Status == STATUS_SUCCESS) {
  473. Status = STATUS_DIRECTORY_NOT_EMPTY;
  474. } else if (Status == STATUS_NO_MORE_FILES) {
  475. Status = STATUS_SUCCESS;
  476. }
  477. RxDbgTrace(-1, Dbg, ("SmbPseExchangeStart_SetDeleteDisposition exit w %08lx\n", Status ));
  478. return Status;
  479. }
  480. MRxSmbSetDeleteDisposition(
  481. IN PRX_CONTEXT RxContext
  482. )
  483. /*++
  484. Routine Description:
  485. This routine does a delete for downlevel.
  486. It is impossible to provide exact NTish semantics on a core server. So, all we do here is to ensure that
  487. a directory is empty. The actual delete happens when on the last close.
  488. Arguments:
  489. RxContext - the RDBSS context
  490. Return Value:
  491. RXSTATUS - The return status for the operation
  492. --*/
  493. {
  494. NTSTATUS Status = STATUS_SUCCESS;
  495. PUNICODE_STRING RemainingName;
  496. RxCaptureFcb; RxCaptureFobx;
  497. PSMB_PSE_ORDINARY_EXCHANGE OrdinaryExchange;
  498. PAGED_CODE();
  499. RxDbgTrace(+1, Dbg, ("MRxSmbSetDeleteDisposition\n", 0 ));
  500. ASSERT( NodeType(capFobx->pSrvOpen) == RDBSS_NTC_SRVOPEN );
  501. if (NodeType(capFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY ) {
  502. RxDbgTrace(-1, Dbg, ("MRxSmbSetDeleteDisposition not a directory!\n"));
  503. return(STATUS_SUCCESS);
  504. }
  505. Status = SmbPseCreateOrdinaryExchange(RxContext,
  506. capFobx->pSrvOpen->pVNetRoot,
  507. SMBPSE_OE_FROM_FAKESETDELETEDISPOSITION,
  508. SmbPseExchangeStart_SetDeleteDisposition,
  509. &OrdinaryExchange
  510. );
  511. if (Status != STATUS_SUCCESS) {
  512. RxDbgTrace(-1, Dbg, ("Couldn't get the smb buf!\n"));
  513. return(Status);
  514. }
  515. Status = SmbPseInitiateOrdinaryExchange(OrdinaryExchange);
  516. ASSERT (Status != STATUS_PENDING);
  517. SmbPseFinalizeOrdinaryExchange(OrdinaryExchange);
  518. RxDbgTrace(-1, Dbg, ("MRxSmbSetDeleteDisposition exit with status=%08lx\n", Status ));
  519. return(Status);
  520. }
  521.