summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1999-07-14 13:22:05 +0000
committerAndrew Tridgell <tridge@samba.org>1999-07-14 13:22:05 +0000
commit9b011b6975ca17772afb7a204b6b9bc8b4ed0341 (patch)
treef16693f359f243491be37e3437a924b1ddf9db9e
parent2a274a8755210e13da6bbf29d25f834f53275752 (diff)
downloadsamba-9b011b6975ca17772afb7a204b6b9bc8b4ed0341.tar.gz
the smbd changes from the 2.0 branch. This is going to need a _lot_ of
testing over the next few days.
-rw-r--r--source/smbd/close.c2
-rw-r--r--source/smbd/connection.c2
-rw-r--r--source/smbd/dir.c12
-rw-r--r--source/smbd/dosmode.c4
-rw-r--r--source/smbd/fileio.c86
-rw-r--r--source/smbd/files.c5
-rw-r--r--source/smbd/ipc.c4
-rw-r--r--source/smbd/nttrans.c128
-rw-r--r--source/smbd/open.c78
-rw-r--r--source/smbd/oplock.c455
-rw-r--r--source/smbd/password.c6
-rw-r--r--source/smbd/process.c46
-rw-r--r--source/smbd/reply.c148
-rw-r--r--source/smbd/server.c31
-rw-r--r--source/smbd/trans2.c2
15 files changed, 690 insertions, 319 deletions
diff --git a/source/smbd/close.c b/source/smbd/close.c
index 84723ecc75f..1afa30cce98 100644
--- a/source/smbd/close.c
+++ b/source/smbd/close.c
@@ -118,7 +118,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
del_share_mode(token, fsp);
}
- if(fsp->granted_oplock == True)
+ if(EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
release_file_oplock(fsp);
if(fd_attempt_close(fsp->fd_ptr,&err) == 0)
diff --git a/source/smbd/connection.c b/source/smbd/connection.c
index b771b2d2348..ad5fb1b0a79 100644
--- a/source/smbd/connection.c
+++ b/source/smbd/connection.c
@@ -34,7 +34,7 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
struct connect_record crec;
pstring fname;
int fd;
- int mypid = getpid();
+ pid_t mypid = getpid();
int i;
DEBUG(3,("Yielding connection to %s\n",name));
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index 0512b0bad75..b78656f8727 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -30,7 +30,7 @@ extern int DEBUGLEVEL;
typedef struct _dptr_struct {
struct _dptr_struct *next, *prev;
int dnum;
- int pid;
+ uint16 spid;
connection_struct *conn;
void *ptr;
BOOL expect_close;
@@ -314,15 +314,15 @@ void dptr_idlecnum(connection_struct *conn)
}
/****************************************************************************
- Close a dptr that matches a given path, only if it matches the pid also.
+ Close a dptr that matches a given path, only if it matches the spid also.
****************************************************************************/
-void dptr_closepath(char *path,int pid)
+void dptr_closepath(char *path,uint16 spid)
{
dptr_struct *dptr, *next;
for(dptr = dirptrs; dptr; dptr = next) {
next = dptr->next;
- if (pid == dptr->pid && strequal(dptr->path,path))
+ if (spid == dptr->spid && strequal(dptr->path,path))
dptr_close_internal(dptr);
}
}
@@ -394,7 +394,7 @@ static void dptr_old_close_oldest(void)
me at Andrew's knee.... :-) :-). JRA.
****************************************************************************/
-int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,int pid)
+int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
{
dptr_struct *dptr;
@@ -463,7 +463,7 @@ int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect
dptr->ptr = conn->dirptr;
string_set(&dptr->path,path);
dptr->conn = conn;
- dptr->pid = pid;
+ dptr->spid = spid;
dptr->expect_close = expect_close;
dptr->wcard = NULL; /* Only used in lanman2 searches */
dptr->attr = 0; /* Only used in lanman2 searches */
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index 567561f0f29..41d4e80444f 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -50,7 +50,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
can always create a file in a read-only directory. */
result |= (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH | S_IWUSR);
/* Apply directory mask */
- result &= lp_dir_mode(SNUM(conn));
+ result &= lp_dir_mask(SNUM(conn));
/* Add in force bits */
result |= lp_force_dir_mode(SNUM(conn));
} else {
@@ -64,7 +64,7 @@ mode_t unix_mode(connection_struct *conn,int dosmode)
result |= S_IXOTH;
/* Apply mode mask */
- result &= lp_create_mode(SNUM(conn));
+ result &= lp_create_mask(SNUM(conn));
/* Add in force bits */
result |= lp_force_create_mode(SNUM(conn));
}
diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c
index da48da9b32a..5e0fd432e11 100644
--- a/source/smbd/fileio.c
+++ b/source/smbd/fileio.c
@@ -114,7 +114,7 @@ ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
write to a file
****************************************************************************/
-ssize_t write_file(files_struct *fsp,char *data,size_t n)
+ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
{
if (!fsp->can_write) {
@@ -133,6 +133,90 @@ ssize_t write_file(files_struct *fsp,char *data,size_t n)
}
}
+ /*
+ * If this file is level II oplocked then we need
+ * to grab the shared memory lock and inform all
+ * other files with a level II lock that they need
+ * to flush their read caches. We keep the lock over
+ * the shared memory area whilst doing this.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+ share_mode_entry *share_list = NULL;
+ pid_t pid = getpid();
+ int token = -1;
+ int num_share_modes = 0;
+ int i;
+
+ if (lock_share_entry(fsp->conn, dev, inode, &token) == False) {
+ DEBUG(0,("write_file: failed to lock share mode entry for file %s.\n", fsp->fsp_name ));
+ }
+
+ num_share_modes = get_share_modes(fsp->conn, token, dev, inode, &share_list);
+
+ for(i = 0; i < num_share_modes; i++) {
+ share_mode_entry *share_entry = &share_list[i];
+
+ /*
+ * As there could have been multiple writes waiting at the lock_share_entry
+ * gate we may not be the first to enter. Hence the state of the op_types
+ * in the share mode entries may be partly NO_OPLOCK and partly LEVEL_II
+ * oplock. It will do no harm to re-send break messages to those smbd's
+ * that are still waiting their turn to remove their LEVEL_II state, and
+ * also no harm to ignore existing NO_OPLOCK states. JRA.
+ */
+
+ if (share_entry->op_type == NO_OPLOCK)
+ continue;
+
+ /* Paranoia .... */
+ if (EXLUSIVE_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(0,("write_file: PANIC. share mode entry %d is an exlusive oplock !\n", i ));
+ abort();
+ }
+
+ /*
+ * Check if this is a file we have open (including the
+ * file we've been called to do write_file on. If so
+ * then break it directly without releasing the lock.
+ */
+
+ if (pid == share_entry->pid) {
+ files_struct *new_fsp = file_find_dit(dev, inode, &share_entry->time);
+
+ /* Paranoia check... */
+ if(new_fsp == NULL) {
+ DEBUG(0,("write_file: PANIC. share mode entry %d is not a local file !\n", i ));
+ abort();
+ }
+ oplock_break_level2(new_fsp, True, token);
+
+ } else {
+
+ /*
+ * This is a remote file and so we send an asynchronous
+ * message.
+ */
+
+ request_oplock_break(share_entry, dev, inode);
+ }
+ }
+
+ free((char *)share_list);
+ unlock_share_entry(fsp->conn, dev, inode, token);
+ }
+
+ /* Paranoia check... */
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ DEBUG(0,("write_file: PANIC. File %s still has a level II oplock.\n", fsp->fsp_name));
+ abort();
+ }
+
+ if ((pos != -1) && (seek_file(fsp,pos) == -1))
+ return -1;
+
return(write_data(fsp->fd_ptr->fd,data,n));
}
diff --git a/source/smbd/files.c b/source/smbd/files.c
index 8381e07d4bb..d6203580cf5 100644
--- a/source/smbd/files.c
+++ b/source/smbd/files.c
@@ -94,7 +94,6 @@ files_struct *file_new(void )
first_file = (i+1) % real_max_open_files;
bitmap_set(file_bmap, i);
-
files_used++;
fsp->fnum = i + FILE_HANDLE_OFFSET;
@@ -376,8 +375,8 @@ void file_free(files_struct *fsp)
bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
files_used--;
- DEBUG(5,("freed files structure %d fnum = %d (%d used)\n",
- fsp->fnum - FILE_HANDLE_OFFSET, fsp->fnum, files_used));
+ DEBUG(5,("freed files structure %d (%d used)\n",
+ fsp->fnum, files_used));
/* this is paranoia, just in case someone tries to reuse the
information */
diff --git a/source/smbd/ipc.c b/source/smbd/ipc.c
index 4698e2b87cc..bb21a899662 100644
--- a/source/smbd/ipc.c
+++ b/source/smbd/ipc.c
@@ -94,7 +94,7 @@ static int CopyAndAdvance(char** dst, char* src, int* n)
{
int l;
if (!src || !dst || !n || !(*dst)) return(0);
- StrnCpy(*dst,src,*n);
+ StrnCpy(*dst,src,*n-1);
l = strlen(*dst) + 1;
(*dst) += l;
(*n) -= l;
@@ -401,7 +401,7 @@ va_dcl
needed = get_counter(&p->curpos);
{
char *s = va_arg(args,char*);
- if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed);
+ if (p->buflen >= needed) StrnCpy(p->structbuf,s?s:"",needed-1);
}
break;
case 'z': /* offset to zero terminated string (4 byte) */
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 4fd0dad5d67..145e5513896 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -788,9 +788,9 @@ int reply_ntcreate_and_X(connection_struct *conn,
*/
if (create_options & FILE_NON_DIRECTORY_FILE) {
- SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
file_free(fsp);
restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
return(ERROR(0, 0xc0000000|NT_STATUS_FILE_IS_A_DIRECTORY));
}
@@ -869,9 +869,9 @@ int reply_ntcreate_and_X(connection_struct *conn,
if (oplock_request && lp_fake_oplocks(SNUM(conn)))
smb_action |= EXTENDED_OPLOCK_GRANTED;
- if(oplock_request && fsp->granted_oplock)
+ if(oplock_request && EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
smb_action |= EXTENDED_OPLOCK_GRANTED;
-
+
set_message(outbuf,34,0,True);
p = outbuf + smb_vwv2;
@@ -880,9 +880,14 @@ int reply_ntcreate_and_X(connection_struct *conn,
* Currently as we don't support level II oplocks we just report
* exclusive & batch here.
*/
-
- SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? BATCH_OPLOCK : 0));
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ else
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
p++;
SSVAL(p,0,fsp->fnum);
p += 2;
@@ -1101,7 +1106,28 @@ static int call_nt_transact_create(connection_struct *conn,
if (!fsp->open) {
- if(errno == EACCES && stat_open_only) {
+ if(errno == EISDIR) {
+
+ /*
+ * Fail the open if it was explicitly a non-directory file.
+ */
+
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
+ return(ERROR(0, 0xc0000000|NT_STATUS_FILE_IS_A_DIRECTORY));
+ }
+
+ oplock_request = 0;
+ open_directory(fsp, conn, fname, smb_ofun, unixmode, &smb_action);
+
+ if(!fsp->open) {
+ file_free(fsp);
+ restore_case_semantics(file_attributes);
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+ } else if(errno == EACCES && stat_open_only) {
/*
* We couldn't open normally and all we want
@@ -1159,7 +1185,7 @@ static int call_nt_transact_create(connection_struct *conn,
if (oplock_request && lp_fake_oplocks(SNUM(conn)))
smb_action |= EXTENDED_OPLOCK_GRANTED;
- if(oplock_request && fsp->granted_oplock)
+ if(oplock_request && EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
smb_action |= EXTENDED_OPLOCK_GRANTED;
}
}
@@ -1174,7 +1200,13 @@ static int call_nt_transact_create(connection_struct *conn,
memset((char *)params,'\0',69);
p = params;
- SCVAL(p,0, (smb_action & EXTENDED_OPLOCK_GRANTED ? BATCH_OPLOCK : 0));
+ if (smb_action & EXTENDED_OPLOCK_GRANTED)
+ SCVAL(p,0, BATCH_OPLOCK_RETURN);
+ else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ SCVAL(p,0, LEVEL_II_OPLOCK_RETURN);
+ else
+ SCVAL(p,0,NO_OPLOCK_RETURN);
+
p += 2;
if (IS_IPC(conn)) {
SSVAL(p,0,pnum);
@@ -1509,18 +1541,20 @@ void remove_pending_change_notify_requests_by_filename(files_struct *fsp)
/****************************************************************************
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.
*****************************************************************************/
-void process_pending_change_notify_queue(time_t t)
+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;
+ return False;
if(cnbp->next_check_time >= t)
- return;
+ return True;
/*
* It's time to check. Go through the queue and see if
@@ -1598,6 +1632,18 @@ directory %s\n", cnbp->fsp->fsp_name ));
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);
}
/****************************************************************************
@@ -2155,6 +2201,7 @@ static int call_nt_transact_set_security_desc(connection_struct *conn,
SMB_STRUCT_STAT sbuf;
files_struct *fsp = NULL;
uint32 security_info_sent = 0;
+ BOOL got_dacl = False;
if(!lp_nt_acl_support())
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2206,6 +2253,11 @@ security descriptor.\n"));
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
+ if (psd->dacl != NULL)
+ got_dacl = True;
+
+ free_sec_desc(&psd);
+
/*
* Get the current state of the file.
*/
@@ -2223,8 +2275,9 @@ security descriptor.\n"));
else
ret = sys_fstat(fsp->fd_ptr->fd,&sbuf);
- if(ret != 0)
+ if(ret != 0) {
return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
}
/*
@@ -2233,41 +2286,68 @@ security descriptor.\n"));
if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
- DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
- fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+ DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+ if(dos_chown( fsp->fsp_name, user, grp) == -1) {
+ DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /*
+ * Recheck the current state of the file, which may have changed.
+ * (suid/sgid bits, for instance)
+ */
- if(dos_chown( fsp->fsp_name, user, grp) == -1) {
- DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
- fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ if(fsp->is_directory) {
+ if(dos_stat(fsp->fsp_name, &sbuf) != 0) {
return(UNIXERROR(ERRDOS,ERRnoaccess));
}
+ } else {
+
+ int ret;
+
+ if(fsp->fd_ptr == NULL)
+ ret = dos_stat(fsp->fsp_name, &sbuf);
+ else
+ ret = sys_fstat(fsp->fd_ptr->fd,&sbuf);
+
+ if(ret != 0)
+ return(UNIXERROR(ERRDOS,ERRnoaccess));
+ }
}
/*
* Only change security if we got a DACL.
*/
- if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
-
- free_sec_desc(&psd);
+ if((security_info_sent & DACL_SECURITY_INFORMATION) && got_dacl) {
/*
* Check to see if we need to change anything.
+ * Enforce limits on modified bits.
*/
if(fsp->is_directory) {
- perms &= lp_dir_mode(SNUM(conn));
- perms |= lp_force_dir_mode(SNUM(conn));
+ perms &= lp_dir_security_mask(SNUM(conn));
+ perms |= lp_force_dir_security_mode(SNUM(conn));
} else {
- perms &= lp_create_mode(SNUM(conn));
- perms |= lp_force_create_mode(SNUM(conn));
+ perms &= lp_security_mask(SNUM(conn));
+ perms |= lp_force_security_mode(SNUM(conn));
}
/*
+ * Preserve special bits.
+ */
+
+ perms |= (sbuf.st_mode & ~0777);
+
+ /*
* Do we need to chmod ?
*/
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 67a8f22b35d..a28a0c348a3 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -26,10 +26,10 @@ extern int DEBUGLEVEL;
extern pstring sesssetup_user;
extern uint16 global_oplock_port;
-
/****************************************************************************
fd support routines - attempt to do a dos_open
****************************************************************************/
+
static int fd_attempt_open(char *fname, int flags, mode_t mode)
{
int fd = dos_open(fname,flags,mode);
@@ -82,6 +82,7 @@ static int fd_attempt_open(char *fname, int flags, mode_t mode)
Cache a uid_t currently with this file open. This is an optimization only
used when multiple sessionsetup's have been done to one smbd.
****************************************************************************/
+
void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u)
{
if(fd_ptr->uid_cache_count >= sizeof(fd_ptr->uid_users_cache)/sizeof(uid_t))
@@ -93,6 +94,7 @@ void fd_add_to_uid_cache(file_fd_struct *fd_ptr, uid_t u)
Remove a uid_t that currently has this file open. This is an optimization only
used when multiple sessionsetup's have been done to one smbd.
****************************************************************************/
+
static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u)
{
int i;
@@ -110,6 +112,7 @@ static void fd_remove_from_uid_cache(file_fd_struct *fd_ptr, uid_t u)
Check if a uid_t that currently has this file open is present. This is an
optimization only used when multiple sessionsetup's have been done to one smbd.
****************************************************************************/
+
static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u)
{
int i;
@@ -119,11 +122,11 @@ static BOOL fd_is_in_uid_cache(file_fd_struct *fd_ptr, uid_t u)
return False;
}
-
/****************************************************************************
fd support routines - attempt to re-open an already open fd as O_RDWR.
Save the already open fd (we cannot close due to POSIX file locking braindamage.
****************************************************************************/
+
static void fd_attempt_reopen(char *fname, mode_t mode, file_fd_struct *fd_ptr)
{
int fd = dos_open( fname, O_RDWR, mode);
@@ -288,11 +291,12 @@ is no longer waiting ! Error = %s\n", strerror(errno) ));
/****************************************************************************
check a filename for the pipe string
****************************************************************************/
+
static void check_for_pipe(char *fname)
{
/* special case of pipe opens */
char s[10];
- StrnCpy(s,fname,9);
+ StrnCpy(s,fname,sizeof(s)-1);
strlower(s);
if (strstr(s,"pipe/")) {
DEBUG(3,("Rejecting named pipe open for %s\n",fname));
@@ -304,6 +308,7 @@ static void check_for_pipe(char *fname)
/****************************************************************************
open a file
****************************************************************************/
+
static void open_file(files_struct *fsp,connection_struct *conn,
char *fname1,int flags,mode_t mode, SMB_STRUCT_STAT *sbuf)
{
@@ -315,7 +320,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
fsp->open = False;
fsp->fd_ptr = 0;
- fsp->granted_oplock = False;
+ fsp->oplock_type = NO_OPLOCK;
errno = EPERM;
pstrcpy(fname,fname1);
@@ -543,8 +548,8 @@ static void open_file(files_struct *fsp,connection_struct *conn,
fsp->share_mode = 0;
fsp->print_file = conn->printer;
fsp->modified = False;
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = False;
fsp->stat_open = False;
fsp->directory_delete_on_close = False;
@@ -568,7 +573,7 @@ static void open_file(files_struct *fsp,connection_struct *conn,
*/
if (fsp->print_file && lp_postscript(SNUM(conn)) && fsp->can_write) {
DEBUG(3,("Writing postscript line\n"));
- write_file(fsp,"%!\n",3);
+ write_file(fsp,"%!\n",-1,3);
}
DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
@@ -594,7 +599,7 @@ static void mmap_open_file(files_struct *fsp)
/* mmap it if read-only */
if (!fsp->can_write) {
fsp->mmap_size = dos_file_size(fsp->fsp_name);
- if (fsp->mmap_size < MAX_MMAP_SIZE) {
+ if (fsp->mmap_size < MAX_MMAP_SIZE && fsp->mmap_size > 0) {
fsp->mmap_ptr = (char *)sys_mmap(NULL,fsp->mmap_size,
PROT_READ,MAP_SHARED,fsp->fd_ptr->fd,(SMB_OFF_T)0);
@@ -613,6 +618,7 @@ static void mmap_open_file(files_struct *fsp)
Helper for open_file_shared.
Truncate a file after checking locking; close file if locked.
**************************************************************************/
+
static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, int token,
BOOL *share_locked)
{
@@ -638,19 +644,19 @@ static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, i
}
}
-
enum {AFAIL,AREAD,AWRITE,AALL};
/*******************************************************************
reproduce the share mode access table
********************************************************************/
+
static int access_table(int new_deny,int old_deny,int old_mode,
- int share_pid,char *fname)
+ pid_t share_pid,char *fname)
{
if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL);
if (new_deny == DENY_DOS || old_deny == DENY_DOS) {
- int pid = getpid();
+ pid_t pid = getpid();
if (old_deny == new_deny && share_pid == pid)
return(AALL);
@@ -692,10 +698,10 @@ static int access_table(int new_deny,int old_deny,int old_mode,
return(AFAIL);
}
-
/****************************************************************************
check if we can open a file with a share mode
****************************************************************************/
+
static int check_share_mode( share_mode_entry *share, int deny_mode,
char *fname,
BOOL fcbopen, int *flags)
@@ -739,7 +745,7 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
{
DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d\n",
deny_mode,old_deny_mode,old_open_mode,
- share->pid,fname, fcbopen, *flags, access_allowed));
+ (int)share->pid,fname, fcbopen, *flags, access_allowed));
unix_ERR_class = ERRDOS;
unix_ERR_code = ERRbadshare;
@@ -758,7 +764,6 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
return True;
}
-
/****************************************************************************
open a file with a share mode
****************************************************************************/
@@ -779,7 +784,7 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
SMB_INO_T inode = 0;
int num_share_modes = 0;
int oplock_contention_count = 0;
-
+ BOOL all_current_opens_are_level_II = False;
fsp->open = False;
fsp->fd_ptr = 0;
@@ -893,6 +898,8 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
{
broke_oplock = False;
+ all_current_opens_are_level_II = True;
+
for(i = 0; i < num_share_modes; i++)
{
share_mode_entry *share_entry = &old_shares[i];
@@ -904,7 +911,8 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
* Check if someone has an oplock on this file. If so we must break
* it before continuing.
*/
- if(share_entry->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
+ if((oplock_request && EXLUSIVE_OPLOCK_TYPE(share_entry->op_type)) ||
+ (!oplock_request && (share_entry->op_type != NO_OPLOCK)))
{
DEBUG(5,("open_file_shared: breaking oplock (%x) on file %s, \
@@ -926,7 +934,10 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
}
lock_share_entry(conn, dev, inode, &token);
broke_oplock = True;
+ all_current_opens_are_level_II = False;
break;
+ } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ all_current_opens_are_level_II = False;
}
/* someone else has a share lock on it, check to see
@@ -1023,18 +1034,19 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
{
uint16 port = 0;
- /* JRA. Currently this only services Exlcusive and batch
- oplocks (no other opens on this file). This needs to
- be extended to level II oplocks (multiple reader
- oplocks). */
+ /*
+ * Setup the oplock info in both the shared memory and
+ * file structs.
+ */
- if((oplock_request) && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) &&
- !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp) )
- {
+ if(oplock_request && (num_share_modes == 0) && lp_oplocks(SNUM(conn)) &&
+ !IS_VETO_OPLOCK_PATH(conn,fname) && set_file_oplock(fsp, oplock_request) ) {
port = global_oplock_port;
- }
- else
- {
+ } else if (oplock_request && all_current_opens_are_level_II) {
+ port = global_oplock_port;
+ oplock_request = LEVEL_II_OPLOCK;
+ set_file_oplock(fsp, oplock_request);
+ } else {
port = 0;
oplock_request = 0;
}
@@ -1102,8 +1114,8 @@ int open_file_stat(files_struct *fsp,connection_struct *conn,
fsp->share_mode = 0;
fsp->print_file = False;
fsp->modified = False;
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = False;
fsp->stat_open = True;
fsp->directory_delete_on_close = False;
@@ -1137,7 +1149,7 @@ int open_directory(files_struct *fsp,connection_struct *conn,
}
if (got_stat && (GET_FILE_OPEN_DISPOSITION(smb_ofun) == FILE_EXISTS_FAIL)) {
- errno = EEXIST;
+ errno = EEXIST; /* Setup so correct error is returned to client. */
return -1;
}
@@ -1208,8 +1220,8 @@ int open_directory(files_struct *fsp,connection_struct *conn,
fsp->share_mode = 0;
fsp->print_file = False;
fsp->modified = False;
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = True;
fsp->directory_delete_on_close = False;
fsp->conn = conn;
@@ -1239,7 +1251,7 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
int num_share_modes;
SMB_STRUCT_STAT sbuf;
int token;
- int pid = getpid();
+ pid_t pid = getpid();
SMB_DEV_T dev;
SMB_INO_T inode;
@@ -1276,7 +1288,7 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
* Check if someone has an oplock on this file. If so we must
* break it before continuing.
*/
- if(share_entry->op_type & BATCH_OPLOCK)
+ if(BATCH_OPLOCK_TYPE(share_entry->op_type))
{
/*
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
index e74c3ca431d..c53be859119 100644
--- a/source/smbd/oplock.c
+++ b/source/smbd/oplock.c
@@ -26,13 +26,15 @@ extern int DEBUGLEVEL;
/* Oplock ipc UDP socket. */
static int oplock_sock = -1;
uint16 global_oplock_port = 0;
-#if defined(HAVE_KERNEL_OPLOCKS)
static int oplock_pipe_read = -1;
+
+#if defined(HAVE_KERNEL_OPLOCKS)
static int oplock_pipe_write = -1;
-#endif /* HAVE_KERNEL_OPLOCKS */
+#endif
/* Current number of oplocks we have outstanding. */
-static int32 global_oplocks_open = 0;
+static int32 exclusive_oplocks_open = 0;
+static int32 level_II_oplocks_open = 0;
BOOL global_oplock_break = False;
extern int smb_read_error;
@@ -40,12 +42,12 @@ extern int smb_read_error;
static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local);
/****************************************************************************
- Get the number of current oplocks.
+ Get the number of current exclusive oplocks.
****************************************************************************/
-int32 get_number_of_open_oplocks(void)
+int32 get_number_of_exclusive_open_oplocks(void)
{
- return global_oplocks_open;
+ return exclusive_oplocks_open;
}
/****************************************************************************
@@ -72,8 +74,9 @@ BOOL setup_kernel_oplock_pipe(void)
}
/****************************************************************************
- open the oplock IPC socket communication
+ Open the oplock IPC socket communication.
****************************************************************************/
+
BOOL open_oplock_ipc(void)
{
struct sockaddr_in sock_name;
@@ -136,10 +139,8 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
int selrtn;
int maxfd = oplock_sock;
-#if defined(HAVE_KERNEL_OPLOCKS)
- if(lp_kernel_oplocks())
+ if(lp_kernel_oplocks() && (oplock_pipe_read != -1))
maxfd = MAX(maxfd, oplock_pipe_read);
-#endif /* HAVE_KERNEL_OPLOCKS */
to.tv_sec = timeout / 1000;
to.tv_usec = (timeout % 1000) * 1000;
@@ -221,14 +222,9 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
buffer += OPBRK_CMD_HEADER_LEN;
SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD);
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_DEV_OFFSET,dev);
-#ifdef LARGE_SMB_INO_T
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET,inode & 0xFFFFFFFF);
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET+4, (inode >> 32 ) & 0xFFFFFFFF );
-#else /* LARGE_SMB_INO_T */
- SIVAL(buffer,KERNEL_OPLOCK_BREAK_INODE_OFFSET,inode);
-#endif /* LARGE_SMB_INO_T */
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev));
+ memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));
return True;
}
@@ -274,11 +270,11 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
}
/****************************************************************************
- Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
- disabled (just sets flags). Returns True if oplock set.
+ Attempt to set an kernel oplock on a file. Always returns True if kernel
+ oplocks not available.
****************************************************************************/
-BOOL set_file_oplock(files_struct *fsp)
+static BOOL set_kernel_oplock(files_struct *fsp, int oplock_type)
{
#if defined(HAVE_KERNEL_OPLOCKS)
if(lp_kernel_oplocks()) {
@@ -302,24 +298,38 @@ inode = %.0f. Another process had the file open.\n",
}
#endif /* HAVE_KERNEL_OPLOCKS */
+ return True;
+}
+
+/****************************************************************************
+ Attempt to set an oplock on a file. Always succeeds if kernel oplocks are
+ disabled (just sets flags). Returns True if oplock set.
+****************************************************************************/
+
+BOOL set_file_oplock(files_struct *fsp, int oplock_type)
+{
+ if (!set_kernel_oplock(fsp, oplock_type))
+ return False;
+
+ fsp->oplock_type = oplock_type;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+ if ( oplock_type == LEVEL_II_OPLOCK)
+ level_II_oplocks_open++;
+ else
+ exclusive_oplocks_open++;
DEBUG(5,("set_file_oplock: granted oplock on file %s, dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev, (double)fsp->fd_ptr->inode,
(int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec ));
- fsp->granted_oplock = True;
- fsp->sent_oplock_break = False;
- global_oplocks_open++;
-
return True;
}
/****************************************************************************
- Attempt to release an oplock on a file. Always succeeds if kernel oplocks are
- disabled (just clears flags).
+ Release a kernel oplock on a file.
****************************************************************************/
-void release_file_oplock(files_struct *fsp)
+static void release_kernel_oplock(files_struct *fsp)
{
#if defined(HAVE_KERNEL_OPLOCKS)
@@ -338,7 +348,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
}
/*
- * Remote the kernel oplock on this file.
+ * Remove the kernel oplock on this file.
*/
if(fcntl(fsp->fd_ptr->fd, F_OPLKACK, OP_REVOKE) < 0)
@@ -353,10 +363,37 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->fd_ptr->dev,
}
}
#endif /* HAVE_KERNEL_OPLOCKS */
+}
+
+
+/****************************************************************************
+ Attempt to release an oplock on a file. Decrements oplock count.
+****************************************************************************/
- fsp->granted_oplock = False;
- fsp->sent_oplock_break = False;
- global_oplocks_open--;
+void release_file_oplock(files_struct *fsp)
+{
+ release_kernel_oplock(fsp);
+
+ if (fsp->oplock_type == LEVEL_II_OPLOCK)
+ level_II_oplocks_open--;
+ else
+ exclusive_oplocks_open--;
+
+ fsp->oplock_type = NO_OPLOCK;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
+}
+
+/****************************************************************************
+ Attempt to downgrade an oplock on a file. Doesn't decrement oplock count.
+****************************************************************************/
+
+void downgrade_file_oplock(files_struct *fsp)
+{
+ release_kernel_oplock(fsp);
+ fsp->oplock_type = LEVEL_II_OPLOCK;
+ exclusive_oplocks_open--;
+ level_II_oplocks_open++;
+ fsp->sent_oplock_break = NO_BREAK_SENT;
}
/****************************************************************************
@@ -374,12 +411,10 @@ int setup_oplock_select_set( fd_set *fds)
FD_SET(oplock_sock,fds);
-#if defined(HAVE_KERNEL_OPLOCKS)
- if(lp_kernel_oplocks()) {
+ if(lp_kernel_oplocks() && (oplock_pipe_read != -1)) {
FD_SET(oplock_pipe_read,fds);
maxfd = MAX(maxfd,oplock_pipe_read);
}
-#endif /* HAVE_KERNEL_OPLOCKS */
return maxfd;
}
@@ -396,9 +431,10 @@ BOOL process_local_message(char *buffer, int buf_size)
char *msg_start;
SMB_DEV_T dev;
SMB_INO_T inode;
- uint32 remotepid;
+ pid_t remotepid;
struct timeval tval;
struct timeval *ptval = NULL;
+ uint16 break_cmd_type;
msg_len = IVAL(buffer,OPBRK_CMD_LEN_OFFSET);
from_port = SVAL(buffer,OPBRK_CMD_PORT_OFFSET);
@@ -412,7 +448,9 @@ BOOL process_local_message(char *buffer, int buf_size)
* Pull the info out of the requesting packet.
*/
- switch(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET))
+ break_cmd_type = SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET);
+
+ switch(break_cmd_type)
{
#if defined(HAVE_KERNEL_OPLOCKS)
case KERNEL_OPLOCK_BREAK_CMD:
@@ -424,18 +462,8 @@ should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
return False;
}
{
- /*
- * Warning - beware of SMB_INO_T <> 4 bytes. !!
- */
-#ifdef LARGE_SMB_INO_T
- SMB_INO_T inode_low = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET);
- SMB_INO_T inode_high = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET + 4);
- inode = inode_low | (inode_high << 32);
-#else /* LARGE_SMB_INO_T */
- inode = IVAL(msg_start, KERNEL_OPLOCK_BREAK_INODE_OFFSET);
-#endif /* LARGE_SMB_INO_T */
-
- dev = IVAL(msg_start,KERNEL_OPLOCK_BREAK_DEV_OFFSET);
+ memcpy((char *)&inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(inode));
+ memcpy((char *)&dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(dev));
ptval = NULL;
@@ -446,36 +474,34 @@ file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
#endif /* HAVE_KERNEL_OPLOCKS */
case OPLOCK_BREAK_CMD:
+ case LEVEL_II_OPLOCK_BREAK_CMD:
+
/* Ensure that the msg length is correct. */
if(msg_len != OPLOCK_BREAK_MSG_LEN)
{
- DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, \
-should be %d).\n", (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
+ DEBUG(0,("process_local_message: incorrect length for OPLOCK_BREAK_CMD (was %d, should be %d).\n",
+ (int)msg_len, (int)OPLOCK_BREAK_MSG_LEN));
return False;
}
{
- /*
- * Warning - beware of SMB_INO_T <> 4 bytes. !!
- */
-#ifdef LARGE_SMB_INO_T
- SMB_INO_T inode_low = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
- SMB_INO_T inode_high = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET + 4);
- inode = inode_low | (inode_high << 32);
-#else /* LARGE_SMB_INO_T */
- inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
-#endif /* LARGE_SMB_INO_T */
-
- dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+ long usec;
+ time_t sec;
- tval.tv_sec = (time_t)IVAL(msg_start, OPLOCK_BREAK_SEC_OFFSET);
- tval.tv_usec = (long)IVAL(msg_start, OPLOCK_BREAK_USEC_OFFSET);
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&sec, msg_start+OPLOCK_BREAK_SEC_OFFSET,sizeof(sec));
+ tval.tv_sec = sec;
+ memcpy((char *)&usec, msg_start+OPLOCK_BREAK_USEC_OFFSET, sizeof(usec));
+ tval.tv_usec = usec;
ptval = &tval;
- remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
- DEBUG(5,("process_local_message: oplock break request from \
-pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)dev, (double)inode));
+ DEBUG(5,("process_local_message: (%s) oplock break request from \
+pid %d, port %d, dev = %x, inode = %.0f\n",
+ (break_cmd_type == OPLOCK_BREAK_CMD) ? "exclusive" : "level II",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode));
}
break;
@@ -494,22 +520,12 @@ reply - dumping info.\n"));
}
{
- /*
- * Warning - beware of SMB_INO_T <> 4 bytes. !!
- */
-#ifdef LARGE_SMB_INO_T
- SMB_INO_T inode_low = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
- SMB_INO_T inode_high = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET + 4);
- inode = inode_low | (inode_high << 32);
-#else /* LARGE_SMB_INO_T */
- inode = IVAL(msg_start, OPLOCK_BREAK_INODE_OFFSET);
-#endif /* LARGE_SMB_INO_T */
-
- remotepid = IVAL(msg_start,OPLOCK_BREAK_PID_OFFSET);
- dev = IVAL(msg_start,OPLOCK_BREAK_DEV_OFFSET);
+ memcpy((char *)&inode, msg_start+OPLOCK_BREAK_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&remotepid, msg_start+OPLOCK_BREAK_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&dev, msg_start+OPLOCK_BREAK_DEV_OFFSET,sizeof(dev));
DEBUG(0,("process_local_message: unsolicited oplock break reply from \
-pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)dev, (double)inode));
+pid %d, port %d, dev = %x, inode = %.0f\n", (int)remotepid, from_port, (unsigned int)dev, (double)inode));
}
return False;
@@ -524,9 +540,9 @@ pid %d, port %d, dev = %x, inode = %.0f\n", remotepid, from_port, (unsigned int)
* Now actually process the break request.
*/
- if(global_oplocks_open != 0)
+ if((exclusive_oplocks_open + level_II_oplocks_open) != 0)
{
- if(oplock_break(dev, inode, ptval, False) == False)
+ if (oplock_break(dev, inode, ptval, False) == False)
{
DEBUG(0,("process_local_message: oplock break failed.\n"));
return False;
@@ -545,7 +561,7 @@ oplocks. Returning success.\n"));
}
/*
- * Do the appropriate reply - none in the kernel case.
+ * Do the appropriate reply - none in the kernel or level II case.
*/
if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD)
@@ -564,13 +580,13 @@ oplocks. Returning success.\n"));
(struct sockaddr *)&toaddr, sizeof(toaddr)) < 0)
{
DEBUG(0,("process_local_message: sendto process %d failed. Errno was %s\n",
- remotepid, strerror(errno)));
+ (int)remotepid, strerror(errno)));
return False;
}
DEBUG(5,("process_local_message: oplock break reply sent to \
pid %d, port %d, for file dev = %x, inode = %.0f\n",
- remotepid, from_port, (unsigned int)dev, (double)inode));
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode));
}
return True;
@@ -597,31 +613,44 @@ static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2)
}
/****************************************************************************
- Process an oplock break directly.
+ Function to do the waiting before sending a local break.
****************************************************************************/
-static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local_request)
+static void wait_before_sending_break(BOOL local_request)
{
- extern struct current_user current_user;
extern struct timeval smb_last_time;
- extern int Client;
- char *inbuf = NULL;
- char *outbuf = NULL;
+
+ if(local_request) {
+ struct timeval cur_tv;
+ long wait_left = (long)lp_oplock_break_wait_time();
+
+ GetTimeOfDay(&cur_tv);
+
+ wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) +
+ ((cur_tv.tv_usec - smb_last_time.tv_usec)/1000);
+
+ if(wait_left > 0) {
+ wait_left = MIN(wait_left, 1000);
+ sys_usleep(wait_left * 1000);
+ }
+ }
+}
+
+/****************************************************************************
+ Ensure that we have a valid oplock.
+****************************************************************************/
+
+static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)
+{
files_struct *fsp = NULL;
- time_t start_time;
- BOOL shutdown_server = False;
- connection_struct *saved_conn;
- int saved_vuid;
- pstring saved_dir;
- int break_counter = OPLOCK_BREAK_RESENDS;
- int timeout = (OPLOCK_BREAK_TIMEOUT/OPLOCK_BREAK_RESENDS) * 1000;
if( DEBUGLVL( 3 ) )
{
- dbgtext( "oplock_break: called for dev = %x, inode = %.0f tv_sec = %x, tv_usec = %x.\n",
- (unsigned int)dev, (double)inode, tval ? (int)tval->tv_sec : 0,
+ dbgtext( "initial_break_processing: called for dev = %x, inode = %.0f tv_sec = %x, tv_usec = %x.\n",
+ (unsigned int)dev, (double)inode, tval ? (int)tval->tv_sec : 0,
tval ? (int)tval->tv_usec : 0);
- dbgtext( "Current global_oplocks_open = %d\n", global_oplocks_open );
+ dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n",
+ exclusive_oplocks_open, level_II_oplocks_open );
}
/* We need to search the file open table for the
@@ -634,11 +663,11 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
/* The file could have been closed in the meantime - return success. */
if( DEBUGLVL( 0 ) )
{
- dbgtext( "oplock_break: cannot find open file with " );
+ dbgtext( "initial_break_processing: cannot find open file with " );
dbgtext( "dev = %x, inode = %.0f ", (unsigned int)dev, (double)inode);
dbgtext( "allowing break to succeed.\n" );
}
- return True;
+ return NULL;
}
/* Ensure we have an oplock on the file */
@@ -650,18 +679,128 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
as we may have just freed it.
*/
- if(!fsp->granted_oplock)
+ if(fsp->oplock_type == NO_OPLOCK)
{
if( DEBUGLVL( 0 ) )
{
- dbgtext( "oplock_break: file %s ", fsp->fsp_name );
+ dbgtext( "initial_break_processing: file %s ", fsp->fsp_name );
dbgtext( "(dev = %x, inode = %.0f) has no oplock.\n", (unsigned int)dev, (double)inode );
dbgtext( "Allowing break to succeed regardless.\n" );
}
- return True;
+ return NULL;
+ }
+
+ return fsp;
+}
+
+/****************************************************************************
+ Process a level II oplock break directly.
+****************************************************************************/
+
+BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
+{
+ extern int Client;
+ extern uint32 global_client_caps;
+ char outbuf[128];
+ BOOL got_lock = False;
+ SMB_DEV_T dev = fsp->fd_ptr->dev;
+ SMB_INO_T inode = fsp->fd_ptr->inode;
+
+ /*
+ * We can have a level II oplock even if the client is not
+ * level II oplock aware. In this case just remove the
+ * flags and don't send the break-to-none message to
+ * the client.
+ */
+
+ if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
+ /*
+ * If we are sending an oplock break due to an SMB sent
+ * by our own client we ensure that we wait at leat
+ * lp_oplock_break_wait_time() milliseconds before sending
+ * the packet. Sending the packet sooner can break Win9x
+ * and has reported to cause problems on NT. JRA.
+ */
+
+ wait_before_sending_break(local_request);
+
+ /* Prepare the SMBlockingX message. */
+
+ prepare_break_message( outbuf, fsp, False);
+ send_smb(Client, outbuf);
+ }
+
+ /*
+ * Now we must update the shared memory structure to tell
+ * everyone else we no longer have a level II oplock on
+ * this open file. If local_request is true then token is
+ * the existing lock on the shared memory area.
+ */
+
+ if(!local_request && lock_share_entry(fsp->conn, dev, inode, &token) == False) {
+ DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
+ } else {
+ got_lock = True;
+ }
+
+ if(remove_share_oplock(token, fsp)==False) {
+ DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
+ }
+
+ if (got_lock)
+ unlock_share_entry(fsp->conn, dev, inode, token);
+
+ fsp->oplock_type = NO_OPLOCK;
+ level_II_oplocks_open--;
+
+ if(level_II_oplocks_open < 0)
+ {
+ DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n",
+ level_II_oplocks_open));
+ abort();
+ }
+
+ if( DEBUGLVL( 3 ) )
+ {
+ dbgtext( "oplock_break_level2: returning success for " );
+ dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
+ dbgtext( "Current level II oplocks_open = %d\n", level_II_oplocks_open );
}
- /* mark the oplock break as sent - we don't want to send twice! */
+ return True;
+}
+
+/****************************************************************************
+ Process an oplock break directly.
+****************************************************************************/
+
+static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local_request)
+{
+ extern uint32 global_client_caps;
+ extern struct current_user current_user;
+ extern int Client;
+ char *inbuf = NULL;
+ char *outbuf = NULL;
+ files_struct *fsp = NULL;
+ time_t start_time;
+ BOOL shutdown_server = False;
+ connection_struct *saved_conn;
+ int saved_vuid;
+ pstring saved_dir;
+ int break_counter = OPLOCK_BREAK_RESENDS;
+ int timeout = (OPLOCK_BREAK_TIMEOUT/OPLOCK_BREAK_RESENDS) * 1000;
+
+ if((fsp = initial_break_processing(dev, inode, tval)) == NULL)
+ return True;
+
+ /*
+ * Deal with a level II oplock going break to none separately.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
+ return oplock_break_level2(fsp, local_request, -1);
+
+ /* Mark the oplock break as sent - we don't want to send twice! */
if (fsp->sent_oplock_break)
{
if( DEBUGLVL( 0 ) )
@@ -713,29 +852,22 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
* and has reported to cause problems on NT. JRA.
*/
- if(local_request) {
- struct timeval cur_tv;
- long wait_left = (long)lp_oplock_break_wait_time();
+ wait_before_sending_break(local_request);
- GetTimeOfDay(&cur_tv);
-
- wait_left -= ((cur_tv.tv_sec - smb_last_time.tv_sec)*1000) +
- ((cur_tv.tv_usec - smb_last_time.tv_usec)/1000);
+ /* Prepare the SMBlockingX message. */
- if(wait_left > 0) {
- wait_left = MIN(wait_left, 1000);
- sys_usleep(wait_left * 1000);
- }
+ if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && !lp_kernel_oplocks() && lp_level2_oplocks(SNUM(fsp->conn))) {
+ prepare_break_message( outbuf, fsp, True);
+ /* Remember we just sent a break to level II on this file. */
+ fsp->sent_oplock_break = LEVEL_II_BREAK_SENT;
+ } else {
+ prepare_break_message( outbuf, fsp, False);
+ /* Remember we just sent a break to none on this file. */
+ fsp->sent_oplock_break = EXCLUSIVE_BREAK_SENT;
}
- /* Prepare the SMBlockingX message. */
-
- prepare_break_message( outbuf, fsp, False);
send_smb(Client, outbuf);
- /* Remember we just sent an oplock break on this file. */
- fsp->sent_oplock_break = True;
-
/* We need this in case a readraw crosses on the wire. */
global_oplock_break = True;
@@ -757,7 +889,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
/* Save the chain fnum. */
file_chain_save();
- while(OPEN_FSP(fsp) && fsp->granted_oplock)
+ while(OPEN_FSP(fsp) && EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
{
if(receive_smb(Client,inbuf, timeout) == False)
{
@@ -814,12 +946,12 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
if((time(NULL) - start_time) > OPLOCK_BREAK_TIMEOUT)
{
if( DEBUGLVL( 0 ) )
- {
+ {
dbgtext( "oplock_break: no break received from client " );
dbgtext( "within %d seconds.\n", OPLOCK_BREAK_TIMEOUT );
dbgtext( "oplock_break failed for file %s ", fsp->fsp_name );
dbgtext( "(dev = %x, inode = %.0f).\n", (unsigned int)dev, (double)inode );
- }
+ }
shutdown_server = True;
break;
}
@@ -865,11 +997,11 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
}
/* Santity check - remove this later. JRA */
- if(global_oplocks_open < 0)
+ if(exclusive_oplocks_open < 0)
{
- DEBUG(0,("oplock_break: global_oplocks_open < 0 (%d). PANIC ERROR\n",
- global_oplocks_open));
- exit_server("oplock_break: global_oplocks_open < 0");
+ DEBUG(0,("oplock_break: exclusive_oplocks_open < 0 (%d). PANIC ERROR\n",
+ exclusive_oplocks_open));
+ abort();
}
@@ -877,7 +1009,7 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B
{
dbgtext( "oplock_break: returning success for " );
dbgtext( "dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
- dbgtext( "Current global_oplocks_open = %d\n", global_oplocks_open );
+ dbgtext( "Current exclusive_oplocks_open = %d\n", exclusive_oplocks_open );
}
return True;
@@ -893,9 +1025,11 @@ BOOL request_oplock_break(share_mode_entry *share_entry,
{
char op_break_msg[OPLOCK_BREAK_MSG_LEN];
struct sockaddr_in addr_out;
- int pid = getpid();
+ pid_t pid = getpid();
time_t start_time;
int time_left;
+ long usec;
+ time_t sec;
if(pid == share_entry->pid)
{
@@ -903,7 +1037,7 @@ BOOL request_oplock_break(share_mode_entry *share_entry,
if(share_entry->op_port != global_oplock_port)
{
DEBUG(0,("request_oplock_break: corrupt share mode entry - pid = %d, port = %d \
-should be %d\n", pid, share_entry->op_port, global_oplock_port));
+should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));
return False;
}
@@ -916,20 +1050,18 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
/* We need to send a OPLOCK_BREAK_CMD message to the
port in the share mode entry. */
- SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
- SIVAL(op_break_msg,OPLOCK_BREAK_PID_OFFSET,pid);
- SIVAL(op_break_msg,OPLOCK_BREAK_SEC_OFFSET,(uint32)share_entry->time.tv_sec);
- SIVAL(op_break_msg,OPLOCK_BREAK_USEC_OFFSET,(uint32)share_entry->time.tv_usec);
- SIVAL(op_break_msg,OPLOCK_BREAK_DEV_OFFSET,dev);
- /*
- * WARNING - beware of SMB_INO_T <> 4 bytes.
- */
-#ifdef LARGE_SMB_INO_T
- SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,(inode & 0xFFFFFFFFL));
- SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET+4,((inode >> 32) & 0xFFFFFFFFL));
-#else /* LARGE_SMB_INO_T */
- SIVAL(op_break_msg,OPLOCK_BREAK_INODE_OFFSET,inode);
-#endif /* LARGE_SMB_INO_T */
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD);
+ } else {
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD);
+ }
+ memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
+ sec = (time_t)share_entry->time.tv_sec;
+ memcpy(op_break_msg+OPLOCK_BREAK_SEC_OFFSET,(char *)&sec,sizeof(sec));
+ usec = (long)share_entry->time.tv_usec;
+ memcpy(op_break_msg+OPLOCK_BREAK_USEC_OFFSET,(char *)&usec,sizeof(usec));
+ memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
+ memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
/* set the address and port */
memset((char *)&addr_out,'\0',sizeof(addr_out));
@@ -940,7 +1072,7 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 3 ) )
{
dbgtext( "request_oplock_break: sending a oplock break message to " );
- dbgtext( "pid %d on port %d ", share_entry->pid, share_entry->op_port );
+ dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
(unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
(int)share_entry->time.tv_usec );
@@ -953,7 +1085,7 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 0 ) )
{
dbgtext( "request_oplock_break: failed when sending a oplock " );
- dbgtext( "break message to pid %d ", share_entry->pid );
+ dbgtext( "break message to pid %d ", (int)share_entry->pid );
dbgtext( "on port %d ", share_entry->op_port );
dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
(unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
@@ -964,6 +1096,16 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
}
/*
+ * If we just sent a message to a level II oplock share entry then
+ * we are done and may return.
+ */
+
+ if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
+ DEBUG(3,("request_oplock_break: sent break message to level II entry.\n"));
+ return True;
+ }
+
+ /*
* Now we must await the oplock broken message coming back
* from the target smbd process. Timeout if it fails to
* return in (OPLOCK_BREAK_TIMEOUT + OPLOCK_BREAK_TIMEOUT_FUDGEFACTOR) seconds.
@@ -983,10 +1125,8 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
FD_ZERO(&fds);
FD_SET(oplock_sock,&fds);
-#if defined(HAVE_KERNEL_OPLOCKS)
- if(lp_kernel_oplocks())
+ if(lp_kernel_oplocks() && (oplock_pipe_read != -1))
FD_SET(oplock_pipe_read,&fds);
-#endif /* HAVE_KERNEL_OPLOCKS */
if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),
time_left ? time_left * 1000 : 1) == False)
@@ -996,7 +1136,7 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 0 ) )
{
dbgtext( "request_oplock_break: no response received to oplock " );
- dbgtext( "break request to pid %d ", share_entry->pid );
+ dbgtext( "break request to pid %d ", (int)share_entry->pid );
dbgtext( "on port %d ", share_entry->op_port );
dbgtext( "for dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode );
dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
@@ -1017,7 +1157,7 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
if( DEBUGLVL( 0 ) )
{
dbgtext( "request_oplock_break: error in response received " );
- dbgtext( "to oplock break request to pid %d ", share_entry->pid );
+ dbgtext( "to oplock break request to pid %d ", (int)share_entry->pid );
dbgtext( "on port %d ", share_entry->op_port );
dbgtext( "for dev = %x, inode = %.0f, tv_sec = %x, tv_usec = %x\n",
(unsigned int)dev, (double)inode, (int)share_entry->time.tv_sec,
@@ -1095,12 +1235,13 @@ should be %d\n", pid, share_entry->op_port, global_oplock_port));
Used as a last ditch attempt to free a space in the
file table when we have run out.
****************************************************************************/
+
BOOL attempt_close_oplocked_file(files_struct *fsp)
{
DEBUG(5,("attempt_close_oplocked_file: checking file %s.\n", fsp->fsp_name));
- if (fsp->open && fsp->granted_oplock && !fsp->sent_oplock_break && (fsp->fd_ptr != NULL)) {
+ if (fsp->open && EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !fsp->sent_oplock_break && (fsp->fd_ptr != NULL)) {
/* Try and break the oplock. */
file_fd_struct *fd_ptr = fsp->fd_ptr;
diff --git a/source/smbd/password.c b/source/smbd/password.c
index 0b69963b19b..b8ed62af833 100644
--- a/source/smbd/password.c
+++ b/source/smbd/password.c
@@ -276,7 +276,7 @@ uint16 register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
DEBUG(3, ("Clearing default real name\n"));
fstrcpy(vuser->real_name, "<Full Name>\0");
if (lp_unix_realname()) {
- if ((pwfile=getpwnam(vuser->name))!= NULL)
+ if ((pwfile=sys_getpwnam(vuser->name))!= NULL)
{
DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->name,pwfile->pw_gecos));
fstrcpy(vuser->real_name, pwfile->pw_gecos);
@@ -568,8 +568,8 @@ BOOL user_ok(char *user,int snum)
pstring valid, invalid;
BOOL ret;
- StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
- StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
+ StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)-1);
+ StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)-1);
string_sub(valid,"%S",lp_servicename(snum));
string_sub(invalid,"%S",lp_servicename(snum));
diff --git a/source/smbd/process.c b/source/smbd/process.c
index 497d99d8530..9b088cb9df3 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -244,12 +244,12 @@ void respond_to_all_remaining_local_messages(void)
fd_set fds;
/*
- * Assert we have no open oplocks.
+ * Assert we have no exclusive open oplocks.
*/
- if(get_number_of_open_oplocks()) {
- DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d oplocks.\n",
- get_number_of_open_oplocks() ));
+ if(get_number_of_exclusive_open_oplocks()) {
+ DEBUG(0,("respond_to_all_remaining_local_messages: PANIC : we have %d exclusive oplocks.\n",
+ get_number_of_exclusive_open_oplocks() ));
return;
}
@@ -414,14 +414,14 @@ do a switch on the message type, and return the response size
****************************************************************************/
static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize)
{
- static int pid= -1;
+ static pid_t pid= (pid_t)-1;
int outsize = 0;
static int num_smb_messages =
sizeof(smb_messages) / sizeof(struct smb_message_struct);
int match;
extern int Client;
- if (pid == -1)
+ if (pid == (pid_t)-1)
pid = getpid();
errno = 0;
@@ -445,7 +445,7 @@ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize
}
else
{
- DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,pid));
+ DEBUG(3,("switch message %s (pid %d)\n",smb_messages[match].name,(int)pid));
if(global_oplock_break)
{
@@ -787,6 +787,29 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
}
/****************************************************************************
+ Setup the needed select timeout.
+****************************************************************************/
+
+static int setup_select_timeout(void)
+{
+ int change_notify_timeout = lp_change_notify_timeout() * 1000;
+ int select_timeout;
+
+ /*
+ * Increase the select timeout back to SMBD_SELECT_TIMEOUT if we
+ * have removed any blocking locks. JRA.
+ */
+
+ select_timeout = blocking_locks_pending() ? SMBD_SELECT_TIMEOUT_WITH_PENDING_LOCKS*1000 :
+ SMBD_SELECT_TIMEOUT*1000;
+
+ if (change_notifies_pending())
+ select_timeout = MIN(select_timeout, change_notify_timeout);
+
+ return select_timeout;
+}
+
+/****************************************************************************
Process any timeout housekeeping. Return False if the caler should exit.
****************************************************************************/
@@ -942,12 +965,11 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup ));
process_pending_change_notify_queue(t);
/*
- * Increase the select timeout back to SMBD_SELECT_TIMEOUT if we
- * have removed any blocking locks. JRA.
+ * Modify the select timeout depending upon
+ * what we have remaining in our queues.
*/
- *select_timeout = blocking_locks_pending() ? SMBD_SELECT_TIMEOUT_WITH_PENDING_LOCKS*1000 :
- SMBD_SELECT_TIMEOUT*1000;
+ *select_timeout = setup_select_timeout();
return True;
}
@@ -991,7 +1013,7 @@ void smbd_process(void)
{
int deadtime = lp_deadtime()*60;
BOOL got_smb = False;
- int select_timeout = SMBD_SELECT_TIMEOUT*1000;
+ int select_timeout = setup_select_timeout();
if (deadtime <= 0)
deadtime = DEFAULT_SMBD_TIMEOUT;
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 1957243da0f..11054f568ba 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -1504,7 +1504,7 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
return(outsize);
}
@@ -1599,7 +1599,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
smb_action |= EXTENDED_OPLOCK_GRANTED;
}
- if(ex_oplock_request && fsp->granted_oplock) {
+ if(ex_oplock_request && EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
smb_action |= EXTENDED_OPLOCK_GRANTED;
}
@@ -1612,7 +1612,7 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(core_oplock_request && fsp->granted_oplock) {
+ if(core_oplock_request && EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
@@ -1735,7 +1735,7 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
DEBUG( 2, ( "new file %s\n", fname ) );
@@ -1809,7 +1809,7 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
}
- if(fsp->granted_oplock)
+ if(EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
DEBUG( 2, ( "created temp file %s\n", fname2 ) );
@@ -1843,8 +1843,9 @@ static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
}
/****************************************************************************
- reply to a unlink
+ Reply to a unlink
****************************************************************************/
+
int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
{
int outsize = 0;
@@ -1858,6 +1859,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
BOOL has_wild;
BOOL exists=False;
BOOL bad_path = False;
+ BOOL rc = True;
*directory = *mask = 0;
@@ -1867,7 +1869,7 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
DEBUG(3,("reply_unlink : %s\n",name));
- unix_convert(name,conn,0,&bad_path,NULL);
+ rc = unix_convert(name,conn,0,&bad_path,NULL);
p = strrchr(name,'/');
if (!p) {
@@ -1879,7 +1881,16 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
@@ -2306,13 +2317,8 @@ int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size,
if (is_locked(fsp,conn,tcount,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if (seek_file(fsp,startpos) == -1) {
- DEBUG(0,("couldn't seek to %.0f in writebraw\n",(double)startpos));
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
-
if (numtowrite>0)
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
@@ -2397,16 +2403,13 @@ int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int siz
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
/* The special X/Open SMB protocol handling of
zero length writes is *NOT* done for
this call */
if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
if (lp_syncalways(SNUM(conn)))
sync_file(conn,fsp);
@@ -2450,16 +2453,13 @@ int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int d
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
/* X/Open SMB protocol says that if smb_vwv1 is
zero then the file size should be extended or
truncated to the size given in smb_vwv[2-3] */
if(numtowrite == 0)
nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos);
else
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
if (lp_syncalways(SNUM(conn)))
sync_file(conn,fsp);
@@ -2531,9 +2531,6 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done, just a write of zero. To truncate a file,
@@ -2541,7 +2538,7 @@ int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int leng
if(numtowrite == 0)
nwritten = 0;
else
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
return(UNIXERROR(ERRDOS,ERRnoaccess));
@@ -2785,11 +2782,8 @@ int reply_writeclose(connection_struct *conn,
if (is_locked(fsp,conn,numtowrite,startpos, F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
-
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- nwritten = write_file(fsp,data,numtowrite);
+
+ nwritten = write_file(fsp,data,startpos,numtowrite);
set_filetime(conn, fsp->fsp_name,mtime);
@@ -3123,7 +3117,7 @@ int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_
numtowrite = SVAL(smb_buf(inbuf),1);
data = smb_buf(inbuf) + 3;
- if (write_file(fsp,data,numtowrite) != numtowrite)
+ if (write_file(fsp,data,-1,numtowrite) != numtowrite)
return(UNIXERROR(ERRDOS,ERRnoaccess));
DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
@@ -3449,10 +3443,11 @@ int rename_internals(connection_struct *conn,
int count=0;
int error = ERRnoaccess;
BOOL exists=False;
+ BOOL rc = True;
*directory = *mask = 0;
- unix_convert(name,conn,0,&bad_path1,NULL);
+ rc = unix_convert(name,conn,0,&bad_path1,NULL);
unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
/*
@@ -3475,7 +3470,16 @@ int rename_internals(connection_struct *conn,
*p = '/'; /* Replace needed for exceptional test below. */
}
- if (is_mangled(mask))
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
@@ -3760,6 +3764,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
BOOL target_is_directory=False;
BOOL bad_path1 = False;
BOOL bad_path2 = False;
+ BOOL rc = True;
*directory = *mask = 0;
@@ -3774,7 +3779,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
return(ERROR(ERRSRV,ERRinvdevice));
}
- unix_convert(name,conn,0,&bad_path1,NULL);
+ rc = unix_convert(name,conn,0,&bad_path1,NULL);
unix_convert(newname,conn,0,&bad_path2,NULL);
target_is_directory = dos_directory_exist(newname,NULL);
@@ -3803,7 +3808,16 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
pstrcpy(mask,p+1);
}
- if (is_mangled(mask))
+ /*
+ * We should only check the mangled cache
+ * here if unix_convert failed. This means
+ * that the path in 'mask' doesn't exist
+ * on the file system and so we need to look
+ * for a possible mangle. This patch from
+ * Tine Smukavec <valentin.smukavec@hermes.si>.
+ */
+
+ if (!rc && is_mangled(mask))
check_mangled_cache( mask );
has_wild = strchr(mask,'*') || strchr(mask,'?');
@@ -3844,7 +3858,7 @@ int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
pstrcpy(destname,newname);
if (resolve_wildcards(fname,destname) &&
- copy_file(directory,newname,conn,ofun,
+ copy_file(fname,destname,conn,ofun,
count,target_is_directory,&err)) count++;
DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
}
@@ -3935,6 +3949,7 @@ SMB_OFF_T get_lock_count( char *data, int data_offset, BOOL large_file_format, B
((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
#else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
/*
* NT4.x seems to be broken in that it sends large file
* lockingX calls even if the CAP_LARGE_FILES was *not*
@@ -4031,6 +4046,7 @@ SMB_OFF_T get_lock_offset( char *data, int data_offset, BOOL large_file_format,
((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
#else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
+
/*
* NT4.x seems to be broken in that it sends large file
* lockingX calls even if the CAP_LARGE_FILES was *not*
@@ -4125,9 +4141,9 @@ int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,
DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
fsp->fnum));
/*
- * Make sure we have granted an oplock on this file.
+ * Make sure we have granted an exclusive or batch oplock on this file.
*/
- if(!fsp->granted_oplock)
+ if(!EXLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
{
DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
no oplock granted on this file.\n", fsp->fnum));
@@ -4140,13 +4156,38 @@ no oplock granted on this file.\n", fsp->fnum));
}
/* Remove the oplock flag from the sharemode. */
- lock_share_entry(fsp->conn, dev, inode, &token);
- if(remove_share_oplock(token, fsp)==False) {
- DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
-dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode));
+ if (lock_share_entry(fsp->conn, dev, inode, &token) == False) {
+ DEBUG(0,("reply_lockingX: failed to lock share entry for file %s\n",
+ fsp->fsp_name ));
+ }
+
+ if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) {
+
+ /*
+ * Deal with a reply when a break-to-none was sent.
+ */
+
+ if(remove_share_oplock(token, fsp)==False) {
+ DEBUG(0,("reply_lockingX: failed to remove share oplock for file %s fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
+ }
+
+ release_file_oplock(fsp);
+
+ } else {
+
+ /*
+ * Deal with a reply when a break-to-level II was sent.
+ */
+
+ if(downgrade_share_oplock(token, fsp)==False) {
+ DEBUG(0,("reply_lockingX: failed to downgrade share oplock for file %s fnum %d, \
+dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
+ }
+
+ downgrade_file_oplock(fsp);
}
- release_file_oplock(fsp);
unlock_share_entry(fsp->conn, dev, inode, token);
/* if this is a pure oplock break request then don't send a reply */
@@ -4355,10 +4396,7 @@ int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size,
if (is_locked(fsp,conn,tcount,startpos,F_WRLCK))
return(ERROR(ERRDOS,ERRlock));
- if(seek_file(fsp,startpos) == -1)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
if(lp_syncalways(SNUM(conn)) || write_through)
sync_file(conn,fsp);
@@ -4459,19 +4497,7 @@ int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_siz
if(wbms->wr_discard)
return -1; /* Just discard the packet */
- if(seek_file(fsp,startpos) == -1)
- {
- if(write_through)
- {
- /* We are returning an error - we can delete the aux struct */
- if (wbms) free((char *)wbms);
- fsp->wbmpx_ptr = NULL;
- return(UNIXERROR(ERRDOS,ERRnoaccess));
- }
- return(CACHE_ERROR(wbms,ERRDOS,ERRnoaccess));
- }
-
- nwritten = write_file(fsp,data,numtowrite);
+ nwritten = write_file(fsp,data,startpos,numtowrite);
if(lp_syncalways(SNUM(conn)) || write_through)
sync_file(conn,fsp);
diff --git a/source/smbd/server.c b/source/smbd/server.c
index c9eab1aa378..14fba0cd7a8 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -476,19 +476,21 @@ usage on the program
****************************************************************************/
static void usage(char *pname)
{
- DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
-
- printf("Usage: %s [-D] [-p port] [-d debuglevel] ", pname);
- printf("[-l log basename] [-s services file]\n" );
- printf("Version %s\n",VERSION);
- printf("\t-D become a daemon\n");
- printf("\t-p port listen on the specified port\n");
- printf("\t-d debuglevel set the debuglevel\n");
+
+ printf("Usage: %s [-DaoPh?V] [-d debuglevel] [-l log basename] [-p port]\n", pname);
+ printf(" [-O socket options] [-s services file] [-i scope]\n");
+ printf("\t-D Become a daemon\n");
+ printf("\t-a Append to log file (default)\n");
+ printf("\t-o Overwrite log file, don't append\n");
+ printf("\t-P Passive only\n");
+ printf("\t-h Print usage\n");
+ printf("\t-? Print usage\n");
+ printf("\t-V Print version\n");
+ printf("\t-d debuglevel Set the debuglevel\n");
printf("\t-l log basename. Basename for log/debug files\n");
+ printf("\t-p port Listen on the specified port\n");
+ printf("\t-O socket options Socket options\n");
printf("\t-s services file. Filename of services file\n");
- printf("\t-P passive only\n");
- printf("\t-a append to log file (default)\n");
- printf("\t-o overwrite log file, don't append\n");
printf("\t-i scope NetBIOS scope to use (default none)\n");
printf("\n");
}
@@ -557,7 +559,7 @@ static void usage(char *pname)
argc--;
}
- while ( EOF != (opt = getopt(argc, argv, "O:i:l:s:d:Dp:h?Paof:")) )
+ while ( EOF != (opt = getopt(argc, argv, "O:i:l:s:d:Dp:h?VPaof:")) )
switch (opt) {
case 'O':
pstrcpy(user_socket_options,optarg);
@@ -611,7 +613,12 @@ static void usage(char *pname)
exit(0);
break;
+ case 'V':
+ printf("Version %s\n",VERSION);
+ exit(0);
+ break;
default:
+ DEBUG(0,("Incorrect program usage - are you sure the command line is correct?\n"));
usage(argv[0]);
exit(1);
}
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 0f357a96e05..14059f639f1 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -1828,7 +1828,7 @@ dev = %x, inode = %.0f from %x to %x\n",
iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
(double)inode, iterate_fsp->share_mode, new_share_mode ));
- if(modify_share_mode(token, iterate_fsp, new_share_mode)==False)
+ if(modify_share_mode(token, iterate_fsp, new_share_mode, iterate_fsp->oplock_type)==False)
DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode));
}