First implementation of ChangeNotify - this version only checks
authorJeremy Allison <jra@samba.org>
Mon, 3 Aug 1998 19:07:55 +0000 (19:07 +0000)
committerJeremy Allison <jra@samba.org>
Mon, 3 Aug 1998 19:07:55 +0000 (19:07 +0000)
for changes in the directory modify timestamps. A better version
will look at the requested client flags, and create a hash that
represents the current state of the directory, and check against
this instead.
debug.c: Added lp_timestamp_logs() function.
loadparm.c: Added "change notify timeout" in seconds (default 60)
- this is the scan rate for a directory.
            Added ""timestamp logs" boolean - default True. Turns
off log timestamps (so I can read them :-).
nttrans.c: ChangeNotify implementation.
server.c: ChangeNotify implementation.
shmem_sysv.c: Added exits on shmem errors (without them smbd can
              core dump if some calls fail).
smb.h: Added ChangeNotify flags for future use.
util.c: Tidied up typedef.
Jeremy.

source/include/proto.h
source/include/smb.h
source/lib/debug.c
source/lib/util.c
source/locking/shmem_sysv.c
source/param/loadparm.c
source/smbd/nttrans.c
source/smbd/server.c

index 10f01c1b9d93f5773670eedbc80948c2d6d1a8e6..d3dcd70c160fa5a59c35c6800b8318b55e09253e 100644 (file)
@@ -1024,6 +1024,7 @@ BOOL lp_strip_dot(void);
 BOOL lp_encrypted_passwords(void);
 BOOL lp_update_encrypted(void);
 BOOL lp_syslog_only(void);
+BOOL lp_timestamp_logs(void);
 BOOL lp_browse_list(void);
 BOOL lp_unix_realname(void);
 BOOL lp_nis_home_map(void);
@@ -1058,6 +1059,7 @@ int lp_announce_as(void);
 int lp_lm_announce(void);
 int lp_lm_interval(void);
 int lp_machine_password_timeout(void);
+int lp_change_notify_timeout(void);
 int lp_ldap_port(void);
 char *lp_preexec(int );
 char *lp_postexec(int );
@@ -1603,6 +1605,9 @@ char *get_nt_error_msg(uint32 nt_code);
 int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize);
 int reply_ntcancel(char *inbuf,char *outbuf,int length,int bufsize);
 int reply_nttranss(char *inbuf,char *outbuf,int length,int bufsize);
+void remove_pending_change_notify_requests_by_fid(int fnum);
+void remove_pending_change_notify_requests_by_mid(int mid);
+void process_pending_change_notify_queue(time_t t);
 int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize);
 
 /*The following definitions come from  params.c  */
index 60e214d73ec9a9f5589f771c6f3db793c2a36f6e..b33db0ce66e90d5fc4cdc18fbe2b5d62e0498a5f 100644 (file)
@@ -190,7 +190,7 @@ implemented */
 #define STYPE_IPC       3      /* Interprocess communication (IPC) */
 #define STYPE_HIDDEN    0x80000000 /* share is a hidden one (ends with $) */
 
-/* SMB X/Open error codes for the ERRdos error class */
+/* SMB X/Open error codes for the ERRDOS error class */
 #define ERRbadfunc 1 /* Invalid function (or system call) */
 #define ERRbadfile 2 /* File not found (pathname error) */
 #define ERRbadpath 3 /* Directory not found */
@@ -1076,7 +1076,7 @@ struct parm_struct
 #define smb_nt_DataOffset (smb_vwv0 + 31)
 #define smb_nt_SetupCount (smb_vwv0 + 35)
 #define smb_nt_Function (smb_vwv0 + 36)
-#define smb_nt_SetupStart (smb_vwv0 + 39)
+#define smb_nt_SetupStart (smb_vwv0 + 38)
 
 /* these are for the NT trans secondary request. */
 #define smb_nts_TotalParameterCount (smb_vwv0 + 3)
@@ -1195,6 +1195,17 @@ struct parm_struct
 #define FILE_UNICODE_ON_DISK 0x4
 #define FILE_PERISITANT_ACLS 0x8
 
