]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/file.c
Merge changes from CUPS 1.6svn-r10002
[thirdparty/cups.git] / cups / file.c
index d3726cf53448e4513f1e5dbff484dffb61537c63..2711e56800fef4f7031a27eaa3bee78f3bd1e302 100644 (file)
@@ -1,14 +1,14 @@
 /*
- * "$Id: file.c 6962 2007-09-17 20:35:47Z mike $"
+ * "$Id: file.c 7672 2008-06-18 22:03:02Z mike $"
  *
- *   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.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2011 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *
  * 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.
+ *   _cupsFileCheck()       - Check the permissions of the given filename.
+ *   _cupsFileCheckFilter() - Report file check results as CUPS filter messages.
+ *   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.
+ *   cupsFilePutConf()      - Write a configuration line.
+ *   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_open()            - Safely open a file for writing.
+ *   cups_read()            - Read from a file descriptor.
+ *   cups_write()           - Write to a file descriptor.
  */
 
 /*
  * Include necessary headers...
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
+#include "file-private.h"
+#include <sys/stat.h>
 #include <sys/types.h>
-#include <fcntl.h>
-#include "http-private.h"
-#include "globals.h"
-#include "debug.h"
+
+
+/*
+ * Local functions...
+ */
 
 #ifdef HAVE_LIBZ
-#  include <zlib.h>
+static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
 #endif /* HAVE_LIBZ */
-#ifdef WIN32
-#  include <io.h>
-#  include <sys/locking.h>
-#endif /* WIN32 */
+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
 /*
- * Some operating systems support large files via open flag O_LARGEFILE...
+ * '_cupsFileCheck()' - Check the permissions of the given filename.
  */
 
-#ifndef O_LARGEFILE
-#  define O_LARGEFILE 0
-#endif /* !O_LARGEFILE */
+_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 */
 
-/*
- * 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 */
+ /*
+  * Does the filename contain a relative path ("../")?
+  */
 
+  if (strstr(filename, "../"))
+  {
+   /*
+    * Yes, fail it!
+    */
 
-/*
- * Types and structures...
- */
+    result = _CUPS_FILE_CHECK_RELATIVE_PATH;
+    goto finishup;
+  }
 
-struct _cups_file_s                    /**** CUPS file structure... ****/
+ /*
+  * Does the program even exist and is it accessible?
+  */
 
-{
-  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 */
+  if (stat(filename, &fileinfo))
+  {
+   /*
+    * Nope...
+    */
 
-#ifdef HAVE_LIBZ
-  z_stream     stream;                 /* (De)compression stream */
-  Bytef                cbuf[4096];             /* (De)compression buffer */
-  uLong                crc;                    /* (De)compression CRC */
-#endif /* HAVE_LIBZ */
-};
+    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);
+}
 
 
 /*
- * Local functions...
+ * '_cupsFileCheckFilter()' - Report file check results as CUPS filter messages.
  */
 
