summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/include/proto.h1
-rw-r--r--source/libsmb/clientgen.c37
-rw-r--r--source/smbd/reply.c28
-rw-r--r--source/smbd/server.c54
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--;
}