+/* ChangeNotify flags. */
+#define FILE_NOTIFY_CHANGE_FILE_NAME   0x001
+#define FILE_NOTIFY_CHANGE_DIR_NAME    0x002
+#define FILE_NOTIFY_CHANGE_ATTRIBUTES  0x004
+#define FILE_NOTIFY_CHANGE_SIZE        0x008
+#define FILE_NOTIFY_CHANGE_LAST_WRITE  0x010
+#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x020
+#define FILE_NOTIFY_CHANGE_CREATION    0x040
+#define FILE_NOTIFY_CHANGE_EA          0x080
+#define FILE_NOTIFY_CHANGE_SECURITY    0x100
+
 /* where to find the base of the SMB packet proper */
 #define smb_base(buf) (((char *)(buf))+4)
 
index 476023a7babd3469b38b254166e22e74e9ff1ddd..02bf6710f5531a4c1e492fab05eb741e8358ed2b 100644 (file)
@@ -477,8 +477,9 @@ BOOL dbghdr( int level, char *file, char *func, int line )
     return( True );
 
   /* Print it all out at once. */
-  Debug1( "[%s, %d] %s%s%s(%d)\n",
-          timestring(), level, file, (*file)?":":"", func, line );
+  if(lp_timestamp_logs())
+    Debug1( "[%s, %d] %s%s%s(%d)\n",
+            timestring(), level, file, (*file)?":":"", func, line );
   return( True );
   } /* dbghdr */
 
index 0c9fa55d7d39de83ddd260c4036c3f79291c96af..a5e1819ae27197c7f4523015df247cb626f65c7c 100644 (file)
@@ -2334,7 +2334,7 @@ BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout)
  for processing.
 ****************************************************************************/
 
-typedef struct smb_message_list {
+typedef struct {
    ubi_slNode msg_next;
    char *msg_buf;
    int msg_len;
index 0809e0546f5792af1510919371a0a40ab0bbf1b0..b8b9c2cb45654f2b383d74ce8096989f9546ee78 100644 (file)
@@ -572,7 +572,8 @@ struct shmem_ops *sysv_shm_open(int ronly)
                        su.val = 1;
                        for (i=0;i<hash_size+1;i++) {
                                if (semctl(sem_id, i, SETVAL, su) != 0) {
-                                       DEBUG(1,("Failed to init semaphore %d\n", i));
+                                       DEBUG(1,("Failed to init semaphore %d. Error was %s\n",
+                          i, strerror(errno)));
                                }
                        }
                }
@@ -581,14 +582,16 @@ struct shmem_ops *sysv_shm_open(int ronly)
                sem_id = semget(SEMAPHORE_KEY, 0, 0);
        }
        if (sem_id == -1) {
-               DEBUG(0,("Can't create or use semaphore %s\n", 
+               DEBUG(0,("Can't create or use semaphore.Error was %s\n", 
                         strerror(errno)));
                return NULL;
        }   
 
        su.buf = &sem_ds;
        if (semctl(sem_id, 0, IPC_STAT, su) != 0) {
-               DEBUG(0,("ERROR shm_open : can't IPC_STAT\n"));
+               DEBUG(0,("ERROR semctl: can't IPC_STAT. Error was %s\n",
+              strerror(errno)));
+               return NULL;
        }
        hash_size = sem_ds.sem_nsems-1;
 
@@ -604,18 +607,18 @@ struct shmem_ops *sysv_shm_open(int ronly)
                                 pid));
                        su.val = 1;
                        if (semctl(sem_id, 0, SETVAL, su) != 0) {
-                               DEBUG(0,("ERROR: Failed to clear global lock\n"));
+                               DEBUG(0,("ERROR: Failed to clear global lock. Error was %s\n",
+                      strerror(errno)));
                        }
                }
 
                sem_ds.sem_perm.mode = SEMAPHORE_PERMS;
                if (semctl(sem_id, 0, IPC_SET, su) != 0) {
-                       DEBUG(0,("ERROR shm_open : can't IPC_SET\n"));
+                       DEBUG(0,("ERROR shmctl : can't IPC_SET. Error was %s\n",
+                  strerror(errno)));
                }
        }
 
