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.

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