[PATCH] file change notification

Juergen Hasch Hasch at t-online.de
Fri Feb 14 19:28:55 GMT 2003


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:
0000  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.æ@. at .  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:
0000  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   ..Ú)@. at . Þ¿À¨..À¨
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

-------------- next part --------------
--- smbd/notify_kernel.orig	2003-01-14 21:57:16.000000000 +0100
+++ smbd/notify_kernel.c	2003-02-02 00:01:24.000000000 +0100
@@ -37,7 +37,6 @@
 #define DN_MULTISHOT    0x80000000      /* 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_FN	1027
+
+/* 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.orig	2003-01-14 21:57:29.000000000 +0100
+++ smbd/notify.c	2003-02-02 00:40:54.000000000 +0100
@@ -45,20 +45,54 @@
 /****************************************************************************
  Setup the common parts of the return packet and send it.
 *****************************************************************************/
-static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code)
+
+static void change_notify_reply_error_packet(char *inbuf, NTSTATUS error_code)
 {
 	char outbuf[smb_size+38];
 
 	memset(outbuf, '\0', sizeof(outbuf));
 	construct_reply_common(inbuf, outbuf);
 
-	ERROR_NT(error_code);
-
 	/*
 	 * Seems NT needs a transact command with an error code
 	 * in it. This is a longer packet than a simple error.
 	 */
+		ERROR_NT(error_code);
 	set_message(outbuf,18,0,False);
+		if (!send_smb(smbd_server_fd(),outbuf))
+			exit_server("change_notify_reply_packet: send_smb failed.");
+}
+
+static void change_notify_reply_packet(char *inbuf,char *filename, unsigned long event)
+{
+
+	char outbuf[smb_size+200];
+	char *p = outbuf+76;
+	FILE_NOTIFY_INFORMATION *fi;
+
+	memset(outbuf, '\0', sizeof(outbuf));
+	construct_reply_common(inbuf, outbuf);
+
+	set_message(outbuf,18,33,False);
+
+DEBUG(0,("send_reply_packet: %s, %u\n",filename,event));
+	fi = (FILE_NOTIFY_INFORMATION *) p;
+	fi->NextEntryOffset=0;
+	/* convert event type */
+	if (event & DN_MODIFY) fi->Action |= FILE_ACTION_MODIFIED;
+	if (event & DN_CREATE) fi->Action |= FILE_ACTION_ADDED;
+	if (event & DN_DELETE) fi->Action |= FILE_ACTION_REMOVED;
+	if (event & DN_RENAME) fi->Action |= FILE_ACTION_RENAMED_NEW_NAME;
+
+	fi->FileNameLength=dos_PutUniCode(fi->FileName,unix_to_dos_static(filename),sizeof(fstring), False);
+	/* fallback if no filename is given */
+	if (fi->FileNameLength == 0)
+		change_notify_reply_error_packet(inbuf,STATUS_NOTIFY_ENUM_DIR);
+
+	SIVAL(outbuf,smb_ntr_TotalParameterCount,12+fi->FileNameLength);
+	SIVAL(outbuf,smb_ntr_ParameterCount,12+fi->FileNameLength);
+	SIVAL(outbuf,smb_ntr_ParameterOffset,72); 	// vom SMB header bis zum NT_NOTIFY_INFORMATION
+	SIVAL(outbuf,smb_ntr_DataOffset,104); 		// Ende des Pakets
 
 	if (!send_smb(smbd_server_fd(),outbuf))
 		exit_server("change_notify_reply_packet: send_smb failed.");
@@ -104,7 +138,7 @@
 	for (cnbp=change_notify_list; cnbp; cnbp=next) {
 		next=cnbp->next;
 		if(SVAL(cnbp->request_buf,smb_mid) == mid) {
-			change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
+			change_notify_reply_error_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
 			change_notify_remove(cnbp);
 		}
 	}
@@ -126,7 +160,7 @@
 		 * the filename are identical.
 		 */
 		if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
-			change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
+			change_notify_reply_error_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
 			change_notify_remove(cnbp);
 		}
 	}
@@ -146,6 +180,15 @@
  Returns True if there are still outstanding change notify requests on the
  queue.
 *****************************************************************************/
+struct dnotify_info_struct {
+	unsigned long		event;
+	char filename[NAME_MAX+1];
+};
+
+struct change_data {
+	int directory_handle;
+	struct dnotify_info_struct fi;
+};
 
 BOOL process_pending_change_notify_queue(time_t t)
 {
@@ -159,7 +202,11 @@
 
 		if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) {
 			DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name ));
-			change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR);
+			struct change_data *data = (struct change_data *) cnbp->change_data;
+			if (data->fi.event > 0)
+				change_notify_reply_packet(cnbp->request_buf, data->fi.filename, data->fi.event);
+			else
+				change_notify_reply_error_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR);
 			change_notify_remove(cnbp);
 		}
 	}
--- include/smb.orig	2003-02-02 00:44:14.000000000 +0100
+++ include/smb.h	2003-02-01 18:46:26.000000000 +0100
@@ -1203,6 +1203,23 @@
 #define FILE_NOTIFY_CHANGE_SECURITY    0x100
 #define FILE_NOTIFY_CHANGE_FILE_NAME   0x200
 
+/* FILE_NOTIFY_INFORMATION */
+#define FILE_ACTION_ADDED            0x00000001
+#define FILE_ACTION_REMOVED          0x00000002
+#define FILE_ACTION_MODIFIED         0x00000003
+#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
+#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
+#define FILE_ACTION_ADDED_STREAM     0x00000006
+#define FILE_ACTION_REMOVED_STREAM   0x00000007
+#define FILE_ACTION_MODIFIED_STREAM  0x00000008
+
+typedef struct {
+	uint32 NextEntryOffset;
+	uint32 Action;
+	uint32 FileNameLength;
+	char FileName[1];
+} FILE_NOTIFY_INFORMATION;
+
 /* where to find the base of the SMB packet proper */
 #define smb_base(buf) (((char *)(buf))+4)
 



More information about the samba-technical mailing list