summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>1998-08-03 19:07:55 +0000
committerJeremy Allison <jra@samba.org>1998-08-03 19:07:55 +0000
commit7448091da6ee11709b8e5117ff6810515567f88a (patch)
tree3fd35134c9636b00e3737e718a0cb04eaf902064 /source3
parent103857e8e33c724805baf5283335dc4e3901f007 (diff)
downloadsamba-7448091da6ee11709b8e5117ff6810515567f88a.tar.gz
samba-7448091da6ee11709b8e5117ff6810515567f88a.tar.bz2
samba-7448091da6ee11709b8e5117ff6810515567f88a.zip
First implementation of ChangeNotify - this version only checks
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. (This used to be commit a0748c3f53974483680ebe2ea4f556ece8d7fa43)
Diffstat (limited to 'source3')
-rw-r--r--source3/include/proto.h5
-rw-r--r--source3/include/smb.h15
-rw-r--r--source3/lib/debug.c5
-rw-r--r--source3/lib/util.c2
-rw-r--r--source3/locking/shmem_sysv.c22
-rw-r--r--source3/param/loadparm.c16
-rw-r--r--source3/smbd/nttrans.c304
-rw-r--r--source3/smbd/server.c13
8 files changed, 344 insertions, 38 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 10f01c1b9d..d3dcd70c16 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -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 */
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 60e214d73e..b33db0ce66 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -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)
diff --git a/source3/lib/debug.c b/source3/lib/debug.c
index 476023a7ba..02bf6710f5 100644
--- a/source3/lib/debug.c
+++ b/source3/lib/debug.c
@@ -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 */
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 0c9fa55d7d..a5e1819ae2 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -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;
diff --git a/source3/locking/shmem_sysv.c b/source3/locking/shmem_sysv.c
index 0809e0546f..b8b9c2cb45 100644
--- a/source3/locking/shmem_sysv.c
+++ b/source3/locking/shmem_sysv.c
@@ -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) {
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 2a42546662..ce8ff7122d 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -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)
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index d845076f36..4ee271cd6b 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -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)
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 2fc6bd2007..97a1a79239 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -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)