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.

809 lines
29 KiB

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