summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcvs2svn Import User <samba-bugs@samba.org>2002-10-01 05:55:26 +0000
committercvs2svn Import User <samba-bugs@samba.org>2002-10-01 05:55:26 +0000
commitd7ae4079e7f8b75064dbf84c0989208c2d0b4674 (patch)
tree72be61eb7412af330464bf7aeb83c88548d02666
parentb5406c2c3782262c07f6b33432c2dead31e1c7be (diff)
parentef7bcaf1b7e1ca073b27a8836c6aa86e112b5bee (diff)
downloadsamba-d7ae4079e7f8b75064dbf84c0989208c2d0b4674.tar.gz
samba-d7ae4079e7f8b75064dbf84c0989208c2d0b4674.tar.xz
samba-d7ae4079e7f8b75064dbf84c0989208c2d0b4674.zip
This commit was manufactured by cvs2svn to create branch
'SAMBA_2_2_RELEASE'.
-rw-r--r--docs/textdocs/CUPS-PrintingInfo.txt589
-rw-r--r--source/lib/sendfile.c382
2 files changed, 971 insertions, 0 deletions
diff --git a/docs/textdocs/CUPS-PrintingInfo.txt b/docs/textdocs/CUPS-PrintingInfo.txt
new file mode 100644
index 00000000000..bbe14f33e8f
--- /dev/null
+++ b/docs/textdocs/CUPS-PrintingInfo.txt
@@ -0,0 +1,589 @@
+Date: Sun, 22 Sep 2002 15:38:02 +0200
+From: "Kurt Pfeifle" <kpfeifle@danka.de>
+Reply-To: kpfeifle@danka.de
+Organization: Danka Deutschland GmbH
+To: samba@lists.samba.org
+Subject: CUPS filtering mechanism explained, was: [cups raw mode, was Re: [Samba] unlink data file in cups_job_submit]
+
+Paul Janzen wrote on Samba digest:
+
+ > Message: 7
+ > To: Gerald Carter <jerry@samba.org>
+ > Cc: samba@lists.samba.org
+ > From: Paul Janzen <pcj@samba.sez.to>
+ > Subject: cups raw mode, was Re: [Samba] unlink data file in cups_job_submit
+ > Date: 21 Sep 2002 12:09:23 -0700
+ >
+ >
+ > Gerald Carter <jerry@samba.org> writes:
+ >
+ > > Looks right to me [:-)] Applying it now. Thanks. I've been meaning to
+ > > track this one down.
+ >
+ >
+ > Thanks!
+ >
+ > While we are on the subject... [:-)]
+ >
+ > If I am using native printer drivers on Windows clients, I would like
+ > the "raw" option to get propagated to CUPS. Otherwise cups does not
+ > pass the data on to the printer.
+
+Paul,
+
+I see you know about what you call the "raw data passthrough feature".
+I guess you mean the lines in "/etc/cups/mime.types" and
+"/etc/cups/mime.convs" which need to be uncommented to allow "raw"
+printing ?
+
+Here is some clarification (likely not very useful for you, but
+possibly for some other readers of the Samba list):
+
+### If you have "printing = cups" and "printcap = cups" enabled,
+--- everything is handled by Samba accessing the CUPS API. (And any
+ "print command" directive in Samba will be ignored.) If the CUPS
+ API is not available (because Samba might not be compiled against
+libcups), it automatically maps to the "System V" command set, with
+"-oraw" enabled automatically.
+
+ > (If I enable cups's application/
+ > octet-stream raw-data passthrough feature, both cupsomatic and the
+ > Windows driver add PJL headers and footers, which is not what I want
+ > either.)
+
+### According to my experience, cupsomatic on the Samba/CUPS server
+--- does *not* add any features if a file is really printed "raw".
+ However, if you have loaded the driver for the Windows client
+from the CUPS server, using the "cupsaddsmb" utility, and if this
+driver is one using a "Foomatic" PPD, the PJL header in question is
+already added on the Windows client, at the time when the driver
+initially generated the PostScript data -- and CUPS in true "-oraw"
+manner doesn't remove this PJL header and passes the file "as is"
+to its printer communication backend.
+
+NOTE, please, that the editing in the "mime.convs" and the
+----- "mime.types" file does not *enforce* "raw" printing, it
+ only *allows* it. Any file arriving from Windows is
+"auto-typed" by CUPS, which might consecutively lead to its
+treatment by various filters automatically (depending on the
+actual outcome of the auto-typing and the configuration of the
+printqueue in question):
+
+ --> Files generated by PCL drivers and destined to PCL
+ printers get auto-typed "application/octet-stream"
+ and are indeed printed "raw". Also, unknown file
+ types are getting tagged as "application/octet-stream".
+
+ --> Files generated by a PostScript driver (and destined
+ for any target printer type) are auto-typed. Depending
+ on the driver, the discovered MIME type may be
+
+ * application/postscript or
+ * application/vnd.cups-postscript
+
+"application/postscript" goes first thru the "pstops" filter
+ (where also the page counting and accounting takes place
+ currently), and the outcome will be of MIME type
+ "application/vnd.cups-postscript". The pstopsfilter reads and
+ uses information from the PPD and inserts user-provided options
+ into the PostScript file. As a consequence, the filtered file
+ will possibly have the PJL header you don't want.
+
+"application/postscript" will be all files with a ".ps", ".ai",
+ ".eps" suffix or which have as their first character string one
+ of "%!" or "<04>%".
+
+"application/vnd.cups-postscript" will be those files which do both,
+ first...
+ ...carry a string "LANGUAGE=POSTSCRIPT" (or similar variations
+ with different capitalization) amongst the first 512 bytes,
+ *plus*...
+ ...contain the "PJL super escape code" amongst the first 128
+ bytes ("<1B>%-12345X"). Very likely, most PostScript files
+ generated on Windows using a CUPS- or other PPD, will have
+ to be auto-typed as "vnd.cups-postscript".
+ Probably a file produced with a "Generic PostScript driver"
+ will be just "application/postscript" (have not checked).
+
+Once the file is in "application/vnd.cups-postscript" format,
+either "pstoraster" or "cupsomatic" will take over (depending
+on the printer configuration, as determined by the PPD in use).
+
+NOTE: a printer queue with *no* PPD associated to it is a "raw"
+----- printer and all files will go directly there as received
+ by the spooler; the exeption are file types
+"application/octet-stream" which need the mentioned "passthrough
+feature" enabled. "Raw" queues don't do any filtering at all, they
+hand the file directly to the CUPS backend. This backend is
+responsible for the sending of the data to the device (as visible
+in the "device URI" notation as lpd://, socket://, smb://, ipp://,
+http://, parallel:/, serial:/, usb:/ etc.)
+
+NOTE, please, also the following fact: "cupsomatic"/Foomatic are
+----- *not* native CUPS drivers and they don't ship with CUPS.
+ They are a Third Party add-on, developed at Linuxprinting.org.
+As such, they are a brilliant hack to make all models (driven by
+Ghostscript drivers/filters in traditional spoolers) also work via
+CUPS, with the same (good or bad!) quality as in these other
+spoolers. "cupsomatic" is only a vehicle to execute a ghostscript
+commandline at that stage in the CUPS filtering chain, where
+"normally" the native CUPS "pstoraster" filter would kick in.
+cupsomatic by-passes pstoraster, "kidnaps" the printfile from CUPS
+away and re-directs it to go through Ghostscipt. CUPS accepts this,
+because the associated CUPS-O-Matic-/Foomatic-PPD carries a line
+reading
+
+ *cupsFilter: "application/vnd.cups-postscript 0 cupsomatic"
+
+This line persuades CUPS to hand the file to cupsomatic, once it
+has successfully converted it to the MIME type
+"application/vnd.cups-postscript". This conversion will not
+happen for Jobs arriving from Windows which are autotyped
+"application/octet-stream", with the according changes in
+"/etc/cups/mime.types" in place.
+
+See small drawings at the end...
+
+I am not a programmer, so please correct me if I am wrong.
+
+ > With traditional lpr, you can just add "-oraw" to the "print command"
+ > line in smb.conf. With cups, you don't have that alternative.
+
+You *do* have it, I think.
+
+But you need to disable the settings "printing = cups" and "printcap =
+= cups" and use "printing = bsd" and "printcap = /etc/printcap"
+instead. [Additionally, you will probably have to enable and configure
+the CUPS mini-LPD daemon ("cups-lpd") run from inetd... but I have not
+checked, so take this item with a grain of salt and a proper dose of
+caution, please.]
+
+ > The result is that to support both unix printing and native-driver
+ > Windows printing from CUPS, you have to have two logical printers per
+ > physical printer: one ("cooked") for Unix clients and one ("raw") for
+ > Samba to use.
+
+Yes, that is one current workaround, if you don't want the auto-typing
+of CUPS influencing Samba/Windows client PostScript jobs.
+
+CUPS is widely configurable and flexible, even regarding its filtering
+mechanism. Another workaround in some situations would be to have
+lines in "/etc/cups/mime.types" saying
+
+ application/postscript application/vnd.cups-raw 0 -
+ application/vnd.cups-postscript application/vnd.cups-raw 0 -
+
+This would prevent all Postscript files to be filtered (or rather, they
+will go thru the virtual "nullfilter" denoted with "-". (This could only
+be useful for PS printers, or if you want to print PS code on non-PS
+printers ;-)
+
+A single line of
+
+ */* application/vnd.cups-raw 0 -
+
+would effectively send *all* files towards the backend immediately
+(good luck!)
+
+Last, you could have the following (without the need for a Samba
+patch):
+
+ application/vnd.cups-postscript application/vnd.cups-raw 0 my_PJL_stripping_filter
+
+You'd need to write a "my_PJL_stripping_filter" (could be a shellscript)
+which parses the PostScript and removes the undesired PJL. This would
+need to conform to CUPS filter design (mainly, receive and pass the
+parameters printername, job-id, username, jobtitle, copies, printoptions
+and possibly the filename). It would just go as world executably into
+"/usr/lib/cups/filters/" and work from there, called by cups if it
+encounters a MIME type "application/vnd.cups-postscript"
+
+ > The attached patch allows you to specify an option string for cups
+ > printers in smb.conf.
+
+I think your patch is in any case very useful (if it works as
+advertised ;-). It is the most generic, simple and flexible
+approach to complement CUPS.
+
+ > So, if you want to use native Windows drivers,
+ > all you need is
+ >
+ > cups printer options = raw
+ >
+ > in smb.conf. You can add any other options that cups and the printer
+ > understand.
+
+Now this last sentence makes me very curious. Do you mean you can add
+*multiple* options to this directive? Which syntax would be required
+for this ? (Some CUPS options are specified by an "-o option=value"
+pair on the commandline, some are single values, like the "-o raw"
+one...)
+
+I am thinking on one specific usage now:
+
+-----------------------------------------------------------------------
+-> passing any available IPP job attribute to the printer / the spooler
+-----------------------------------------------------------------------
+
+For example, CUPS can handle "-o job-hold-until=indefinite". This
+keeps the job in the queue "on hold". It will only be printed upon
+manual release by the printer operator. This is a requirement in
+many "central reproduction departments", where a few operators
+manage the jobs of hundreds of users on some big machine, where no
+user is allowed to have direct access. (The operators often need to
+load the proper paper type before running the 10.000 page job
+requested by marketing for the mailing, etc.).
+
+A lot more useful applications come to mind, if I could pass
+"any other options that cups and the printer understand" via
+the smb.conf directive!!
+
+Thanks a lot!
+
+Cheers,
+Kurt
+
+P.S.: List, please give me some feedback, if you think this type of
+ explanation could be useful in the Samba HOWTO Collection. In
+ that case, I'll try to write it up in a nicer form.
+
+
+#########################################################################
+#
+# CUPS in and of itself has this (general) filter chain (CAPITAL
+# letters are FILE-FORMATS or MIME types, other are filters (this is
+# true for pre-1.1.15 of pre-4.3 versions of CUPS and ESP PrintPro):
+#
+# <SOMETHNG>-FILEFORMAT
+# |
+# |
+# V
+# <something>tops
+# |
+# |
+# V
+# APPLICATION/POSTSCRIPT
+# |
+# |
+# V
+# pstops
+# |
+# |
+# V
+# APPLICATION/VND.CUPS-POSTSCRIPT
+# |
+# |
+# V
+# pstoraster # as shipped with CUPS, independent from any Ghostscipt
+# | # installation on the system
+# | (= "postscipt interpreter")
+# |
+# V
+# APPLICATION/VND.CUPS-RASTER
+# |
+# |
+# V
+# rasterto<something> (f.e. Gimp-Print filters may be plugged in here)
+# | (= "raster driver")
+# |
+# V
+# SOMETHING-DEVICE-SPECIFIC
+# |
+# |
+# V
+# backend
+#
+#
+# ESP PrintPro has some enhanced "rasterto<something>" filters as compared to
+# CUPS, and also a somewhat improved "pstoraster" filter.
+#
+# NOTE: Gimp-Print and some other 3rd-Party-Filters (like TurboPrint) to
+# CUPS and ESP PrintPro plug-in where rasterto<something> is noted.
+#
+#
+#########################################################################
+#
+# This is how "cupsomatic" comes into play:
+# =========================================
+#
+# <SOMETHNG>-FILEFORMAT
+# |
+# |
+# V
+# <something>tops
+# |
+# |
+# V
+# APPLICATION/POSTSCRIPT
+# |
+# |
+# V
+# pstops
+# |
+# |
+# V
+# APPLICATION/VND.CUPS-POSTSCRIPT ----------------+
+# | |
+# | V
+# V cupsomatic
+# pstoraster (constructs complicated
+# | (= "postscipt interpreter") Ghostscript commandline
+# | to let the file be
+# V processed by a
+# APPLICATION/VND.CUPS-RASTER "-sDEVICE=<s.th.>"
+# | call...)
+# | |
+# V |
+# rasterto<something> V
+# | (= "raster driver") +-------------------------+
+# | | Ghostscript at work.... |
+# V | |
+# SOMETHING-DEVICE-SPECIFIC *-------------------------+
+# | |
+# | |
+# V |
+# backend <------------------------------------+
+# |
+# |
+# V
+# THE PRINTER
+#
+#
+#
+# Note, that cupsomatic "kidnaps" the printfile after the
+# "APPLICATION/VND.CUPS-POSTSCRPT" stage and deviates it through
+# the CUPS-external, systemwide Ghostscript installation, bypassing the
+# "pstoraster" filter (therefor also bypassing the CUPS-raster-drivers
+# "rasterto<something>", and hands the rasterized file directly to the CUPS
+# backend...
+#
+# cupsomatic is not made by the CUPS developers. It is an independent
+# contribution to printing development, made by people from
+# Linuxprinting.org. (see also http://www.cups.org/cups-help.html)
+#
+# NOTE: Gimp-Print and some other 3rd-Party-Filters (like TurboPrint) to
+# CUPS and ESP PrintPro plug-in where rasterto<something> is noted.
+#
+#
+#########################################################################
+#
+# And this is how it works for ESP PrintPro from 4.3:
+# ===================================================
+#
+# <SOMETHNG>-FILEFORMAT
+# |
+# |
+# V
+# <something>tops
+# |
+# |
+# V
+# APPLICATION/POSTSCRIPT
+# |
+# |
+# V
+# pstops
+# |
+# |
+# V
+# APPLICATION/VND.CUPS-POSTSCRIPT
+# |
+# |
+# V
+# gsrip
+# | (= "postscipt interpreter")
+# |
+# V
+# APPLICATION/VND.CUPS-RASTER
+# |
+# |
+# V
+# rasterto<something> (f.e. Gimp-Print filters may be plugged in here)
+# | (= "raster driver")
+# |
+# V
+# SOMETHING-DEVICE-SPECIFIC
+# |
+# |
+# V
+# backend
+#
+# NOTE: Gimp-Print and some other 3rd-Party-Filters (like TurboPrint) to
+# CUPS and ESP PrintPro plug-in where rasterto<something> is noted.
+#
+#
+#########################################################################
+#
+# This is how "cupsomatic" would come into play with ESP PrintPro:
+# ================================================================
+#
+#
+# <SOMETHNG>-FILEFORMAT
+# |
+# |
+# V
+# <something>tops
+# |
+# |
+# V
+# APPLICATION/POSTSCRIPT
+# |
+# |
+# V
+# pstops
+# |
+# |
+# V
+# APPLICATION/VND.CUPS-POSTSCRIPT ----------------+
+# | |
+# | V
+# V cupsomatic
+# gsrip (constructs complicated
+# | (= "postscipt interpreter") Ghostscript commandline
+# | to let the file be
+# V processed by a
+# APPLICATION/VND.CUPS-RASTER "-sDEVICE=<s.th.>"
+# | call...)
+# | |
+# V |
+# rasterto<something> V
+# | (= "raster driver") +-------------------------+
+# | | Ghostscript at work.... |
+# V | |
+# SOMETHING-DEVICE-SPECIFIC *-------------------------+
+# | |
+# | |
+# V |
+# backend <------------------------------------+
+# |
+# |
+# V
+# THE PRINTER
+#
+# NOTE: Gimp-Print and some other 3rd-Party-Filters (like TurboPrint) to
+# CUPS and ESP PrintPro plug-in where rasterto<something> is noted.
+#
+#########################################################################
+#
+# And this is how it works for CUPS from 1.1.15:
+# ==============================================
+#
+# <SOMETHNG>-FILEFORMAT
+# |
+# |
+# V
+# <something>tops
+# |
+# |
+# V
+# APPLICATION/POSTSCRIPT
+# |
+# |
+# V
+# pstops
+# |
+# |
+# V
+# APPLICATION/VND.CUPS-POSTSCRIPT-----+
+# |
+# +------------------v------------------------------+
+# | Ghostscript |
+# | at work... |
+# | (with |
+# | "-sDEVICE=cups") |
+# | |
+# | (= "postscipt interpreter") |
+# | |
+# +------------------v------------------------------+
+# |
+# |
+# APPLICATION/VND.CUPS-RASTER <-------+
+# |
+# |
+# V
+# rasterto<something>
+# | (= "raster driver")
+# |
+# V
+# SOMETHING-DEVICE-SPECIFIC
+# |
+# |
+# V
+# backend
+#
+#
+# NOTE: since version 1.1.15 CUPS "outsourced" the pstoraster process to
+# Ghostscript. GNU Ghostscript needs to be patched to handle the
+# CUPS requirement; ESP Ghostscript has this builtin. In any case,
+# "gs -h" needs to show up a "cups" device. pstoraster is now a
+# calling an appropriate "gs -sDEVICE=cups..." commandline to do
+# the job. It will output "application/vnd.cup-raster", which will
+# be finally processed by a CUPS raster driver "rasterto<something>"
+# Note the difference to "cupsomatic", which will *not* output
+# CUPS-raster, but a final version of the printfile, ready to be
+# sent to the printer. cupsomatic also doesn't use the "cups"
+# devicemode in Ghostscript, but one of the classical devicemodes....
+#
+# NOTE: Gimp-Print and some other 3rd-Party-Filters (like TurboPrint) to
+# CUPS and ESP PrintPro plug-in where rasterto<something> is noted.
+#
+#########################################################################
+#
+# And this is how it works for CUPS from 1.1.15, with cupsomatic included:
+# ========================================================================
+#
+# <SOMETHNG>-FILEFORMAT
+# |
+# |
+# V
+# <something>tops
+# |
+# |
+# V
+# APPLICATION/POSTSCRIPT
+# |
+# |
+# V
+# pstops
+# |
+# |
+# V
+# APPLICATION/VND.CUPS-POSTSCRIPT-----+
+# |
+# +------------------v------------------------------+
+# | Ghostscript . Ghostscript at work.... |
+# | at work... . (with "-sDEVICE= |
+# | (with . <s.th.>" |
+# | "-sDEVICE=cups") . |
+# | . |
+# | (CUPS standard) . (cupsomatic) |
+# | . |
+# | (= "postscript interpreter") |
+# | . |
+# +------------------v--------------v---------------+
+# | |
+# | |
+# APPLICATION/VND.CUPS-RASTER <-------+ |
+# | |
+# | |
+# V |
+# rasterto<something> |
+# | (= "raster driver") |
+# | |
+# V |
+# SOMETHING-DEVICE-SPECIFIC <------------------------+
+# |
+# |
+# V
+# backend
+#
+#
+# NOTE: Gimp-Print and some other 3rd-Party-Filters (like TurboPrint) to
+# CUPS and ESP PrintPro plug-in where rasterto<something> is noted.
+#
+##########################################################################
+
+I hope this helps more people understand how CUPS works and how they
+can possibly tweak it to their needs.
+
+
diff --git a/source/lib/sendfile.c b/source/lib/sendfile.c
new file mode 100644
index 00000000000..ccebd25cc1a
--- /dev/null
+++ b/source/lib/sendfile.c
@@ -0,0 +1,382 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2.x / 3.0.x
+ sendfile implementations.
+ Copyright (C) Jeremy Allison 2002.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ * This file handles the OS dependent sendfile implementations.
+ * The API is such that it returns -1 on error, else returns the
+ * number of bytes written.
+ */
+
+#include "includes.h"
+
+#if defined(LINUX_SENDFILE_API)
+
+#include <sys/sendfile.h>
+
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ ssize_t ret;
+ ssize_t hdr_len = 0;
+
+ /*
+ * Send the header first.
+ * Use MSG_MORE to cork the TCP output until sendfile is called.
+ */
+
+ if (header) {
+ hdr_len = header->length;
+ while (total < hdr_len) {
+ ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
+ if (ret == -1)
+ return -1;
+ total += ret;
+ }
+ }
+
+ total = count;
+ while (total) {
+ ssize_t nwritten;
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
+ nwritten = sendfile64(tofd, fromfd, &offset, total);
+#else
+ nwritten = sendfile(tofd, fromfd, &offset, total);
+#endif
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+ total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(LINUX_BROKEN_SENDFILE_API)
+
+/*
+ * We must use explicit 32 bit types here. This code path means Linux
+ * won't do proper 64-bit sendfile. JRA.
+ */
+
+extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
+
+
+#ifndef MSG_MORE
+#define MSG_MORE 0x8000
+#endif
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ ssize_t ret;
+ ssize_t hdr_len = 0;
+ uint32 small_total = 0;
+ int32 small_offset;
+
+ /*
+ * Fix for broken Linux 2.4 systems with no working sendfile64().
+ * If the offset+count > 2 GB then pretend we don't have the
+ * system call sendfile at all. The upper layer catches this
+ * and uses a normal read. JRA.
+ */
+
+ if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /*
+ * Send the header first.
+ * Use MSG_MORE to cork the TCP output until sendfile is called.
+ */
+
+ if (header) {
+ hdr_len = header->length;
+ while (total < hdr_len) {
+ ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
+ if (ret == -1)
+ return -1;
+ total += ret;
+ }
+ }
+
+ small_total = (uint32)count;
+ small_offset = (int32)offset;
+
+ while (small_total) {
+ int32 nwritten;
+ do {
+ nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+ small_total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+
+#elif defined(SOLARIS_SENDFILE_API)
+
+/*
+ * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
+ */
+
+#include <sys/sendfile.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ int sfvcnt;
+ size_t total, xferred;
+ struct sendfilevec vec[2];
+ ssize_t hdr_len = 0;
+
+ if (header) {
+ sfvcnt = 2;
+
+ vec[0].sfv_fd = SFV_FD_SELF;
+ vec[0].sfv_flag = 0;
+ vec[0].sfv_off = header->data;
+ vec[0].sfv_len = hdr_len = header->length;
+
+ vec[1].sfv_fd = fromfd;
+ vec[1].sfv_flag = 0;
+ vec[1].sfv_off = offset;
+ vec[1].sfv_len = count;
+
+ } else {
+ sfvcnt = 1;
+
+ vec[0].sfv_fd = fromfd;
+ vec[0].sfv_flag = 0;
+ vec[0].sfv_off = offset;
+ vec[0].sfv_len = count;
+ }
+
+ total = count + hdr_len;
+
+ while (total) {
+ ssize_t nwritten;
+
+ /*
+ * Although not listed in the API error returns, this is almost certainly
+ * a slow system call and will be interrupted by a signal with EINTR. JRA.
+ */
+
+ xferred = 0;
+
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
+ nwritten = sendfilev64(tofd, vec, sfvcnt, &xferred);
+#else
+ nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
+#endif
+ if (nwritten == -1 && errno == EINTR) {
+ if (xferred == 0)
+ continue; /* Nothing written yet. */
+ else
+ nwritten = xferred;
+ }
+
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than vec[0].sfv_len bytes.
+ * We move vec[1].* to vec[0].* and set sfvcnt to 1
+ */
+
+ if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
+ vec[1].sfv_off += nwritten - vec[0].sfv_len;
+ vec[1].sfv_len -= nwritten - vec[0].sfv_len;
+
+ /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
+ vec[0] = vec[1];
+ sfvcnt = 1;
+ } else {
+ vec[0].sfv_off += nwritten;
+ vec[0].sfv_len -= nwritten;
+ }
+ total -= nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(HPUX_SENDFILE_API)
+
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ struct iovec hdtrl[2];
+ size_t hdr_len = 0;
+
+ if (header) {
+ /* Set up the header/trailer iovec. */
+ hdtrl[0].iov_base = header->data;
+ hdtrl[0].iov_len = hdr_len = header->length;
+ } else {
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = hdr_len = 0;
+ }
+ hdtrl[1].iov_base = NULL;
+ hdtrl[1].iov_base = 0;
+
+ total = count;
+ while (total + hdtrl[0].iov_len) {
+ ssize_t nwritten;
+
+ /*
+ * HPUX guarantees that if any data was written before
+ * a signal interrupt then sendfile returns the number of
+ * bytes written (which may be less than requested) not -1.
+ * nwritten includes the header data sent.
+ */
+
+ do {
+#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
+ nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
+#else
+ nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
+#endif
+ } while (nwritten == -1 && errno == EINTR);
+ if (nwritten == -1)
+ return -1;
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than hdtrl[0].iov_len bytes.
+ * We change nwritten to be the number of file bytes written.
+ */
+
+ if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
+ if (nwritten >= hdtrl[0].iov_len) {
+ nwritten -= hdtrl[0].iov_len;
+ hdtrl[0].iov_base = NULL;
+ hdtrl[0].iov_len = 0;
+ } else {
+ /* iov_base is defined as a void *... */
+ hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten;
+ hdtrl[0].iov_len -= nwritten;
+ nwritten = 0;
+ }
+ }
+ total -= nwritten;
+ offset += nwritten;
+ }
+ return count + hdr_len;
+}
+
+#elif defined(FREEBSD_SENDFILE_API)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ size_t total=0;
+ struct sf_hdtr hdr;
+ struct iovec hdtrl;
+ size_t hdr_len = 0;
+
+ hdr.headers = &hdtrl;
+ hdr.hdr_cnt = 1;
+ hdr.trailers = NULL;
+ hdr.trl_cnt = 0;
+
+ /* Set up the header iovec. */
+ if (header) {
+ hdtrl.iov_base = header->data;
+ hdtrl.iov_len = hdr_len = header->length;
+ } else {
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ }
+
+ total = count;
+ while (total + hdtrl.iov_len) {
+ SMB_OFF_T nwritten;
+ int ret;
+
+ /*
+ * FreeBSD sendfile returns 0 on success, -1 on error.
+ * Remember, the tofd and fromfd are reversed..... :-).
+ * nwritten includes the header data sent.
+ */
+
+ do {
+ ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1)
+ return -1;
+
+ if (nwritten == 0)
+ return -1; /* I think we're at EOF here... */
+
+ /*
+ * If this was a short (signal interrupted) write we may need
+ * to subtract it from the header data, or null out the header
+ * data altogether if we wrote more than hdtrl.iov_len bytes.
+ * We change nwritten to be the number of file bytes written.
+ */
+
+ if (hdtrl.iov_base && hdtrl.iov_len) {
+ if (nwritten >= hdtrl.iov_len) {
+ nwritten -= hdtrl.iov_len;
+ hdtrl.iov_base = NULL;
+ hdtrl.iov_len = 0;
+ } else {
+ hdtrl.iov_base += nwritten;
+ hdtrl.iov_len -= nwritten;
+ nwritten = 0;
+ }
+ }
+ total -= nwritten;
+ offset += nwritten;
+ }
+ return count + hdr_len;
+}
+
+#else /* No sendfile implementation. Return error. */
+
+ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
+{
+ /* No sendfile syscall. */
+ errno = ENOSYS;
+ return -1;
+}
+#endif