Re: [PATCH] file change notification
On Mon, 3 Mar 2003 22:03:02 +0100 [EMAIL PROTECTED] (Juergen Hasch) wrote: Hi, attached is a modified version of Hal's file change notification patch. It's against Samba HEAD and works for me. Changes: - use push_ucs2() to send unicode file names - make some functions static (make proto works now) - limit maximum number of directory entries stored in the TDB to 2000, so large directories won't create monster TDBs. - the maximum reply packet size is limited to 64K. I guess this should never be a problem :-) What ist the maximum allowed size of a NT_TRANS packet anyway ? Each packet can be no more than 64K but an SMB_COM_NT_TRANSACTION may be multiple PDUs for what might amount to an endless stream (i.e. named pipe). The MaxParameterCount field in the request indicates how large the response can be. From the one pcap I have of W2K--W2K it's 4096. Mike -- A program should be written to model the concepts of the task it performs rather than the physical world or a process because this maximizes the potential for it to be applied to tasks that are conceptually similar and, more important, to tasks that have not yet been conceived.
Re: [PATCH] file change notification
Hi, attached is a modified version of Hal's file change notification patch. It's against Samba HEAD and works for me. Changes: - use push_ucs2() to send unicode file names - make some functions static (make proto works now) - limit maximum number of directory entries stored in the TDB to 2000, so large directories won't create monster TDBs. - the maximum reply packet size is limited to 64K. I guess this should never be a problem :-) What ist the maximum allowed size of a NT_TRANS packet anyway ? ...Juergen --- smbd/notify.orig 2002-12-12 03:01:53.0 +0100 +++ smbd/notify.c 2003-03-03 21:56:56.0 +0100 @@ -21,9 +21,21 @@ #include includes.h +#define MAX_DIRENTRIES 1000 + static struct cnotify_fns *cnotify; / +This structure holds a list of files and associated notification actions. +*/ +struct file_action { + struct file_action *next, *prev; + int action; + char *filename; + int filename_length; +}; + +/ This is the structure to queue to implement NT change notify. It consists of smb_size bytes stored from the transact command (to keep the mid, tid etc around). @@ -35,16 +47,145 @@ files_struct *fsp; connection_struct *conn; uint32 flags; + uint32 max_parameter_count; char request_buf[smb_size]; void *change_data; + TDB_CONTEXT *file_data; + struct file_action *file_actions; }; static struct change_notify *change_notify_list; -/ - Setup the common parts of the return packet and send it. -*/ -static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code) +/** + * Return a file action struct with the given filename and fileaction + * + **/ +static struct file_action *change_notify_get_file_action(char *filename, int fileaction) +{ + struct file_action *fa; + + if (!(fa = (struct file_action *)malloc(sizeof(struct file_action { + DEBUG(0, (malloc failed!)); + } + fa-action = fileaction; + fa-filename = strdup(filename); + fa-filename_length = strlen(filename); + + return fa; +} + +/** + * Check to make sure that the file in the given cnbp.file_data record + * still exists. + * + **/ +static int change_notify_file_data_exists(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *status) +{ + + struct file_action *fa; + struct change_notify *cnbp = (struct change_notify *)status; + char *filename; + char *path = ((struct change_notify *)cnbp)-fsp-fsp_name; + int filename_len = strlen((char *)key.dptr) + strlen((char *)path) + 2; + int fd; + + if (!(filename = (char *)malloc(filename_len))) { + DEBUG(0, (malloc failed)); + } + + filename[0] = '\0'; + safe_strcat(filename, (char *)path, filename_len); + safe_strcat(filename, /, filename_len); + safe_strcat(filename, (char *)key.dptr, filename_len); + + if ((fd = open(filename, O_RDONLY)) == -1) { + fa = change_notify_get_file_action + ((char *)key.dptr, FILE_ACTION_REMOVED); + DLIST_ADD(cnbp-file_actions, fa); + } else { + close(fd); + } + + return 0; +} + +/** + * Get a list of all the file notification actions + * + **/ +static int change_notify_find_file_actions(struct change_notify *cnbp) +{ + void *dp; + char *fname; + TDB_DATA tdb_key, tdb_data; + SMB_STRUCT_STAT old_st, new_st; + pstring full_name; + size_t fullname_len, remaining_len; + char *p; + int count; + struct file_action *fa; + + cnbp-file_actions = NULL; + + if (!(dp = OpenDir(cnbp-conn, cnbp-fsp-fsp_name, True))) { + DEBUG(0, (Failed to open directory '%s', + cnbp-fsp-fsp_name)); + } + + pstrcpy(full_name, cnbp-fsp-fsp_name); + pstrcat(full_name, /); + + fullname_len = strlen(full_name); + remaining_len = sizeof(full_name) - fullname_len - 1; + p = full_name[fullname_len]; + count = 0; + + while ((fname = ReadDirName(dp)) count MAX_DIRENTRIES) { + count ++; + if (strequal(fname, .) || strequal(fname, ..)) { + continue; + } + + DEBUG(10, (check file: %s\n, fname)); + safe_strcpy(p, fname, remaining_len); + vfs_stat(cnbp-conn, full_name, old_st); + tdb_key.dptr = (void *)fname; + tdb_key.dsize = strlen(fname) + 1; + tdb_data = tdb_fetch(cnbp-file_data, tdb_key); + if (!tdb_data.dptr) { + fa = change_notify_get_file_action +(fname, FILE_ACTION_ADDED); + DLIST_ADD(cnbp-file_actions, fa); + continue; + } + new_st = *((SMB_STRUCT_STAT *)tdb_data.dptr); + free(tdb_data.dptr); + if ((old_st.st_atime != new_st.st_atime) || + (old_st.st_mtime != new_st.st_mtime) || + (old_st.st_ctime != new_st.st_ctime)) { + fa = change_notify_get_file_action +(fname, FILE_ACTION_MODIFIED); + DLIST_ADD(cnbp-file_actions, fa); + } + } + + /* check for deleted files */ + if (tdb_traverse(cnbp-file_data,
Re: [PATCH] file change notification
Hello Hal, thanks for coding this patch, unfortunately it doesn't work for me. Checking the generated network packets with ethereal shows that the NT_NOTIFY packet I receive on the Windwows side is invalid. The packet (frame size as shown in ethereal) is much too short, it's size is 93 bytes, it should be 162. Below is the hex dump of a defect packet: 00 04 e2 1c 6f c0 00 04 e2 1c 6f 55 08 00 45 10 ..â.oÀ.. â.oU..E. 0010 00 4f 18 e6 40 00 40 06 a0 56 c0 a8 00 04 c0 a8 .O.æ@.@. VÀ¨..À¨ 0020 00 08 00 8b 04 c8 0e 6a 4a aa d4 2d f3 f9 50 18 .È.j JªÔ-óùP. 0030 16 d0 01 12 00 00 00 00 00 23 ff 53 4d 42 a0 00 .Ð.. .#ÿSMB . 0040 00 00 00 88 01 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 01 00 9c 05 64 00 c0 6f 40 20 00..d. Ào@ . This is what a W2K generated packet looks like: 00 04 e2 1c 6f c0 00 50 56 4b 85 6f 08 00 45 10 ..â.oÀ.P VK.o..E. 0010 00 94 da 29 40 00 40 06 de bf c0 a8 00 12 c0 a8 ..Ú)@.@. Þ¿À¨..À¨ 0020 00 08 00 8b 04 ba 92 f9 13 50 b8 db b8 fd 50 18 .º.ù .P¸Û¸ýP. 0030 2e 10 9a 20 00 00 00 00 00 68 ff 53 4d 42 a0 00 ... .hÿSMB . 0040 00 00 00 88 01 00 00 00 00 00 00 00 00 00 00 00 0050 00 00 01 00 c0 03 64 00 c1 ac 12 00 00 00 1e 00 À.d. Á¬.. 0060 00 00 00 00 00 00 1e 00 00 00 48 00 00 00 00 00 ..H. 0070 00 00 00 00 00 00 68 00 00 00 00 00 00 00 00 21 ..h. ...! 0080 00 00 00 00 00 00 03 00 00 00 12 00 00 00 66 00 ..f. 0090 69 00 6c 00 65 00 32 00 2e 00 74 00 78 00 74 00 i.l.e.2. ..t.x.t. 00a0 00 00 .. I attached my own hack which creates a reply packet identical to Windows (see the change_notify_reply_packet function). It only replies one single file name per reply packet, because you don't get more than one file change per signal using dnotify. Another thing I noticed is that you don't return an unicode filename, you simply return the filename with the unix charset and pad it with zeroes. Please convert the filename to Unicode when you assemble the packet. ...Juergen --- smbd/notify_kernel.orig 2003-01-14 21:57:16.0 +0100 +++ smbd/notify_kernel.c2003-02-02 00:01:24.0 +0100 @@ -37,7 +37,6 @@ #define DN_MULTISHOT0x8000 /* Don't remove notifier */ #endif - #ifndef RT_SIGNAL_NOTIFY #define RT_SIGNAL_NOTIFY 34 #endif @@ -50,6 +49,14 @@ #define F_NOTIFY 1026 #endif +#define F_NOTIFY_FN1027 + +/* this gets returned from the kernel */ +struct dnotify_info_struct { + unsigned long event; + char filename[NAME_MAX+1]; +}; + / This is the structure to keep the information needed to determine if a directory has changed. @@ -57,6 +64,8 @@ struct change_data { int directory_handle; +// uint32 Action; + struct dnotify_info_struct fi; }; / @@ -95,9 +104,10 @@ BlockSignals(True, RT_SIGNAL_NOTIFY); for (i = 0; i signals_received; i++) { if (data-directory_handle == (int)fd_pending_array[i]) { - DEBUG(3,(kernel_check_notify: kernel change notify on %s fd[%d]=%d (signals_received=%d)\n, - path, i, (int)fd_pending_array[i], (int)signals_received )); - + data-fi.event=0; + fcntl((int)fd_pending_array[i],F_NOTIFY_FN,(data-fi.event)); + DEBUG(0,(kernel_check_notify: kernel change notify on %s in +file %s, event %d, fd[%d]=%d (signals_received=%d)\n, + path, +data-fi.filename,data-fi.event, i, (int)fd_pending_array[i], (int)signals_received +)); close((int)fd_pending_array[i]); fd_pending_array[i] = (SIG_ATOMIC_T)-1; if (signals_received - i - 1) { @@ -166,7 +176,7 @@ return NULL; } - kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion changes everything! */ + kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME|DN_MULTISHOT; /* +creation/deletion changes everything! */ if (flags FILE_NOTIFY_CHANGE_FILE)kernel_flags |= DN_MODIFY; if (flags FILE_NOTIFY_CHANGE_DIR_NAME)kernel_flags |= DN_RENAME|DN_DELETE; if (flags FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB; --- smbd/notify.orig2003-01-14 21:57:29.0 +0100 +++ smbd/notify.c 2003-02-02 00:40:54.0 +0100 @@ -45,20 +45,54 @@ / Setup the common parts of the return packet and send it. */ -static void
Re: [PATCH] file change notification
Hi Tim, Am Freitag, 14. Februar 2003 21:52 schrieb Tim Potter: On Fri, Feb 14, 2003 at 08:28:55PM +0100, Juergen Hasch wrote: Hello Hal, thanks for coding this patch, unfortunately it doesn't work for me. Checking the generated network packets with ethereal shows that the NT_NOTIFY packet I receive on the Windwows side is invalid. The packet (frame size as shown in ethereal) is much too short, it's size is 93 bytes, it should be 162. How well does ethereal handle SMB change notify? I can honestly say that I've never seen it happen. (-: actually it looks quite good :-) Attached is a capture from two W2K machines talking to each other. Packet No. 19 shows the NT NOTIFY response packet. This capture was made using the Windows version of ethereal, the Linux version crashes on my machine when opening the capture file. Maybe you can fix that ;-) If you send me a bunch of captures I can fix any misdissections or any other problems with ethereal in this regard. Tim. ...Juergen
Re: [PATCH] file change notification
On Fri, Feb 14, 2003 at 10:21:04PM +0100, Juergen Hasch wrote: actually it looks quite good :-) That's good to hear! Attached is a capture from two W2K machines talking to each other. Packet No. 19 shows the NT NOTIFY response packet. This capture was made using the Windows version of ethereal, the Linux version crashes on my machine when opening the capture file. Maybe you can fix that ;-) OK that's definitely something worth doing. Thanks, Tim.
[PATCH] file change notification
Attached is a patch that adds support for reporting individual files during file change notification. The patch keeps a table of the stats of all files in a watched directory and then compares the current stats of the files with the stored stats whenever there is a notification event. Note that all of the code is in the generic notify.c file, so it works regardless of whether the server is using hash_notify.c or kernel_notify.c. The costs are 1) the memory cost of storing the tdb info in memory and 2) the performance cost of having to check each file to figure out which one changed everytime there is a file notification event. The memory use could be reduced by storing the table on disk instead of in memory, but that would incur a cost in performance and could result in a lot of *tdb files sitting around (one per directory watched). The only way to reduce the performance cost is to make the kernel stuff return a file name with its notification. This change wouldn't be too hard to add to the kernel, but I'd rather not require a hacked kernel to make samba work as it should. The only thing that doesn't work quite as it should is that the code does not report a file name change event as such, but instead just treats a name change as a file remove and then a file add. Supporting this would make the code a lot more complex (I'd have to keep a separate, inode indexed table of file stats in addition to the file name indexed one), and I can't imagine when a remove/add instead of a move would break a client, though it might cause performance issues. Also, though this is a separate issue, the file change stuff still doesn't support deep notifications as it should as far as I can tell (which is to say not at all). -hal diff -u -r samba-2.2.7a.dist/source/include/smb.h samba-2.2.7a/source/include/smb.h --- samba-2.2.7a.dist/source/include/smb.h Wed Dec 4 12:16:36 2002 +++ samba-2.2.7a/source/include/smb.h Wed Jan 22 16:26:56 2003 @@ -1202,6 +1202,16 @@ #define FILE_NOTIFY_CHANGE_SECURITY0x100 #define FILE_NOTIFY_CHANGE_FILE_NAME 0x200 +/* file notification actions */ +#define FILE_ACTION_ADDED 0x0001 +#define FILE_ACTION_REMOVED0x0002 +#define FILE_ACTION_MODIFIED 0x0003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x0004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x0005 +#define FILE_ACTION_ADDED_STREAM 0x0006 +#define FILE_ACTION_REMOVED_STREAM 0x0007 +#define FILE_ACTION_MODIFIED_STREAM0x0008 + /* where to find the base of the SMB packet proper */ #define smb_base(buf) (((char *)(buf))+4) diff -u -r samba-2.2.7a.dist/source/smbd/notify.c samba-2.2.7a/source/smbd/notify.c --- samba-2.2.7a.dist/source/smbd/notify.c Fri Feb 1 17:14:47 2002 +++ samba-2.2.7a/source/smbd/notify.c Thu Feb 6 16:08:07 2003 @@ -25,6 +25,16 @@ static struct cnotify_fns *cnotify; / +This structure holds a list of files and associated notification actions. +*/ +struct file_action { + struct file_action *next, *prev; + int action; + char *filename; + int filename_length; +}; + +/ This is the structure to queue to implement NT change notify. It consists of smb_size bytes stored from the transact command (to keep the mid, tid etc around). @@ -38,14 +48,250 @@ uint32 flags; char request_buf[smb_size]; void *change_data; + TDB_CONTEXT *file_data; + struct file_action *file_actions; }; static struct change_notify *change_notify_list; / + Return a file action struct with the given filename and fileaction +*/ +struct file_action *change_notify_get_file_action(char *filename, + int fileaction) { + + struct file_action *fa; + + if (!(fa = (struct file_action *)malloc(sizeof(struct file_action { + DEBUG(0, (malloc failed!)); + } + + fa-action = fileaction; + fa-filename = strdup(filename); + fa-filename_length = strlen(filename); + + return fa; +} + +/ + Check to make sure that the file in the given cnbp.file_data record + still exists. +*/ +int change_notify_file_data_exists(TDB_CONTEXT *tdb, TDB_DATA key, + TDB_DATA data, void *status) { + + struct file_action *fa; + struct change_notify *cnbp = (struct change_notify *)status; + char *filename; + char