/*
- * "$Id: file.c 5057 2006-02-02 20:38:29Z mike $"
+ * "$Id: file.c 6962 2007-09-17 20:35:47Z mike $"
*
* File functions for the Common UNIX Printing System (CUPS).
*
* our own file functions allows us to provide transparent support of
* gzip'd print files, PPD files, etc.
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2008 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
* cupsFileFlush() - Flush pending output.
* cupsFileGetChar() - Get a single character from a file.
* cupsFileGetConf() - Get a line from a configuration file...
+ * cupsFileGetLine() - Get a CR and/or LF-terminated line that may contain
+ * binary data.
* cupsFileGets() - Get a CR and/or LF-terminated line.
* cupsFileLock() - Temporarily lock access to a file.
- * cupsFileNumber() - Return the file descriptor associated with a CUPS file.
+ * cupsFileNumber() - Return the file descriptor associated with a CUPS
+ * file.
* cupsFileOpen() - Open a CUPS file.
* cupsFileOpenFd() - Open a CUPS file using a file descriptor.
* cupsFilePeekChar() - Peek at the next character from a file.
* cupsFilePutChar() - Write a character.
* cupsFilePuts() - Write a string.
* cupsFileRead() - Read from a file.
- * cupsFileRewind() - Rewind a file.
+ * cupsFileRewind() - Set the current file position to the beginning of
+ * the file.
* cupsFileSeek() - Seek in a file.
+ * cupsFileStderr() - Return a CUPS file associated with stderr.
+ * cupsFileStdin() - Return a CUPS file associated with stdin.
+ * cupsFileStdout() - Return a CUPS file associated with stdout.
* cupsFileTell() - Return the current file position.
* cupsFileUnlock() - Unlock access to a file.
* cupsFileWrite() - Write to a file.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include "http-private.h"
-#include "string.h"
#include <errno.h>
-#include <cups/debug.h>
#include <sys/types.h>
#include <fcntl.h>
+#include "http-private.h"
+#include "globals.h"
+#include "debug.h"
-#include "file.h"
#ifdef HAVE_LIBZ
# include <zlib.h>
#endif /* HAVE_LIBZ */
#endif /* !O_LARGEFILE */
+/*
+ * Some operating systems don't define O_BINARY, which is used by Microsoft
+ * and IBM to flag binary files...
+ */
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif /* !O_BINARY */
+
+
/*
* Types and structures...
*/
int fd; /* File descriptor */
char mode, /* Mode ('r' or 'w') */
compressed, /* Compression used? */
+ is_stdio, /* stdin/out/err? */
eof, /* End of file? */
buf[4096], /* Buffer */
*ptr, /* Pointer into buffer */
*end; /* End of buffer data */
- off_t pos; /* File position for start of buffer */
+ off_t pos, /* Position in file */
+ bufpos; /* File position for start of buffer */
#ifdef HAVE_LIBZ
z_stream stream; /* (De)compression stream */
/*
* 'cupsFileClose()' - Close a CUPS file.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 0 on success, -1 on error */
int fd; /* File descriptor */
char mode; /* Open mode */
int status; /* Return status */
+ int is_stdio; /* Is a stdio file? */
DEBUG_printf(("cupsFileClose(fp=%p)\n", fp));
* Save the file descriptor we used and free memory...
*/
- fd = fp->fd;
- mode = fp->mode;
+ fd = fp->fd;
+ mode = fp->mode;
+ is_stdio = fp->is_stdio;
free(fp);
if (closesocket(fd) < 0)
status = -1;
}
- else
+ else if (!is_stdio)
{
if (close(fd) < 0)
status = -1;
/*
* 'cupsFileCompression()' - Return whether a file is compressed.
+ *
+ * @since CUPS 1.2@
*/
-int /* O - CUPS_FILE_NONE or CUPS_FILE_GZIP */
+int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
cupsFileCompression(cups_file_t *fp) /* I - CUPS file */
{
- return (fp->compressed);
+ return (fp ? fp->compressed : CUPS_FILE_NONE);
}
/*
* 'cupsFileEOF()' - Return the end-of-file status.
+ *
+ * @since CUPS 1.2@
*/
-int /* O - 1 on EOF, 0 otherwise */
+int /* O - 1 on end of file, 0 otherwise */
cupsFileEOF(cups_file_t *fp) /* I - CUPS file */
{
- return (fp->eof);
+ return (fp ? fp->eof : 1);
}
* This function allows the paths in the path string to be separated by
* colons (UNIX standard) or semicolons (Windows standard) and stores the
* result in the buffer supplied. If the file cannot be found in any of
- * the supplied paths, NULL is returned. A NULL path only matches the
- * current directory.
+ * the supplied paths, @code NULL@ is returned. A @code NULL@ path only
+ * matches the current directory.
+ *
+ * @since CUPS 1.2@
*/
-const char * /* O - Full path to file or NULL */
+const char * /* O - Full path to file or @code NULL@ if not found */
cupsFileFind(const char *filename, /* I - File to find */
const char *path, /* I - Colon/semicolon-separated path */
int executable, /* I - 1 = executable files, 0 = any file/dir */
while (*path)
{
+#ifdef WIN32
+ if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
+#else
if (*path == ';' || *path == ':')
+#endif /* WIN32 */
{
if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
*bufptr++ = '/';
#else
if (!access(buffer, executable ? X_OK : 0))
#endif /* WIN32 */
+ {
+ DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
return (buffer);
+ }
bufptr = buffer;
}
strlcpy(bufptr, filename, bufend - bufptr);
if (!access(buffer, 0))
+ {
+ DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
return (buffer);
+ }
else
+ {
+ DEBUG_puts("cupsFileFind: Returning NULL");
return (NULL);
+ }
}
/*
* 'cupsFileFlush()' - Flush pending output.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 0 on success, -1 on error */
cupsFileFlush(cups_file_t *fp) /* I - CUPS file */
{
- size_t bytes; /* Bytes to write */
+ ssize_t bytes; /* Bytes to write */
DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp));
if (!fp || fp->mode != 'w')
{
- DEBUG_puts(" Attempt to flush a read-only file...");
+ DEBUG_puts("cupsFileFlush: Attempt to flush a read-only file...");
return (-1);
}
- bytes = fp->ptr - fp->buf;
+ bytes = (ssize_t)(fp->ptr - fp->buf);
+
+ DEBUG_printf(("cupsFileFlush: Flushing " CUPS_LLFMT " bytes...\n",
+ CUPS_LLCAST bytes));
if (bytes > 0)
{
/*
* 'cupsFileGetChar()' - Get a single character from a file.
+ *
+ * @since CUPS 1.2@
*/
-int /* O - Character or -1 on EOF */
+int /* O - Character or -1 on end of file */
cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */
{
/*
* Range check input...
*/
+ DEBUG_printf(("cupsFileGetChar(fp=%p)\n", fp));
+
if (!fp || (fp->mode != 'r' && fp->mode != 's'))
+ {
+ DEBUG_puts("cupsFileGetChar: Bad arguments!");
return (-1);
+ }
/*
* If the input buffer is empty, try to read more data...
if (fp->ptr >= fp->end)
if (cups_fill(fp) < 0)
+ {
+ DEBUG_puts("cupsFileGetChar: Unable to fill buffer!");
return (-1);
+ }
/*
* Return the next character in the buffer...
*/
+ DEBUG_printf(("cupsFileGetChar: Returning %d...\n", *(fp->ptr) & 255));
+
+ fp->pos ++;
+
+ DEBUG_printf(("cupsFileGetChar: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
return (*(fp->ptr)++ & 255);
}
/*
* 'cupsFileGetConf()' - Get a line from a configuration file...
+ *
+ * @since CUPS 1.2@
*/
-char * /* O - Line read of NULL on eof/error */
+char * /* O - Line read or @code NULL@ on end of file or error */
cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
char *buf, /* O - String buffer */
size_t buflen, /* I - Size of string buffer */
* Range check input...
*/
+ DEBUG_printf(("cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
+ ", value=%p, linenum=%p)\n", fp, buf, CUPS_LLCAST buflen,
+ value, linenum));
+
if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
!buf || buflen < 2 || !value)
{
*/
*value = NULL;
-
+
while (cupsFileGets(fp, buf, buflen))
{
(*linenum) ++;
if ((ptr = strchr(buf, '#')) != NULL)
{
- while (ptr > buf)
+ if (ptr > buf && ptr[-1] == '\\')
{
- if (!isspace(ptr[-1] & 255))
- break;
-
- ptr --;
+ // Unquote the #...
+ _cups_strcpy(ptr - 1, ptr);
}
+ else
+ {
+ // Strip the comment and any trailing whitespace...
+ while (ptr > buf)
+ {
+ if (!isspace(ptr[-1] & 255))
+ break;
+
+ ptr --;
+ }
- *ptr = '\0';
+ *ptr = '\0';
+ }
}
/*
}
+/*
+ * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
+ * contain binary data.
+ *
+ * This function differs from @link cupsFileGets@ in that the trailing CR
+ * and LF are preserved, as is any binary data on the line. The buffer is
+ * nul-terminated, however you should use the returned length to determine
+ * the number of bytes on the line.
+ *
+ * @since CUPS 1.2@
+ */
+
+size_t /* O - Number of bytes on line or 0 on end of file */
+cupsFileGetLine(cups_file_t *fp, /* I - File to read from */
+ char *buf, /* I - Buffer */
+ size_t buflen) /* I - Size of buffer */
+{
+ int ch; /* Character from file */
+ char *ptr, /* Current position in line buffer */
+ *end; /* End of line buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")\n",
+ fp, buf, CUPS_LLCAST buflen));
+
+ if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
+ return (0);
+
+ /*
+ * Now loop until we have a valid line...
+ */
+
+ for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
+ {
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ break;
+
+ *ptr++ = ch = *(fp->ptr)++;
+ fp->pos ++;
+
+ if (ch == '\r')
+ {
+ /*
+ * Check for CR LF...
+ */
+
+ if (fp->ptr >= fp->end)
+ if (cups_fill(fp) <= 0)
+ break;
+
+ if (*(fp->ptr) == '\n')
+ {
+ *ptr++ = *(fp->ptr)++;
+ fp->pos ++;
+ }
+
+ break;
+ }
+ else if (ch == '\n')
+ {
+ /*
+ * Line feed ends a line...
+ */
+
+ break;
+ }
+ }
+
+ *ptr = '\0';
+
+ DEBUG_printf(("cupsFileGetLine: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ return (ptr - buf);
+}
+
+
/*
* 'cupsFileGets()' - Get a CR and/or LF-terminated line.
+ *
+ * @since CUPS 1.2@
*/
-char * /* O - Line read or NULL on eof/error */
+char * /* O - Line read or @code NULL@ on end of file or error */
cupsFileGets(cups_file_t *fp, /* I - CUPS file */
char *buf, /* O - String buffer */
size_t buflen) /* I - Size of string buffer */
* Range check input...
*/
+ DEBUG_printf(("cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")\n", fp, buf,
+ CUPS_LLCAST buflen));
+
if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
return (NULL);
}
ch = *(fp->ptr)++;
+ fp->pos ++;
if (ch == '\r')
{
break;
if (*(fp->ptr) == '\n')
- fp->ptr ++;
+ {
+ fp->ptr ++;
+ fp->pos ++;
+ }
break;
}
*ptr = '\0';
+ DEBUG_printf(("cupsFileGets: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
return (buf);
}
/*
* 'cupsFileLock()' - Temporarily lock access to a file.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 0 on success, -1 on error */
-cupsFileLock(cups_file_t *fp, /* I - File to lock */
+cupsFileLock(cups_file_t *fp, /* I - CUPS file */
int block) /* I - 1 to wait for the lock, 0 to fail right away */
{
/*
/*
* 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
+ *
+ * @since CUPS 1.2@
*/
int /* O - File descriptor */
cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
{
- return (fp->fd);
+ if (fp)
+ return (fp->fd);
+ else
+ return (-1);
}
/*
* 'cupsFileOpen()' - Open a CUPS file.
+ *
+ * The "mode" parameter can be "r" to read, "w" to write, overwriting any
+ * existing file, "a" to append to an existing file or create a new file,
+ * or "s" to open a socket connection.
+ *
+ * When opening for writing ("w"), an optional number from 1 to 9 can be
+ * supplied which enables Flate compression of the file. Compression is
+ * not supported for the "a" (append) mode.
+ *
+ * When opening a socket connection, the filename is a string of the form
+ * "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
+ * connection as needed, generally preferring IPv6 connections when there is
+ * a choice.
+ *
+ * @since CUPS 1.2@
*/
-cups_file_t * /* O - CUPS file or NULL */
+cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
cupsFileOpen(const char *filename, /* I - Name of file */
const char *mode) /* I - Open mode */
{
http_addrlist_t *addrlist; /* Host address list */
+ DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")\n", filename,
+ mode));
+
/*
* Range check input...
*/
if (!filename || !mode ||
- (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
+ (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
+ (*mode == 'a' && isdigit(mode[1] & 255)))
return (NULL);
/*
switch (*mode)
{
case 'a' : /* Append file */
- fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE, 0666);
+ fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
break;
case 'r' : /* Read file */
- fd = open(filename, O_RDONLY | O_LARGEFILE, 0);
+ fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
break;
case 'w' : /* Write file */
- fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE, 0666);
+ fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
break;
case 's' : /* Read/write socket */
/*
* 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
+ *
+ * The "mode" parameter can be "r" to read, "w" to write, "a" to append,
+ * or "s" to treat the file descriptor as a bidirectional socket connection.
+ *
+ * When opening for writing ("w"), an optional number from 1 to 9 can be
+ * supplied which enables Flate compression of the file. Compression is
+ * not supported for the "a" (append) mode.
+ *
+ * @since CUPS 1.2@
*/
-cups_file_t * /* O - CUPS file or NULL */
+cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */
cupsFileOpenFd(int fd, /* I - File descriptor */
const char *mode) /* I - Open mode */
{
cups_file_t *fp; /* New CUPS file */
+ DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")\n", fd, mode));
+
/*
* Range check input...
*/
if (fd < 0 || !mode ||
- (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
+ (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
+ (*mode == 'a' && isdigit(mode[1] & 255)))
return (NULL);
/*
switch (*mode)
{
- case 'w' :
case 'a' :
+ fp->pos = lseek(fd, 0, SEEK_END);
+
+ case 'w' :
fp->mode = 'w';
fp->ptr = fp->buf;
fp->end = fp->buf + sizeof(fp->buf);
/*
* 'cupsFilePeekChar()' - Peek at the next character from a file.
+ *
+ * @since CUPS 1.2@
*/
-int /* O - Character or -1 on EOF */
+int /* O - Character or -1 on end of file */
cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
{
/*
/*
* 'cupsFilePrintf()' - Write a formatted string.
+ *
+ * @since CUPS 1.2@
*/
-int /* O - Number of bytes written or -1 */
+int /* O - Number of bytes written or -1 on error */
cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
const char *format, /* I - Printf-style format string */
...) /* I - Additional args as necessary */
{
va_list ap; /* Argument list */
- size_t bytes; /* Formatted size */
- char buf[2048]; /* Formatted text */
+ ssize_t bytes; /* Formatted size */
+ char buf[8192]; /* Formatted text */
+
+ DEBUG_printf(("cupsFilePrintf(fp=%p, format=\"%s\", ...)\n", fp, format));
if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
bytes = vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
+ if (bytes >= sizeof(buf))
+ return (-1);
+
if (fp->mode == 's')
- return (cups_write(fp, buf, bytes));
+ {
+ if (cups_write(fp, buf, bytes) < 0)
+ return (-1);
+
+ fp->pos += bytes;
+
+ DEBUG_printf(("cupsFilePrintf: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ return (bytes);
+ }
if ((fp->ptr + bytes) > fp->end)
if (cupsFileFlush(fp))
fp->pos += bytes;
+ DEBUG_printf(("cupsFilePrintf: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
if (bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
/*
* 'cupsFilePutChar()' - Write a character.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 0 on success, -1 on error */
fp->pos ++;
+ DEBUG_printf(("cupsFilePutChar: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
return (0);
}
/*
* 'cupsFilePuts()' - Write a string.
+ *
+ * Like the @code fputs@ function, no newline is appended to the string.
+ *
+ * @since CUPS 1.2@
*/
-int /* O - Number of bytes written or -1 */
+int /* O - Number of bytes written or -1 on error */
cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
const char *s) /* I - String to write */
{
- size_t bytes; /* Bytes to write */
+ ssize_t bytes; /* Bytes to write */
/*
* Write the string...
*/
- bytes = strlen(s);
+ bytes = (int)strlen(s);
if (fp->mode == 's')
{
fp->pos += bytes;
+ DEBUG_printf(("cupsFilePuts: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
return (bytes);
}
fp->pos += bytes;
+ DEBUG_printf(("cupsFilePuts: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
if (bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
/*
* 'cupsFileRead()' - Read from a file.
+ *
+ * @since CUPS 1.2@
*/
-ssize_t /* O - Number of bytes read or -1 */
+ssize_t /* O - Number of bytes read or -1 on error */
cupsFileRead(cups_file_t *fp, /* I - CUPS file */
char *buf, /* O - Buffer */
size_t bytes) /* I - Number of bytes to read */
{
- size_t total, /* Total bytes read */
- count; /* Bytes read */
+ size_t total; /* Total bytes read */
+ ssize_t count; /* Bytes read */
- DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
- (long)bytes));
+ DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+ CUPS_LLCAST bytes));
/*
* Range check input...
if (fp->ptr >= fp->end)
if (cups_fill(fp) <= 0)
{
- DEBUG_printf((" cups_fill() returned -1, total=%d\n", total));
+ DEBUG_printf(("cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT "\n",
+ CUPS_LLCAST total));
if (total > 0)
- return (total);
+ return ((ssize_t)total);
else
return (-1);
}
- count = fp->end - fp->ptr;
- if (count > bytes)
- count = bytes;
+ count = (ssize_t)(fp->end - fp->ptr);
+ if (count > (ssize_t)bytes)
+ count = (ssize_t)bytes;
memcpy(buf, fp->ptr, count);
fp->ptr += count;
+ fp->pos += count;
+
+ DEBUG_printf(("cupsFileRead: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
/*
* Update the counts for the last read...
* Return the total number of bytes read...
*/
- DEBUG_printf((" total=%d\n", total));
+ DEBUG_printf(("cupsFileRead: total=%d\n", (int)total));
- return (total);
+ return ((ssize_t)total);
}
/*
- * 'cupsFileRewind()' - Rewind a file.
+ * 'cupsFileRewind()' - Set the current file position to the beginning of the
+ * file.
+ *
+ * @since CUPS 1.2@
*/
-off_t /* O - New file position or -1 */
+off_t /* O - New file position or -1 on error */
cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
{
- return (cupsFileSeek(fp, 0L));
+ /*
+ * Range check input...
+ */
+
+ DEBUG_printf(("cupsFileRewind(fp=%p)\n", fp));
+ DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ if (!fp || fp->mode != 'r')
+ return (-1);
+
+ /*
+ * Handle special cases...
+ */
+
+ if (fp->bufpos == 0)
+ {
+ /*
+ * No seeking necessary...
+ */
+
+ fp->pos = 0;
+
+ if (fp->ptr)
+ {
+ fp->ptr = fp->buf;
+ fp->eof = 0;
+ }
+
+ DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ return (0);
+ }
+
+ /*
+ * Otherwise, seek in the file and cleanup any compression buffers...
+ */
+
+#ifdef HAVE_LIBZ
+ if (fp->compressed)
+ {
+ inflateEnd(&fp->stream);
+ fp->compressed = 0;
+ }
+#endif /* HAVE_LIBZ */
+
+ if (lseek(fp->fd, 0, SEEK_SET))
+ {
+ DEBUG_printf(("cupsFileRewind: lseek failed: %s\n", strerror(errno)));
+ return (-1);
+ }
+
+ fp->bufpos = 0;
+ fp->pos = 0;
+ fp->ptr = NULL;
+ fp->end = NULL;
+ fp->eof = 0;
+
+ DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ return (0);
}
/*
* 'cupsFileSeek()' - Seek in a file.
+ *
+ * @since CUPS 1.2@
*/
-off_t /* O - New file position or -1 */
+off_t /* O - New file position or -1 on error */
cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
off_t pos) /* I - Position in file */
{
- size_t bytes; /* Number bytes in buffer */
+ ssize_t bytes; /* Number bytes in buffer */
- DEBUG_printf(("cupsFileSeek(fp=%p, pos=%ld)\n", fp, (long)pos));
- DEBUG_printf((" fp->pos=%ld\n", (long)fp->pos));
+ DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")\n", fp,
+ CUPS_LLCAST pos));
+ DEBUG_printf(("cupsFileSeek: fp->pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+ DEBUG_printf(("cupsFileSeek: fp->ptr=%p, fp->end=%p\n", fp->ptr, fp->end));
/*
* Range check input...
return (-1);
/*
- * Figure out the number of bytes in the current buffer, and then
- * see if we are outside of it...
+ * Handle special cases...
+ */
+
+ if (pos == 0)
+ return (cupsFileRewind(fp));
+
+ if (fp->ptr)
+ {
+ bytes = (ssize_t)(fp->end - fp->buf);
+
+ if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
+ {
+ /*
+ * No seeking necessary...
+ */
+
+ fp->pos = pos;
+ fp->ptr = fp->buf + pos - fp->bufpos;
+ fp->eof = 0;
+
+ return (pos);
+ }
+ }
+
+#ifdef HAVE_LIBZ
+ if (!fp->compressed && !fp->ptr)
+ {
+ /*
+ * Preload a buffer to determine whether the file is compressed...
+ */
+
+ if (cups_fill(fp) < 0)
+ return (-1);
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Seek forwards or backwards...
*/
- bytes = fp->end - fp->buf;
fp->eof = 0;
- if (pos < fp->pos)
+ DEBUG_printf(("cupsFileSeek: bytes=" CUPS_LLFMT "\n", CUPS_LLCAST bytes));
+
+ if (pos < fp->bufpos)
{
/*
* Need to seek backwards...
*/
+ DEBUG_puts("cupsFileSeek: SEEK BACKWARDS");
+
#ifdef HAVE_LIBZ
if (fp->compressed)
{
inflateEnd(&fp->stream);
lseek(fp->fd, 0, SEEK_SET);
- fp->pos = 0;
- fp->ptr = NULL;
- fp->end = NULL;
+ fp->bufpos = 0;
+ fp->pos = 0;
+ fp->ptr = NULL;
+ fp->end = NULL;
while ((bytes = cups_fill(fp)) > 0)
- if (pos >= fp->pos && pos < (fp->pos + bytes))
+ if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
break;
if (bytes <= 0)
return (-1);
+
+ fp->ptr = fp->buf + pos - fp->bufpos;
+ fp->pos = pos;
}
else
#endif /* HAVE_LIBZ */
{
- fp->pos = lseek(fp->fd, pos, SEEK_SET);
- DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
- fp->ptr = NULL;
- fp->end = NULL;
+ fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
+ fp->pos = fp->bufpos;
+ fp->ptr = NULL;
+ fp->end = NULL;
+
+ DEBUG_printf(("cupsFileSeek: lseek() returned " CUPS_LLFMT "...\n",
+ CUPS_LLCAST fp->pos));
}
}
- else if (pos >= (fp->pos + bytes))
+ else
{
/*
* Need to seek forwards...
*/
+ DEBUG_puts("cupsFileSeek: SEEK FORWARDS");
+
#ifdef HAVE_LIBZ
if (fp->compressed)
{
while ((bytes = cups_fill(fp)) > 0)
- if (pos >= fp->pos && pos < (fp->pos + bytes))
+ {
+ if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
break;
+ }
if (bytes <= 0)
return (-1);
+
+ fp->ptr = fp->buf + pos - fp->bufpos;
+ fp->pos = pos;
}
else
#endif /* HAVE_LIBZ */
{
- fp->pos = lseek(fp->fd, pos, SEEK_SET);
- DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
- fp->ptr = NULL;
- fp->end = NULL;
+ fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
+ fp->pos = fp->bufpos;
+ fp->ptr = NULL;
+ fp->end = NULL;
+
+ DEBUG_printf(("cupsFileSeek: lseek() returned " CUPS_LLFMT "...\n",
+ CUPS_LLCAST fp->pos));
}
}
- else
+
+ DEBUG_printf(("cupsFileSeek: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ return (fp->pos);
+}
+
+
+/*
+ * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
+ *
+ * @since CUPS 1.2@
+ */
+
+cups_file_t * /* O - CUPS file */
+cupsFileStderr(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
+
+
+ /*
+ * Open file descriptor 2 as needed...
+ */
+
+ if (!cg->stdio_files[2])
{
/*
- * Just reposition the current pointer, since we have the right
- * range...
+ * Flush any pending output on the stdio file...
*/
- fp->ptr = fp->buf + pos - fp->pos;
- DEBUG_puts((" seek inside buffer..."));
+ fflush(stderr);
+
+ /*
+ * Open file descriptor 2...
+ */
+
+ if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
+ cg->stdio_files[2]->is_stdio = 1;
}
- return (fp->pos);
+ return (cg->stdio_files[2]);
+}
+
+
+/*
+ * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
+ *
+ * @since CUPS 1.2@
+ */
+
+cups_file_t * /* O - CUPS file */
+cupsFileStdin(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
+
+
+ /*
+ * Open file descriptor 0 as needed...
+ */
+
+ if (!cg->stdio_files[0])
+ {
+ /*
+ * Open file descriptor 0...
+ */
+
+ if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
+ cg->stdio_files[0]->is_stdio = 1;
+ }
+
+ return (cg->stdio_files[0]);
+}
+
+
+/*
+ * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
+ *
+ * @since CUPS 1.2@
+ */
+
+cups_file_t * /* O - CUPS file */
+cupsFileStdout(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
+
+
+ /*
+ * Open file descriptor 1 as needed...
+ */
+
+ if (!cg->stdio_files[1])
+ {
+ /*
+ * Flush any pending output on the stdio file...
+ */
+
+ fflush(stdout);
+
+ /*
+ * Open file descriptor 1...
+ */
+
+ if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
+ cg->stdio_files[1]->is_stdio = 1;
+ }
+
+ return (cg->stdio_files[1]);
}
/*
* 'cupsFileTell()' - Return the current file position.
+ *
+ * @since CUPS 1.2@
*/
off_t /* O - File position */
cupsFileTell(cups_file_t *fp) /* I - CUPS file */
{
- return (fp->pos);
+ DEBUG_printf(("cupsFileTell(fp=%p)\n", fp));
+ DEBUG_printf(("cupsFileTell: pos=" CUPS_LLFMT "\n", CUPS_LLCAST (fp ? fp->pos : -1)));
+
+ return (fp ? fp->pos : 0);
}
/*
* 'cupsFileUnlock()' - Unlock access to a file.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 0 on success, -1 on error */
-cupsFileUnlock(cups_file_t *fp) /* I - File to lock */
+cupsFileUnlock(cups_file_t *fp) /* I - CUPS file */
{
/*
* Range check...
*/
+ DEBUG_printf(("cupsFileUnlock(fp=%p)\n", fp));
+
if (!fp || fp->mode == 's')
return (-1);
/*
* 'cupsFileWrite()' - Write to a file.
+ *
+ * @since CUPS 1.2@
*/
-ssize_t /* O - Number of bytes written */
+ssize_t /* O - Number of bytes written or -1 on error */
cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
const char *buf, /* I - Buffer */
size_t bytes) /* I - Number of bytes to write */
* Range check input...
*/
+ DEBUG_printf(("cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n",
+ fp, buf, CUPS_LLCAST bytes));
+
if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
if (cups_write(fp, buf, bytes) < 0)
return (-1);
- fp->pos += bytes;
+ fp->pos += (off_t)bytes;
- return (bytes);
+ DEBUG_printf(("cupsFileWrite: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+
+ return ((ssize_t)bytes);
}
if ((fp->ptr + bytes) > fp->end)
if (cupsFileFlush(fp))
return (-1);
- fp->pos += bytes;
+ fp->pos += (off_t)bytes;
+
+ DEBUG_printf(("cupsFileWrite: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
if (bytes > sizeof(fp->buf))
{
{
memcpy(fp->ptr, buf, bytes);
fp->ptr += bytes;
- return (bytes);
+ return ((ssize_t)bytes);
}
}
const char *buf, /* I - Buffer */
size_t bytes) /* I - Number bytes */
{
+ DEBUG_printf(("cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT "\n", fp, buf,
+ CUPS_LLCAST bytes));
+
/*
* Update the CRC...
*/
* Flush the current buffer...
*/
+ DEBUG_printf(("cups_compress: avail_in=%d, avail_out=%d\n",
+ fp->stream.avail_in, fp->stream.avail_out));
+
if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
{
if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
return (-1);
+
+ fp->stream.next_out = fp->cbuf;
+ fp->stream.avail_out = sizeof(fp->cbuf);
}
deflate(&(fp->stream), Z_NO_FLUSH);
{
ssize_t bytes; /* Number of bytes read */
#ifdef HAVE_LIBZ
+ int status; /* Decompression status */
const unsigned char *ptr, /* Pointer into buffer */
*end; /* End of buffer */
#endif /* HAVE_LIBZ */
DEBUG_printf(("cups_fill(fp=%p)\n", fp));
- DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, fp->pos=%ld\n",
- fp->ptr, fp->end, fp->buf, (long)fp->pos));
-
- /*
- * Update the "pos" element as needed...
- */
+ DEBUG_printf(("cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, "
+ "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d\n",
+ fp->ptr, fp->end, fp->buf, CUPS_LLCAST fp->bufpos, fp->eof));
if (fp->ptr && fp->end)
- fp->pos += fp->end - fp->buf;
+ fp->bufpos += fp->end - fp->buf;
#ifdef HAVE_LIBZ
+ DEBUG_printf(("cups_fill: fp->compressed=%d\n", fp->compressed));
+
while (!fp->ptr || fp->compressed)
{
/*
*/
fp->compressed = 0;
- fp->pos = 0;
/*
* Read the first bytes in the file to determine if we have a gzip'd
* Can't read from file!
*/
+ DEBUG_printf(("cups_fill: cups_read() returned " CUPS_LLFMT "!\n",
+ CUPS_LLCAST bytes));
+
return (-1);
}
fp->ptr = fp->buf;
fp->end = fp->buf + bytes;
+ DEBUG_printf(("cups_fill: Returning " CUPS_LLFMT "!\n",
+ CUPS_LLCAST bytes));
+
return (bytes);
}
fp->stream.next_out = (Bytef *)fp->buf;
fp->stream.avail_out = sizeof(fp->buf);
- if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END)
+ status = inflate(&(fp->stream), Z_NO_FLUSH);
+
+ if (fp->stream.next_out > (Bytef *)fp->buf)
+ fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
+ fp->stream.next_out - (Bytef *)fp->buf);
+
+ if (status == Z_STREAM_END)
{
/*
* Read the CRC and length...
* Bad CRC, mark end-of-file...
*/
+ DEBUG_printf(("cups_fill: tcrc=%08x, fp->crc=%08x\n",
+ (unsigned int)tcrc, (unsigned int)fp->crc));
+
fp->eof = 1;
return (-1);
ssize_t total; /* Total bytes read */
+ DEBUG_printf(("cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+ CUPS_LLCAST bytes));
+
/*
* Loop until we read at least 0 bytes...
*/
for (;;)
{
+#ifdef WIN32
+ if (fp->mode == 's')
+ total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
+ else
+ total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
+#else
if (fp->mode == 's')
total = recv(fp->fd, buf, bytes, 0);
else
total = read(fp->fd, buf, bytes);
+#endif /* WIN32 */
+
+ DEBUG_printf(("cups_read: total=" CUPS_LLFMT "\n", CUPS_LLCAST total));
if (total >= 0)
break;
const char *buf, /* I - Buffer */
size_t bytes) /* I - Number bytes */
{
- size_t total, /* Total bytes written */
- count; /* Count this time */
+ size_t total; /* Total bytes written */
+ ssize_t count; /* Count this time */
+
+ DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+ CUPS_LLCAST bytes));
/*
* Loop until all bytes are written...
total = 0;
while (bytes > 0)
{
+#ifdef WIN32
+ if (fp->mode == 's')
+ count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
+ else
+ count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
+#else
if (fp->mode == 's')
count = send(fp->fd, buf, bytes, 0);
else
count = write(fp->fd, buf, bytes);
+#endif /* WIN32 */
+
+ DEBUG_printf(("cups_write: count=" CUPS_LLFMT "\n", CUPS_LLCAST count));
if (count < 0)
{
* Return the total number of bytes written...
*/
- return (total);
+ return ((ssize_t)total);
}
/*
- * End of "$Id: file.c 5057 2006-02-02 20:38:29Z mike $".
+ * End of "$Id: file.c 6962 2007-09-17 20:35:47Z mike $".
*/