-       
-       
        if (!global_lock())
                return NULL;
 
@@ -627,7 +630,8 @@ struct shmem_ops *sysv_shm_open(int ronly)
                                 i, pid));
                        su.val = 1;
                        if (semctl(sem_id, i, SETVAL, su) != 0) {
-                               DEBUG(0,("ERROR: Failed to clear IPC lock %d\n", i));
+                               DEBUG(0,("ERROR: Failed to clear IPC lock %d. Error was %s\n",
+                      i, strerror(errno)));
                        }
                }
        }
@@ -674,7 +678,7 @@ struct shmem_ops *sysv_shm_open(int ronly)
           we use a registration file containing the processids of the file
           mapping processes */
        if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
-               DEBUG(0,("ERROR shm_open : can't IPC_STAT. Error was %s\n", strerror(errno)));
+               DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n", strerror(errno)));
        }
 
        if (!read_only) {
index 2a425466623bda8eaee2b23292c2b9c62fb24be6..ce8ff7122decd51199991f0425845e88a78842a0 100644 (file)
@@ -176,6 +176,7 @@ typedef struct
   int client_code_page;
   int announce_as;   /* This is initialised in init_globals */
   int machine_password_timeout;
+  int change_notify_timeout;
 #ifdef WITH_LDAP
   int ldap_port;
 #endif /* WITH_LDAP */
@@ -223,6 +224,7 @@ typedef struct
   BOOL bUnixPasswdSync;
   BOOL bPasswdChatDebug;
   BOOL bOleLockingCompat;
+  BOOL bTimestampLogs;
 } global;
 
 static global Globals;
@@ -552,6 +554,7 @@ static struct parm_struct parm_table[] =
   {"syslog only",      P_BOOL,    P_GLOBAL, &Globals.bSyslogOnly,       NULL,   NULL,  0},
   {"log file",         P_STRING,  P_GLOBAL, &Globals.szLogFile,         NULL,   NULL,  0},
   {"max log size",     P_INTEGER, P_GLOBAL, &Globals.max_log_size,      NULL,   NULL,  0},
+  {"timestamp logs",   P_BOOL,    P_GLOBAL, &Globals.bTimestampLogs,    NULL,   NULL,  0},
   {"status",           P_BOOL,    P_LOCAL,  &sDefault.status,           NULL,   NULL,  FLAG_GLOBAL},
 
   {"Protocol Options", P_SEP, P_SEPARATOR},
@@ -573,6 +576,7 @@ static struct parm_struct parm_table[] =
   {"time server",      P_BOOL,    P_GLOBAL, &Globals.bTimeServer,      NULL,   NULL,  0},
 
   {"Tuning Options", P_SEP, P_SEPARATOR},
+  {"change notify timeout", P_INTEGER, P_GLOBAL, &Globals.change_notify_timeout, NULL,   NULL,  0},
   {"max disk size",    P_INTEGER, P_GLOBAL, &Globals.maxdisksize,       NULL,   NULL,  0},
   {"lpq cache time",   P_INTEGER, P_GLOBAL, &Globals.lpqcachetime,      NULL,   NULL,  0},
   {"getwd cache",      P_BOOL,    P_GLOBAL, &use_getwd_cache,           NULL,   NULL,  0},
@@ -808,11 +812,13 @@ static void init_globals(void)
   Globals.bStripDot = False;
   Globals.syslog = 1;
   Globals.bSyslogOnly = False;
+  Globals.bTimestampLogs = True;
   Globals.os_level = 0;
-  Globals.max_ttl = 60*60*24*3; /* 3 days default */
-  Globals.max_wins_ttl = 60*60*24*6; /* 6 days default */
-  Globals.min_wins_ttl = 60*60*6; /* 6 hours default */
-  Globals.machine_password_timeout = 60*60*24*7; /* 7 days default */
+  Globals.max_ttl = 60*60*24*3; /* 3 days default. */
+  Globals.max_wins_ttl = 60*60*24*6; /* 6 days default. */
+  Globals.min_wins_ttl = 60*60*6; /* 6 hours default. */
+  Globals.machine_password_timeout = 60*60*24*7; /* 7 days default. */
+  Globals.change_notify_timeout = 60; /* 1 minute default. */
   Globals.ReadSize = 16*1024;
   Globals.lm_announce = 2;   /* = Auto: send only if LM clients found */
   Globals.lm_interval = 60;
