diff --git a/SMBLibrary/Client/SMB2FileStore.cs b/SMBLibrary/Client/SMB2FileStore.cs index f5f77ffe..f4db9bed 100644 --- a/SMBLibrary/Client/SMB2FileStore.cs +++ b/SMBLibrary/Client/SMB2FileStore.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using SMBLibrary.SMB2; -using Utilities; namespace SMBLibrary.Client { @@ -18,12 +17,15 @@ public class SMB2FileStore : ISMBFileStore private SMB2Client m_client; private uint m_treeID; private bool m_encryptShareData; + private readonly Dictionary _activeNotifies; + private readonly object _lock = new object(); public SMB2FileStore(SMB2Client client, uint treeID, bool encryptShareData) { m_client = client; m_treeID = treeID; m_encryptShareData = encryptShareData; + _activeNotifies = new Dictionary(); } public NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, FileAttributes fileAttributes, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions, SecurityContext securityContext) @@ -291,12 +293,55 @@ public NTStatus SetSecurityInformation(object handle, SecurityInformation securi public NTStatus NotifyChange(out object ioRequest, object handle, NotifyChangeFilter completionFilter, bool watchTree, int outputBufferSize, OnNotifyChangeCompleted onNotifyChangeCompleted, object context) { - throw new NotImplementedException(); + ChangeNotifyRequest request = new ChangeNotifyRequest + { + FileId = (FileID)handle, + CompletionFilter = completionFilter, + WatchTree = watchTree, + OutputBufferLength = (uint)outputBufferSize + }; + + ioRequest = request; + // Add some reference for cancelation + lock (_lock) + { + _activeNotifies[request] = true; + } + + TrySendCommand(request); + + SMB2Command response = m_client.WaitForCommand(request.MessageID); + + lock (_lock) + { + if (!_activeNotifies.ContainsKey(request)) + { + return NTStatus.STATUS_CANCELLED; + } + // Request is finished + _activeNotifies.Remove(request); + } + + // Timeout occurred + if (response == null) + { + onNotifyChangeCompleted?.Invoke(NTStatus.STATUS_IO_TIMEOUT, null, context); + return NTStatus.STATUS_IO_TIMEOUT; + } + + // Normal response + onNotifyChangeCompleted?.Invoke(response.Header.Status, response.GetBytes(), context); + return response.Header.Status; } public NTStatus Cancel(object ioRequest) { - throw new NotImplementedException(); + lock (_lock) + { + _activeNotifies.Remove(ioRequest); + } + + return NTStatus.STATUS_SUCCESS; } public NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength)