/// <summary> /// Create a file with create context /// </summary> /// <param name="fileName">Name of the file</param> /// <param name="desiredAccess">The desired access</param> /// <param name="shareAccess">Sharing mode for the open</param> /// <param name="impersonationLevel">The impersonation level</param> /// <param name="fileAttribute">The file attribute, this field is only valid when create file.</param> /// <param name="createDisposition">Defines the action the server MUST take if the file that is specified in the name field already exists</param> /// <param name="createOption">Specifies the options to be applied when creating or opening the file</param> /// <param name="contextRequest">Create contexts to be sent in the create request</param> /// <param name="status">Status of the response packet</param> /// <param name="serverCreateContexts">Create contexts to be received in the create response</param> /// <param name="contextResponse">Create response payload to be received in the create response</param> public void Create( string fileName, FsFileDesiredAccess desiredAccess, ShareAccess_Values shareAccess, FsImpersonationLevel impersonationLevel, FsFileAttribute fileAttribute, FsCreateDisposition createDisposition, FsCreateOption createOption, Smb2CreateContextRequest[] contextRequest, out uint status, out Smb2CreateContextResponse[] serverCreateContexts, out CREATE_Response createResponse) { if (createOption.HasFlag(FsCreateOption.FILE_DIRECTORY_FILE)) { throw new ArgumentException("createOption can not contain FILE_DIRECTORY_FILE when creating file."); } Packet_Header header; status = client.Create( 1, 1, headerFlags, messageId++, sessionId, treeId, fileName, (AccessMask)desiredAccess, shareAccess, (CreateOptions_Values)createOption, (CreateDisposition_Values)createDisposition, (File_Attributes)fileAttribute, (ImpersonationLevel_Values)impersonationLevel, SecurityFlags_Values.NONE, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, contextRequest, out fileId, out serverCreateContexts, out header, out createResponse); }
/// <summary> /// Check the status code of create response /// </summary> /// <param name="isNonAdmin">true for non admin credential</param> /// <param name="createOption">The create option set in create request</param> /// <param name="accessMask">The access mark set in create request</param> /// <param name="header">Header of create response</param> /// <param name="response">create response</param> /// <param name="fileNameType">file name type</param> private void CheckCreateResponse(bool isNonAdmin, CreateOptions_Values createOption, AccessMask accessMask, Packet_Header header, CREATE_Response response, FileNameType fileNameType) { switch (fileNameType) { case FileNameType.SymbolicLinkInMiddle: { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_STOPPED_ON_SYMLINK, header.Status, "3.3.5.9: If any intermediate component of the path specified in the create request is a symbolic link, " + "the server MUST return an error as specified in section 2.2.2.1. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); break; } case FileNameType.SymbolicLinkAtLast: { if (!createOption.HasFlag(CreateOptions_Values.FILE_OPEN_REPARSE_POINT)) { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_STOPPED_ON_SYMLINK, header.Status, "3.3.5.9: If the final component of the path is a symbolic link, the server behavior depends on whether the flag FILE_OPEN_REPARSE_POINT was specified in the CreateOptions field of the request. " + "If FILE_OPEN_REPARSE_POINT was specified, the server MUST open the underlying file or directory and return a handle to it. " + "Otherwise, the server MUST return an error as specified in section 2.2.2.1. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); } break; } case FileNameType.InvalidSymbolicLink: { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_STOPPED_ON_SYMLINK, header.Status, "3.3.5.9: If the underlying object store returns a failure indicating that the attempted open operation failed due to the presence of a symbolic link in the target path name, " + "the server MUST fail the create operation with the error code STATUS_STOPPED_ON_SYMLINK. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); break; } case FileNameType.NotExistedValidFileName: { if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE) && !(accessMask.HasFlag(AccessMask.DELETE) || accessMask.HasFlag(AccessMask.GENERIC_ALL))) { if (testConfig.Platform == Platform.NonWindows) { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " + "DesiredAccess does not include DELETE or GENERIC_ALL. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); } else if (testConfig.Platform == Platform.WindowsServer2008 || testConfig.Platform == Platform.WindowsServer2008R2) { //TD does not specify the behavior of windows 2008 and 2008R2, not check here } else if(testConfig.Platform == Platform.WindowsServer2012) { //For platform windows 2012 BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_INVALID_PARAMETER, header.Status, "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " + "DesiredAccess does not include DELETE or GENERIC_ALL. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); } else { //For platform windows 2012R2 and above BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_ACCESS_DENIED, header.Status, "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " + "DesiredAccess does not include DELETE or GENERIC_ALL. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); } } else if (createOption.HasFlag(CreateOptions_Values.FILE_DELETE_ON_CLOSE) && isNonAdmin) { //NonAdminAccountCredential does not include DELETE or GENERIC_ALL in MaximalAccess if (testConfig.Platform == Platform.NonWindows) { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " + "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); } else if (testConfig.Platform == Platform.WindowsServer2008 || testConfig.Platform == Platform.WindowsServer2008R2) { //TD does not specify te behavior of windows 2008 and 2008R2, not check here } else { //For platform win2012 and 2012R2 BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_ACCESS_DENIED, header.Status, "3.3.5.9: If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and any of the following conditions is TRUE, the server SHOULD<242> fail the request with STATUS_ACCESS_DENIED. " + "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL. " + "Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status)); } } else { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); } break; } case FileNameType.ExistedValidFileName: { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns with {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); } break; default: throw new ArgumentException("fileNameType"); } }