From 6cc3953196e3feb340f7b9b7bb823575414c5683 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Oct 2001 00:56:03 +0000 Subject: Restored old Bmpx code - actually used by OS/2. Jeremy. (This used to be commit 7c1688fd67c1bda1477aaf870371c825280db870) --- source3/include/smb.h | 1 + source3/include/smb_macros.h | 12 ++ source3/smbd/error.c | 16 +++ source3/smbd/process.c | 8 +- source3/smbd/reply.c | 304 +++++++++++++++++++++++++++++++++++-------- 5 files changed, 280 insertions(+), 61 deletions(-) (limited to 'source3') diff --git a/source3/include/smb.h b/source3/include/smb.h index a805407b9f..fba08aed43 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -401,6 +401,7 @@ typedef struct files_struct SMB_OFF_T size; mode_t mode; uint16 vuid; + write_bmpx_struct *wbmpx_ptr; write_cache *wcp; struct timeval open_time; int share_mode; diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index b4264937cf..05a358573d 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -82,6 +82,9 @@ #define CHECK_WRITE(fsp) if (!(fsp)->can_write) \ return(ERROR_DOS(ERRDOS,ERRbadaccess)) +#define CHECK_ERROR(fsp) if (HAS_CACHED_ERROR(fsp)) \ + return(CACHED_ERROR(fsp)) + /* translates a connection number into a service number */ #define SNUM(conn) ((conn)?(conn)->service:-1) @@ -136,6 +139,15 @@ #define SMB_LARGE_LKLEN_OFFSET_HIGH(indx) (12 + (20 * (indx))) #define SMB_LARGE_LKLEN_OFFSET_LOW(indx) (16 + (20 * (indx))) +/* Macro to cache an error in a write_bmpx_struct */ +#define CACHE_ERROR(w,c,e) ((w)->wr_errclass = (c), (w)->wr_error = (e), \ + w->wr_discard = True, -1) +/* Macro to test if an error has been cached for this fnum */ +#define HAS_CACHED_ERROR(fsp) ((fsp)->wbmpx_ptr && \ + (fsp)->wbmpx_ptr->wr_discard) +/* Macro to turn the cached error into an error packet */ +#define CACHED_ERROR(fsp) cached_error_packet(outbuf,fsp,__LINE__,__FILE__) + /* these are the datagram types */ #define DGRAM_DIRECT_UNIQUE 0x10 diff --git a/source3/smbd/error.c b/source3/smbd/error.c index 913f2ac266..3c829deb09 100644 --- a/source3/smbd/error.c +++ b/source3/smbd/error.c @@ -25,6 +25,22 @@ int unix_ERR_class=SMB_SUCCESS; int unix_ERR_code=0; +/**************************************************************************** + Create an error packet from a cached error. +****************************************************************************/ + +int cached_error_packet(char *outbuf,files_struct *fsp,int line,const char *file) +{ + write_bmpx_struct *wbmpx = fsp->wbmpx_ptr; + + int32 eclass = wbmpx->wr_errclass; + int32 err = wbmpx->wr_error; + + /* We can now delete the auxiliary struct */ + free((char *)wbmpx); + fsp->wbmpx_ptr = NULL; + return error_packet(outbuf,NT_STATUS_OK,eclass,err,line,file); +} struct { diff --git a/source3/smbd/process.c b/source3/smbd/process.c index edcb6b345f..a0bfdbb2a2 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -361,11 +361,11 @@ struct smb_message_struct /* 0x19 */ { NULL, NULL, 0 }, /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER}, /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER}, -/* 0x1c */ { "SMBreadBs",NULL,AS_USER}, +/* 0x1c */ { "SMBreadBs",NULL,0 }, /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER}, -/* 0x1e */ { NULL,NULL,0}, -/* 0x1f */ { NULL,NULL,0}, -/* 0x20 */ { NULL,NULL,0}, +/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER}, +/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER}, +/* 0x20 */ { "SMBwritec",NULL,0}, /* 0x21 */ { NULL, NULL, 0 }, /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE }, /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER }, diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 8b6e754549..845fabda92 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3786,84 +3786,83 @@ no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name)); return chain_reply(inbuf,outbuf,length,bufsize); } - /**************************************************************************** - reply to a SMBreadbmpx (read block multiplex) request + Reply to a SMBreadbmpx (read block multiplex) request. ****************************************************************************/ + int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize) { - ssize_t nread = -1; - ssize_t total_read; - char *data; - SMB_OFF_T startpos; - int outsize; - size_t maxcount; - int max_per_packet; - size_t tcount; - int pad; - files_struct *fsp = file_fsp(inbuf,smb_vwv0); - START_PROFILE(SMBreadBmpx); + ssize_t nread = -1; + ssize_t total_read; + char *data; + SMB_OFF_T startpos; + int outsize; + size_t maxcount; + int max_per_packet; + size_t tcount; + int pad; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBreadBmpx); - /* this function doesn't seem to work - disable by default */ - if (!lp_readbmpx()) { - END_PROFILE(SMBreadBmpx); - return ERROR_DOS(ERRSRV,ERRuseSTD); - } + /* this function doesn't seem to work - disable by default */ + if (!lp_readbmpx()) { + END_PROFILE(SMBreadBmpx); + return ERROR_DOS(ERRSRV,ERRuseSTD); + } - outsize = set_message(outbuf,8,0,True); + outsize = set_message(outbuf,8,0,True); - CHECK_FSP(fsp,conn); - CHECK_READ(fsp); + CHECK_FSP(fsp,conn); + CHECK_READ(fsp); - startpos = IVAL(inbuf,smb_vwv1); - maxcount = SVAL(inbuf,smb_vwv3); + startpos = IVAL(inbuf,smb_vwv1); + maxcount = SVAL(inbuf,smb_vwv3); - data = smb_buf(outbuf); - pad = ((long)data)%4; - if (pad) pad = 4 - pad; - data += pad; + data = smb_buf(outbuf); + pad = ((long)data)%4; + if (pad) + pad = 4 - pad; + data += pad; - max_per_packet = bufsize-(outsize+pad); - tcount = maxcount; - total_read = 0; + max_per_packet = bufsize-(outsize+pad); + tcount = maxcount; + total_read = 0; - if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { - END_PROFILE(SMBreadBmpx); - return ERROR_DOS(ERRDOS,ERRlock); - } + if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) { + END_PROFILE(SMBreadBmpx); + return ERROR_DOS(ERRDOS,ERRlock); + } - do - { - size_t N = MIN(max_per_packet,tcount-total_read); + do { + size_t N = MIN(max_per_packet,tcount-total_read); - nread = read_file(fsp,data,startpos,N); + nread = read_file(fsp,data,startpos,N); - if (nread <= 0) nread = 0; + if (nread <= 0) + nread = 0; - if (nread < (ssize_t)N) - tcount = total_read + nread; + if (nread < (ssize_t)N) + tcount = total_read + nread; - set_message(outbuf,8,nread,False); - SIVAL(outbuf,smb_vwv0,startpos); - SSVAL(outbuf,smb_vwv2,tcount); - SSVAL(outbuf,smb_vwv6,nread); - SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf)); + set_message(outbuf,8,nread,False); + SIVAL(outbuf,smb_vwv0,startpos); + SSVAL(outbuf,smb_vwv2,tcount); + SSVAL(outbuf,smb_vwv6,nread); + SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf)); - if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("reply_readbmpx: send_smb failed.\n"); + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("reply_readbmpx: send_smb failed.\n"); - total_read += nread; - startpos += nread; - } - while (total_read < (ssize_t)tcount); + total_read += nread; + startpos += nread; + } while (total_read < (ssize_t)tcount); - END_PROFILE(SMBreadBmpx); - return(-1); + END_PROFILE(SMBreadBmpx); + return(-1); } - /**************************************************************************** - reply to a SMBsetattrE + Reply to a SMBsetattrE. ****************************************************************************/ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) @@ -3919,8 +3918,199 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, } +/* Back from the dead for OS/2..... JRA. */ + +/**************************************************************************** + Reply to a SMBwritebmpx (write block multiplex primary) request. +****************************************************************************/ + +int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) +{ + size_t numtowrite; + ssize_t nwritten = -1; + int outsize = 0; + SMB_OFF_T startpos; + size_t tcount; + BOOL write_through; + int smb_doff; + char *data; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBwriteBmpx); + + CHECK_FSP(fsp,conn); + CHECK_WRITE(fsp); + CHECK_ERROR(fsp); + + tcount = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv3); + write_through = BITSETW(inbuf+smb_vwv7,0); + numtowrite = SVAL(inbuf,smb_vwv10); + smb_doff = SVAL(inbuf,smb_vwv11); + + data = smb_base(inbuf) + smb_doff; + + /* If this fails we need to send an SMBwriteC response, + not an SMBwritebmpx - set this up now so we don't forget */ + CVAL(outbuf,smb_com) = SMBwritec; + + if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) { + END_PROFILE(SMBwriteBmpx); + return(ERROR_DOS(ERRDOS,ERRlock)); + } + + nwritten = write_file(fsp,data,startpos,numtowrite); + + if(lp_syncalways(SNUM(conn)) || write_through) + sync_file(conn,fsp); + + if(nwritten < (ssize_t)numtowrite) { + END_PROFILE(SMBwriteBmpx); + return(UNIXERROR(ERRHRD,ERRdiskfull)); + } + + /* If the maximum to be written to this file + is greater than what we just wrote then set + up a secondary struct to be attached to this + fd, we will use this to cache error messages etc. */ + + if((ssize_t)tcount > nwritten) { + write_bmpx_struct *wbms; + if(fsp->wbmpx_ptr != NULL) + wbms = fsp->wbmpx_ptr; /* Use an existing struct */ + else + wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct)); + if(!wbms) { + DEBUG(0,("Out of memory in reply_readmpx\n")); + END_PROFILE(SMBwriteBmpx); + return(ERROR_DOS(ERRSRV,ERRnoresource)); + } + wbms->wr_mode = write_through; + wbms->wr_discard = False; /* No errors yet */ + wbms->wr_total_written = nwritten; + wbms->wr_errclass = 0; + wbms->wr_error = 0; + fsp->wbmpx_ptr = wbms; + } + + /* We are returning successfully, set the message type back to + SMBwritebmpx */ + CVAL(outbuf,smb_com) = SMBwriteBmpx; + + outsize = set_message(outbuf,1,0,True); + + SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */ + + DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n", + fsp->fnum, (int)numtowrite, (int)nwritten ) ); + + if (write_through && tcount==nwritten) { + /* We need to send both a primary and a secondary response */ + smb_setlen(outbuf,outsize - 4); + if (!send_smb(smbd_server_fd(),outbuf)) + exit_server("reply_writebmpx: send_smb failed.\n"); + + /* Now the secondary */ + outsize = set_message(outbuf,1,0,True); + CVAL(outbuf,smb_com) = SMBwritec; + SSVAL(outbuf,smb_vwv0,nwritten); + } + + END_PROFILE(SMBwriteBmpx); + return(outsize); +} + +/**************************************************************************** + Reply to a SMBwritebs (write block multiplex secondary) request. +****************************************************************************/ + +int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) +{ + size_t numtowrite; + ssize_t nwritten = -1; + int outsize = 0; + SMB_OFF_T startpos; + size_t tcount; + BOOL write_through; + int smb_doff; + char *data; + write_bmpx_struct *wbms; + BOOL send_response = False; + files_struct *fsp = file_fsp(inbuf,smb_vwv0); + START_PROFILE(SMBwriteBs); + + CHECK_FSP(fsp,conn); + CHECK_WRITE(fsp); + + tcount = SVAL(inbuf,smb_vwv1); + startpos = IVAL(inbuf,smb_vwv2); + numtowrite = SVAL(inbuf,smb_vwv6); + smb_doff = SVAL(inbuf,smb_vwv7); + + data = smb_base(inbuf) + smb_doff; + + /* We need to send an SMBwriteC response, not an SMBwritebs */ + CVAL(outbuf,smb_com) = SMBwritec; + + /* This fd should have an auxiliary struct attached, + check that it does */ + wbms = fsp->wbmpx_ptr; + if(!wbms) { + END_PROFILE(SMBwriteBs); + return(-1); + } + + /* If write through is set we can return errors, else we must cache them */ + write_through = wbms->wr_mode; + + /* Check for an earlier error */ + if(wbms->wr_discard) { + END_PROFILE(SMBwriteBs); + return -1; /* Just discard the packet */ + } + + nwritten = write_file(fsp,data,startpos,numtowrite); + + if(lp_syncalways(SNUM(conn)) || write_through) + sync_file(conn,fsp); + + if (nwritten < (ssize_t)numtowrite) { + if(write_through) { + /* We are returning an error - we can delete the aux struct */ + if (wbms) + free((char *)wbms); + fsp->wbmpx_ptr = NULL; + END_PROFILE(SMBwriteBs); + return(ERROR_DOS(ERRHRD,ERRdiskfull)); + } + END_PROFILE(SMBwriteBs); + return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull)); + } + + /* Increment the total written, if this matches tcount + we can discard the auxiliary struct (hurrah !) and return a writeC */ + wbms->wr_total_written += nwritten; + if(wbms->wr_total_written >= tcount) { + if (write_through) { + outsize = set_message(outbuf,1,0,True); + SSVAL(outbuf,smb_vwv0,wbms->wr_total_written); + send_response = True; + } + + free((char *)wbms); + fsp->wbmpx_ptr = NULL; + } + + if(send_response) { + END_PROFILE(SMBwriteBs); + return(outsize); + } + + END_PROFILE(SMBwriteBs); + return(-1); +} + /**************************************************************************** - reply to a SMBgetattrE + Reply to a SMBgetattrE. ****************************************************************************/ int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize) -- cgit