@@ -1115,6 +1121,7 @@ FN_GLOBAL_BOOL(lp_strip_dot,&Globals.bStripDot)
 FN_GLOBAL_BOOL(lp_encrypted_passwords,&Globals.bEncryptPasswords)
 FN_GLOBAL_BOOL(lp_update_encrypted,&Globals.bUpdateEncrypt)
 FN_GLOBAL_BOOL(lp_syslog_only,&Globals.bSyslogOnly)
+FN_GLOBAL_BOOL(lp_timestamp_logs,&Globals.bTimestampLogs)
 FN_GLOBAL_BOOL(lp_browse_list,&Globals.bBrowseList)
 FN_GLOBAL_BOOL(lp_unix_realname,&Globals.bUnixRealname)
 FN_GLOBAL_BOOL(lp_nis_home_map,&Globals.bNISHomeMap)
@@ -1150,6 +1157,7 @@ FN_GLOBAL_INTEGER(lp_announce_as,&Globals.announce_as)
 FN_GLOBAL_INTEGER(lp_lm_announce,&Globals.lm_announce)
 FN_GLOBAL_INTEGER(lp_lm_interval,&Globals.lm_interval)
 FN_GLOBAL_INTEGER(lp_machine_password_timeout,&Globals.machine_password_timeout)
+FN_GLOBAL_INTEGER(lp_change_notify_timeout,&Globals.change_notify_timeout)
 
 #ifdef WITH_LDAP
 FN_GLOBAL_INTEGER(lp_ldap_port,&Globals.ldap_port)
index d845076f3630c2b8859824334dd4310dbb048419..4ee271cd6bb68c2122a2b7775ed20f0162faea7a 100644 (file)
@@ -657,6 +657,9 @@ int reply_ntcreate_and_X(char *inbuf,char *outbuf,int length,int bufsize)
 
   chain_fnum = fnum;
 
+  DEBUG(5,("reply_ntcreate_and_X: open fnum = %d, name = %s\n",
+        fnum, fsp->name ));
+
   return chain_reply(inbuf,outbuf,length,bufsize);
 }
 
@@ -737,12 +740,14 @@ static int call_nt_transact_create(char *inbuf, char *outbuf, int length,
       return(ERROR(ERRSRV,ERRnofids));
     }
 
