public void QueryDirectory(out List <QueryDirectoryFileInformation> result, NtHandle handle, string fileName, FileInformationClass informationClass) { result = new List <QueryDirectoryFileInformation>(); QueryDirectoryRequest request = new QueryDirectoryRequest { Header = { CreditCharge = (ushort)Math.Ceiling((double)m_client.MaxTransactSize / BytesPerCredit) }, FileInformationClass = informationClass, Reopen = true, FileId = (FileID)handle, OutputBufferLength = m_client.MaxTransactSize, FileName = fileName }; SendCommand(request); SMB2Command?response = WaitForCommand(request.MessageID); response.IsSuccessElseThrow(); while (response is QueryDirectoryResponse queryDirectoryResponse) { List <QueryDirectoryFileInformation> page = queryDirectoryResponse.GetFileInformationList(informationClass); result.AddRange(page); request.Reopen = false; SendCommand(request); response = WaitForCommand(request.MessageID); if (response.Header.Status == NTStatus.STATUS_NO_MORE_FILES) { break; } response.IsSuccessElseThrow(); } }
public async Task <(NTStatus status, IEnumerable <QueryDirectoryFileInformation> result)> QueryDirectory(object handle, string fileName, FileInformationClass informationClass, CancellationToken cancellationToken) { QueryDirectoryRequest request = new QueryDirectoryRequest(); request.Header.CreditCharge = (ushort)Math.Ceiling((double)m_client.MaxTransactSize / BytesPerCredit); request.FileInformationClass = informationClass; request.Reopen = true; request.FileId = (FileID)handle; request.OutputBufferLength = m_client.MaxTransactSize; request.FileName = fileName; await TrySendCommandAsync(request, cancellationToken); SMB2Command response = m_client.WaitForCommand(SMB2CommandName.QueryDirectory); if (response != null) { var result = new List <QueryDirectoryFileInformation>(); while (response.Header.Status == NTStatus.STATUS_SUCCESS && response is QueryDirectoryResponse) { var page = ((QueryDirectoryResponse)response).GetFileInformationList(informationClass); result.AddRange(page); request.Reopen = false; await TrySendCommandAsync(request, cancellationToken); response = m_client.WaitForCommand(SMB2CommandName.QueryDirectory); } return(response.Header.Status, result); } return(NTStatus.STATUS_INVALID_SMB, Enumerable.Empty <QueryDirectoryFileInformation>()); }
public NTStatus QueryDirectory(out List <QueryDirectoryFileInformation> result, object handle, string fileName, FileInformationClass informationClass) { result = new List <QueryDirectoryFileInformation>(); QueryDirectoryRequest request = new QueryDirectoryRequest(); request.FileInformationClass = informationClass; request.Reopen = true; request.FileId = (FileID)handle; request.OutputBufferLength = m_client.MaxTransactSize; request.FileName = fileName; ulong messageId = TrySendCommand(request); SMB2Command response = m_client.WaitForCommand(SMB2CommandName.QueryDirectory, messageId); if (response != null) { while (response.Header.Status == NTStatus.STATUS_SUCCESS && response is QueryDirectoryResponse) { List <QueryDirectoryFileInformation> page = ((QueryDirectoryResponse)response).GetFileInformationList(informationClass); result.AddRange(page); request.Reopen = false; messageId = TrySendCommand(request); response = m_client.WaitForCommand(SMB2CommandName.QueryDirectory, messageId); } return(response.Header.Status); } return(NTStatus.STATUS_INVALID_SMB); }
internal static SMB2Command GetQueryDirectoryResponse(QueryDirectoryRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { state.LogToServer(Severity.Verbose, "Query Directory failed. Invalid FileId. (SessionID: {0}, TreeID: {1}, FileId: {2})", request.Header.SessionID, request.Header.TreeID, request.FileId.Volatile); return(new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED)); } if (!((FileSystemShare)share).HasReadAccess(session.SecurityContext, openFile.Path)) { state.LogToServer(Severity.Verbose, "Query Directory on '{0}{1}' failed. User '{2}' was denied access.", share.Name, openFile.Path, session.UserName); return(new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED)); } FileSystemShare fileSystemShare = (FileSystemShare)share; FileID fileID = request.FileId; OpenSearch openSearch = session.GetOpenSearch(fileID); if (openSearch == null || request.Reopen) { if (request.Reopen) { session.RemoveOpenSearch(fileID); } List <QueryDirectoryFileInformation> entries; NTStatus searchStatus = share.FileStore.QueryDirectory(out entries, openFile.Handle, request.FileName, request.FileInformationClass); if (searchStatus != NTStatus.STATUS_SUCCESS) { state.LogToServer(Severity.Verbose, "Query Directory on '{0}{1}', Searched for '{2}', NTStatus: {3}", share.Name, openFile.Path, request.FileName, searchStatus.ToString()); return(new ErrorResponse(request.CommandName, searchStatus)); } state.LogToServer(Severity.Information, "Query Directory on '{0}{1}', Searched for '{2}', found {3} matching entries", share.Name, openFile.Path, request.FileName, entries.Count); openSearch = session.AddOpenSearch(fileID, entries, 0); } if (request.Restart || request.Reopen) { openSearch.EnumerationLocation = 0; } if (openSearch.Entries.Count == 0) { // [MS-SMB2] If there are no entries to return [..] the server MUST fail the request with STATUS_NO_SUCH_FILE. session.RemoveOpenSearch(fileID); return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NO_SUCH_FILE)); } if (openSearch.EnumerationLocation == openSearch.Entries.Count) { return(new ErrorResponse(request.CommandName, NTStatus.STATUS_NO_MORE_FILES)); } List <QueryDirectoryFileInformation> page = new List <QueryDirectoryFileInformation>(); int pageLength = 0; for (int index = openSearch.EnumerationLocation; index < openSearch.Entries.Count; index++) { QueryDirectoryFileInformation fileInformation = openSearch.Entries[index]; if (fileInformation.FileInformationClass != request.FileInformationClass) { // We do not support changing FileInformationClass during a search (unless SMB2_REOPEN is set). return(new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER)); } int entryLength = fileInformation.Length; if (pageLength + entryLength <= request.OutputBufferLength) { page.Add(fileInformation); int paddedLength = (int)Math.Ceiling((double)entryLength / 8) * 8; pageLength += paddedLength; openSearch.EnumerationLocation = index + 1; } else { break; } if (request.ReturnSingleEntry) { break; } } QueryDirectoryResponse response = new QueryDirectoryResponse(); response.SetFileInformationList(page); return(response); }