From 7d388474aceca702073fbb26a98515936da0ae93 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 29 Mar 2010 16:27:23 -0700 Subject: [PATCH] Fix bug #7233 - print fails with jobs >4GB from Win7 clients. New fix - based on work from Sebastian Kloska . Ensure the print path is 64-bit clean. Fix old SMBwrite... style calls that use 32-bit offsets to seek successfully within the 4GB chunk they are working on when writing a large file. Jeremy. --- source3/include/proto.h | 1 + source3/printing/printfsp.c | 20 ++++++++++ source3/printing/printing.c | 2 +- source3/rpc_server/srv_spoolss_nt.c | 6 ++-- source3/smbd/reply.c | 66 ++++++++++++++++++++++------------- 5 files changed, 67 insertions(+), 28 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 65fd9a8..823774c 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -4919,6 +4919,7 @@ NTSTATUS print_fsp_open(struct smb_request *req, connection_struct *conn, const char *fname, uint16_t current_vuid, files_struct *fsp); void print_fsp_end(files_struct *fsp, enum file_close_type close_type); +SMB_OFF_T printfile_offset(files_struct *fsp, SMB_OFF_T offset); /* The following definitions come from printing/printing.c */ diff --git a/source3/printing/printfsp.c b/source3/printing/printfsp.c index b9fe492..0dda70d 100644 --- a/source3/printing/printfsp.c +++ b/source3/printing/printfsp.c @@ -114,3 +114,23 @@ void print_fsp_end(files_struct *fsp, enum file_close_type close_type) print_job_end(SNUM(fsp->conn),jobid, close_type); } + +/**************************************************************************** + Discovered by Sebastian Kloska . When print files + go beyond 4GB, the 32-bit offset sent in old SMBwrite calls is relative + to the current 4GB chunk we're writing to. +****************************************************************************/ + +SMB_OFF_T printfile_offset(files_struct *fsp, SMB_OFF_T offset) +{ + SMB_STRUCT_STAT st; + + if (sys_fstat(fsp->fh->fd, &st, false) == -1) { + DEBUG(3,("printfile_offset: sys_fstat failed on %s (%s)\n", + fsp_str_dbg(fsp), + strerror(errno) )); + return offset; + } + + return (st.st_ex_size & 0xffffffff00000000LL) + offset; +} diff --git a/source3/printing/printing.c b/source3/printing/printing.c index b5b8a56..aff8ac2 100644 --- a/source3/printing/printing.c +++ b/source3/printing/printing.c @@ -2231,7 +2231,7 @@ pause, or resume print job. User name: %s. Printer name: %s.", ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos, size_t size) { const char* sharename = lp_const_servicename(snum); - int return_code; + ssize_t return_code; struct printjob *pjob; pjob = print_job_find(sharename, jobid); diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 92f37e5..0123e34 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -5296,7 +5296,7 @@ WERROR _spoolss_EndDocPrinter(pipes_struct *p, WERROR _spoolss_WritePrinter(pipes_struct *p, struct spoolss_WritePrinter *r) { - uint32_t buffer_written; + ssize_t buffer_written; int snum; Printer_entry *Printer = find_printer_index_by_hnd(p, r->in.handle); @@ -5310,11 +5310,11 @@ WERROR _spoolss_WritePrinter(pipes_struct *p, if (!get_printer_snum(p, r->in.handle, &snum, NULL)) return WERR_BADFID; - buffer_written = (uint32_t)print_job_write(snum, Printer->jobid, + buffer_written = print_job_write(snum, Printer->jobid, (const char *)r->in.data.data, (SMB_OFF_T)-1, (size_t)r->in._data_size); - if (buffer_written == (uint32_t)-1) { + if (buffer_written == (ssize_t)-1) { *r->out.num_written = 0; if (errno == ENOSPC) return WERR_NO_SPOOL_SPACE; diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 8d40ed6..0938524 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3782,15 +3782,19 @@ void reply_writebraw(struct smb_request *req) return; } - init_strict_lock_struct(fsp, (uint32)req->smbpid, - (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK, - &lock); + if (fsp->print_file) { + startpos = printfile_offset(fsp, startpos); + } else { + init_strict_lock_struct(fsp, (uint32)req->smbpid, + (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK, + &lock); - if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); - error_to_writebrawerr(req); - END_PROFILE(SMBwritebraw); - return; + if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { + reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + error_to_writebrawerr(req); + END_PROFILE(SMBwritebraw); + return; + } } if (numtowrite>0) { @@ -3904,7 +3908,9 @@ void reply_writebraw(struct smb_request *req) fsp->fnum, (double)startpos, (int)numtowrite, (int)total_written)); - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + if (!fsp->print_file) { + SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + } /* We won't return a status if write through is not selected - this * follows what WfWg does */ @@ -3928,7 +3934,9 @@ void reply_writebraw(struct smb_request *req) return; strict_unlock: - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + if (!fsp->print_file) { + SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + } END_PROFILE(SMBwritebraw); return; @@ -3978,7 +3986,9 @@ void reply_writeunlock(struct smb_request *req) startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0); data = (const char *)req->buf + 3; - if (numtowrite) { + if (fsp->print_file) { + startpos = printfile_offset(fsp, startpos); + } else if (numtowrite) { init_strict_lock_struct(fsp, (uint32)req->smbpid, (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK, &lock); @@ -4018,7 +4028,7 @@ void reply_writeunlock(struct smb_request *req) goto strict_unlock; } - if (numtowrite) { + if (numtowrite && !fsp->print_file) { status = do_unlock(smbd_messaging_context(), fsp, req->smbpid, @@ -4040,7 +4050,7 @@ void reply_writeunlock(struct smb_request *req) fsp->fnum, (int)numtowrite, (int)nwritten)); strict_unlock: - if (numtowrite) { + if (numtowrite && !fsp->print_file) { SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); } @@ -4099,14 +4109,18 @@ void reply_write(struct smb_request *req) startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0); data = (const char *)req->buf + 3; - init_strict_lock_struct(fsp, (uint32)req->smbpid, - (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK, - &lock); + if (fsp->print_file) { + startpos = printfile_offset(fsp, startpos); + } else { + init_strict_lock_struct(fsp, (uint32)req->smbpid, + (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK, + &lock); - if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { - reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); - END_PROFILE(SMBwrite); - return; + if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) { + reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + END_PROFILE(SMBwrite); + return; + } } /* @@ -4164,7 +4178,9 @@ void reply_write(struct smb_request *req) DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten)); strict_unlock: - SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + if (!fsp->print_file) { + SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); + } END_PROFILE(SMBwrite); return; @@ -4701,7 +4717,9 @@ void reply_writeclose(struct smb_request *req) mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4)); data = (const char *)req->buf + 1; - if (numtowrite) { + if (fsp->print_file) { + startpos = printfile_offset(fsp, startpos); + } else if (numtowrite) { init_strict_lock_struct(fsp, (uint32)req->smbpid, (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK, &lock); @@ -4747,7 +4765,7 @@ void reply_writeclose(struct smb_request *req) SSVAL(req->outbuf,smb_vwv0,nwritten); strict_unlock: - if (numtowrite) { + if (numtowrite && !fsp->print_file) { SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); } @@ -5204,7 +5222,7 @@ void reply_printwrite(struct smb_request *req) data = (const char *)req->buf + 3; - if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) { + if (write_file(req,fsp,data,(SMB_OFF_T)-1,numtowrite) != numtowrite) { reply_nterror(req, map_nt_error_from_unix(errno)); END_PROFILE(SMBsplwr); return; -- 1.7.0.1