jborean93 / smbprotocol

Python SMBv2 and v3 Client
MIT License
318 stars 73 forks source link

Example for FileSystemWatcher #172

Closed tharwan closed 2 years ago

tharwan commented 2 years ago

Hi,

is there an example of how to use FileSystemWatcher somewhere? I could not find anything but it sounds super useful!

jborean93 commented 2 years ago

There's no real example that I know off but you can have a look at the tests for this functionality under test_change_notify.py. It's still under the low level API so it's quite verbose but it would be something like

import smbclient
from smbprotocol.change_notify import (
    ChangeNotifyFlags,
    CompletionFilter,
    FileSystemWatcher,
)

with smbclient.open_file(
    r"\\server\share\folder",
    mode="rb",
    share_access="rw",
    buffering=0,
    file_type="dir",
) as dir_fd:
    watcher = FileSystemWatcher(dir_fd.fd)

    # See https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/598f395a-e7a2-4cc8-afb3-ccb30dd2df7c
    watcher.start(
        CompletionFilter.FILE_NOTIFY_CHANGE_DIR_NAME | CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME,
        flags=ChangeNotifyFlags.SMB2_WATCH_TREE,
    )
    result = watcher.wait()
    for entry in result:
        # Action see - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/634043d7-7b39-47e9-9e26-bda64685e4c9
        action = entry["action"].get_value()
        file_name = entry["file_name"].get_value()
        print(f"Action: {action} FileName: {file_name}")

A big problem I've seen with FileSystemWatcher is that once you get a result back you need to start a new watcher so the time between getting the result and starting a new one a new change may have occurred. I've yet to figure out a decent workaround for this problem. Hopefully that helps!

tharwan commented 2 years ago

Hi, thank you very much for your reply!

We tried to find out how to use it and then stumbled in the same problem you described. So thanks for confirming we are not stupid also :-).

I was wondering if it would be possible to not close the request/join the thread and have it work more like a socket, but I could not figure out if this is at all possible. For our purposes it is better to rely on scanning every few seconds instead, otherwise it seems too dangerous that we might be missing a file.

Thanks again.

jborean93 commented 2 years ago

I was wondering if it would be possible to not close the request/join the thread and have it work more like a socket, but I could not figure out if this is at all possible

When implementing this I couldn’t figure how to do such a thing unfortunately. The thread is essentially just waiting until there is a response to the change notify request which indicates a change occurred. To get a new response a new request needs to be made which means there’s still a gap between the response the the new request. There’s a chance I missed something in the SMB protocol docs that can enable such a thing but I couldn’t find it at the time. If you do learn more I am interested to know.