split all the change notify code out into a separate module
authorAndrew Tridgell <tridge@samba.org>
Mon, 12 Jun 2000 05:32:28 +0000 (05:32 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 12 Jun 2000 05:32:28 +0000 (05:32 +0000)
smbd/notify.c. All the data structures are now private to that
module.

this is in preparation for Linux kernel support for change notify
(coming soon to a CVS tree near you)
(This used to be commit 1bb0aad4f66dbfa2d0f767ea90f926affff20b17)

source3/Makefile.in
source3/include/proto.h
source3/smbd/notify.c [new file with mode: 0644]
source3/smbd/nttrans.c

index ba6424e3d229719b6766dacd979642926a671d57..af46419312cd01266ef551135c5832d109ce228d 100644 (file)
@@ -162,7 +162,7 @@ OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
 SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
             smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \
             smbd/ipc.o smbd/lanman.o smbd/mangle.o smbd/negprot.o \
-            smbd/message.o smbd/nttrans.o smbd/pipes.o \
+            smbd/message.o smbd/nttrans.o smbd/notify.o smbd/pipes.o \
             smbd/reply.o smbd/trans2.o smbd/uid.o \
            smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o smbd/blocking.o \
            smbd/vfs.o smbd/vfs-wrap.o smbd/statcache.o \
index f874f0e1a19c4142d8009d656ab8f6d9860f1476..4f5f3d42d3e9fb52f168adf11631b9843e5f5649 100644 (file)
@@ -3245,6 +3245,17 @@ int reply_negprot(connection_struct *conn,
 
 BOOL disk_quotas(char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize);
 
+/*The following definitions come from  smbd/notify.c  */
+
+#if OLD_NTDOMAIN
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp);
+void remove_pending_change_notify_requests_by_mid(int mid);
+void remove_pending_change_notify_requests_by_filename(files_struct *fsp);
+BOOL process_pending_change_notify_queue(time_t t);
+BOOL change_notifies_pending(void);
+BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags);
+#endif
+
 /*The following definitions come from  smbd/nttrans.c  */
 
 #if OLD_NTDOMAIN
@@ -3256,10 +3267,6 @@ int reply_ntcancel(connection_struct *conn,
                   char *inbuf,char *outbuf,int length,int bufsize);
 int reply_nttranss(connection_struct *conn,
                   char *inbuf,char *outbuf,int length,int bufsize);
-void remove_pending_change_notify_requests_by_fid(files_struct *fsp);
-void remove_pending_change_notify_requests_by_filename(files_struct *fsp);
-BOOL process_pending_change_notify_queue(time_t t);
-BOOL change_notifies_pending(void);
 int reply_nttrans(connection_struct *conn,
                  char *inbuf,char *outbuf,int length,int bufsize);
 #endif
@@ -3294,18 +3301,6 @@ BOOL attempt_close_oplocked_file(files_struct *fsp);
 BOOL init_oplocks(void);
 #endif
 
