diff options
author | Andrew Tridgell <tridge@samba.org> | 1999-07-14 13:22:05 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1999-07-14 13:22:05 +0000 |
commit | 9b011b6975ca17772afb7a204b6b9bc8b4ed0341 (patch) | |
tree | f16693f359f243491be37e3437a924b1ddf9db9e | |
parent | 2a274a8755210e13da6bbf29d25f834f53275752 (diff) | |
download | samba-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.c | 2 | ||||
-rw-r--r-- | source/smbd/connection.c | 2 | ||||
-rw-r--r-- | source/smbd/dir.c | 12 | ||||
-rw-r--r-- | source/smbd/dosmode.c | 4 | ||||
-rw-r--r-- | source/smbd/fileio.c | 86 | ||||
-rw-r--r-- | source/smbd/files.c | 5 | ||||
-rw-r--r-- | source/smbd/ipc.c | 4 | ||||
-rw-r--r-- | source/smbd/nttrans.c | 128 | ||||
-rw-r--r-- | source/smbd/open.c | 78 | ||||
-rw-r--r-- | source/smbd/oplock.c | 455 | ||||
-rw-r--r-- | source/smbd/password.c | 6 | ||||
-rw-r--r-- | source/smbd/process.c | 46 | ||||
-rw-r--r-- | source/smbd/reply.c | 148 | ||||
-rw-r--r-- | source/smbd/server.c | 31 | ||||
-rw-r--r-- | source/smbd/trans2.c | 2 |
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)); } |