Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example for FileSystemWatcher #172

Closed
tharwan opened this issue Apr 3, 2022 · 4 comments
Closed

Example for FileSystemWatcher #172

tharwan opened this issue Apr 3, 2022 · 4 comments

Comments

@tharwan
Copy link

tharwan commented Apr 3, 2022

Hi,

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

@jborean93
Copy link
Owner

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
Copy link
Author

tharwan commented Apr 8, 2022

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.

@tharwan tharwan closed this as completed Apr 8, 2022
@jborean93
Copy link
Owner

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.

@tharwan
Copy link
Author

tharwan commented Nov 1, 2024

I am circling back to this issue every once in a while. The new input this time was from here:

If the client previously issued an NT_TRANSACT_NOTIFY_CHANGE Request on this FID, the server SHOULD already have a change notification buffer associated with the FID. The change notification buffer is used to collect directory change information in between NT_TRANSACT_NOTIFY_CHANGE (section 2.2.7.4) calls that reference the same FID.

And in my testing this is true. So the following works:

  1. open a directory
  2. start a file watcher
  3. create a new file -> watcher stops
  4. create a new file while watcher is stopped
  5. start file watcher
  6. immediately watcher is stopped with info of file creation

The remaining crucial part is the connection. Once the file is closed the watching can not be resumed. I wonder if this can be solved by creating a durable handle however?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants