linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC cifs-utils 0/1] smbinfo: add notify subcommand
@ 2025-12-17 13:44 chenxiaosong.chenxiaosong
  2025-12-17 13:44 ` [PATCH RFC cifs-utils 1/1] " chenxiaosong.chenxiaosong
  0 siblings, 1 reply; 2+ messages in thread
From: chenxiaosong.chenxiaosong @ 2025-12-17 13:44 UTC (permalink / raw)
  To: sfrench, smfrench, linkinjeon, linkinjeon, pc, ronniesahlberg,
	sprasad, tom, bharathsm, senozhatsky
  Cc: linux-cifs, ChenXiaoSong

From: ChenXiaoSong <chenxiaosong@kylinos.cn>

If you have any better ideas, please let me know.

What would be an appropriate maximum value for the `data_len` field in `struct smb3_notify_info`?
Currently, I set `data_len` to `1000`, referring to the implementation in Samba's `smbclient` (see `cmd_notify()`).

ChenXiaoSong (1):
  smbinfo: add notify subcommand

 smbinfo     | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 smbinfo.rst |  2 ++
 2 files changed, 71 insertions(+)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH RFC cifs-utils 1/1] smbinfo: add notify subcommand
  2025-12-17 13:44 [PATCH RFC cifs-utils 0/1] smbinfo: add notify subcommand chenxiaosong.chenxiaosong
@ 2025-12-17 13:44 ` chenxiaosong.chenxiaosong
  0 siblings, 0 replies; 2+ messages in thread
From: chenxiaosong.chenxiaosong @ 2025-12-17 13:44 UTC (permalink / raw)
  To: sfrench, smfrench, linkinjeon, linkinjeon, pc, ronniesahlberg,
	sprasad, tom, bharathsm, senozhatsky
  Cc: linux-cifs, ChenXiaoSong, Steve French

From: ChenXiaoSong <chenxiaosong@kylinos.cn>

Add `notify` subcommand to query a directory for change notifications.

Example:

  ./smbinfo notify /mnt/dir
  # Then create a new file `/server/export/dir/file` on SMB server
  Notify completed, returned data_len is 20
  00000000:  00 00 00 00 01 00 00 00  08 00 00 00 66 00 69 00  ............f.i.
  00000010:  6c 00 65 00                                       l.e.

Link: https://lore.kernel.org/linux-cifs/CAH2r5msHiZWzP5hdtPgb+wV3DL3J31RtgQRLQeuhCa_ULt3PfA@mail.gmail.com/
Suggested-by: Steve French <stfrench@microsoft.com>
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
 smbinfo     | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 smbinfo.rst |  2 ++
 2 files changed, 71 insertions(+)

diff --git a/smbinfo b/smbinfo
index 2e9e42d..2be2395 100755
--- a/smbinfo
+++ b/smbinfo
@@ -27,6 +27,7 @@ import struct
 import stat
 import datetime
 import calendar
+import threading
 
 VERBOSE = False
 
@@ -36,6 +37,7 @@ CIFS_ENUMERATE_SNAPSHOTS = 0x800ccf06
 CIFS_DUMP_KEY            = 0xc03acf08
 CIFS_DUMP_FULL_KEY       = 0xc011cf0a
 CIFS_GET_TCON_INFO       = 0x800ccf0c
+CIFS_IOC_NOTIFY_INFO     = 0xc009cf0b
 
 # large enough input buffer length
 INPUT_BUFFER_LENGTH = 16384
@@ -294,6 +296,10 @@ def main():
     sap.add_argument("file")
     sap.set_defaults(func=cmd_gettconinfo)
 
+    sap = subp.add_parser("notify", help="Query a directory for change notifications")
+    sap.add_argument("file")
+    sap.set_defaults(func=cmd_notify)
+
     # parse arguments
     args = ap.parse_args()
 
@@ -905,5 +911,68 @@ def cmd_gettconinfo(args):
     print("TCON Id: 0x%x"%tcon.tid)
     print("Session Id: 0x%x"%tcon.session_id)
 
+def cmd_notify(args):
+    thread = threading.Thread(target=notify_thread, args=(args,))
+    thread.start()
+
+    try:
+        thread.join()
+    except KeyboardInterrupt:
+        return False
+
+def notify_thread(args):
+    # See `struct smb3_notify_info` in linux kernel fs/smb/client/cifs_ioctl.h
+    completion_filter = 0xFFF
+    watch_tree = False
+    data_len = 1000
+
+    fmt = "<IBI"
+    buf = bytearray(struct.pack(fmt, completion_filter, watch_tree, data_len))
+    buf.extend(bytearray(data_len))
+
+    try:
+        fd = os.open(args.file, os.O_RDONLY)
+        fcntl.ioctl(fd, CIFS_IOC_NOTIFY_INFO, buf, True)
+    except Exception as e:
+        print("syscall failed: %s"%e)
+        return False
+
+    _, _, data_len = struct.unpack_from(fmt, buf, 0)
+    print("Notify completed, returned data_len is", data_len)
+    notify_data, = struct.unpack_from(f'{data_len}s', buf, struct.calcsize(fmt))
+    print_notify(notify_data)
+
+def print_notify(notify_data):
+    if notify_data is None:
+        return
+
+    data_size = len(notify_data)
+    if data_size == 0:
+        return
+
+    BYTES_PER_LINE = 16
+    for offset in range(0, data_size, BYTES_PER_LINE):
+        chunk = notify_data[offset:offset + BYTES_PER_LINE]
+
+        # raw hex data
+        hex_bytes = "".join(
+            (" " if i % 8 == 0 else "") + f"{x:02x} "
+            for i, x in enumerate(chunk)
+        )
+
+        # padding
+        pad_len = BYTES_PER_LINE - len(chunk)
+        pad = "   " * pad_len
+        if (pad_len >= 8):
+            pad += " " * (pad_len // 8)
+
+        # ASCII
+        ascii_part = "".join(
+            chr(x) if 31 < x < 127 else "."
+            for x in chunk
+        )
+
+        print(f"{offset:08x}: {hex_bytes}{pad} {ascii_part}")
+
 if __name__ == '__main__':
     main()
diff --git a/smbinfo.rst b/smbinfo.rst
index 17270c5..91b8895 100644
--- a/smbinfo.rst
+++ b/smbinfo.rst
@@ -98,6 +98,8 @@ the SMB3 traffic of this mount can be decryped e.g. via wireshark
 
 `gettconinfo`: Prints both the TCON Id and Session Id for a cifs file.
 
+`notify`: Query a directory for change notifications.
+
 *****
 NOTES
 *****
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-12-17 13:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-17 13:44 [PATCH RFC cifs-utils 0/1] smbinfo: add notify subcommand chenxiaosong.chenxiaosong
2025-12-17 13:44 ` [PATCH RFC cifs-utils 1/1] " chenxiaosong.chenxiaosong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).