-/*The following definitions come from  smbd/oplock_irix.c  */
-
-#if OLD_NTDOMAIN
-struct kernel_oplocks *irix_init_kernel_oplocks(void) ;
-#endif
-
-/*The following definitions come from  smbd/oplock_linux.c  */
-
-#if OLD_NTDOMAIN
-struct kernel_oplocks *linux_init_kernel_oplocks(void) ;
-#endif
-
 /*The following definitions come from  smbd/password.c  */
 
 #if OLD_NTDOMAIN
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
new file mode 100644 (file)
index 0000000..26be17c
--- /dev/null
@@ -0,0 +1,392 @@
+#define OLD_NTDOMAIN 1
+/*
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   SMB NT transaction handling
+   Copyright (C) Jeremy Allison 1994-1998
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/****************************************************************************
+ This is the structure to keep the information needed to
+ determine if a directory has changed.
+*****************************************************************************/
+
+typedef struct {
+  time_t modify_time; /* Info from the directory we're monitoring. */ 
+  time_t status_time; /* Info from the directory we're monitoring. */
+  time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
+  unsigned int num_entries; /* Zero or the number of files in the directory. */
+} change_hash_data;
+
+/****************************************************************************
+ 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).
+ Plus the fid to examine and the time to check next.
+*****************************************************************************/
+
+typedef struct {
+  ubi_slNode msg_next;
+  files_struct *fsp;
+  connection_struct *conn;
+  uint32 flags;
+  time_t next_check_time;
+  change_hash_data change_data;
+  char request_buf[smb_size];
+} change_notify_buf;
+
+static ubi_slList change_notify_queue = { NULL, (ubi_slNodePtr)&change_notify_queue, 0};
+
+/****************************************************************************
+ Setup the common parts of the return packet and send it.
+*****************************************************************************/
+
+static void change_notify_reply_packet(char *inbuf, int error_class, uint32 error_code)
+{
+  char outbuf[smb_size+38];
+
+  memset(outbuf, '\0', sizeof(outbuf));
+  construct_reply_common(inbuf, outbuf);
+
+  /*
+   * If we're returning a 'too much in the directory changed' we need to
+   * set this is an NT error status flags. If we don't then the (probably
+   * untested) code in the NT redirector has a bug in that it doesn't re-issue
+   * the change notify.... Ah - I *love* it when I get so deeply into this I
+   * can even determine how MS failed to test stuff and why.... :-). JRA.
+   */
+
+  if(error_class == 0) /* NT Error. */
+    SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
+
+  ERROR(error_class,error_code);
+
+  /*
+   * Seems NT needs a transact command with an error code
+   * in it. This is a longer packet than a simple error.
+   */
+  set_message(outbuf,18,0,False);
+
+  send_smb(smbd_server_fd(),outbuf);
+}
+
+/****************************************************************************
+ Create the hash we will use to determine if the contents changed.
+*****************************************************************************/
+
+static BOOL create_directory_notify_hash( change_notify_buf *cnbp, change_hash_data *change_data)
+{
+  SMB_STRUCT_STAT st;
+  files_struct *fsp = cnbp->fsp;
+
+  memset((char *)change_data, '\0', sizeof(change_data));
+
+  /* 
+   * Store the current timestamp on the directory we are monitoring.
+   */
+
+  if(dos_stat(fsp->fsp_name, &st) < 0) {
+    DEBUG(0,("create_directory_notify_hash: Unable to stat name = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+    return False;
+  }
+  change_data->modify_time = st.st_mtime;
+  change_data->status_time = st.st_ctime;
+
+  /*
+   * If we are to watch for changes that are only stored
+   * in inodes of files, not in the directory inode, we must
+   * scan the directory and produce a unique identifier with
+   * which we can determine if anything changed. We use the
+   * modify and change times from all the files in the
+   * directory, added together (ignoring wrapping if it's
+   * larger than the max time_t value).
+   */
+
+  if(cnbp->flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE)) {
+    pstring full_name;
+    char *p;
+    char *fname;
+    size_t remaining_len;
+    size_t fullname_len;
+    void *dp = OpenDir(cnbp->conn, fsp->fsp_name, True);
+
+    if(dp == NULL) {
+      DEBUG(0,("create_directory_notify_hash: Unable to open directory = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+      return False;
+    }
+
+    change_data->num_entries = 0;
+
+    pstrcpy(full_name, fsp->fsp_name);
+    pstrcat(full_name, "/");
+
+    fullname_len = strlen(full_name);
+    remaining_len = sizeof(full_name) - fullname_len - 1;
+    p = &full_name[fullname_len];
+
+    while ((fname = ReadDirName(dp))) {
+      if(strequal(fname, ".") || strequal(fname, ".."))
+        continue;
+
+      change_data->num_entries++;
+      safe_strcpy( p, fname, remaining_len);
+
+      memset(&st, '\0', sizeof(st));
+
+      /*
+       * Do the stat - but ignore errors.
+       */
+
+      if(dos_stat(full_name, &st) < 0) {
+        DEBUG(5,("create_directory_notify_hash: Unable to stat content file = %s. \
+Error was %s\n", fsp->fsp_name, strerror(errno) ));
+      }
+      change_data->total_time += (st.st_mtime + st.st_ctime);
+    }
+
+    CloseDir(dp);
+  }
+
+  return True;
+}
+
+/****************************************************************************
+ Delete entries by fnum from the change notify pending queue.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
+{
+  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+  change_notify_buf *prev = NULL;
+
+  while(cnbp != NULL) {
+    if(cnbp->fsp->fnum == fsp->fnum) {
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      continue;
+    }
+
+    prev = cnbp;
+    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+  }
+}
+
+/****************************************************************************
+ Delete entries by mid from the change notify pending queue. Always send reply.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_mid(int mid)
+{
+  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+  change_notify_buf *prev = NULL;
+
+  while(cnbp != NULL) {
+    if(SVAL(cnbp->request_buf,smb_mid) == mid) {
+      change_notify_reply_packet(cnbp->request_buf,0,0xC0000000 |NT_STATUS_CANCELLED);
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      continue;
+    }
+
+    prev = cnbp;
+    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+  }
+}
+
+/****************************************************************************
+ Delete entries by filename and cnum from the change notify pending queue.
+ Always send reply.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
+{
+  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+  change_notify_buf *prev = NULL;
+
+  while(cnbp != NULL) {
+    /*
+     * We know it refers to the same directory if the connection number and
+     * 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,0,0xC0000000 |NT_STATUS_CANCELLED);
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      continue;
+    }
+
+    prev = cnbp;
+    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+  }
+}
+
+/****************************************************************************
+ Process the change notify queue. Note that this is only called as root.
+ Returns True if there are still outstanding change notify requests on the
+ queue.
+*****************************************************************************/
+
+BOOL process_pending_change_notify_queue(time_t t)
+{
+  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+  change_notify_buf *prev = NULL;
+
+  if(cnbp == NULL)
+    return False;
+
+  if(cnbp->next_check_time >= t)
+    return True;
+
+  /*
+   * It's time to check. Go through the queue and see if
+   * the timestamps changed.
+   */
+
+  while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
+    change_hash_data change_data;
+    connection_struct *conn = cnbp->conn;
+    uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : 
+                  SVAL(cnbp->request_buf,smb_uid);
+
+    ZERO_STRUCT(change_data);
+
+    /*
+     * Ensure we don't have any old chain_fsp values
+     * sitting around....
+     */
+    chain_size = 0;
+    file_chain_reset();
+
+    if(!become_user(conn,vuid)) {
+      DEBUG(0,("process_pending_change_notify_queue: Unable to become user vuid=%d.\n",
+            vuid ));
+      /*
+       * Remove the entry and return an error to the client.
+       */
+      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      continue;
+    }
+
+    if(!become_service(conn,True)) {
+           DEBUG(0,("process_pending_change_notify_queue: Unable to become service Error was %s.\n", strerror(errno) ));
+      /*
+       * Remove the entry and return an error to the client.
+       */
+      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      unbecome_user();
+      continue;
+    }
+
+    if(!create_directory_notify_hash( cnbp, &change_data)) {
+      DEBUG(0,("process_pending_change_notify_queue: Unable to create change data for \
+directory %s\n", cnbp->fsp->fsp_name ));
+      /*
+       * Remove the entry and return an error to the client.
+       */
+      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      unbecome_user();
+      continue;
+    }
+
+    if(memcmp( (char *)&cnbp->change_data, (char *)&change_data, sizeof(change_data))) {
+      /*
+       * Remove the entry and return a change notify to the client.
+       */
+      DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed.\n",
+            cnbp->fsp->fsp_name ));
+      change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
+      free((char *)ubi_slRemNext( &change_notify_queue, prev));
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      unbecome_user();
+      continue;
+    }
+
+    unbecome_user();
+
+    /*
+     * Move to the next in the list.
+     */
+    prev = cnbp;
+    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
+  }
+
+  return (cnbp != NULL);
+}
+
+/****************************************************************************
+ Return true if there are pending change notifies.
+****************************************************************************/
+BOOL change_notifies_pending(void)
+{
+  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+  return (cnbp != NULL);
+}
+
+/****************************************************************************
+   * Now queue an entry on the notify change stack. We timestamp
+   * the entry we are adding so that we know when to scan next.
+   * We only need to save smb_size bytes from this incoming packet
+   * as we will always by returning a 'read the directory yourself'
+   * error.
+****************************************************************************/
+BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags)
+{
+       change_notify_buf *cnbp;
+
+       if((cnbp = (change_notify_buf *)malloc(sizeof(change_notify_buf))) == NULL) {
+               DEBUG(0,("call_nt_transact_notify_change: malloc fail !\n" ));
+               return -1;
+       }
+
+       ZERO_STRUCTP(cnbp);
+
+       memcpy(cnbp->request_buf, inbuf, smb_size);
+       cnbp->fsp = fsp;
+       cnbp->conn = conn;
+       cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
+       cnbp->flags = flags;
+       
+       if (!create_directory_notify_hash(cnbp, &cnbp->change_data)) {
+               free((char *)cnbp);
+               return False;
+       }
+       
+       /*
+        * Adding to the tail enables us to check only
+        * the head when scanning for change, as this entry
+        * is forced to have the first timeout expiration.
+        */
+       
+       ubi_slAddTail(&change_notify_queue, cnbp);
+
+       return True;
+}
+
+#undef OLD_NTDOMAIN
index 8b3eabff80be7da47c55b4f082e5a91f4951cf93..4e4e418efdc77cc3fef82b553f523280439f32a6 100644 (file)
@@ -30,8 +30,6 @@ extern BOOL case_sensitive;
 extern BOOL case_preserve;
 extern BOOL short_case_preserve;
 