-#ifdef HAVE_LIBZ
-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 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);
+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)
+  {
+    default :
+    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@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -149,7 +364,7 @@ cupsFileClose(cups_file_t *fp)              /* I - CUPS file */
   int  is_stdio;                       /* Is a stdio file? */
 
 
-  DEBUG_printf(("cupsFileClose(fp=%p)\n", fp));
+  DEBUG_printf(("cupsFileClose(fp=%p)", fp));
 
  /*
   * Range check...
@@ -242,6 +457,9 @@ cupsFileClose(cups_file_t *fp)              /* I - CUPS file */
   mode     = fp->mode;
   is_stdio = fp->is_stdio;
 
+  if (fp->printf_buffer)
+    free(fp->printf_buffer);
+
   free(fp);
 
  /*
@@ -266,7 +484,7 @@ cupsFileClose(cups_file_t *fp)              /* I - CUPS file */
 /*
  * 'cupsFileCompression()' - Return whether a file is compressed.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
@@ -279,7 +497,7 @@ cupsFileCompression(cups_file_t *fp)        /* I - CUPS file */
 /*
  * 'cupsFileEOF()' - Return the end-of-file status.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - 1 on end of file, 0 otherwise */
@@ -298,7 +516,7 @@ cupsFileEOF(cups_file_t *fp)                /* I - CUPS file */
  * the supplied paths, @code NULL@ is returned. A @code NULL@ path only
  * matches the current directory.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 const char *                           /* O - Full path to file or @code NULL@ if not found */
@@ -316,6 +534,10 @@ cupsFileFind(const char *filename, /* I - File to find */
   * Range check input...
   */
 
+  DEBUG_printf(("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, "
+                "buffer=%p, bufsize=%d)", filename, path, executable, buffer,
+               bufsize));
+
   if (!filename || !buffer || bufsize < 2)
     return (NULL);
 
@@ -360,7 +582,7 @@ cupsFileFind(const char *filename,  /* I - File to find */
       if (!access(buffer, executable ? X_OK : 0))
 #endif /* WIN32 */
       {
-        DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
+        DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
         return (buffer);
       }
 
@@ -383,12 +605,12 @@ cupsFileFind(const char *filename,        /* I - File to find */
 
   if (!access(buffer, 0))
   {
-    DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
+    DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
     return (buffer);
   }
   else
   {
-    DEBUG_puts("cupsFileFind: Returning NULL");
+    DEBUG_puts("1cupsFileFind: Returning NULL");
     return (NULL);
   }
 }
@@ -397,7 +619,7 @@ cupsFileFind(const char *filename,  /* I - File to find */
 /*
  * 'cupsFileFlush()' - Flush pending output.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -406,7 +628,7 @@ cupsFileFlush(cups_file_t *fp)              /* I - CUPS file */
   ssize_t      bytes;                  /* Bytes to write */
 
 
-  DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp));
+  DEBUG_printf(("cupsFileFlush(fp=%p)", fp));
 
  /*
   * Range check input...
@@ -414,13 +636,13 @@ cupsFileFlush(cups_file_t *fp)            /* I - CUPS file */
 
   if (!fp || fp->mode != 'w')
   {
-    DEBUG_puts("cupsFileFlush: Attempt to flush a read-only file...");
+    DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file...");
     return (-1);
   }
 
   bytes = (ssize_t)(fp->ptr - fp->buf);
 
-  DEBUG_printf(("cupsFileFlush: Flushing " CUPS_LLFMT " bytes...\n",
+  DEBUG_printf(("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...",
                 CUPS_LLCAST bytes));
 
   if (bytes > 0)
@@ -437,7 +659,7 @@ cupsFileFlush(cups_file_t *fp)              /* I - CUPS file */
 
     fp->ptr = fp->buf;
   }
-   
+
   return (0);
 }
 
@@ -445,7 +667,7 @@ cupsFileFlush(cups_file_t *fp)              /* I - CUPS file */
 /*
  * 'cupsFileGetChar()' - Get a single character from a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - Character or -1 on end of file */
@@ -455,11 +677,9 @@ 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!");
+    DEBUG_puts("5cupsFileGetChar: Bad arguments!");
     return (-1);
   }
 
@@ -470,7 +690,7 @@ cupsFileGetChar(cups_file_t *fp)    /* I - CUPS file */
   if (fp->ptr >= fp->end)
     if (cups_fill(fp) < 0)
     {
-      DEBUG_puts("cupsFileGetChar: Unable to fill buffer!");
+      DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!");
       return (-1);
     }
 
@@ -478,20 +698,20 @@ cupsFileGetChar(cups_file_t *fp)  /* I - CUPS file */
   * Return the next character in the buffer...
   */
 
-  DEBUG_printf(("cupsFileGetChar: Returning %d...\n", *(fp->ptr) & 255));
+  DEBUG_printf(("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255));
 
   fp->pos ++;
 
-  DEBUG_printf(("cupsFileGetChar: pos=" CUPS_LLFMT "\n", 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@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 char *                                 /* O  - Line read or @code NULL@ on end of file or error */
@@ -508,8 +728,8 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
   * Range check input...
   */
 
-  DEBUG_printf(("cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
-                ", value=%p, linenum=%p)\n", fp, buf, CUPS_LLCAST buflen,
+  DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
+                ", value=%p, linenum=%p)", fp, buf, CUPS_LLCAST buflen,
                value, linenum));
 
   if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
@@ -547,7 +767,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
         // Strip the comment and any trailing whitespace...
        while (ptr > buf)
        {
-         if (!isspace(ptr[-1] & 255))
+         if (!_cups_isspace(ptr[-1]))
            break;
 
          ptr --;
@@ -561,7 +781,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
     * Strip leading whitespace...
     */
 
-    for (ptr = buf; isspace(*ptr & 255); ptr ++);
+    for (ptr = buf; _cups_isspace(*ptr); ptr ++);
 
     if (ptr > buf)
       _cups_strcpy(buf, ptr);
@@ -577,7 +797,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
       */
 
       for (ptr = buf; *ptr; ptr ++)
-        if (isspace(*ptr & 255))
+        if (_cups_isspace(*ptr))
          break;
 
       if (*ptr)
@@ -586,7 +806,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
         * Have a value, skip any other spaces...
        */
 
-        while (isspace(*ptr & 255))
+        while (_cups_isspace(*ptr))
          *ptr++ = '\0';
 
         if (*ptr)
@@ -610,7 +830,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
          return (buf);
        }
 
-        while (ptr > *value && isspace(*ptr & 255))
+        while (ptr > *value && _cups_isspace(*ptr))
          *ptr-- = '\0';
       }
 
@@ -635,7 +855,7 @@ cupsFileGetConf(cups_file_t *fp,    /* I  - CUPS file */
  * nul-terminated, however you should use the returned length to determine
  * the number of bytes on the line.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 size_t                                 /* O - Number of bytes on line or 0 on end of file */
@@ -652,7 +872,7 @@ cupsFileGetLine(cups_file_t *fp,    /* I - File to read from */
   * Range check input...
   */
 
-  DEBUG_printf(("cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")\n",
+  DEBUG_printf(("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")",
                 fp, buf, CUPS_LLCAST buflen));
 
   if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
@@ -701,7 +921,7 @@ cupsFileGetLine(cups_file_t *fp,    /* I - File to read from */
 
   *ptr = '\0';
 
-  DEBUG_printf(("cupsFileGetLine: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   return (ptr - buf);
 }
@@ -710,7 +930,7 @@ cupsFileGetLine(cups_file_t *fp,    /* I - File to read from */
 /*
  * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 char *                                 /* O - Line read or @code NULL@ on end of file or error */
@@ -727,7 +947,7 @@ cupsFileGets(cups_file_t *fp,               /* I - CUPS file */
   * Range check input...
   */
 
-  DEBUG_printf(("cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")\n", fp, buf,
+  DEBUG_printf(("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", fp, buf,
                 CUPS_LLCAST buflen));
 
   if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
@@ -783,7 +1003,7 @@ cupsFileGets(cups_file_t *fp,              /* I - CUPS file */
 
   *ptr = '\0';
 
-  DEBUG_printf(("cupsFileGets: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("4cupsFileGets: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   return (buf);
 }
@@ -792,7 +1012,7 @@ cupsFileGets(cups_file_t *fp,              /* I - CUPS file */
 /*
  * 'cupsFileLock()' - Temporarily lock access to a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -811,7 +1031,7 @@ cupsFileLock(cups_file_t *fp,              /* I - CUPS file */
   */
 
 #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 */
@@ -821,7 +1041,7 @@ cupsFileLock(cups_file_t *fp,              /* I - CUPS file */
 /*
  * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - File descriptor */
@@ -850,7 +1070,7 @@ cupsFileNumber(cups_file_t *fp)            /* I - CUPS file */
  * connection as needed, generally preferring IPv6 connections when there is
  * a choice.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 cups_file_t *                          /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
@@ -864,7 +1084,7 @@ cupsFileOpen(const char *filename, /* I - Name of file */
   http_addrlist_t *addrlist;           /* Host address list */
 
 
-  DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")\n", filename,
+  DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename,
                 mode));
 
  /*
@@ -883,7 +1103,8 @@ cupsFileOpen(const char *filename, /* I - Name of file */
   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 */
@@ -891,7 +1112,21 @@ cupsFileOpen(const char *filename,        /* I - Name of 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 */
@@ -957,7 +1192,7 @@ cupsFileOpen(const char *filename, /* I - Name of file */
  * supplied which enables Flate compression of the file.  Compression is
  * not supported for the "a" (append) mode.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 cups_file_t *                          /* O - CUPS file or @code NULL@ if the file could not be opened */
@@ -967,7 +1202,7 @@ cupsFileOpenFd(int        fd,              /* I - File descriptor */
   cups_file_t  *fp;                    /* New CUPS file */
 
 
-  DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")\n", fd, mode));
+  DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode));
 
  /*
   * Range check input...
@@ -1069,7 +1304,7 @@ cupsFileOpenFd(int        fd,             /* I - File descriptor */
 /*
  * 'cupsFilePeekChar()' - Peek at the next character from a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - Character or -1 on end of file */
@@ -1101,7 +1336,7 @@ cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
 /*
  * 'cupsFilePrintf()' - Write a formatted string.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - Number of bytes written or -1 on error */
@@ -1111,29 +1346,60 @@ cupsFilePrintf(cups_file_t *fp,         /* I - CUPS file */
 {
   va_list      ap;                     /* Argument list */
   ssize_t      bytes;                  /* Formatted size */
-  char         buf[8192];              /* Formatted text */
 
 
-  DEBUG_printf(("cupsFilePrintf(fp=%p, format=\"%s\", ...)\n", fp, format));
+  DEBUG_printf(("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", fp, format));
 
   if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
     return (-1);
 
+  if (!fp->printf_buffer)
+  {
+   /*
+    * Start with an 1k printf buffer...
+    */
+
+    if ((fp->printf_buffer = malloc(1024)) == NULL)
+      return (-1);
+
+    fp->printf_size = 1024;
+  }
+
   va_start(ap, format);
-  bytes = vsnprintf(buf, sizeof(buf), format, ap);
+  bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
   va_end(ap);
 
-  if (bytes >= sizeof(buf))
-    return (-1);
+  if (bytes >= (ssize_t)fp->printf_size)
+  {
+   /*
+    * Expand the printf buffer...
+    */
+
+    char       *temp;                  /* Temporary buffer pointer */
+
+
+    if (bytes > 65535)
+      return (-1);
+
+    if ((temp = realloc(fp->printf_buffer, bytes + 1)) == NULL)
+      return (-1);
+
+    fp->printf_buffer = temp;
+    fp->printf_size   = bytes + 1;
+
+    va_start(ap, format);
+    bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
+    va_end(ap);
+  }
 
   if (fp->mode == 's')
   {
-    if (cups_write(fp, buf, bytes) < 0)
+    if (cups_write(fp, fp->printf_buffer, bytes) < 0)
       return (-1);
 
     fp->pos += bytes;
 
-    DEBUG_printf(("cupsFilePrintf: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+    DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
     return (bytes);
   }
@@ -1144,20 +1410,20 @@ cupsFilePrintf(cups_file_t *fp,         /* I - CUPS file */
 
   fp->pos += bytes;
 
-  DEBUG_printf(("cupsFilePrintf: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   if (bytes > sizeof(fp->buf))
   {
 #ifdef HAVE_LIBZ
     if (fp->compressed)
-      return (cups_compress(fp, buf, bytes));
+      return (cups_compress(fp, fp->printf_buffer, bytes));
     else
 #endif /* HAVE_LIBZ */
-      return (cups_write(fp, buf, bytes));
+      return (cups_write(fp, fp->printf_buffer, bytes));
   }
   else
   {
-    memcpy(fp->ptr, buf, bytes);
+    memcpy(fp->ptr, fp->printf_buffer, bytes);
     fp->ptr += bytes;
     return (bytes);
   }
@@ -1167,7 +1433,7 @@ cupsFilePrintf(cups_file_t *fp,           /* I - CUPS file */
 /*
  * 'cupsFilePutChar()' - Write a character.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -1210,18 +1476,79 @@ cupsFilePutChar(cups_file_t *fp,        /* I - CUPS file */
 
   fp->pos ++;
 
-  DEBUG_printf(("cupsFilePutChar: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   return (0);
 }
 
 
+/*
+ * 'cupsFilePutConf()' - Write a configuration line.
+ *
+ * This function handles any comment escaping of the value.
+ *
+ * @since CUPS 1.4/Mac OS X 10.6@
+ */
+
+ssize_t                                        /* O - Number of bytes written or -1 on error */
+cupsFilePutConf(cups_file_t *fp,       /* I - CUPS file */
+                const char *directive, /* I - Directive */
+               const char *value)      /* I - Value */
+{
+  ssize_t      bytes,                  /* Number of bytes written */
+               temp;                   /* Temporary byte count */
+  const char   *ptr;                   /* Pointer into value */
+
+
+  if (!fp || !directive || !*directive)
+    return (-1);
+
+  if ((bytes = cupsFilePuts(fp, directive)) < 0)
+    return (-1);
+
+  if (cupsFilePutChar(fp, ' ') < 0)
+    return (-1);
+  bytes ++;
+
+  if (value && *value)
+  {
+    if ((ptr = strchr(value, '#')) != NULL)
+    {
+     /*
+      * Need to quote the first # in the info string...
+      */
+
+      if ((temp = cupsFileWrite(fp, value, ptr - value)) < 0)
+        return (-1);
+      bytes += temp;
+
+      if (cupsFilePutChar(fp, '\\') < 0)
+        return (-1);
+      bytes ++;
+
+      if ((temp = cupsFilePuts(fp, ptr)) < 0)
+        return (-1);
+      bytes += temp;
+    }
+    else if ((temp = cupsFilePuts(fp, value)) < 0)
+      return (-1);
+    else
+      bytes += temp;
+  }
+
+  if (cupsFilePutChar(fp, '\n') < 0)
+    return (-1);
+  else
+    return (bytes + 1);
+}
+
+
 /*
  * 'cupsFilePuts()' - Write a string.
  *
  * Like the @code fputs@ function, no newline is appended to the string.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - Number of bytes written or -1 on error */
@@ -1251,7 +1578,7 @@ cupsFilePuts(cups_file_t *fp,             /* I - CUPS file */
 
     fp->pos += bytes;
 
-    DEBUG_printf(("cupsFilePuts: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+    DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
     return (bytes);
   }
@@ -1262,7 +1589,7 @@ cupsFilePuts(cups_file_t *fp,             /* I - CUPS file */
 
   fp->pos += bytes;
 
-  DEBUG_printf(("cupsFilePuts: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   if (bytes > sizeof(fp->buf))
   {
@@ -1285,7 +1612,7 @@ cupsFilePuts(cups_file_t *fp,             /* I - CUPS file */
 /*
  * 'cupsFileRead()' - Read from a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 ssize_t                                        /* O - Number of bytes read or -1 on error */
@@ -1297,14 +1624,14 @@ cupsFileRead(cups_file_t *fp,           /* I - CUPS file */
   ssize_t      count;                  /* Bytes read */
 
 
-  DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+  DEBUG_printf(("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
                 CUPS_LLCAST bytes));
 
  /*
   * 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)
@@ -1320,8 +1647,8 @@ cupsFileRead(cups_file_t *fp,             /* I - CUPS file */
     if (fp->ptr >= fp->end)
       if (cups_fill(fp) <= 0)
       {
-        DEBUG_printf(("cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT "\n",
-                     CUPS_LLCAST total));
+        DEBUG_printf(("4cupsFileRead: cups_fill() returned -1, total="
+                     CUPS_LLFMT, CUPS_LLCAST total));
 
         if (total > 0)
           return ((ssize_t)total);
@@ -1337,7 +1664,7 @@ cupsFileRead(cups_file_t *fp,             /* I - CUPS file */
     fp->ptr += count;
     fp->pos += count;
 
-    DEBUG_printf(("cupsFileRead: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+    DEBUG_printf(("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
    /*
     * Update the counts for the last read...
@@ -1352,7 +1679,7 @@ cupsFileRead(cups_file_t *fp,             /* I - CUPS file */
   * Return the total number of bytes read...
   */
 
-  DEBUG_printf(("cupsFileRead: total=%d\n", (int)total));
+  DEBUG_printf(("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total));
 
   return ((ssize_t)total);
 }
@@ -1362,7 +1689,7 @@ cupsFileRead(cups_file_t *fp,             /* I - CUPS file */
  * 'cupsFileRewind()' - Set the current file position to the beginning of the
  *                      file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 off_t                                  /* O - New file position or -1 on error */
@@ -1372,8 +1699,8 @@ cupsFileRewind(cups_file_t *fp)           /* I - CUPS file */
   * Range check input...
   */
 
-  DEBUG_printf(("cupsFileRewind(fp=%p)\n", fp));
-  DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("cupsFileRewind(fp=%p)", fp));
+  DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   if (!fp || fp->mode != 'r')
     return (-1);
@@ -1396,7 +1723,7 @@ cupsFileRewind(cups_file_t *fp)           /* I - CUPS file */
       fp->eof = 0;
     }
 
-    DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+    DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
     return (0);
   }
@@ -1415,7 +1742,7 @@ cupsFileRewind(cups_file_t *fp)           /* I - CUPS file */
 
   if (lseek(fp->fd, 0, SEEK_SET))
   {
-    DEBUG_printf(("cupsFileRewind: lseek failed: %s\n", strerror(errno)));
+    DEBUG_printf(("1cupsFileRewind: lseek failed: %s", strerror(errno)));
     return (-1);
   }
 
@@ -1425,7 +1752,7 @@ cupsFileRewind(cups_file_t *fp)           /* I - CUPS file */
   fp->end    = NULL;
   fp->eof    = 0;
 
-  DEBUG_printf(("cupsFileRewind: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   return (0);
 }
@@ -1434,7 +1761,7 @@ cupsFileRewind(cups_file_t *fp)           /* I - CUPS file */
 /*
  * 'cupsFileSeek()' - Seek in a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 off_t                                  /* O - New file position or -1 on error */
@@ -1444,10 +1771,10 @@ cupsFileSeek(cups_file_t *fp,           /* I - CUPS file */
   ssize_t      bytes;                  /* Number bytes in buffer */
 
 
-  DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")\n", fp,
+  DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", 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));
+  DEBUG_printf(("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
+  DEBUG_printf(("2cupsFileSeek: fp->ptr=%p, fp->end=%p", fp->ptr, fp->end));
 
  /*
   * Range check input...
@@ -1467,6 +1794,8 @@ cupsFileSeek(cups_file_t *fp,             /* I - CUPS file */
   {
     bytes = (ssize_t)(fp->end - fp->buf);
 
+    DEBUG_printf(("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes));
+
     if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
     {
      /*
@@ -1499,15 +1828,13 @@ cupsFileSeek(cups_file_t *fp,           /* I - CUPS file */
 
   fp->eof = 0;
 
-  DEBUG_printf(("cupsFileSeek: bytes=" CUPS_LLFMT "\n", CUPS_LLCAST bytes));
-
   if (pos < fp->bufpos)
   {
    /*
     * Need to seek backwards...
     */
 
-    DEBUG_puts("cupsFileSeek: SEEK BACKWARDS");
+    DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS");
 
 #ifdef HAVE_LIBZ
     if (fp->compressed)
@@ -1538,7 +1865,7 @@ cupsFileSeek(cups_file_t *fp,             /* I - CUPS file */
       fp->ptr    = NULL;
       fp->end    = NULL;
 
-      DEBUG_printf(("cupsFileSeek: lseek() returned " CUPS_LLFMT "...\n",
+      DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT,
                     CUPS_LLCAST fp->pos));
     }
   }
@@ -1548,7 +1875,7 @@ cupsFileSeek(cups_file_t *fp,             /* I - CUPS file */
     * Need to seek forwards...
     */
 
-    DEBUG_puts("cupsFileSeek: SEEK FORWARDS");
+    DEBUG_puts("2cupsFileSeek: SEEK FORWARDS");
 
 #ifdef HAVE_LIBZ
     if (fp->compressed)
@@ -1573,12 +1900,12 @@ cupsFileSeek(cups_file_t *fp,           /* I - CUPS file */
       fp->ptr    = NULL;
       fp->end    = NULL;
 
-      DEBUG_printf(("cupsFileSeek: lseek() returned " CUPS_LLFMT "...\n",
+      DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT,
                     CUPS_LLCAST fp->pos));
     }
   }
 
-  DEBUG_printf(("cupsFileSeek: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   return (fp->pos);
 }
@@ -1587,7 +1914,7 @@ cupsFileSeek(cups_file_t *fp,             /* I - CUPS file */
 /*
  * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 cups_file_t *                          /* O - CUPS file */
@@ -1623,7 +1950,7 @@ cupsFileStderr(void)
 /*
  * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 cups_file_t *                          /* O - CUPS file */
@@ -1653,7 +1980,7 @@ cupsFileStdin(void)
 /*
  * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 cups_file_t *                          /* O - CUPS file */
@@ -1689,14 +2016,15 @@ cupsFileStdout(void)
 /*
  * 'cupsFileTell()' - Return the current file position.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 off_t                                  /* O - File position */
 cupsFileTell(cups_file_t *fp)          /* I - CUPS file */
 {
-  DEBUG_printf(("cupsFileTell(fp=%p)\n", fp));
-  DEBUG_printf(("cupsFileTell: pos=" CUPS_LLFMT "\n", CUPS_LLCAST (fp ? fp->pos : -1)));
+  DEBUG_printf(("2cupsFileTell(fp=%p)", fp));
+  DEBUG_printf(("3cupsFileTell: pos=" CUPS_LLFMT,
+               CUPS_LLCAST (fp ? fp->pos : -1)));
 
   return (fp ? fp->pos : 0);
 }
@@ -1705,7 +2033,7 @@ cupsFileTell(cups_file_t *fp)             /* I - CUPS file */
 /*
  * 'cupsFileUnlock()' - Unlock access to a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 int                                    /* O - 0 on success, -1 on error */
@@ -1715,7 +2043,7 @@ cupsFileUnlock(cups_file_t *fp)           /* I - CUPS file */
   * Range check...
   */
 
-  DEBUG_printf(("cupsFileUnlock(fp=%p)\n", fp));
+  DEBUG_printf(("cupsFileUnlock(fp=%p)", fp));
 
   if (!fp || fp->mode == 's')
     return (-1);
@@ -1725,7 +2053,7 @@ cupsFileUnlock(cups_file_t *fp)           /* I - CUPS file */
   */
 
 #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 */
@@ -1735,7 +2063,7 @@ cupsFileUnlock(cups_file_t *fp)           /* I - CUPS file */
 /*
  * 'cupsFileWrite()' - Write to a file.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 ssize_t                                        /* O - Number of bytes written or -1 on error */
@@ -1747,10 +2075,10 @@ cupsFileWrite(cups_file_t *fp,          /* I - CUPS file */
   * Range check input...
   */
 
-  DEBUG_printf(("cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n",
+  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)
@@ -1767,7 +2095,7 @@ cupsFileWrite(cups_file_t *fp,            /* I - CUPS file */
 
     fp->pos += (off_t)bytes;
 
-    DEBUG_printf(("cupsFileWrite: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+    DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
     return ((ssize_t)bytes);
   }
@@ -1778,7 +2106,7 @@ cupsFileWrite(cups_file_t *fp,            /* I - CUPS file */
 
   fp->pos += (off_t)bytes;
 
-  DEBUG_printf(("cupsFileWrite: pos=" CUPS_LLFMT "\n", CUPS_LLCAST fp->pos));
+  DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
 
   if (bytes > sizeof(fp->buf))
   {
@@ -1800,7 +2128,7 @@ cupsFileWrite(cups_file_t *fp,            /* I - CUPS file */
 
 #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 */
@@ -1808,7 +2136,7 @@ cups_compress(cups_file_t *fp,            /* I - CUPS file */
               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,
+  DEBUG_printf(("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
                 CUPS_LLCAST bytes));
 
  /*
@@ -1830,7 +2158,7 @@ cups_compress(cups_file_t *fp,            /* I - CUPS file */
     * Flush the current buffer...
     */
 
-    DEBUG_printf(("cups_compress: avail_in=%d, avail_out=%d\n",
+    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))
@@ -1851,7 +2179,7 @@ cups_compress(cups_file_t *fp,            /* I - CUPS file */
 
 
 /*
- * 'cups_fill()' - Fill the input buffer...
+ * 'cups_fill()' - Fill the input buffer.
  */
 
 static ssize_t                         /* O - Number of bytes or -1 */
@@ -1865,16 +2193,16 @@ cups_fill(cups_file_t *fp)              /* I - CUPS file */
 #endif /* HAVE_LIBZ */
 
 
-  DEBUG_printf(("cups_fill(fp=%p)\n", fp));
-  DEBUG_printf(("cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, "
-                "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d\n",
+  DEBUG_printf(("7cups_fill(fp=%p)", fp));
+  DEBUG_printf(("9cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, "
+                "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d",
                 fp->ptr, fp->end, fp->buf, CUPS_LLCAST fp->bufpos, fp->eof));
 
   if (fp->ptr && fp->end)
     fp->bufpos += fp->end - fp->buf;
 
 #ifdef HAVE_LIBZ
-  DEBUG_printf(("cups_fill: fp->compressed=%d\n", fp->compressed));
+  DEBUG_printf(("9cups_fill: fp->compressed=%d", fp->compressed));
 
   while (!fp->ptr || fp->compressed)
   {
@@ -1902,7 +2230,7 @@ cups_fill(cups_file_t *fp)                /* I - CUPS file */
        * Can't read from file!
        */
 
-        DEBUG_printf(("cups_fill: cups_read() returned " CUPS_LLFMT "!\n",
+        DEBUG_printf(("9cups_fill: cups_read() returned " CUPS_LLFMT,
                      CUPS_LLCAST bytes));
 
        return (-1);
@@ -1919,7 +2247,7 @@ cups_fill(cups_file_t *fp)                /* I - CUPS file */
        fp->ptr = fp->buf;
        fp->end = fp->buf + bytes;
 
-        DEBUG_printf(("cups_fill: Returning " CUPS_LLFMT "!\n",
+        DEBUG_printf(("9cups_fill: Returning " CUPS_LLFMT,
                      CUPS_LLCAST bytes));
 
        return (bytes);
@@ -2110,7 +2438,7 @@ cups_fill(cups_file_t *fp)                /* I - CUPS file */
             * Bad CRC, mark end-of-file...
            */
 
-            DEBUG_printf(("cups_fill: tcrc=%08x, fp->crc=%08x\n",
+            DEBUG_printf(("9cups_fill: tcrc=%08x, fp->crc=%08x",
                          (unsigned int)tcrc, (unsigned int)fp->crc));
 
            fp->eof = 1;
@@ -2171,6 +2499,94 @@ cups_fill(cups_file_t *fp)               /* I - CUPS file */
 }
 
 
+/*
+ * '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.
  */
@@ -2183,7 +2599,7 @@ cups_read(cups_file_t *fp,                /* I - CUPS file */
   ssize_t      total;                  /* Total bytes read */
 
 
-  DEBUG_printf(("cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+  DEBUG_printf(("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
                 CUPS_LLCAST bytes));
 
  /*
@@ -2204,7 +2620,7 @@ cups_read(cups_file_t *fp,                /* I - CUPS file */
       total = read(fp->fd, buf, bytes);
 #endif /* WIN32 */
 
-    DEBUG_printf(("cups_read: total=" CUPS_LLFMT "\n", CUPS_LLCAST total));
+    DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total));
 
     if (total >= 0)
       break;
@@ -2240,7 +2656,7 @@ cups_write(cups_file_t *fp,               /* I - CUPS file */
   ssize_t      count;                  /* Count this time */
 
 
-  DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")\n", fp, buf,
+  DEBUG_printf(("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
                 CUPS_LLCAST bytes));
 
  /*
@@ -2262,7 +2678,7 @@ cups_write(cups_file_t *fp,               /* I - CUPS file */
       count = write(fp->fd, buf, bytes);
 #endif /* WIN32 */
 
-    DEBUG_printf(("cups_write: count=" CUPS_LLFMT "\n", CUPS_LLCAST count));
+    DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count));
 
     if (count < 0)
     {
@@ -2294,5 +2710,5 @@ cups_write(cups_file_t *fp,               /* I - CUPS file */
 
 
 /*
- * End of "$Id: file.c 6962 2007-09-17 20:35:47Z mike $".
+ * End of "$Id: file.c 7672 2008-06-18 22:03:02Z mike $".
  */