+    fsp = &Files[fnum];
+
     if (!check_name(fname,cnum)) { 
       if((errno == ENOENT) && bad_path) {
         unix_ERR_class = ERRDOS;
         unix_ERR_code = ERRbadpath;
       }
-      Files[fnum].reserved = False;
+      fsp->reserved = False;
 
       restore_case_semantics(file_attributes);
 
@@ -783,14 +788,12 @@ static int call_nt_transact_create(char *inbuf, char *outbuf, int length,
       open_file_shared(fnum,cnum,fname,smb_open_mode,smb_ofun,unixmode,
                        oplock_request,&rmode,&smb_action);
 
-      fsp = &Files[fnum];
-    
       if (!fsp->open) { 
         if((errno == ENOENT) && bad_path) {
           unix_ERR_class = ERRDOS;
           unix_ERR_code = ERRbadpath;
         }
-        Files[fnum].reserved = False;
+        fsp->reserved = False;
 
         restore_case_semantics(file_attributes);
 
@@ -887,12 +890,22 @@ static int call_nt_transact_create(char *inbuf, char *outbuf, int length,
 }
 
 /****************************************************************************
- Reply to a NT CANCEL request - just ignore it.
+ Reply to a NT CANCEL request.
 ****************************************************************************/
 
 int reply_ntcancel(char *inbuf,char *outbuf,int length,int bufsize)
 {
-  DEBUG(4,("Ignoring ntcancel of length %d\n",length));
+  /*
+   * Go through and cancel any pending change notifies.
+   * TODO: When we add blocking locks we will add cancel
+   * for them here too.
+   */
+
+  int mid = SVAL(inbuf,smb_mid);
+  remove_pending_change_notify_requests_by_mid(mid);
+
+  DEBUG(3,("reply_ntcancel: cancel called on mid = %d.\n", mid));
+
   return(-1);
 }
 
@@ -933,6 +946,10 @@ static int call_nt_transact_rename(char *inbuf, char *outbuf, int length,
      * Rename was successful.
      */
     send_nt_replies(outbuf, bufsize, NULL, 0, NULL, 0);
+
+    DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", 
+          Files[fnum].name, new_name));
+
     outsize = -1;
   }
 
@@ -940,7 +957,175 @@ static int call_nt_transact_rename(char *inbuf, char *outbuf, int length,
 }
    
 /****************************************************************************
- Reply to a notify change - we should never get this (for now) as we
+ 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;
+  int fnum;
+  int cnum;
+  time_t next_check_time;
+  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.
+ Code stolen from construct_reply() in server.c
+*****************************************************************************/
+
+static void change_notify_reply_packet(char *inbuf, int error_class, uint32 error_code)
+{
+  extern int Client;
+  char outbuf[smb_size];
+
+  bzero(outbuf,smb_size);
+
+  CVAL(outbuf,smb_com) = CVAL(inbuf,smb_com);
+  set_message(outbuf,0,0,True);
+  memcpy(outbuf+4,inbuf+4,4);
+  CVAL(outbuf,smb_rcls) = SMB_SUCCESS;
+  CVAL(outbuf,smb_reh) = 0;
+  CVAL(outbuf,smb_flg) = 0x80 | (CVAL(inbuf,smb_flg) & 0x8); /* bit 7 set
+                                 means a reply */
+  SSVAL(outbuf,smb_flg2,1); /* say we support long filenames */
+  SSVAL(outbuf,smb_err,SMB_SUCCESS);
+  SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid));
+  SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid));
+  SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid));
+  SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid));
+
+  ERROR(error_class,error_code);
+  send_smb(Client,outbuf);
+}
+
+/****************************************************************************
+ Delete entries by fnum from the change notify pending queue.
+*****************************************************************************/
+
+void remove_pending_change_notify_requests_by_fid(int fnum)
+{
+  change_notify_buf *cnbp = (change_notify_buf *)ubi_slFirst( &change_notify_queue );
+  change_notify_buf *prev = NULL;
+
+  while(cnbp != NULL) {
+    if(cnbp->fnum == fnum) {
+      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,ERRSRV,ERRaccess);
+      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.
+*****************************************************************************/
+
+void 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;
+
+  if(cnbp->next_check_time >= t)
+    return;
+
+  /*
+   * It's time to check. Go through the queue and see if
+   * the timestamps changed.
+   */
+
+  while((cnbp != NULL) && (cnbp->next_check_time <= t)) {
+    struct stat st;
+    int fnum = cnbp->fnum;
+    int cnum = cnbp->cnum;
+    files_struct *fsp = &Files[fnum];
+    uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : 
+                  SVAL(cnbp->request_buf,smb_uid);
+
+    if(!become_user(&Connections[cnum],cnum,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);
+      ubi_slRemNext( &change_notify_queue, prev);
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      continue;
+    }
+
+    if(sys_stat(fsp->name, &st) < 0) {
+      DEBUG(0,("process_pending_change_notify_queue: Unable to stat directory %s. \
+Error was %s.\n", fsp->name, strerror(errno) ));
+      /*
+       * Remove the entry and return an error to the client.
+       */
+      change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
+      ubi_slRemNext( &change_notify_queue, prev);
+      cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue));
+      unbecome_user();
+      continue;
+    }
+
+    if(fsp->f_u.dir_ptr->modify_time != st.st_mtime ||
+       fsp->f_u.dir_ptr->status_time != st.st_ctime) {
+      /*
+       * Remove the entry and return a change notify to the client.
+       */
+      DEBUG(5,("process_pending_change_notify_queue: directory fnum = %d, name = %s changed\n",
+            fnum, fsp->name ));
+      change_notify_reply_packet(cnbp->request_buf,ERRDOS,ERROR_NOTIFY_ENUM_DIR);
+      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);
+  }
+}
+
+/****************************************************************************
+ Reply to a notify change - queue the request and 
  don't allow a directory to be opened.
 ****************************************************************************/
 
