* Since stdio files max out at 256 files on many systems, we have to
* write similar functions without this limit. At the same time, using
* our own file functions allows us to provide transparent support of
- * gzip'd print files, PPD files, etc.
+ * different line endings, gzip'd print files, PPD files, etc.
*
- * Copyright 2007-2015 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright © 2007-2019 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
*
- * These coded instructions, statements, and computer programs are the
- * 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/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
*/
#include "file-private.h"
+#include "debug-internal.h"
#include <sys/stat.h>
#include <sys/types.h>
+# ifdef HAVE_LIBZ
+# include <zlib.h>
+# endif /* HAVE_LIBZ */
+
+
+/*
+ * Internal structures...
+ */
+
+struct _cups_file_s /**** CUPS file structure... ****/
+
+{
+ 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, /* Position in file */
+ bufpos; /* File position for start of buffer */
+
+#ifdef HAVE_LIBZ
+ z_stream stream; /* (De)compression stream */
+ Bytef cbuf[4096]; /* (De)compression buffer */
+ uLong crc; /* (De)compression CRC */
+#endif /* HAVE_LIBZ */
+
+ char *printf_buffer; /* cupsFilePrintf buffer */
+ size_t printf_size; /* Size of cupsFilePrintf buffer */
+};
+
/*
* Local functions...
static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
-#ifndef WIN32
+#ifndef _WIN32
/*
* '_cupsFileCheck()' - Check the permissions of the given filename.
*/
fprintf(stderr, "%s: %s\n", prefix, message);
}
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
* 'cupsFileClose()' - Close a CUPS file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
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)", (void *)fp));
#endif /* HAVE_LIBZ */
/*
+ * If this is one of the cupsFileStdin/out/err files, return now and don't
+ * actually free memory or close (these last the life of the process...)
+ */
+
+ if (fp->is_stdio)
+ return (status);
+
+/*
* Save the file descriptor we used and free memory...
*/
- fd = fp->fd;
- mode = fp->mode;
- is_stdio = fp->is_stdio;
+ fd = fp->fd;
+ mode = fp->mode;
if (fp->printf_buffer)
free(fp->printf_buffer);
if (httpAddrClose(NULL, fd) < 0)
status = -1;
}
- else if (!is_stdio)
- {
- if (close(fd) < 0)
- status = -1;
- }
+ else if (close(fd) < 0)
+ status = -1;
return (status);
}
/*
* 'cupsFileCompression()' - Return whether a file is compressed.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
/*
* 'cupsFileEOF()' - Return the end-of-file status.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - 1 on end of file, 0 otherwise */
* the supplied paths, @code NULL@ is returned. A @code NULL@ path only
* matches the current directory.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
const char * /* O - Full path to file or @code NULL@ if not found */
while (*path)
{
-#ifdef WIN32
+#ifdef _WIN32
if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
#else
if (*path == ';' || *path == ':')
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
*bufptr++ = '/';
strlcpy(bufptr, filename, (size_t)(bufend - bufptr));
-#ifdef WIN32
+#ifdef _WIN32
if (!access(buffer, 0))
#else
if (!access(buffer, executable ? X_OK : 0))
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
return (buffer);
/*
* 'cupsFileFlush()' - Flush pending output.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - 0 on success, -1 on error */
/*
* 'cupsFileGetChar()' - Get a single character from a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - Character or -1 on end of file */
return (-1);
}
+ if (fp->eof)
+ {
+ DEBUG_puts("5cupsFileGetChar: End-of-file!");
+ return (-1);
+ }
+
/*
* If the input buffer is empty, try to read more data...
*/
/*
* 'cupsFileGetConf()' - Get a line from a configuration file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
char * /* O - Line read or @code NULL@ on end of file or error */
* nul-terminated, however you should use the returned length to determine
* the number of bytes on the line.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
size_t /* O - Number of bytes on line or 0 on end of file */
/*
* 'cupsFileGets()' - Get a CR and/or LF-terminated line.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
char * /* O - Line read or @code NULL@ on end of file or error */
/*
* 'cupsFileLock()' - Temporarily lock access to a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - 0 on success, -1 on error */
* Try the lock...
*/
-#ifdef WIN32
+#ifdef _WIN32
return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
#else
return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
/*
* 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - File descriptor */
* connection as needed, generally preferring IPv6 connections when there is
* a choice.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
}
if (fd >= 0)
-#ifdef WIN32
+#ifdef _WIN32
_chsize(fd, 0);
#else
ftruncate(fd, 0);
-#endif /* WIN32 */
+#endif /* _WIN32 */
break;
case 's' : /* Read/write socket */
* supplied which enables Flate compression of the file. Compression is
* not supported for the "a" (append) mode.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */
* Don't pass this file to child processes...
*/
-#ifndef WIN32
+#ifndef _WIN32
fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
return (fp);
}
+/*
+ * '_cupsFilePeekAhead()' - See if the requested character is buffered up.
+ */
+
+int /* O - 1 if present, 0 otherwise */
+_cupsFilePeekAhead(cups_file_t *fp, /* I - CUPS file */
+ int ch) /* I - Character */
+{
+ return (fp && fp->ptr && memchr(fp->ptr, ch, (size_t)(fp->end - fp->ptr)));
+}
+
+
/*
* 'cupsFilePeekChar()' - Peek at the next character from a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - Character or -1 on end of file */
/*
* 'cupsFilePrintf()' - Write a formatted string.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - Number of bytes written or -1 on error */
{
memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
fp->ptr += bytes;
- return ((int)bytes);
+
+ if (fp->is_stdio && cupsFileFlush(fp))
+ return (-1);
+ else
+ return ((int)bytes);
}
}
/*
* 'cupsFilePutChar()' - Write a character.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - 0 on success, -1 on error */
*
* This function handles any comment escaping of the value.
*
- * @since CUPS 1.4/OS X 10.6@
+ * @since CUPS 1.4/macOS 10.6@
*/
ssize_t /* O - Number of bytes written or -1 on error */
*
* Like the @code fputs@ function, no newline is appended to the string.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - Number of bytes written or -1 on error */
{
memcpy(fp->ptr, s, (size_t)bytes);
fp->ptr += bytes;
- return ((int)bytes);
+
+ if (fp->is_stdio && cupsFileFlush(fp))
+ return (-1);
+ else
+ return ((int)bytes);
}
}
/*
* 'cupsFileRead()' - Read from a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
ssize_t /* O - Number of bytes read or -1 on error */
if (bytes == 0)
return (0);
+ if (fp->eof)
+ {
+ DEBUG_puts("5cupsFileRead: End-of-file!");
+ return (-1);
+ }
+
/*
* Loop until all bytes are read...
*/
* 'cupsFileRewind()' - Set the current file position to the beginning of the
* file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
off_t /* O - New file position or -1 on error */
/*
* 'cupsFileSeek()' - Seek in a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
off_t /* O - New file position or -1 on error */
/*
* 'cupsFileStderr()' - Return a CUPS file associated with stderr.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
cups_file_t * /* O - CUPS file */
/*
* 'cupsFileStdin()' - Return a CUPS file associated with stdin.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
cups_file_t * /* O - CUPS file */
/*
* 'cupsFileStdout()' - Return a CUPS file associated with stdout.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
cups_file_t * /* O - CUPS file */
/*
* 'cupsFileTell()' - Return the current file position.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
off_t /* O - File position */
/*
* 'cupsFileUnlock()' - Unlock access to a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
int /* O - 0 on success, -1 on error */
* Unlock...
*/
-#ifdef WIN32
+#ifdef _WIN32
return (_locking(fp->fd, _LK_UNLCK, 0));
#else
return (lockf(fp->fd, F_ULOCK, 0));
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
/*
* 'cupsFileWrite()' - Write to a file.
*
- * @since CUPS 1.2/OS X 10.5@
+ * @since CUPS 1.2/macOS 10.5@
*/
ssize_t /* O - Number of bytes written or -1 on error */
* file header...
*/
+ inflateEnd(&fp->stream);
+
fp->compressed = 0;
}
else if (status < Z_OK)
{
int fd; /* File descriptor */
struct stat fileinfo; /* File information */
-#ifndef WIN32
+#ifndef _WIN32
struct stat linkinfo; /* Link information */
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
/*
return (-1);
}
-#ifdef WIN32
+#ifdef _WIN32
if (fileinfo.st_mode & _S_IFDIR)
#else
if (S_ISDIR(fileinfo.st_mode))
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
close(fd);
errno = EISDIR;
return (-1);
}
-#ifndef WIN32
+#ifndef _WIN32
/*
* Then use lstat to determine whether the filename is a symlink...
*/
errno = EPERM;
return (-1);
}
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
return (fd);
}
for (;;)
{
-#ifdef WIN32
+#ifdef _WIN32
if (fp->mode == 's')
total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
else
total = recv(fp->fd, buf, bytes, 0);
else
total = read(fp->fd, buf, bytes);
-#endif /* WIN32 */
+#endif /* _WIN32 */
DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total));
total = 0;
while (bytes > 0)
{
-#ifdef WIN32
+#ifdef _WIN32
if (fp->mode == 's')
count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
else
count = send(fp->fd, buf, bytes, 0);
else
count = write(fp->fd, buf, bytes);
-#endif /* WIN32 */
+#endif /* _WIN32 */
DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count));