/*
- * "$Id: file.c 7672 2008-06-18 22:03:02Z mike $"
+ * "$Id$"
*
- * File functions for the Common UNIX Printing System (CUPS).
+ * File functions for CUPS.
*
- * 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.
+ * 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.
*
- * Copyright 2007-2009 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2014 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/".
+ * 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/".
*
- * Contents:
- *
- * cupsFileClose() - Close a CUPS file.
- * cupsFileCompression() - Return whether a file is compressed.
- * cupsFileEOF() - Return the end-of-file status.
- * cupsFileFind() - Find a file using the specified path.
- * 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.
- * cupsFileOpen() - Open a CUPS file.
- * cupsFileOpenFd() - Open a CUPS file using a file descriptor.
- * cupsFilePeekChar() - Peek at the next character from a file.
- * cupsFilePrintf() - Write a formatted string.
- * cupsFilePutChar() - Write a character.
- * cupsFilePuts() - Write a string.
- * cupsFileRead() - Read from 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.
- * cups_compress() - Compress a buffer of data...
- * cups_fill() - Fill the input buffer...
- * cups_read() - Read from a file descriptor.
- * cups_write() - Write to a file descriptor.
+ * This file is subject to the Apple OS-Developed Software exception.
*/
/*
*/
#include "file-private.h"
+#include <sys/stat.h>
+#include <sys/types.h>
/*
static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
#endif /* HAVE_LIBZ */
static ssize_t cups_fill(cups_file_t *fp);
+static int cups_open(const char *filename, int mode);
static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
+#ifndef WIN32
+/*
+ * '_cupsFileCheck()' - Check the permissions of the given filename.
+ */
+
+_cups_fc_result_t /* O - Check result */
+_cupsFileCheck(
+ const char *filename, /* I - Filename to check */
+ _cups_fc_filetype_t filetype, /* I - Type of file checks? */
+ int dorootchecks, /* I - Check for root permissions? */
+ _cups_fc_func_t cb, /* I - Callback function */
+ void *context) /* I - Context pointer for callback */
+
+{
+ struct stat fileinfo; /* File information */
+ char message[1024], /* Message string */
+ temp[1024], /* Parent directory filename */
+ *ptr; /* Pointer into parent directory */
+ _cups_fc_result_t result; /* Check result */
+
+
+ /*
+ * Does the filename contain a relative path ("../")?
+ */
+
+ if (strstr(filename, "../"))
+ {
+ /*
+ * Yes, fail it!
+ */
+
+ result = _CUPS_FILE_CHECK_RELATIVE_PATH;
+ goto finishup;
+ }
+
+ /*
+ * Does the program even exist and is it accessible?
+ */
+
+ if (stat(filename, &fileinfo))
+ {
+ /*
+ * Nope...
+ */
+
+ result = _CUPS_FILE_CHECK_MISSING;
+ goto finishup;
+ }
+
+ /*
+ * Check the execute bit...
+ */
+
+ result = _CUPS_FILE_CHECK_OK;
+
+ switch (filetype)
+ {
+ case _CUPS_FILE_CHECK_DIRECTORY :
+ if (!S_ISDIR(fileinfo.st_mode))
+ result = _CUPS_FILE_CHECK_WRONG_TYPE;
+ break;
+
+ default :
+ if (!S_ISREG(fileinfo.st_mode))
+ result = _CUPS_FILE_CHECK_WRONG_TYPE;
+ break;
+ }
+
+ if (result)
+ goto finishup;
+
+ /*
+ * Are we doing root checks?
+ */
+
+ if (!dorootchecks)
+ {
+ /*
+ * Nope, so anything (else) goes...
+ */
+
+ goto finishup;
+ }
+
+ /*
+ * Verify permission of the file itself:
+ *
+ * 1. Must be owned by root
+ * 2. Must not be writable by group
+ * 3. Must not be setuid
+ * 4. Must not be writable by others
+ */
+
+ if (fileinfo.st_uid || /* 1. Must be owned by root */
+ (fileinfo.st_mode & S_IWGRP) || /* 2. Must not be writable by group */
+ (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
+ (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
+ {
+ result = _CUPS_FILE_CHECK_PERMISSIONS;
+ goto finishup;
+ }
+
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY ||
+ filetype == _CUPS_FILE_CHECK_FILE_ONLY)
+ goto finishup;
+
+ /*
+ * Now check the containing directory...
+ */
+
+ strlcpy(temp, filename, sizeof(temp));
+ if ((ptr = strrchr(temp, '/')) != NULL)
+ {
+ if (ptr == temp)
+ ptr[1] = '\0';
+ else
+ *ptr = '\0';
+ }
+
+ if (stat(temp, &fileinfo))
+ {
+ /*
+ * Doesn't exist?!?
+ */
+
+ result = _CUPS_FILE_CHECK_MISSING;
+ filetype = _CUPS_FILE_CHECK_DIRECTORY;
+ filename = temp;
+
+ goto finishup;
+ }
+
+ if (fileinfo.st_uid || /* 1. Must be owned by root */
+ (fileinfo.st_mode & S_IWGRP) || /* 2. Must not be writable by group */
+ (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
+ (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
+ {
+ result = _CUPS_FILE_CHECK_PERMISSIONS;
+ filetype = _CUPS_FILE_CHECK_DIRECTORY;
+ filename = temp;
+ }
+
+ /*
+ * Common return point...
+ */
+
+ finishup:
+
+ if (cb)
+ {
+ cups_lang_t *lang = cupsLangDefault();
+ /* Localization information */
+
+ switch (result)
+ {
+ case _CUPS_FILE_CHECK_OK :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" permissions OK "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" permissions OK "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ break;
+
+ case _CUPS_FILE_CHECK_MISSING :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" not available: "
+ "%s")),
+ filename, strerror(errno));
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" not available: %s")),
+ filename, strerror(errno));
+ break;
+
+ case _CUPS_FILE_CHECK_PERMISSIONS :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" has insecure "
+ "permissions "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" has insecure "
+ "permissions "
+ "(0%o/uid=%d/gid=%d).")),
+ filename, fileinfo.st_mode, (int)fileinfo.st_uid,
+ (int)fileinfo.st_gid);
+ break;
+
+ case _CUPS_FILE_CHECK_WRONG_TYPE :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" is a file.")),
+ filename);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" is a directory.")),
+ filename);
+ break;
+
+ case _CUPS_FILE_CHECK_RELATIVE_PATH :
+ if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("Directory \"%s\" contains a "
+ "relative path.")), filename);
+ else
+ snprintf(message, sizeof(message),
+ _cupsLangString(lang, _("File \"%s\" contains a relative "
+ "path.")), filename);
+ break;
+ }
+
+ (*cb)(context, result, message);
+ }
+
+ return (result);
+}
+
+
+/*
+ * '_cupsFileCheckFilter()' - Report file check results as CUPS filter messages.
+ */
+
+void
+_cupsFileCheckFilter(
+ void *context, /* I - Context pointer (unused) */
+ _cups_fc_result_t result, /* I - Result code */
+ const char *message) /* I - Message text */
+{
+ const char *prefix; /* Messaging prefix */
+
+
+ (void)context;
+
+ switch (result)
+ {
+ case _CUPS_FILE_CHECK_OK :
+ prefix = "DEBUG2";
+ break;
+
+ case _CUPS_FILE_CHECK_MISSING :
+ case _CUPS_FILE_CHECK_WRONG_TYPE :
+ prefix = "ERROR";
+ fputs("STATE: +cups-missing-filter-warning\n", stderr);
+ break;
+
+ case _CUPS_FILE_CHECK_PERMISSIONS :
+ case _CUPS_FILE_CHECK_RELATIVE_PATH :
+ prefix = "ERROR";
+ fputs("STATE: +cups-insecure-filter-warning\n", stderr);
+ break;
+ }
+
+ fprintf(stderr, "%s: %s\n", prefix, message);
+}
+#endif /* !WIN32 */
+
+
/*
* 'cupsFileClose()' - Close a CUPS file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - 0 on success, -1 on error */
if (fp->stream.next_out > fp->cbuf)
{
if (cups_write(fp, (char *)fp->cbuf,
- fp->stream.next_out - fp->cbuf) < 0)
+ (size_t)(fp->stream.next_out - fp->cbuf)) < 0)
status = -1;
fp->stream.next_out = fp->cbuf;
* Write the CRC and length...
*/
- trailer[0] = fp->crc;
- trailer[1] = fp->crc >> 8;
- trailer[2] = fp->crc >> 16;
- trailer[3] = fp->crc >> 24;
- trailer[4] = fp->pos;
- trailer[5] = fp->pos >> 8;
- trailer[6] = fp->pos >> 16;
- trailer[7] = fp->pos >> 24;
+ trailer[0] = (unsigned char)fp->crc;
+ trailer[1] = (unsigned char)(fp->crc >> 8);
+ trailer[2] = (unsigned char)(fp->crc >> 16);
+ trailer[3] = (unsigned char)(fp->crc >> 24);
+ trailer[4] = (unsigned char)fp->pos;
+ trailer[5] = (unsigned char)(fp->pos >> 8);
+ trailer[6] = (unsigned char)(fp->pos >> 16);
+ trailer[7] = (unsigned char)(fp->pos >> 24);
if (cups_write(fp, (char *)trailer, 8) < 0)
status = -1;
if (mode == 's')
{
- if (closesocket(fd) < 0)
+ if (httpAddrClose(NULL, fd) < 0)
status = -1;
}
else if (!is_stdio)
/*
* 'cupsFileCompression()' - Return whether a file is compressed.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
/*
* 'cupsFileEOF()' - Return the end-of-file status.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 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/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
const char * /* O - Full path to file or @code NULL@ if not found */
if (!access(filename, 0))
{
- strlcpy(buffer, filename, bufsize);
+ strlcpy(buffer, filename, (size_t)bufsize);
return (buffer);
}
else
if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
*bufptr++ = '/';
- strlcpy(bufptr, filename, bufend - bufptr);
+ strlcpy(bufptr, filename, (size_t)(bufend - bufptr));
#ifdef WIN32
if (!access(buffer, 0))
if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
*bufptr++ = '/';
- strlcpy(bufptr, filename, bufend - bufptr);
+ strlcpy(bufptr, filename, (size_t)(bufend - bufptr));
if (!access(buffer, 0))
{
/*
* 'cupsFileFlush()' - Flush pending output.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - 0 on success, -1 on error */
{
#ifdef HAVE_LIBZ
if (fp->compressed)
- bytes = cups_compress(fp, fp->buf, bytes);
+ bytes = cups_compress(fp, fp->buf, (size_t)bytes);
else
#endif /* HAVE_LIBZ */
- bytes = cups_write(fp, fp->buf, bytes);
+ bytes = cups_write(fp, fp->buf, (size_t)bytes);
if (bytes < 0)
return (-1);
fp->ptr = fp->buf;
}
-
+
return (0);
}
/*
* 'cupsFileGetChar()' - Get a single character from a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - Character or -1 on end of file */
if (!fp || (fp->mode != 'r' && fp->mode != 's'))
{
- DEBUG_puts("3cupsFileGetChar: Bad arguments!");
+ DEBUG_puts("5cupsFileGetChar: Bad arguments!");
return (-1);
}
if (fp->ptr >= fp->end)
if (cups_fill(fp) < 0)
{
- DEBUG_puts("3cupsFileGetChar: Unable to fill buffer!");
+ DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!");
return (-1);
}
* Return the next character in the buffer...
*/
- DEBUG_printf(("3cupsFileGetChar: Returning %d...", *(fp->ptr) & 255));
+ DEBUG_printf(("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255));
fp->pos ++;
- DEBUG_printf(("4cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+ DEBUG_printf(("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
return (*(fp->ptr)++ & 255);
}
/*
- * 'cupsFileGetConf()' - Get a line from a configuration file...
+ * 'cupsFileGetConf()' - Get a line from a configuration file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
char * /* O - Line read or @code NULL@ on end of file or error */
// Strip the comment and any trailing whitespace...
while (ptr > buf)
{
- if (!isspace(ptr[-1] & 255))
+ if (!_cups_isspace(ptr[-1]))
break;
ptr --;
* Strip leading whitespace...
*/
- for (ptr = buf; isspace(*ptr & 255); ptr ++);
+ for (ptr = buf; _cups_isspace(*ptr); ptr ++);
if (ptr > buf)
_cups_strcpy(buf, ptr);
*/
for (ptr = buf; *ptr; ptr ++)
- if (isspace(*ptr & 255))
+ if (_cups_isspace(*ptr))
break;
if (*ptr)
* Have a value, skip any other spaces...
*/
- while (isspace(*ptr & 255))
+ while (_cups_isspace(*ptr))
*ptr++ = '\0';
if (*ptr)
return (buf);
}
- while (ptr > *value && isspace(*ptr & 255))
+ while (ptr > *value && _cups_isspace(*ptr))
*ptr-- = '\0';
}
* nul-terminated, however you should use the returned length to determine
* the number of bytes on the line.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
size_t /* O - Number of bytes on line or 0 on end of file */
DEBUG_printf(("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
- return (ptr - buf);
+ return ((size_t)(ptr - buf));
}
/*
* 'cupsFileGets()' - Get a CR and/or LF-terminated line.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
char * /* O - Line read or @code NULL@ on end of file or error */
break;
}
else
- *ptr++ = ch;
+ *ptr++ = (char)ch;
}
*ptr = '\0';
/*
* 'cupsFileLock()' - Temporarily lock access to a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - 0 on success, -1 on error */
*/
#ifdef WIN32
- return (locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
+ return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
#else
return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
#endif /* WIN32 */
/*
* 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - File descriptor */
* connection as needed, generally preferring IPv6 connections when there is
* a choice.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
switch (*mode)
{
case 'a' : /* Append file */
- fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
+ fd = cups_open(filename,
+ O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY);
break;
case 'r' : /* Read file */
break;
case 'w' : /* Write file */
- fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
+ fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
+ if (fd < 0 && errno == ENOENT)
+ {
+ fd = cups_open(filename,
+ O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY);
+ if (fd < 0 && errno == EEXIST)
+ fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
+ }
+
+ if (fd >= 0)
+#ifdef WIN32
+ _chsize(fd, 0);
+#else
+ ftruncate(fd, 0);
+#endif /* WIN32 */
break;
case 's' : /* Read/write socket */
if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
{
if (*mode == 's')
- closesocket(fd);
+ httpAddrClose(NULL, fd);
else
close(fd);
}
* supplied which enables Flate compression of the file. Compression is
* not supported for the "a" (append) mode.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */
header[1] = 0x8b;
header[2] = Z_DEFLATED;
header[3] = 0;
- header[4] = curtime;
- header[5] = curtime >> 8;
- header[6] = curtime >> 16;
- header[7] = curtime >> 24;
+ header[4] = (unsigned char)curtime;
+ header[5] = (unsigned char)(curtime >> 8);
+ header[6] = (unsigned char)(curtime >> 16);
+ header[7] = (unsigned char)(curtime >> 24);
header[8] = 0;
header[9] = 0x03;
/*
* 'cupsFilePeekChar()' - Peek at the next character from a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - Character or -1 on end of file */
/*
* 'cupsFilePrintf()' - Write a formatted string.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - Number of bytes written or -1 on error */
bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
va_end(ap);
- if (bytes >= fp->printf_size)
+ if (bytes >= (ssize_t)fp->printf_size)
{
/*
* Expand the printf buffer...
if (bytes > 65535)
return (-1);
- if ((temp = realloc(fp->printf_buffer, bytes + 1)) == NULL)
+ if ((temp = realloc(fp->printf_buffer, (size_t)(bytes + 1))) == NULL)
return (-1);
fp->printf_buffer = temp;
- fp->printf_size = bytes + 1;
+ fp->printf_size = (size_t)(bytes + 1);
va_start(ap, format);
bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
if (fp->mode == 's')
{
- if (cups_write(fp, fp->printf_buffer, bytes) < 0)
+ if (cups_write(fp, fp->printf_buffer, (size_t)bytes) < 0)
return (-1);
fp->pos += bytes;
DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
- return (bytes);
+ return ((int)bytes);
}
if ((fp->ptr + bytes) > fp->end)
DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
- if (bytes > sizeof(fp->buf))
+ if ((size_t)bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
if (fp->compressed)
- return (cups_compress(fp, fp->printf_buffer, bytes));
+ return ((int)cups_compress(fp, fp->printf_buffer, (size_t)bytes));
else
#endif /* HAVE_LIBZ */
- return (cups_write(fp, fp->printf_buffer, bytes));
+ return ((int)cups_write(fp, fp->printf_buffer, (size_t)bytes));
}
else
{
- memcpy(fp->ptr, fp->printf_buffer, bytes);
+ memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
fp->ptr += bytes;
- return (bytes);
+ return ((int)bytes);
}
}
/*
* 'cupsFilePutChar()' - Write a character.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - 0 on success, -1 on error */
char ch; /* Output character */
- ch = c;
+ ch = (char)c;
if (send(fp->fd, &ch, 1, 0) < 1)
return (-1);
if (cupsFileFlush(fp))
return (-1);
- *(fp->ptr) ++ = c;
+ *(fp->ptr) ++ = (char)c;
}
fp->pos ++;
*
* This function handles any comment escaping of the value.
*
- * @since CUPS 1.4@
+ * @since CUPS 1.4/OS X 10.6@
*/
ssize_t /* O - Number of bytes written or -1 on error */
* Need to quote the first # in the info string...
*/
- if ((temp = cupsFileWrite(fp, value, ptr - value)) < 0)
+ if ((temp = cupsFileWrite(fp, value, (size_t)(ptr - value))) < 0)
return (-1);
bytes += temp;
*
* Like the @code fputs@ function, no newline is appended to the string.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - Number of bytes written or -1 on error */
* Write the string...
*/
- bytes = (int)strlen(s);
+ bytes = (ssize_t)strlen(s);
if (fp->mode == 's')
{
- if (cups_write(fp, s, bytes) < 0)
+ if (cups_write(fp, s, (size_t)bytes) < 0)
return (-1);
fp->pos += bytes;
DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
- return (bytes);
+ return ((int)bytes);
}
if ((fp->ptr + bytes) > fp->end)
DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
- if (bytes > sizeof(fp->buf))
+ if ((size_t)bytes > sizeof(fp->buf))
{
#ifdef HAVE_LIBZ
if (fp->compressed)
- return (cups_compress(fp, s, bytes));
+ return ((int)cups_compress(fp, s, (size_t)bytes));
else
#endif /* HAVE_LIBZ */
- return (cups_write(fp, s, bytes));
+ return ((int)cups_write(fp, s, (size_t)bytes));
}
else
{
- memcpy(fp->ptr, s, bytes);
+ memcpy(fp->ptr, s, (size_t)bytes);
fp->ptr += bytes;
- return (bytes);
+ return ((int)bytes);
}
}
/*
* 'cupsFileRead()' - Read from a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
ssize_t /* O - Number of bytes read or -1 on error */
* Range check input...
*/
- if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's'))
+ if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
return (-1);
if (bytes == 0)
if (count > (ssize_t)bytes)
count = (ssize_t)bytes;
- memcpy(buf, fp->ptr, count);
+ memcpy(buf, fp->ptr,(size_t) count);
fp->ptr += count;
fp->pos += count;
* Update the counts for the last read...
*/
- bytes -= count;
- total += count;
+ bytes -= (size_t)count;
+ total += (size_t)count;
buf += count;
}
* 'cupsFileRewind()' - Set the current file position to the beginning of the
* file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
off_t /* O - New file position or -1 on error */
/*
* 'cupsFileSeek()' - Seek in a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
off_t /* O - New file position or -1 on error */
/*
* 'cupsFileStderr()' - Return a CUPS file associated with stderr.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
cups_file_t * /* O - CUPS file */
/*
* 'cupsFileStdin()' - Return a CUPS file associated with stdin.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
cups_file_t * /* O - CUPS file */
/*
* 'cupsFileStdout()' - Return a CUPS file associated with stdout.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
cups_file_t * /* O - CUPS file */
/*
* 'cupsFileTell()' - Return the current file position.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
off_t /* O - File position */
/*
* 'cupsFileUnlock()' - Unlock access to a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
int /* O - 0 on success, -1 on error */
*/
#ifdef WIN32
- return (locking(fp->fd, _LK_UNLCK, 0));
+ return (_locking(fp->fd, _LK_UNLCK, 0));
#else
return (lockf(fp->fd, F_ULOCK, 0));
#endif /* WIN32 */
/*
* 'cupsFileWrite()' - Write to a file.
*
- * @since CUPS 1.2/Mac OS X 10.5@
+ * @since CUPS 1.2/OS X 10.5@
*/
ssize_t /* O - Number of bytes written or -1 on error */
DEBUG_printf(("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")",
fp, buf, CUPS_LLCAST bytes));
- if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
+ if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
return (-1);
if (bytes == 0)
#ifdef HAVE_LIBZ
/*
- * 'cups_compress()' - Compress a buffer of data...
+ * 'cups_compress()' - Compress a buffer of data.
*/
static ssize_t /* O - Number of bytes written or -1 */
* Update the CRC...
*/
- fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
+ fp->crc = crc32(fp->crc, (const Bytef *)buf, (uInt)bytes);
/*
* Deflate the bytes...
*/
fp->stream.next_in = (Bytef *)buf;
- fp->stream.avail_in = bytes;
+ fp->stream.avail_in = (uInt)bytes;
while (fp->stream.avail_in > 0)
{
DEBUG_printf(("9cups_compress: avail_in=%d, avail_out=%d",
fp->stream.avail_in, fp->stream.avail_out));
- if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
+ if (fp->stream.avail_out < (uInt)(sizeof(fp->cbuf) / 8))
{
- if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
+ if (cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)) < 0)
return (-1);
fp->stream.next_out = fp->cbuf;
deflate(&(fp->stream), Z_NO_FLUSH);
}
- return (bytes);
+ return ((ssize_t)bytes);
}
#endif /* HAVE_LIBZ */
/*
- * 'cups_fill()' - Fill the input buffer...
+ * 'cups_fill()' - Fill the input buffer.
*/
static ssize_t /* O - Number of bytes or -1 */
*/
if ((bytes = end - ptr) > 0)
- memcpy(fp->cbuf, ptr, bytes);
+ memcpy(fp->cbuf, ptr, (size_t)bytes);
/*
* Setup the decompressor data...
fp->stream.opaque = (voidpf)0;
fp->stream.next_in = (Bytef *)fp->cbuf;
fp->stream.next_out = NULL;
- fp->stream.avail_in = bytes;
+ fp->stream.avail_in = (uInt)bytes;
fp->stream.avail_out = 0;
fp->crc = crc32(0L, Z_NULL, 0);
return (-1);
fp->stream.next_in = fp->cbuf;
- fp->stream.avail_in = bytes;
+ fp->stream.avail_in = (uInt)bytes;
}
/*
if (fp->stream.next_out > (Bytef *)fp->buf)
fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
- fp->stream.next_out - (Bytef *)fp->buf);
+ (uInt)(fp->stream.next_out - (Bytef *)fp->buf));
if (status == Z_STREAM_END)
{
uLong tcrc; /* Trailer CRC */
- if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
+ if (read(fp->fd, trailer, sizeof(trailer)) < (ssize_t)sizeof(trailer))
{
/*
* Can't get it, so mark end-of-file...
}
else
{
- tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
- trailer[0];
+ tcrc = ((((((uLong)trailer[3] << 8) | (uLong)trailer[2]) << 8) |
+ (uLong)trailer[1]) << 8) | (uLong)trailer[0];
if (tcrc != fp->crc)
{
* Bad CRC, mark end-of-file...
*/
- DEBUG_printf(("9cups_fill: tcrc=%08x, fp->crc=%08x",
+ DEBUG_printf(("9cups_fill: tcrc=%08x != fp->crc=%08x",
(unsigned int)tcrc, (unsigned int)fp->crc));
fp->eof = 1;
}
}
- bytes = sizeof(fp->buf) - fp->stream.avail_out;
+ bytes = (ssize_t)sizeof(fp->buf) - (ssize_t)fp->stream.avail_out;
/*
* Return the decompressed data...
}
+/*
+ * 'cups_open()' - Safely open a file for writing.
+ *
+ * We don't allow appending to directories or files that are hard-linked or
+ * symlinked.
+ */
+
+static int /* O - File descriptor or -1 otherwise */
+cups_open(const char *filename, /* I - Filename */
+ int mode) /* I - Open mode */
+{
+ int fd; /* File descriptor */
+ struct stat fileinfo; /* File information */
+#ifndef WIN32
+ struct stat linkinfo; /* Link information */
+#endif /* !WIN32 */
+
+
+ /*
+ * Open the file...
+ */
+
+ if ((fd = open(filename, mode, 0666)) < 0)
+ return (-1);
+
+ /*
+ * Then verify that the file descriptor doesn't point to a directory or hard-
+ * linked file.
+ */
+
+ if (fstat(fd, &fileinfo))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ if (fileinfo.st_nlink != 1)
+ {
+ close(fd);
+ errno = EPERM;
+ return (-1);
+ }
+
+#ifdef WIN32
+ if (fileinfo.st_mode & _S_IFDIR)
+#else
+ if (S_ISDIR(fileinfo.st_mode))
+#endif /* WIN32 */
+ {
+ close(fd);
+ errno = EISDIR;
+ return (-1);
+ }
+
+#ifndef WIN32
+ /*
+ * Then use lstat to determine whether the filename is a symlink...
+ */
+
+ if (lstat(filename, &linkinfo))
+ {
+ close(fd);
+ return (-1);
+ }
+
+ if (S_ISLNK(linkinfo.st_mode) ||
+ fileinfo.st_dev != linkinfo.st_dev ||
+ fileinfo.st_ino != linkinfo.st_ino ||
+#ifdef HAVE_ST_GEN
+ fileinfo.st_gen != linkinfo.st_gen ||
+#endif /* HAVE_ST_GEN */
+ fileinfo.st_nlink != linkinfo.st_nlink ||
+ fileinfo.st_mode != linkinfo.st_mode)
+ {
+ /*
+ * Yes, don't allow!
+ */
+
+ close(fd);
+ errno = EPERM;
+ return (-1);
+ }
+#endif /* !WIN32 */
+
+ return (fd);
+}
+
+
/*
* 'cups_read()' - Read from a file descriptor.
*/
* Update the counts for the last write call...
*/
- bytes -= count;
- total += count;
+ bytes -= (size_t)count;
+ total += (size_t)count;
buf += count;
}
/*
- * End of "$Id: file.c 7672 2008-06-18 22:03:02Z mike $".
+ * End of "$Id$".
*/