@@ -948,10 +1133,83 @@ static int call_nt_transact_notify_change(char *inbuf, char *outbuf, int length,
                                           int bufsize, int cnum,
                                           char **ppsetup, char **ppparams, char **ppdata)
 {
+#if 0
   DEBUG(0,("call_nt_transact_notify_change: Should not be called !\n"));
   return(ERROR(ERRSRV,ERRnosupport));
+#else /* Under development. */
+  char *setup = *ppsetup;
+  files_struct *fsp;
+  int fnum = -1;
+  change_notify_buf *cnbp;
+  struct stat st;
+
+  fnum = SVAL(setup,4);
+
+  DEBUG(0,("call_nt_transact_notify_change: fnum = %d.\n", fnum));
+
+  if(!VALID_FNUM(fnum))
+    return(ERROR(ERRDOS,ERRbadfid));
+
+  fsp = &Files[fnum];
+
+  if((!fsp->open) || (!fsp->is_directory) || (cnum != fsp->cnum))
+    return(ERROR(ERRDOS,ERRbadfid));
+
+  /*
+   * Setup the current directory information in the
+   * directory entry in the files_struct. We will use
+   * this to check against when the timer expires.
+   */
+
+  if(sys_stat(fsp->name, &st) < 0) {
+                       DEBUG(0,("call_nt_transact_notify_change: Unable to stat fnum = %d, name = %s. \
+               Error was %s\n", fnum, fsp->name, strerror(errno) ));
+                       return -1;
+  }
+  if(fsp->f_u.dir_ptr == NULL) {
+    if((fsp->f_u.dir_ptr = (dir_status_struct *)malloc(sizeof(dir_status_struct))) == NULL) {
+      DEBUG(0,("call_nt_transact_notify_change: Malloc fail !\n" ));
+      return -1;
+    }
+  }
+
+  fsp->f_u.dir_ptr->modify_time = st.st_mtime;
+  fsp->f_u.dir_ptr->status_time = st.st_ctime;
+
+  /*
+   * 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 (2) !\n" ));
+    return -1;
+  }
+
+  memcpy(cnbp->request_buf, inbuf, smb_size);
+  cnbp->fnum = fnum;
+  cnbp->cnum = cnum;
+  cnbp->next_check_time = time(NULL) + lp_change_notify_timeout();
+
+  /*
+   * 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 fid=%d, name = %s\n",
+        fnum, fsp->name ));
+
+  return -1;
+#endif
 }
-   
+
 /****************************************************************************
  Reply to query a security descriptor - currently this is not implemented (it
  is planned to be though).
@@ -996,7 +1254,7 @@ static int call_nt_transact_ioctl(char *inbuf, char *outbuf, int length,
 
 int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
 {
-  int outsize = 0;
+  int  outsize = 0;
   int cnum = SVAL(inbuf,smb_tid);
 #if 0 /* Not used. */
   uint16 max_setup_count = CVAL(inbuf, smb_nt_MaxSetupCount);
@@ -1009,7 +1267,7 @@ int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
   uint32 parameter_offset = IVAL(inbuf,smb_nt_ParameterOffset);
   uint32 data_count = IVAL(inbuf,smb_nt_DataCount);
   uint32 data_offset = IVAL(inbuf,smb_nt_DataOffset);
-  uint16 setup_count = CVAL(inbuf,smb_nt_SetupCount);
+  uint16 setup_count = 2*CVAL(inbuf,smb_nt_SetupCount); /* setup count is in *words* */
   uint16 function_code = SVAL( inbuf, smb_nt_Function);
   char *params = NULL, *data = NULL, *setup = NULL;
   uint32 num_params_sofar, num_data_sofar;
@@ -1019,8 +1277,8 @@ int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
      * Queue this open message as we are the process of an oplock break.
      */
 
-    DEBUG( 2, ( "reply_nttrans: queueing message NT_TRANSACT_CREATE " ) );
-    DEBUGADD( 2, ( "due to being in oplock break state.\n" ) );
+    DEBUG(2,("reply_nttrans: queueing message NT_TRANSACT_CREATE \
+due to being in oplock break state.\n" ));
 
     push_oplock_pending_smb_message( inbuf, length);
     return -1;
@@ -1033,9 +1291,9 @@ int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
    * Ensure this is so as a sanity check.
    */
 
-  if(CVAL(inbuf, smb_wct) != 19 + setup_count) {
+  if(CVAL(inbuf, smb_wct) != 19 + (setup_count/2)) {
     DEBUG(2,("Invalid smb_wct %d in nttrans call (should be %d)\n",
-          CVAL(inbuf, smb_wct), 19 + setup_count));
+          CVAL(inbuf, smb_wct), 19 + (setup_count/2)));
     return(ERROR(ERRSRV,ERRerror));
   }
     
