Re: [PATCH] file change notification

2003-03-04 Thread Michael B. Allen
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

2003-03-03 Thread Juergen Hasch
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

2003-02-14 Thread Juergen Hasch
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

2003-02-14 Thread Juergen Hasch
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

2003-02-14 Thread Tim Potter
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

2003-02-06 Thread Hal Roberts
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