-static void remove_pending_change_notify_requests_by_mid(int mid);
-
 static char *known_nt_pipes[] = {
   "\\LANMAN",
   "\\srvsvc",
@@ -1407,6 +1405,41 @@ int reply_nttranss(connection_struct *conn,
        return(-1);
 }
 
+/****************************************************************************
+ Reply to a notify change - queue the request and 
+ don't allow a directory to be opened.
+****************************************************************************/
+static int call_nt_transact_notify_change(connection_struct *conn,
+                                  char *inbuf, char *outbuf, int length,
+                                  int bufsize, 
+                                  char **ppsetup, 
+                                  char **ppparams, char **ppdata)
+{
+  char *setup = *ppsetup;
+  files_struct *fsp;
+  uint32 flags;
+
+  fsp = file_fsp(setup,4);
+  flags = IVAL(setup, 0);
+
+  DEBUG(3,("call_nt_transact_notify_change\n"));
+
+  if(!fsp)
+    return(ERROR(ERRDOS,ERRbadfid));
+
+  if((!fsp->is_directory) || (conn != fsp->conn))
+    return(ERROR(ERRDOS,ERRbadfid));
+
+  if (!change_notify_set(inbuf, fsp, conn, flags)) {
+         return(UNIXERROR(ERRDOS,ERRbadfid));
+  }
+
+  DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
+name = %s\n", fsp->fsp_name ));
+
+  return -1;
+}
+
 /****************************************************************************
  Reply to an NT transact rename command.
 ****************************************************************************/
@@ -1445,396 +1478,6 @@ static int call_nt_transact_rename(connection_struct *conn,
   return(outsize);
 }
    
-/****************************************************************************
- This is the structure to keep the information needed to
- determine if a directory has changed.
-*****************************************************************************/
-
-typedef struct {
-  time_t modify_time; /* Info from the directory we're monitoring. */ 
-  time_t status_time; /* Info from the directory we're monitoring. */
-  time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
-  unsigned int num_entries; /* Zero or the number of files in the directory. */
-} change_hash_data;
-
-/****************************************************************************
- 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).
- Plus the fid to examine and the time to check next.
-*****************************************************************************/
-
-typedef struct {
-  ubi_slNode msg_next;
-  files_struct *fsp;
-  connection_struct *conn;
-  uint32 flags;
-  time_t next_check_time;
-  change_hash_data change_data;
-  char request_buf[smb_size];
-} change_notify_buf;
-
-static ubi_slList change_notify_queue = { NULL, (ubi_slNodePtr)&change_notify_queue, 0};
-
-/****************************************************************************
- Setup the common parts of the return packet and send it.
-*****************************************************************************/
-
-static void change_notify_reply_packet(char *inbuf, int error_class, uint32 error_code)
-{
-  char outbuf[smb_size+38];
-
-  memset(outbuf, '\0', sizeof(outbuf));
-  construct_reply_common(inbuf, outbuf);
-
-  /*
-   * If we're returning a 'too much in the directory changed' we need to
-   * set this is an NT error status flags. If we don't then the (probably
-   * untested) code in the NT redirector has a bug in that it doesn't re-issue
-   * the change notify.... Ah - I *love* it when I get so deeply into this I
-   * can even determine how MS failed to test stuff and why.... :-). JRA.
-   */
-
-  if(error_class == 0) /* NT Error. */
-    SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
-
-  ERROR(error_class,error_code);
-
-  /*
-   * Seems NT needs a transact command with an error code
-   * in it. This is a longer packet than a simple error.
-   */
-  set_message(outbuf,18,0,False);
-
-  send_smb(smbd_server_fd(),outbuf);
-}
-
-/****************************************************************************
- Create the hash we will use to determine if the contents changed.
-*****************************************************************************/
-
-static BOOL create_directory_notify_hash( change_notify_buf *cnbp, change_hash_data *change_data)
-{
-  SMB_STRUCT_STAT st;
-  files_struct *fsp = cnbp->fsp;
-
-  memset((char *)change_data, '\0', sizeof(change_data));
-
-  /* 
-   * Store the current timestamp on the directory we are monitoring.
-   */
-
-  if(dos_stat(fsp->fsp_name, &st) < 0) {
-    DEBUG(0,("create_directory_notify_hash: Unable to stat name = %s. \
-Error was %s\n", fsp->fsp_name, strerror(errno) ));
-    return False;
-  }
-  change_data->modify_time = st.st_mtime;
-  change_data->status_time = st.st_ctime;
-
-  /*
-   * If we are to watch for changes that are only stored
-   * in inodes of files, not in the directory inode, we must
-   * scan the directory and produce a unique identifier with
-   * which we can determine if anything changed. We use the
-   * modify and change times from all the files in the
-   * directory, added together (ignoring wrapping if it's
-   * larger than the max time_t value).
-   */
-
-  if(cnbp->flags & (FILE_NOTIFY_CHANGE_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE)) {
-    pstring full_name;
-    char *p;
-    char *fname;
-    size_t remaining_len;
-    size_t fullname_len;
-    void *dp = OpenDir(cnbp->conn, fsp->fsp_name, True);
-
-    if(dp == NULL) {
-      DEBUG(0,("create_directory_notify_hash: Unable to open directory = %s. \
-Error was %s\n", fsp->fsp_name, strerror(errno) ));
-      return False;
-    }
-
-    change_data->num_entries = 0;
-
-    pstrcpy(full_name, fsp->fsp_name);
-    pstrcat(full_name, "/");
-
-    fullname_len = strlen(full_name);
-    remaining_len = sizeof(full_name) - fullname_len - 1;
-    p = &full_name[fullname_len];
-
-    while ((fname = ReadDirName(dp))) {
-      if(strequal(fname, ".") || strequal(fname, ".."))
-        continue;
-
-      change_data->num_entries++;
-      safe_strcpy( p, fname, remaining_len);
-
-      memset(&st, '\0', sizeof(st));
-
-      /*
-       * Do the stat - but ignore errors.
-       */
-
-      if(dos_stat(full_name, &st) < 0) {
-        DEBUG(5,("create_directory_notify_hash: Unable to stat content file = %s. \
-Error was %s\n", fsp->fsp_name, strerror(errno) ));
-      }
-      change_data->total_time += (st.st_mtime + st.st_ctime);
-    }
-
-    CloseDir(dp);
-  }
-
-  return True;
-}
-
-/****************************************************************************
- Delete entries by fnum from the change notify pending queue.
-*****************************************************************************/
-
-void remove_pending_change_notify_requests_by_fid(files_struct *fsp)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  while(cnbp != NULL) {
-    if(cnbp->fsp->fnum == fsp->fnum) {
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
-}
-
-/****************************************************************************
- Delete entries by mid from the change notify pending queue. Always send reply.
-*****************************************************************************/
-
-static void remove_pending_change_notify_requests_by_mid(int mid)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  while(cnbp != NULL) {
-    if(SVAL(cnbp->request_buf,smb_mid) == mid) {
-      change_notify_reply_packet(cnbp->request_buf,0,0xC0000000 |NT_STATUS_CANCELLED);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
-}
-
-/****************************************************************************
- Delete entries by filename and cnum from the change notify pending queue.
- Always send reply.
-*****************************************************************************/
-
-void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  while(cnbp != NULL) {
-    /*
-     * We know it refers to the same directory if the connection number and
-     * 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,0,0xC0000000 |NT_STATUS_CANCELLED);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
-}
-
-/****************************************************************************
- Process the change notify queue. Note that this is only called as root.
- Returns True if there are still outstanding change notify requests on the
- queue.
-*****************************************************************************/
-
-BOOL process_pending_change_notify_queue(time_t t)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  change_notify_buf *prev = NULL;
-
-  if(cnbp == NULL)
-    return False;
-
-  if(cnbp->next_check_time >= t)
-    return True;
-
-  /*
-   * It's time to check. Go through the queue and see if
-   * the timestamps changed.
-   */
-
-  while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
-    change_hash_data change_data;
-    connection_struct *conn = cnbp->conn;
-    uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : 
-                  SVAL(cnbp->request_buf,smb_uid);
-
-    ZERO_STRUCT(change_data);
-
-    /*
-     * Ensure we don't have any old chain_fsp values
-     * sitting around....
-     */
-    chain_size = 0;
-    file_chain_reset();
-
-    if(!become_user(conn,vuid)) {
-      DEBUG(0,("process_pending_change_notify_queue: Unable to become user vuid=%d.\n",
-            vuid ));
-      /*
-       * Remove the entry and return an error to the client.
-       */
-      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      continue;
-    }
-
-    if(!become_service(conn,True)) {
-           DEBUG(0,("process_pending_change_notify_queue: Unable to become service Error was %s.\n", strerror(errno) ));
-      /*
-       * Remove the entry and return an error to the client.
-       */
-      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      unbecome_user();
-      continue;
-    }
-
-    if(!create_directory_notify_hash( cnbp, &change_data)) {
-      DEBUG(0,("process_pending_change_notify_queue: Unable to create change data for \
-directory %s\n", cnbp->fsp->fsp_name ));
-      /*
-       * Remove the entry and return an error to the client.
-       */
-      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      unbecome_user();
-      continue;
-    }
-
-    if(memcmp( (char *)&cnbp->change_data, (char *)&change_data, sizeof(change_data))) {
-      /*
-       * Remove the entry and return a change notify to the client.
-       */
-      DEBUG(5,("process_pending_change_notify_queue: directory name = %s changed.\n",
-            cnbp->fsp->fsp_name ));
-      change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
-      free((char *)ubi_slRemNext( &change_notify_queue, prev));
-      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
-      unbecome_user();
-      continue;
-    }
-
-    unbecome_user();
-
-    /*
-     * Move to the next in the list.
-     */
-    prev = cnbp;
-    cnbp = (change_notify_buf *)ubi_slNext(cnbp);
-  }
-
-  return (cnbp != NULL);
-}
-
-/****************************************************************************
- Return true if there are pending change notifies.
-****************************************************************************/
-
-BOOL change_notifies_pending(void)
-{
-  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
-  return (cnbp != NULL);
-}
-
-/****************************************************************************
- Reply to a notify change - queue the request and 
- don't allow a directory to be opened.
-****************************************************************************/
-
-static int call_nt_transact_notify_change(connection_struct *conn,
-                                          char *inbuf, char *outbuf, int length,
-                                          int bufsize, 
-                                          char **ppsetup, 
-                                          char **ppparams, char **ppdata)
-{
-  char *setup = *ppsetup;
-  files_struct *fsp;
-  change_notify_buf *cnbp;
-
-  fsp = file_fsp(setup,4);
-
-  DEBUG(3,("call_nt_transact_notify_change\n"));
-
-  if(!fsp)
-    return(ERROR(ERRDOS,ERRbadfid));
-
-  if((!fsp->is_directory) || (conn != fsp->conn))
-    return(ERROR(ERRDOS,ERRbadfid));
-
-  /*
-   * Now queue an entry on the notify change stack. We timestamp
-   * the entry we are adding so that we know when to scan next.
-   * We only need to save smb_size bytes from this incoming packet
-   * as we will always by returning a 'read the directory yourself'
-   * error.
-   */
-
-  if((cnbp = (change_notify_buf *)malloc(sizeof(change_notify_buf))) == NULL) {
-    DEBUG(0,("call_nt_transact_notify_change: malloc fail !\n" ));
-    return -1;
-  }
-
-  memset((char *)cnbp, '\0', sizeof(change_notify_buf));
-
-  memcpy(cnbp->request_buf, inbuf, smb_size);
-  cnbp->fsp = fsp;
-  cnbp->conn = conn;
-  cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
-  cnbp->flags = IVAL(setup, 0);
-
-  if(!create_directory_notify_hash( cnbp, &cnbp->change_data )) {
-    free((char *)cnbp);
-    return(UNIXERROR(ERRDOS,ERRbadfid));
-  }
-
-  /*
-   * Adding to the tail enables us to check only
-   * the head when scanning for change, as this entry
-   * is forced to have the first timeout expiration.
-   */
-
-  ubi_slAddTail(&change_notify_queue, cnbp);
-
-  DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
-name = %s\n", fsp->fsp_name ));
-
-  return -1;
-}
 
 /****************************************************************************
  Reply to query a security descriptor - currently this is not implemented (it