@@ -1062,12 +1320,21 @@ int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
   if (parameter_count > total_parameter_count || data_count > total_data_count)
     exit_server("reply_nttrans: invalid sizes in packet.\n");
 
-  if(setup)
+  if(setup) {
     memcpy( setup, &inbuf[smb_nt_SetupStart], setup_count);
-  if(params)
+    DEBUG(10,("reply_nttrans: setup_count = %d\n", setup_count));
+    dump_data(10, setup, setup_count);
+  }
+  if(params) {
     memcpy( params, smb_base(inbuf) + parameter_offset, parameter_count);
-  if(data)
+    DEBUG(10,("reply_nttrans: parameter_count = %d\n", parameter_count));
+    dump_data(10, params, parameter_count);
+  }
+  if(data) {
     memcpy( data, smb_base(inbuf) + data_offset, data_count);
+    DEBUG(10,("reply_nttrans: data_count = %d\n",data_count));
+    dump_data(10, data, data_count);
+  }
 
   if(num_data_sofar < total_data_count || num_params_sofar < total_parameter_count) {
     /* We need to send an interim response then receive the rest
@@ -1145,8 +1412,7 @@ int reply_nttrans(char *inbuf,char *outbuf,int length,int bufsize)
       break;
     default:
       /* Error in request */
-      DEBUG( 0, ( "reply_nttrans: Unknown request %d in nttrans call\n",
-                  function_code ) );
+      DEBUG(0,("reply_nttrans: Unknown request %d in nttrans call\n", function_code));
       if(setup)
         free(setup);
       if(params)
index 2fc6bd2007e0ad09efefdaa5d8be89c3157bfbbb..97a1a79239b4fbd4636649aa95b72656c28b1513 100644 (file)
@@ -1475,6 +1475,8 @@ void close_directory(int fnum)
      change notify requests and free
      any pertaining to this fnum. */
 
+  remove_pending_change_notify_requests_by_fid(fnum);
+
   /*
    * Do the code common to files and directories.
    */
@@ -1532,6 +1534,9 @@ int open_directory(int fnum,int cnum,char *fname, int smb_ofun, int unixmode, in
     *action = FILE_WAS_OPENED;
   }
 
+  DEBUG(5,("open_directory: opening directory %s, fnum = %d\n",
+        fname, fnum ));
+
   /*
    * Setup the files_struct for it.
    */
@@ -4029,7 +4034,7 @@ int reply_nt1(char *outbuf)
 
 /*
   other valid capabilities which we may support at some time...
-                     CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+                     CAP_LARGE_FILES|
                      CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
  */
 
@@ -5116,6 +5121,12 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup ));
         trust_password_unlock();
         global_machine_pasword_needs_changing = False;
       }
+
+      /*
+       * Check to see if we have any change notifies 
+       * outstanding on the queue.
+       */
+      process_pending_change_notify_queue(t);
     }
 
     if(got_smb)