diff options
-rw-r--r-- | source/include/proto.h | 1 | ||||
-rw-r--r-- | source/libsmb/clientgen.c | 37 | ||||
-rw-r--r-- | source/smbd/reply.c | 28 | ||||
-rw-r--r-- | source/smbd/server.c | 54 |
4 files changed, 96 insertions, 24 deletions
diff --git a/source/include/proto.h b/source/include/proto.h index c47b7582f30..7302fb4998e 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -65,6 +65,7 @@ BOOL cli_session_setup(struct cli_state *cli, BOOL cli_send_tconX(struct cli_state *cli, char *share, char *dev, char *pass, int passlen); BOOL cli_tdis(struct cli_state *cli); +BOOL cli_mv(struct cli_state *cli, char *fname_src, char *fname_dst); BOOL cli_unlink(struct cli_state *cli, char *fname); BOOL cli_mkdir(struct cli_state *cli, char *dname); BOOL cli_rmdir(struct cli_state *cli, char *dname); diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c index 1bd55cffe86..69e940845ce 100644 --- a/source/libsmb/clientgen.c +++ b/source/libsmb/clientgen.c @@ -574,6 +574,43 @@ BOOL cli_tdis(struct cli_state *cli) } /**************************************************************************** +rename a file +****************************************************************************/ +BOOL cli_mv(struct cli_state *cli, char *fname_src, char *fname_dst) +{ + char *p; + + bzero(cli->outbuf,smb_size); + bzero(cli->inbuf,smb_size); + + set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True); + + CVAL(cli->outbuf,smb_com) = SMBmv; + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN); + + p = smb_buf(cli->outbuf); + *p++ = 4; + strcpy(p,fname_src); + p = skip_string(p,1); + *p++ = 4; + strcpy(p,fname_dst); + + send_smb(cli->fd,cli->outbuf); + if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) { + return False; + } + + if (CVAL(cli->inbuf,smb_rcls) != 0) { + return False; + } + + return True; +} + +/**************************************************************************** delete a file ****************************************************************************/ BOOL cli_unlink(struct cli_state *cli, char *fname) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index ec94ab0552a..06b96b13d9f 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1257,7 +1257,11 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize) int fnum = -1; int smb_mode = SVAL(inbuf,smb_vwv3); int smb_attr = SVAL(inbuf,smb_vwv5); - BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf); + /* Breakout the oplock request bits so we can set the + reply bits separately. */ + BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf); + BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf); + BOOL oplock_request = ex_oplock_request | core_oplock_request; #if 0 int open_flags = SVAL(inbuf,smb_vwv2); int smb_sattr = SVAL(inbuf,smb_vwv4); @@ -1324,13 +1328,29 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize) return(ERROR(ERRDOS,ERRnoaccess)); } - if (oplock_request && lp_fake_oplocks(SNUM(cnum))) { + /* If the caller set the extended oplock request bit + and we granted one (by whatever means) - set the + correct bit for extended oplock reply. + */ + + if (ex_oplock_request && lp_fake_oplocks(SNUM(cnum))) { smb_action |= EXTENDED_OPLOCK_GRANTED; - CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; } - if(fsp->granted_oplock) { + if(ex_oplock_request && fsp->granted_oplock) { smb_action |= EXTENDED_OPLOCK_GRANTED; + } + + /* If the caller set the core oplock request bit + and we granted one (by whatever means) - set the + correct bit for core oplock reply. + */ + + if (core_oplock_request && lp_fake_oplocks(SNUM(cnum))) { + CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; + } + + if(core_oplock_request && fsp->granted_oplock) { CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED; } diff --git a/source/smbd/server.c b/source/smbd/server.c index 77c8fc319f0..9ca4ab5b781 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -1326,6 +1326,7 @@ static void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct fsp->print_file = Connections[cnum].printer; fsp->modified = False; fsp->granted_oplock = False; + fsp->sent_oplock_break = False; fsp->cnum = cnum; string_set(&fsp->name,dos_to_unix(fname,False)); fsp->wbmpx_ptr = NULL; @@ -1476,6 +1477,8 @@ void close_file(int fnum, BOOL normal_close) if(fs_p->granted_oplock == True) global_oplocks_open--; + fs_p->sent_oplock_break = False; + DEBUG(2,("%s %s closed file %s (numopen=%d)\n", timestring(),Connections[cnum].user,fs_p->name, Connections[cnum].num_files_open)); @@ -2773,22 +2776,6 @@ BOOL oplock_break(uint32 dev, uint32 inode, struct timeval *tval) DEBUG(3,("%s oplock_break: called for dev = %x, inode = %x. Current \ global_oplocks_open = %d\n", timestring(), dev, inode, global_oplocks_open)); - if(inbuf == NULL) - { - inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(inbuf == NULL) { - DEBUG(0,("oplock_break: malloc fail for input buffer.\n")); - return False; - } - outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); - if(outbuf == NULL) { - DEBUG(0,("oplock_break: malloc fail for output buffer.\n")); - free(inbuf); - inbuf = NULL; - return False; - } - } - /* We need to search the file open table for the entry containing this dev and inode, and ensure we have an oplock on it. */ @@ -2831,16 +2818,35 @@ allowing break to succeed.\n", timestring(), dev, inode, fnum)); /* mark the oplock break as sent - we don't want to send twice! */ if (fsp->sent_oplock_break) { - DEBUG(0,("%s ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, inode)); - return True; - } + DEBUG(0,("%s oplock_break: ERROR: oplock_break already sent for file %s (fnum = %d, dev = %x, inode = %x)\n", timestring(), fsp->name, fnum, dev, inode)); - fsp->sent_oplock_break = True; + /* We have to fail the open here as we cannot send another oplock break on this + file whilst we are awaiting a response from the client - neither can we + allow another open to succeed while we are waiting for the client. */ + return False; + } /* Now comes the horrid part. We must send an oplock break to the client, and then process incoming messages until we get a close or oplock release. + At this point we know we need a new inbuf/outbuf buffer pair. + We cannot use these staticaly as we may recurse into here due to + messages crossing on the wire. */ + if((inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL) + { + DEBUG(0,("oplock_break: malloc fail for input buffer.\n")); + return False; + } + + if((outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN))==NULL) + { + DEBUG(0,("oplock_break: malloc fail for output buffer.\n")); + free(inbuf); + inbuf = NULL; + return False; + } + /* Prepare the SMBlockingX message. */ bzero(outbuf,smb_size); set_message(outbuf,8,0,True); @@ -2858,6 +2864,9 @@ allowing break to succeed.\n", timestring(), dev, inode, fnum)); 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; @@ -2909,6 +2918,10 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode)); } } + /* Free the buffers we've been using to recurse. */ + free(inbuf); + free(outbuf); + /* We need this in case a readraw crossed on the wire. */ if(global_oplock_break) global_oplock_break = False; @@ -2932,6 +2945,7 @@ inode = %x).\n", timestring(), fsp->name, fnum, dev, inode)); from the sharemode. */ /* Paranoia.... */ fsp->granted_oplock = False; + fsp->sent_oplock_break = False; global_oplocks_open--; } |