Module Name: src Committed By: bouyer Date: Tue Oct 27 20:31:15 UTC 2009
Modified Files: src/sys/netsmb [netbsd-5]: smb_smb.c Log Message: Pull up following revision(s) (requested by tron in ticket #1104): sys/netsmb/smb_smb.c: revision 1.31 sys/netsmb/smb_smb.c: revision 1.32 Fix detection of SMB capabilities according to the CIFS spec: 1.) SMB_CAP_LARGE_FILES advertises support for 64-bit file offsets. 2.) SMB_CAP_LARGE_READX and SMB_CAP_LARGE_WRITEX advertise support for large reads and writes (larger than 64KB). The code previously only used SMB_CAP_LARGE_READX and SMB_CAP_LARGE_WRITEX which is not correct and doesn't work for the Apple Time Capsule which only supports SMB_CAP_LARGE_FILES. With these changes SMBFS can copy a 5GB to a Time Capsule and read it back without problems. Thanks a lot to Allen Briggs for pointing out the broke assumptions and explaining the CIFS spec to me. This fixes PR kern/42175. Fix cut & paste error spotted by Nicolas Joly. To generate a diff of this commit: cvs rdiff -u -r1.29 -r1.29.6.1 src/sys/netsmb/smb_smb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netsmb/smb_smb.c diff -u src/sys/netsmb/smb_smb.c:1.29 src/sys/netsmb/smb_smb.c:1.29.6.1 --- src/sys/netsmb/smb_smb.c:1.29 Tue Jun 24 10:37:19 2008 +++ src/sys/netsmb/smb_smb.c Tue Oct 27 20:31:15 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: smb_smb.c,v 1.29 2008/06/24 10:37:19 gmcgarry Exp $ */ +/* $NetBSD: smb_smb.c,v 1.29.6.1 2009/10/27 20:31:15 bouyer Exp $ */ /* * Copyright (c) 2000-2001 Boris Popov @@ -38,7 +38,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smb_smb.c,v 1.29 2008/06/24 10:37:19 gmcgarry Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smb_smb.c,v 1.29.6.1 2009/10/27 20:31:15 bouyer Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -594,6 +594,22 @@ u_int16_t residhi, residlo, off, doff; u_int32_t resid; + if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES) && + uio->uio_offset >= (1LL << 32)) { + /* Cannot read at/beyond 4G */ + return (EFBIG); + } + + if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX)) { + size_t blksz; + + blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 64; + if (blksz > 0xffff) + blksz = 0xffff; + + *len = min(blksz, *len); + } + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp); if (error) return error; @@ -674,8 +690,26 @@ u_int8_t wc; u_int16_t resid; + if (!(SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_FILES) && + uio->uio_offset >= (1LL << 32)) { + /* Cannot write at/beyond 4G */ + return (EFBIG); + } + + if (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX) { + *len = min(SSTOVC(ssp)->vc_wxmax, *len); + } else { + size_t blksz; + + blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 64; + if (blksz > 0xffff) + blksz = 0xffff; + + *len = min(blksz, *len); + } + error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp); - if (error) + if (error != 0) return (error); smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); @@ -687,7 +721,6 @@ mb_put_uint32le(mbp, 0); /* MBZ (timeout) */ mb_put_uint16le(mbp, 0); /* !write-thru */ mb_put_uint16le(mbp, 0); - *len = min(SSTOVC(ssp)->vc_wxmax, *len); mb_put_uint16le(mbp, *len >> 16); mb_put_uint16le(mbp, *len); mb_put_uint16le(mbp, 64); /* data offset from header start */ @@ -785,7 +818,8 @@ { size_t tsize, len, resid; int error = 0; - int rx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX); + bool rx = (SMB_CAPS(SSTOVC(ssp)) & + (SMB_CAP_LARGE_FILES|SMB_CAP_LARGE_READX)) != 0; resid = 0; /* XXX gcc */ @@ -866,7 +900,8 @@ { int error = 0; size_t len, tsize, resid; - int wx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX); + bool wx = (SMB_CAPS(SSTOVC(ssp)) & + (SMB_CAP_LARGE_FILES|SMB_CAP_LARGE_WRITEX)) != 0; resid = 0; /* XXX gcc */ @@ -877,7 +912,7 @@ error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred); else error = smb_smb_write(ssp, fid, &len, &resid, uio, scred); - if (error) + if (error != 0) break; if (resid < len) { error = EIO;