Coverage Report

Created: 2026-02-26 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/file.c
Line
Count
Source
1
//
2
// File functions for CUPS.
3
//
4
// Since stdio files max out at 256 files on many systems, we have to
5
// write similar functions without this limit.  At the same time, using
6
// our own file functions allows us to provide transparent support of
7
// different line endings, gzip'd print files, PPD files, etc.
8
//
9
// Copyright © 2020-2026 by OpenPrinting.
10
// Copyright © 2007-2019 by Apple Inc.
11
// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
12
//
13
// Licensed under Apache License v2.0.  See the file "LICENSE" for more
14
// information.
15
//
16
17
#include "file-private.h"
18
#include "debug-internal.h"
19
#include <sys/stat.h>
20
#include <sys/types.h>
21
#include <zlib.h>
22
23
24
//
25
// Internal structures...
26
//
27
28
struct _cups_file_s     // CUPS file structure...
29
{
30
  int   fd;     // File descriptor
31
  char    mode,     // Mode ('r' or 'w')
32
    compressed,   // Compression used?
33
    is_stdio,   // stdin/out/err?
34
    eof,      // End of file?
35
    buf[4096],    // Buffer
36
    *ptr,     // Pointer into buffer
37
    *end;     // End of buffer data
38
  off_t   pos,      // Position in file
39
    bufpos;     // File position for start of buffer
40
  z_stream  stream;     // (De)compression stream
41
  Bytef   cbuf[4096];   // (De)compression buffer
42
  uLong   crc;      // (De)compression CRC
43
  char    *printf_buffer;   // cupsFilePrintf buffer
44
  size_t  printf_size;    // Size of cupsFilePrintf buffer
45
};
46
47
48
//
49
// Local functions...
50
//
51
52
static ssize_t  cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
53
static ssize_t  cups_fill(cups_file_t *fp);
54
static int  cups_open(const char *filename, int oflag, int mode);
55
static ssize_t  cups_read(cups_file_t *fp, char *buf, size_t bytes);
56
static ssize_t  cups_write(cups_file_t *fp, const char *buf, size_t bytes);
57
58
59
#ifndef _WIN32
60
//
61
// '_cupsFileCheck()' - Check the permissions of the given filename.
62
//
63
64
_cups_fc_result_t     // O - Check result
65
_cupsFileCheck(
66
    const char          *filename,  // I - Filename to check
67
    _cups_fc_filetype_t filetype, // I - Type of file checks?
68
    int                 dorootchecks, // I - Check for root permissions?
69
    _cups_fc_func_t     cb,   // I - Callback function
70
    void                *context) // I - Context pointer for callback
71
72
0
{
73
0
  struct stat   fileinfo; // File information
74
0
  char      message[1024],  // Message string
75
0
      temp[1024], // Parent directory filename
76
0
      *ptr;   // Pointer into parent directory
77
0
  _cups_fc_result_t result;   // Check result
78
79
80
  // Does the filename contain a relative path ("../")?
81
0
  if (strstr(filename, "../"))
82
0
  {
83
    // Yes, fail it!
84
0
    result = _CUPS_FILE_CHECK_RELATIVE_PATH;
85
0
    goto finishup;
86
0
  }
87
88
  // Does the program even exist and is it accessible?
89
0
  if (stat(filename, &fileinfo))
90
0
  {
91
    // Nope...
92
0
    result = _CUPS_FILE_CHECK_MISSING;
93
0
    goto finishup;
94
0
  }
95
96
  // Check the execute bit...
97
0
  result = _CUPS_FILE_CHECK_OK;
98
99
0
  if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
100
0
  {
101
0
    if (!S_ISDIR(fileinfo.st_mode))
102
0
      result = _CUPS_FILE_CHECK_WRONG_TYPE;
103
0
  }
104
0
  else  if (!S_ISREG(fileinfo.st_mode))
105
0
  {
106
0
    result = _CUPS_FILE_CHECK_WRONG_TYPE;
107
0
  }
108
109
0
  if (result)
110
0
    goto finishup;
111
112
  // Are we doing root checks?
113
0
  if (!dorootchecks)
114
0
  {
115
    // Nope, so anything (else) goes...
116
0
    goto finishup;
117
0
  }
118
119
  // Verify permission of the file itself:
120
  //
121
  // 1. Must be owned by root
122
  // 2. Must not be writable by group
123
  // 3. Must not be setuid
124
  // 4. Must not be writable by others
125
0
  if (fileinfo.st_uid ||   // 1. Must be owned by root
126
0
      (fileinfo.st_mode & S_IWGRP)  ||  // 2. Must not be writable by group
127
0
      (fileinfo.st_mode & S_ISUID) || // 3. Must not be setuid
128
0
      (fileinfo.st_mode & S_IWOTH)) // 4. Must not be writable by others
129
0
  {
130
0
    result = _CUPS_FILE_CHECK_PERMISSIONS;
131
0
    goto finishup;
132
0
  }
133
134
0
  if (filetype == _CUPS_FILE_CHECK_DIRECTORY ||
135
0
      filetype == _CUPS_FILE_CHECK_FILE_ONLY)
136
0
    goto finishup;
137
138
  // Now check the containing directory...
139
0
  cupsCopyString(temp, filename, sizeof(temp));
140
0
  if ((ptr = strrchr(temp, '/')) != NULL)
141
0
  {
142
0
    if (ptr == temp)
143
0
      ptr[1] = '\0';
144
0
    else
145
0
      *ptr = '\0';
146
0
  }
147
148
0
  if (stat(temp, &fileinfo))
149
0
  {
150
    // Doesn't exist?!?
151
0
    result   = _CUPS_FILE_CHECK_MISSING;
152
0
    filetype = _CUPS_FILE_CHECK_DIRECTORY;
153
0
    filename = temp;
154
155
0
    goto finishup;
156
0
  }
157
158
0
  if (fileinfo.st_uid ||   // 1. Must be owned by root
159
0
      (fileinfo.st_mode & S_IWGRP) || // 2. Must not be writable by group
160
0
      (fileinfo.st_mode & S_ISUID) || // 3. Must not be setuid
161
0
      (fileinfo.st_mode & S_IWOTH)) // 4. Must not be writable by others
162
0
  {
163
0
    result   = _CUPS_FILE_CHECK_PERMISSIONS;
164
0
    filetype = _CUPS_FILE_CHECK_DIRECTORY;
165
0
    filename = temp;
166
0
  }
167
168
  // Common return point...
169
0
  finishup:
170
171
0
  if (cb)
172
0
  {
173
0
    cups_lang_t *lang = cupsLangDefault();
174
          // Localization information
175
176
0
    switch (result)
177
0
    {
178
0
      case _CUPS_FILE_CHECK_OK :
179
0
    if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
180
0
      snprintf(message, sizeof(message),
181
0
         _cupsLangString(lang, _("Directory \"%s\" permissions OK "
182
0
               "(0%o/uid=%d/gid=%d).")),
183
0
         filename, fileinfo.st_mode, (int)fileinfo.st_uid,
184
0
         (int)fileinfo.st_gid);
185
0
    else
186
0
      snprintf(message, sizeof(message),
187
0
         _cupsLangString(lang, _("File \"%s\" permissions OK "
188
0
               "(0%o/uid=%d/gid=%d).")),
189
0
         filename, fileinfo.st_mode, (int)fileinfo.st_uid,
190
0
         (int)fileinfo.st_gid);
191
0
          break;
192
193
0
      case _CUPS_FILE_CHECK_MISSING :
194
0
    if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
195
0
      snprintf(message, sizeof(message),
196
0
         _cupsLangString(lang, _("Directory \"%s\" not available: "
197
0
               "%s")),
198
0
         filename, strerror(errno));
199
0
    else
200
0
      snprintf(message, sizeof(message),
201
0
         _cupsLangString(lang, _("File \"%s\" not available: %s")),
202
0
         filename, strerror(errno));
203
0
          break;
204
205
0
      case _CUPS_FILE_CHECK_PERMISSIONS :
206
0
    if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
207
0
      snprintf(message, sizeof(message),
208
0
         _cupsLangString(lang, _("Directory \"%s\" has insecure "
209
0
               "permissions "
210
0
               "(0%o/uid=%d/gid=%d).")),
211
0
         filename, fileinfo.st_mode, (int)fileinfo.st_uid,
212
0
         (int)fileinfo.st_gid);
213
0
    else
214
0
      snprintf(message, sizeof(message),
215
0
         _cupsLangString(lang, _("File \"%s\" has insecure "
216
0
                                 "permissions "
217
0
               "(0%o/uid=%d/gid=%d).")),
218
0
         filename, fileinfo.st_mode, (int)fileinfo.st_uid,
219
0
         (int)fileinfo.st_gid);
220
0
          break;
221
222
0
      case _CUPS_FILE_CHECK_WRONG_TYPE :
223
0
    if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
224
0
      snprintf(message, sizeof(message),
225
0
         _cupsLangString(lang, _("Directory \"%s\" is a file.")),
226
0
         filename);
227
0
    else
228
0
      snprintf(message, sizeof(message),
229
0
         _cupsLangString(lang, _("File \"%s\" is a directory.")),
230
0
         filename);
231
0
          break;
232
233
0
      case _CUPS_FILE_CHECK_RELATIVE_PATH :
234
0
    if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
235
0
      snprintf(message, sizeof(message),
236
0
         _cupsLangString(lang, _("Directory \"%s\" contains a "
237
0
               "relative path.")), filename);
238
0
    else
239
0
      snprintf(message, sizeof(message),
240
0
         _cupsLangString(lang, _("File \"%s\" contains a relative "
241
0
               "path.")), filename);
242
0
          break;
243
0
    }
244
245
0
    (*cb)(context, result, message);
246
0
  }
247
248
0
  return (result);
249
0
}
250
251
252
//
253
// '_cupsFileCheckFilter()' - Report file check results as CUPS filter messages.
254
//
255
256
void
257
_cupsFileCheckFilter(
258
    void              *context,   // I - Context pointer (unused)
259
    _cups_fc_result_t result,   // I - Result code
260
    const char        *message)   // I - Message text
261
0
{
262
0
  const char  *prefix;    // Messaging prefix
263
264
265
0
  (void)context;
266
267
0
  switch (result)
268
0
  {
269
0
    default :
270
0
    case _CUPS_FILE_CHECK_OK :
271
0
        prefix = "DEBUG2";
272
0
  break;
273
274
0
    case _CUPS_FILE_CHECK_MISSING :
275
0
    case _CUPS_FILE_CHECK_WRONG_TYPE :
276
0
        prefix = "ERROR";
277
0
  fputs("STATE: +cups-missing-filter-warning\n", stderr);
278
0
  break;
279
280
0
    case _CUPS_FILE_CHECK_PERMISSIONS :
281
0
    case _CUPS_FILE_CHECK_RELATIVE_PATH :
282
0
        prefix = "ERROR";
283
0
  fputs("STATE: +cups-insecure-filter-warning\n", stderr);
284
0
  break;
285
0
  }
286
287
0
  fprintf(stderr, "%s: %s\n", prefix, message);
288
0
}
289
#endif // !_WIN32
290
291
292
//
293
// 'cupsFileClose()' - Close a CUPS file.
294
//
295
// @since CUPS 1.2@
296
//
297
298
int         // O - 0 on success, -1 on error
299
cupsFileClose(cups_file_t *fp)    // I - CUPS file
300
0
{
301
0
  int fd;       // File descriptor
302
0
  char  mode;       // Open mode
303
0
  int status;       // Return status
304
305
306
0
  DEBUG_printf("cupsFileClose(fp=%p)", (void *)fp);
307
308
  // Range check...
309
0
  if (!fp)
310
0
    return (-1);
311
312
  // Flush pending write data...
313
0
  if (fp->mode == 'w')
314
0
    status = cupsFileFlush(fp);
315
0
  else
316
0
    status = 0;
317
318
0
  if (fp->compressed && status >= 0)
319
0
  {
320
0
    if (fp->mode == 'r')
321
0
    {
322
      // Free decompression data...
323
0
      inflateEnd(&fp->stream);
324
0
    }
325
0
    else
326
0
    {
327
      // Flush any remaining compressed data...
328
0
      unsigned char trailer[8]; // Trailer CRC and length
329
0
      int   done;   // Done writing...
330
331
332
0
      fp->stream.avail_in = 0;
333
334
0
      for (done = 0;;)
335
0
      {
336
0
        if (fp->stream.next_out > fp->cbuf)
337
0
  {
338
0
    if (cups_write(fp, (char *)fp->cbuf,
339
0
                   (size_t)(fp->stream.next_out - fp->cbuf)) < 0)
340
0
      status = -1;
341
342
0
    fp->stream.next_out  = fp->cbuf;
343
0
    fp->stream.avail_out = sizeof(fp->cbuf);
344
0
  }
345
346
0
        if (done || status < 0)
347
0
    break;
348
349
0
        done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END &&
350
0
         fp->stream.next_out == fp->cbuf;
351
0
      }
352
353
      // Write the CRC and length...
354
0
      trailer[0] = (unsigned char)fp->crc;
355
0
      trailer[1] = (unsigned char)(fp->crc >> 8);
356
0
      trailer[2] = (unsigned char)(fp->crc >> 16);
357
0
      trailer[3] = (unsigned char)(fp->crc >> 24);
358
0
      trailer[4] = (unsigned char)fp->pos;
359
0
      trailer[5] = (unsigned char)(fp->pos >> 8);
360
0
      trailer[6] = (unsigned char)(fp->pos >> 16);
361
0
      trailer[7] = (unsigned char)(fp->pos >> 24);
362
363
0
      if (cups_write(fp, (char *)trailer, 8) < 0)
364
0
        status = -1;
365
366
      // Free all memory used by the compression stream...
367
0
      deflateEnd(&(fp->stream));
368
0
    }
369
0
  }
370
371
  // If this is one of the cupsFileStdin/out/err files, return now and don't
372
  // actually free memory or close (these last the life of the process...)
373
0
  if (fp->is_stdio)
374
0
    return (status);
375
376
  // Save the file descriptor we used and free memory...
377
0
  fd   = fp->fd;
378
0
  mode = fp->mode;
379
380
0
  if (fp->printf_buffer)
381
0
    free(fp->printf_buffer);
382
383
0
  free(fp);
384
385
  // Close the file, returning the close status...
386
0
  if (mode == 's')
387
0
  {
388
0
    if (httpAddrClose(NULL, fd) < 0)
389
0
      status = -1;
390
0
  }
391
0
  else if (close(fd) < 0)
392
0
    status = -1;
393
394
0
  return (status);
395
0
}
396
397
398
//
399
// 'cupsFileCompression()' - Return whether a file is compressed.
400
//
401
// @deprecated@ @exclude all@
402
//
403
404
int         // O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@
405
cupsFileCompression(cups_file_t *fp)  // I - CUPS file
406
0
{
407
0
  return (fp ? fp->compressed : CUPS_FILE_NONE);
408
0
}
409
410
411
//
412
// 'cupsFileEOF()' - Return the end-of-file status.
413
//
414
// @since CUPS 1.2@
415
//
416
417
int         // O - 1 on end of file, 0 otherwise
418
cupsFileEOF(cups_file_t *fp)    // I - CUPS file
419
0
{
420
0
  return (fp ? fp->eof : 1);
421
0
}
422
423
424
//
425
// 'cupsFileFind()' - Find a file using the specified path.
426
//
427
// This function allows the paths in the path string to be separated by
428
// colons (UNIX standard) or semicolons (Windows standard) and stores the
429
// result in the buffer supplied.  If the file cannot be found in any of
430
// the supplied paths, @code NULL@ is returned. A @code NULL@ path only
431
// matches the current directory.
432
//
433
// @since CUPS 1.2@
434
//
435
436
const char *        // O - Full path to file or @code NULL@ if not found
437
cupsFileFind(const char *filename,  // I - File to find
438
             const char *path,    // I - Colon/semicolon-separated path
439
             int        executable, // I - 1 = executable files, 0 = any file/dir
440
       char       *buffer,  // I - Filename buffer
441
       int        bufsize)  // I - Size of filename buffer
442
0
{
443
0
  char  *bufptr,      // Current position in buffer
444
0
  *bufend;      // End of buffer
445
446
447
  // Range check input...
448
0
  DEBUG_printf("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, buffer=%p, bufsize=%d)", filename, path, executable, (void *)buffer, bufsize);
449
450
0
  if (!filename || !buffer || bufsize < 2)
451
0
    return (NULL);
452
453
0
  if (!path)
454
0
  {
455
    // No path, so check current directory...
456
0
    if (!access(filename, 0))
457
0
    {
458
0
      cupsCopyString(buffer, filename, (size_t)bufsize);
459
0
      return (buffer);
460
0
    }
461
0
    else
462
0
      return (NULL);
463
0
  }
464
465
  // Now check each path and return the first match...
466
0
  bufend = buffer + bufsize - 1;
467
0
  bufptr = buffer;
468
469
0
  while (*path)
470
0
  {
471
#ifdef _WIN32
472
    if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
473
#else
474
0
    if (*path == ';' || *path == ':')
475
0
#endif // _WIN32
476
0
    {
477
0
      if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
478
0
        *bufptr++ = '/';
479
480
0
      cupsCopyString(bufptr, filename, (size_t)(bufend - bufptr));
481
482
#ifdef _WIN32
483
      if (!access(buffer, 0))
484
#else
485
0
      if (!access(buffer, executable ? X_OK : 0))
486
0
#endif // _WIN32
487
0
      {
488
0
        DEBUG_printf("1cupsFileFind: Returning \"%s\"", buffer);
489
0
        return (buffer);
490
0
      }
491
492
0
      bufptr = buffer;
493
0
    }
494
0
    else if (bufptr < bufend)
495
0
      *bufptr++ = *path;
496
497
0
    path ++;
498
0
  }
499
500
  // Check the last path...
501
0
  if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
502
0
    *bufptr++ = '/';
503
504
0
  cupsCopyString(bufptr, filename, (size_t)(bufend - bufptr));
505
506
0
  if (!access(buffer, 0))
507
0
  {
508
0
    DEBUG_printf("1cupsFileFind: Returning \"%s\"", buffer);
509
0
    return (buffer);
510
0
  }
511
0
  else
512
0
  {
513
0
    DEBUG_puts("1cupsFileFind: Returning NULL");
514
0
    return (NULL);
515
0
  }
516
0
}
517
518
519
//
520
// 'cupsFileFlush()' - Flush pending output.
521
//
522
// @since CUPS 1.2@
523
//
524
525
int         // O - 0 on success, -1 on error
526
cupsFileFlush(cups_file_t *fp)    // I - CUPS file
527
0
{
528
0
  ssize_t bytes;      // Bytes to write
529
530
531
0
  DEBUG_printf("cupsFileFlush(fp=%p)", (void *)fp);
532
533
  // Range check input...
534
0
  if (!fp || fp->mode != 'w')
535
0
  {
536
0
    DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file...");
537
0
    return (-1);
538
0
  }
539
540
0
  bytes = (ssize_t)(fp->ptr - fp->buf);
541
542
0
  DEBUG_printf("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes);
543
544
0
  if (bytes > 0)
545
0
  {
546
0
    if (fp->compressed)
547
0
      bytes = cups_compress(fp, fp->buf, (size_t)bytes);
548
0
    else
549
0
      bytes = cups_write(fp, fp->buf, (size_t)bytes);
550
551
0
    if (bytes < 0)
552
0
      return (-1);
553
554
0
    fp->ptr = fp->buf;
555
0
  }
556
557
0
  return (0);
558
0
}
559
560
561
//
562
// 'cupsFileGetChar()' - Get a single character from a file.
563
//
564
// @since CUPS 1.2@
565
//
566
567
int         // O - Character or -1 on end of file
568
cupsFileGetChar(cups_file_t *fp)  // I - CUPS file
569
0
{
570
  // Range check input...
571
0
  DEBUG_printf("4cupsFileGetChar(fp=%p)", (void *)fp);
572
573
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's'))
574
0
  {
575
0
    DEBUG_puts("5cupsFileGetChar: Bad arguments!");
576
0
    return (-1);
577
0
  }
578
579
0
  if (fp->eof)
580
0
  {
581
0
    DEBUG_puts("5cupsFileGetChar: End-of-file!");
582
0
    return (-1);
583
0
  }
584
585
  // If the input buffer is empty, try to read more data...
586
0
  DEBUG_printf("5cupsFileGetChar: fp->eof=%d, fp->ptr=%p, fp->end=%p", fp->eof, (void *)fp->ptr, (void *)fp->end);
587
588
0
  if (fp->ptr >= fp->end)
589
0
    if (cups_fill(fp) <= 0)
590
0
    {
591
0
      DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!");
592
0
      return (-1);
593
0
    }
594
595
  // Return the next character in the buffer...
596
0
  DEBUG_printf("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255);
597
598
0
  fp->pos ++;
599
600
0
  DEBUG_printf("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
601
602
0
  return (*(fp->ptr)++ & 255);
603
0
}
604
605
606
//
607
// 'cupsFileGetConf()' - Get a line from a configuration file.
608
//
609
// @since CUPS 1.2@
610
//
611
612
char *          // O  - Line read or @code NULL@ on end of file or error
613
cupsFileGetConf(cups_file_t *fp,  // I  - CUPS file
614
                char        *buf, // O  - String buffer
615
    size_t      buflen, // I  - Size of string buffer
616
                char        **value,  // O  - Pointer to value
617
    int         *linenum) // IO - Current line number
618
0
{
619
0
  char  *ptr;       // Pointer into line
620
621
622
  // Range check input...
623
0
  DEBUG_printf("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT ", value=%p, linenum=%p)", (void *)fp, (void *)buf, CUPS_LLCAST buflen, (void *)value, (void *)linenum);
624
625
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2 || !value)
626
0
  {
627
0
    if (value)
628
0
      *value = NULL;
629
630
0
    return (NULL);
631
0
  }
632
633
  // Read the next non-comment line...
634
0
  *value = NULL;
635
636
0
  while (cupsFileGets(fp, buf, buflen))
637
0
  {
638
0
    (*linenum) ++;
639
640
    // Handle escaped characters and strip any comments...
641
0
    for (ptr = buf; *ptr; ptr ++)
642
0
    {
643
0
      if (*ptr == '#')
644
0
      {
645
        // Strip comment text...
646
0
        *ptr = '\0';
647
0
        break;
648
0
      }
649
0
      else if (*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '#' || ptr[1] == 'n' || ptr[1] == 'r'))
650
0
      {
651
  // \\, \#, \n, or \r, remove backslash and update the escaped char as needed...
652
0
  _cups_strcpy(ptr, ptr + 1);
653
654
0
  if (*ptr == 'n')
655
0
    *ptr = '\n';
656
0
  else if (*ptr == 'r')
657
0
    *ptr = '\r';
658
0
      }
659
0
    }
660
661
    // Strip leading whitespace...
662
0
    for (ptr = buf; *ptr; ptr ++)
663
0
    {
664
0
      if (!_cups_isspace(*ptr))
665
0
        break;
666
0
    }
667
668
0
    if (ptr > buf)
669
0
      _cups_strcpy(buf, ptr);
670
671
    // See if there is anything left...
672
0
    if (buf[0])
673
0
    {
674
      // Yes, grab any value and return...
675
0
      for (ptr = buf; *ptr; ptr ++)
676
0
      {
677
0
        if (_cups_isspace(*ptr))
678
0
    break;
679
0
      }
680
681
0
      if (*ptr)
682
0
      {
683
        // Have a value, skip any other spaces...
684
0
        while (_cups_isspace(*ptr))
685
0
    *ptr++ = '\0';
686
687
0
        if (*ptr)
688
0
    *value = ptr;
689
690
        // Strip trailing whitespace and > for lines that begin with <...
691
0
        ptr += strlen(ptr) - 1;
692
693
0
        if (buf[0] == '<' && *ptr == '>')
694
0
        {
695
0
    *ptr-- = '\0';
696
0
  }
697
0
  else if (buf[0] == '<' && *ptr != '>')
698
0
        {
699
    // Syntax error...
700
0
    *value = NULL;
701
0
    return (buf);
702
0
  }
703
704
0
        while (ptr > *value && _cups_isspace(*ptr))
705
0
    *ptr-- = '\0';
706
0
      }
707
708
      // Return the line...
709
0
      return (buf);
710
0
    }
711
0
  }
712
713
0
  return (NULL);
714
0
}
715
716
717
//
718
// 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
719
//                       contain binary data.
720
//
721
// This function differs from @link cupsFileGets@ in that the trailing CR
722
// and LF are preserved, as is any binary data on the line. The buffer is
723
// nul-terminated, however you should use the returned length to determine
724
// the number of bytes on the line.
725
//
726
// @since CUPS 1.2@
727
//
728
729
size_t          // O - Number of bytes on line or 0 on end of file
730
cupsFileGetLine(cups_file_t *fp,  // I - File to read from
731
                char        *buf, // I - Buffer
732
                size_t      buflen) // I - Size of buffer
733
0
{
734
0
  int   ch;     // Character from file
735
0
  char    *ptr,     // Current position in line buffer
736
0
    *end;     // End of line buffer
737
738
739
  // Range check input...
740
0
  DEBUG_printf("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST buflen);
741
742
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
743
0
    return (0);
744
745
  // Now loop until we have a valid line...
746
0
  for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
747
0
  {
748
0
    if (fp->ptr >= fp->end)
749
0
      if (cups_fill(fp) <= 0)
750
0
        break;
751
752
0
    *ptr++ = ch = *(fp->ptr)++;
753
0
    fp->pos ++;
754
755
0
    if (ch == '\r')
756
0
    {
757
      // Check for CR LF...
758
0
      if (fp->ptr >= fp->end)
759
0
  if (cups_fill(fp) <= 0)
760
0
          break;
761
762
0
      if (*(fp->ptr) == '\n')
763
0
      {
764
0
        *ptr++ = *(fp->ptr)++;
765
0
  fp->pos ++;
766
0
      }
767
768
0
      break;
769
0
    }
770
0
    else if (ch == '\n')
771
0
    {
772
      // Line feed ends a line...
773
0
      break;
774
0
    }
775
0
  }
776
777
0
  *ptr = '\0';
778
779
0
  DEBUG_printf("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
780
781
0
  return ((size_t)(ptr - buf));
782
0
}
783
784
785
//
786
// 'cupsFileGets()' - Get a CR and/or LF-terminated line.
787
//
788
// @since CUPS 1.2@
789
//
790
791
char *          // O - Line read or @code NULL@ on end of file or error
792
cupsFileGets(cups_file_t *fp,   // I - CUPS file
793
             char        *buf,    // O - String buffer
794
       size_t      buflen)  // I - Size of string buffer
795
0
{
796
0
  int   ch;     // Character from file
797
0
  char    *ptr,     // Current position in line buffer
798
0
    *end;     // End of line buffer
799
800
801
  // Range check input...
802
0
  DEBUG_printf("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST buflen);
803
804
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
805
0
    return (NULL);
806
807
  // Now loop until we have a valid line...
808
0
  for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
809
0
  {
810
0
    if (fp->ptr >= fp->end)
811
0
      if (cups_fill(fp) <= 0)
812
0
      {
813
0
        if (ptr == buf)
814
0
    return (NULL);
815
0
  else
816
0
          break;
817
0
      }
818
819
0
    ch = *(fp->ptr)++;
820
0
    fp->pos ++;
821
822
0
    if (ch == '\r')
823
0
    {
824
      // Check for CR LF...
825
0
      if (fp->ptr >= fp->end)
826
0
  if (cups_fill(fp) <= 0)
827
0
          break;
828
829
0
      if (*(fp->ptr) == '\n')
830
0
      {
831
0
        fp->ptr ++;
832
0
  fp->pos ++;
833
0
      }
834
835
0
      break;
836
0
    }
837
0
    else if (ch == '\n')
838
0
    {
839
      // Line feed ends a line...
840
0
      break;
841
0
    }
842
0
    else
843
0
      *ptr++ = (char)ch;
844
0
  }
845
846
0
  *ptr = '\0';
847
848
0
  DEBUG_printf("4cupsFileGets: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
849
850
0
  return (buf);
851
0
}
852
853
854
//
855
// 'cupsFileIsCompressed()' - Return whether a file is compressed.
856
//
857
// @since CUPS 2.5@
858
//
859
860
bool          // O - `true` if file is compressed, `false` otherwise
861
cupsFileIsCompressed(cups_file_t *fp) // I - CUPS file
862
0
{
863
0
  return (fp ? fp->compressed != 0 : false);
864
0
}
865
866
867
//
868
// 'cupsFileLock()' - Temporarily lock access to a file.
869
//
870
// @since CUPS 1.2@
871
//
872
873
int         // O - 0 on success, -1 on error
874
cupsFileLock(cups_file_t *fp,   // I - CUPS file
875
             int         block)   // I - 1 to wait for the lock, 0 to fail right away
876
0
{
877
  // Range check...
878
0
  if (!fp || fp->mode == 's')
879
0
    return (-1);
880
881
  // Try the lock...
882
#ifdef _WIN32
883
  return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
884
#else
885
0
  return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
886
0
#endif // _WIN32
887
0
}
888
889
890
//
891
// 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
892
//
893
// @since CUPS 1.2@
894
//
895
896
int         // O - File descriptor
897
cupsFileNumber(cups_file_t *fp)   // I - CUPS file
898
0
{
899
0
  if (fp)
900
0
    return (fp->fd);
901
0
  else
902
0
    return (-1);
903
0
}
904
905
906
//
907
// 'cupsFileOpen()' - Open a CUPS file.
908
//
909
// The "mode" parameter can be "r" to read, "w" to write, overwriting any
910
// existing file, "a" to append to an existing file or create a new file,
911
// or "s" to open a socket connection.
912
//
913
// When opening for writing ("w"), an optional number from 1 to 9 can be
914
// supplied which enables Flate compression of the file.  Compression is
915
// not supported for the "a" (append) mode.
916
//
917
// When opening for writing ("w") or append ("a"), an optional 'm###' suffix
918
// can be used to set the permissions of the opened file.
919
//
920
// When opening a socket connection, the filename is a string of the form
921
// "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
922
// connection as needed, generally preferring IPv6 connections when there is
923
// a choice.
924
//
925
// @since CUPS 1.2@
926
//
927
928
cups_file_t *       // O - CUPS file or @code NULL@ if the file or socket cannot be opened
929
cupsFileOpen(const char *filename,  // I - Name of file
930
             const char *mode)    // I - Open mode
931
0
{
932
0
  cups_file_t *fp;      // New CUPS file
933
0
  int   fd;     // File descriptor
934
0
  char    hostname[1024],   // Hostname
935
0
    *portname;    // Port "name" (number or service)
936
0
  http_addrlist_t *addrlist;    // Host address list
937
0
  int   perm = 0664;    // Permissions for write/append
938
0
  const char  *ptr;     // Pointer into mode string
939
940
941
0
  DEBUG_printf("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename, mode);
942
943
  // Range check input...
944
0
  if (!filename || !mode ||
945
0
      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
946
0
      (*mode == 'a' && isdigit(mode[1] & 255)))
947
0
    return (NULL);
948
949
0
  if ((ptr = strchr(mode, 'm')) != NULL && ptr[1] >= '0' && ptr[1] <= '7')
950
0
  {
951
    // Get permissions from mode string...
952
0
    perm = (int)strtol(mode + 1, NULL, 8);
953
0
  }
954
955
  // Open the file...
956
0
  switch (*mode)
957
0
  {
958
0
    case 'a' : // Append file
959
0
        fd = cups_open(filename, O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, perm);
960
0
        break;
961
962
0
    case 'r' : // Read file
963
0
  fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
964
0
  break;
965
966
0
    case 'w' : // Write file
967
0
        fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
968
0
  if (fd < 0 && errno == ENOENT)
969
0
  {
970
0
    fd = cups_open(filename, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY, perm);
971
0
    if (fd < 0 && errno == EEXIST)
972
0
      fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
973
0
  }
974
975
0
  if (fd >= 0)
976
#ifdef _WIN32
977
    _chsize(fd, 0);
978
#else
979
0
    ftruncate(fd, 0);
980
0
#endif // _WIN32
981
0
        break;
982
983
0
    case 's' : // Read/write socket
984
0
        cupsCopyString(hostname, filename, sizeof(hostname));
985
0
  if ((portname = strrchr(hostname, ':')) != NULL)
986
0
    *portname++ = '\0';
987
0
  else
988
0
    return (NULL);
989
990
        // Lookup the hostname and service...
991
0
        if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
992
0
    return (NULL);
993
994
        // Connect to the server...
995
0
        if (!httpAddrConnect(addrlist, &fd))
996
0
  {
997
0
    httpAddrFreeList(addrlist);
998
0
    return (NULL);
999
0
  }
1000
1001
0
  httpAddrFreeList(addrlist);
1002
0
  break;
1003
1004
0
    default : // Remove bogus compiler warning...
1005
0
        return (NULL);
1006
0
  }
1007
1008
0
  if (fd < 0)
1009
0
    return (NULL);
1010
1011
  // Create the CUPS file structure...
1012
0
  if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
1013
0
  {
1014
0
    if (*mode == 's')
1015
0
      httpAddrClose(NULL, fd);
1016
0
    else
1017
0
      close(fd);
1018
0
  }
1019
1020
  // Return it...
1021
0
  return (fp);
1022
0
}
1023
1024
//
1025
// 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
1026
//
1027
// The "mode" parameter can be "r" to read, "w" to write, "a" to append,
1028
// or "s" to treat the file descriptor as a bidirectional socket connection.
1029
//
1030
// When opening for writing ("w"), an optional number from 1 to 9 can be
1031
// supplied which enables Flate compression of the file.  Compression is
1032
// not supported for the "a" (append) mode.
1033
//
1034
// @since CUPS 1.2@
1035
//
1036
1037
cups_file_t *       // O - CUPS file or @code NULL@ if the file could not be opened
1038
cupsFileOpenFd(int        fd,   // I - File descriptor
1039
         const char *mode)  // I - Open mode
1040
0
{
1041
0
  cups_file_t *fp;      // New CUPS file
1042
1043
1044
0
  DEBUG_printf("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode);
1045
1046
  // Range check input...
1047
0
  if (fd < 0 || !mode ||
1048
0
      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
1049
0
      (*mode == 'a' && isdigit(mode[1] & 255)))
1050
0
    return (NULL);
1051
1052
  // Allocate memory...
1053
0
  if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
1054
0
    return (NULL);
1055
1056
  // Open the file...
1057
0
  fp->fd = fd;
1058
1059
0
  switch (*mode)
1060
0
  {
1061
0
    case 'a' :
1062
0
        fp->pos = lseek(fd, 0, SEEK_END);
1063
1064
0
    case 'w' :
1065
0
  fp->mode = 'w';
1066
0
  fp->ptr  = fp->buf;
1067
0
  fp->end  = fp->buf + sizeof(fp->buf);
1068
1069
0
  if (mode[1] >= '1' && mode[1] <= '9')
1070
0
  {
1071
    // Open a compressed stream, so write the standard gzip file header...
1072
0
          unsigned char header[10]; // gzip file header
1073
0
    time_t  curtime;  // Current time
1074
1075
1076
0
          curtime   = time(NULL);
1077
0
    header[0] = 0x1f;
1078
0
    header[1] = 0x8b;
1079
0
    header[2] = Z_DEFLATED;
1080
0
    header[3] = 0;
1081
0
    header[4] = (unsigned char)curtime;
1082
0
    header[5] = (unsigned char)(curtime >> 8);
1083
0
    header[6] = (unsigned char)(curtime >> 16);
1084
0
    header[7] = (unsigned char)(curtime >> 24);
1085
0
    header[8] = 0;
1086
0
    header[9] = 0x03;
1087
1088
0
    if (cups_write(fp, (char *)header, 10) < 10)
1089
0
    {
1090
0
            free(fp);
1091
0
      return (NULL);
1092
0
    }
1093
1094
          // Initialize the compressor...
1095
0
          if (deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) < Z_OK)
1096
0
          {
1097
0
            free(fp);
1098
0
      return (NULL);
1099
0
          }
1100
1101
0
    fp->stream.next_out  = fp->cbuf;
1102
0
    fp->stream.avail_out = sizeof(fp->cbuf);
1103
0
    fp->compressed       = 1;
1104
0
    fp->crc              = crc32(0L, Z_NULL, 0);
1105
0
  }
1106
0
        break;
1107
1108
0
    case 'r' :
1109
0
  fp->mode = 'r';
1110
0
  break;
1111
1112
0
    case 's' :
1113
0
        fp->mode = 's';
1114
0
  break;
1115
1116
0
    default : // Remove bogus compiler warning...
1117
0
        return (NULL);
1118
0
  }
1119
1120
  // Don't pass this file to child processes...
1121
0
#ifndef _WIN32
1122
0
  fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
1123
0
#endif // !_WIN32
1124
1125
0
  return (fp);
1126
0
}
1127
1128
1129
//
1130
// '_cupsFilePeekAhead()' - See if the requested character is buffered up.
1131
//
1132
1133
int         // O - 1 if present, 0 otherwise
1134
_cupsFilePeekAhead(cups_file_t *fp, // I - CUPS file
1135
                   int         ch)  // I - Character
1136
0
{
1137
0
  return (fp && fp->ptr && memchr(fp->ptr, ch, (size_t)(fp->end - fp->ptr)));
1138
0
}
1139
1140
1141
//
1142
// 'cupsFilePeekChar()' - Peek at the next character from a file.
1143
//
1144
// @since CUPS 1.2@
1145
//
1146
1147
int         // O - Character or -1 on end of file
1148
cupsFilePeekChar(cups_file_t *fp) // I - CUPS file
1149
0
{
1150
  // Range check input...
1151
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's'))
1152
0
    return (-1);
1153
1154
  // If the input buffer is empty, try to read more data...
1155
0
  if (fp->ptr >= fp->end)
1156
0
    if (cups_fill(fp) <= 0)
1157
0
      return (-1);
1158
1159
  // Return the next character in the buffer...
1160
0
  return (*(fp->ptr) & 255);
1161
0
}
1162
1163
1164
//
1165
// 'cupsFilePrintf()' - Write a formatted string.
1166
//
1167
// @since CUPS 1.2@
1168
//
1169
1170
int         // O - Number of bytes written or -1 on error
1171
cupsFilePrintf(cups_file_t *fp,   // I - CUPS file
1172
               const char  *format, // I - Printf-style format string
1173
         ...)     // I - Additional args as necessary
1174
0
{
1175
0
  va_list ap;     // Argument list
1176
0
  ssize_t bytes;      // Formatted size
1177
1178
1179
0
  DEBUG_printf("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", (void *)fp, format);
1180
1181
0
  if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
1182
0
    return (-1);
1183
1184
0
  if (!fp->printf_buffer)
1185
0
  {
1186
    // Start with a 1k printf buffer...
1187
0
    if ((fp->printf_buffer = malloc(1024)) == NULL)
1188
0
      return (-1);
1189
1190
0
    fp->printf_size = 1024;
1191
0
  }
1192
1193
0
  va_start(ap, format);
1194
0
  bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1195
0
  va_end(ap);
1196
1197
0
  if (bytes >= (ssize_t)fp->printf_size)
1198
0
  {
1199
    // Expand the printf buffer...
1200
0
    char  *temp;      // Temporary buffer pointer
1201
1202
1203
0
    if (bytes > 65535)
1204
0
      return (-1);
1205
1206
0
    if ((temp = realloc(fp->printf_buffer, (size_t)(bytes + 1))) == NULL)
1207
0
      return (-1);
1208
1209
0
    fp->printf_buffer = temp;
1210
0
    fp->printf_size   = (size_t)(bytes + 1);
1211
1212
0
    va_start(ap, format);
1213
0
    bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1214
0
    va_end(ap);
1215
0
  }
1216
1217
0
  if (fp->mode == 's')
1218
0
  {
1219
0
    if (cups_write(fp, fp->printf_buffer, (size_t)bytes) < 0)
1220
0
      return (-1);
1221
1222
0
    fp->pos += bytes;
1223
1224
0
    DEBUG_printf("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1225
1226
0
    return ((int)bytes);
1227
0
  }
1228
1229
0
  if ((fp->ptr + bytes) > fp->end)
1230
0
    if (cupsFileFlush(fp))
1231
0
      return (-1);
1232
1233
0
  fp->pos += bytes;
1234
1235
0
  DEBUG_printf("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1236
1237
0
  if ((size_t)bytes > sizeof(fp->buf))
1238
0
  {
1239
0
    if (fp->compressed)
1240
0
      return ((int)cups_compress(fp, fp->printf_buffer, (size_t)bytes));
1241
0
    else
1242
0
      return ((int)cups_write(fp, fp->printf_buffer, (size_t)bytes));
1243
0
  }
1244
0
  else
1245
0
  {
1246
0
    memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
1247
0
    fp->ptr += bytes;
1248
1249
0
    if (fp->is_stdio && cupsFileFlush(fp))
1250
0
      return (-1);
1251
0
    else
1252
0
      return ((int)bytes);
1253
0
  }
1254
0
}
1255
1256
1257
//
1258
// 'cupsFilePutChar()' - Write a character.
1259
//
1260
// @since CUPS 1.2@
1261
//
1262
1263
int         // O - 0 on success, -1 on error
1264
cupsFilePutChar(cups_file_t *fp,  // I - CUPS file
1265
                int         c)    // I - Character to write
1266
0
{
1267
  // Range check input...
1268
0
  if (!fp || (fp->mode != 'w' && fp->mode != 's'))
1269
0
    return (-1);
1270
1271
0
  if (fp->mode == 's')
1272
0
  {
1273
    // Send character immediately over socket...
1274
0
    char ch;        // Output character
1275
1276
1277
0
    ch = (char)c;
1278
1279
0
    if (send(fp->fd, &ch, 1, 0) < 1)
1280
0
      return (-1);
1281
0
  }
1282
0
  else
1283
0
  {
1284
    // Buffer it up...
1285
0
    if (fp->ptr >= fp->end)
1286
0
      if (cupsFileFlush(fp))
1287
0
  return (-1);
1288
1289
0
    *(fp->ptr) ++ = (char)c;
1290
0
  }
1291
1292
0
  fp->pos ++;
1293
1294
0
  DEBUG_printf("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1295
1296
0
  return (0);
1297
0
}
1298
1299
1300
//
1301
// 'cupsFilePutConf()' - Write a configuration line.
1302
//
1303
// This function handles any escaping of the value.
1304
//
1305
// @since CUPS 1.4@
1306
//
1307
1308
ssize_t         // O - Number of bytes written or -1 on error
1309
cupsFilePutConf(cups_file_t *fp,  // I - CUPS file
1310
                const char *directive,  // I - Directive
1311
    const char *value)  // I - Value
1312
0
{
1313
0
  ssize_t bytes,      // Number of bytes written
1314
0
    temp;     // Temporary byte count
1315
1316
1317
0
  if (!fp || !directive || !*directive)
1318
0
    return (-1);
1319
1320
0
  if ((bytes = cupsFilePuts(fp, directive)) < 0)
1321
0
    return (-1);
1322
1323
0
  if (value && *value)
1324
0
  {
1325
0
    const char  *start,     // Start of current fragment
1326
0
    *ptr;     // Pointer into value
1327
1328
0
    if (cupsFilePutChar(fp, ' ') < 0)
1329
0
      return (-1);
1330
0
    bytes ++;
1331
1332
0
    for (start = ptr = value; *ptr; ptr ++)
1333
0
    {
1334
0
      if (strchr("#\\\n\r", *ptr) != NULL)
1335
0
      {
1336
        // Character that needs to be escaped...
1337
0
        if (ptr > start)
1338
0
        {
1339
          // Write unescaped portion...
1340
0
    if ((temp = cupsFileWrite(fp, start, (size_t)(ptr - start))) < 0)
1341
0
      return (-1);
1342
1343
0
    bytes += temp;
1344
0
        }
1345
1346
0
        start = ptr + 1;
1347
1348
0
        if (*ptr == '\\')
1349
0
        {
1350
          // "\" (for escaping)
1351
0
          if (cupsFilePuts(fp, "\\\\") < 0)
1352
0
            return (-1);
1353
0
        }
1354
0
        else if (*ptr == '#')
1355
0
        {
1356
          // "#" (for comment)
1357
0
          if (cupsFilePuts(fp, "\\#") < 0)
1358
0
            return (-1);
1359
0
        }
1360
0
        else if (*ptr == '\n')
1361
0
        {
1362
          // LF
1363
0
          if (cupsFilePuts(fp, "\\n") < 0)
1364
0
            return (-1);
1365
0
        }
1366
0
        else if (cupsFilePuts(fp, "\\r") < 0)
1367
0
        {
1368
0
    return (-1);
1369
0
  }
1370
1371
0
  bytes += 2;
1372
0
      }
1373
0
    }
1374
1375
0
    if (ptr > start)
1376
0
    {
1377
      // Write remaining unescaped portion...
1378
0
      if ((temp = cupsFileWrite(fp, start, (size_t)(ptr - start))) < 0)
1379
0
  return (-1);
1380
1381
0
      bytes += temp;
1382
0
    }
1383
0
  }
1384
1385
0
  if (cupsFilePutChar(fp, '\n') < 0)
1386
0
    return (-1);
1387
0
  else
1388
0
    return (bytes + 1);
1389
0
}
1390
1391
1392
//
1393
// 'cupsFilePuts()' - Write a string.
1394
//
1395
// Like the @code fputs@ function, no newline is appended to the string.
1396
//
1397
// @since CUPS 1.2@
1398
//
1399
1400
int         // O - Number of bytes written or -1 on error
1401
cupsFilePuts(cups_file_t *fp,   // I - CUPS file
1402
             const char  *s)    // I - String to write
1403
0
{
1404
0
  ssize_t bytes;      // Bytes to write
1405
1406
1407
  // Range check input...
1408
0
  if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1409
0
    return (-1);
1410
1411
  // Write the string...
1412
0
  bytes = (ssize_t)strlen(s);
1413
1414
0
  if (fp->mode == 's')
1415
0
  {
1416
0
    if (cups_write(fp, s, (size_t)bytes) < 0)
1417
0
      return (-1);
1418
1419
0
    fp->pos += bytes;
1420
1421
0
    DEBUG_printf("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1422
1423
0
    return ((int)bytes);
1424
0
  }
1425
1426
0
  if ((fp->ptr + bytes) > fp->end)
1427
0
    if (cupsFileFlush(fp))
1428
0
      return (-1);
1429
1430
0
  fp->pos += bytes;
1431
1432
0
  DEBUG_printf("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1433
1434
0
  if ((size_t)bytes > sizeof(fp->buf))
1435
0
  {
1436
0
    if (fp->compressed)
1437
0
      return ((int)cups_compress(fp, s, (size_t)bytes));
1438
0
    else
1439
0
      return ((int)cups_write(fp, s, (size_t)bytes));
1440
0
  }
1441
0
  else
1442
0
  {
1443
0
    memcpy(fp->ptr, s, (size_t)bytes);
1444
0
    fp->ptr += bytes;
1445
1446
0
    if (fp->is_stdio && cupsFileFlush(fp))
1447
0
      return (-1);
1448
0
    else
1449
0
      return ((int)bytes);
1450
0
  }
1451
0
}
1452
1453
1454
//
1455
// 'cupsFileRead()' - Read from a file.
1456
//
1457
// @since CUPS 1.2@
1458
//
1459
1460
ssize_t         // O - Number of bytes read or -1 on error
1461
cupsFileRead(cups_file_t *fp,   // I - CUPS file
1462
             char        *buf,    // O - Buffer
1463
       size_t      bytes)   // I - Number of bytes to read
1464
0
{
1465
0
  size_t  total;      // Total bytes read
1466
0
  ssize_t count;      // Bytes read
1467
1468
1469
0
  DEBUG_printf("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1470
1471
  // Range check input...
1472
0
  if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
1473
0
    return (-1);
1474
1475
0
  if (bytes == 0)
1476
0
    return (0);
1477
1478
0
  if (fp->eof)
1479
0
  {
1480
0
    DEBUG_puts("5cupsFileRead: End-of-file!");
1481
0
    return (-1);
1482
0
  }
1483
1484
  // Loop until all bytes are read...
1485
0
  total = 0;
1486
0
  while (bytes > 0)
1487
0
  {
1488
0
    if (fp->ptr >= fp->end)
1489
0
      if (cups_fill(fp) <= 0)
1490
0
      {
1491
0
        DEBUG_printf("4cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT, CUPS_LLCAST total);
1492
1493
0
        if (total > 0)
1494
0
          return ((ssize_t)total);
1495
0
  else
1496
0
    return (-1);
1497
0
      }
1498
1499
0
    count = (ssize_t)(fp->end - fp->ptr);
1500
0
    if (count > (ssize_t)bytes)
1501
0
      count = (ssize_t)bytes;
1502
1503
0
    memcpy(buf, fp->ptr,(size_t) count);
1504
0
    fp->ptr += count;
1505
0
    fp->pos += count;
1506
1507
0
    DEBUG_printf("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1508
1509
    // Update the counts for the last read...
1510
0
    bytes -= (size_t)count;
1511
0
    total += (size_t)count;
1512
0
    buf   += count;
1513
0
  }
1514
1515
  // Return the total number of bytes read...
1516
0
  DEBUG_printf("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total);
1517
1518
0
  return ((ssize_t)total);
1519
0
}
1520
1521
1522
//
1523
// 'cupsFileRewind()' - Set the current file position to the beginning of the
1524
//                      file.
1525
//
1526
// @since CUPS 1.2@
1527
//
1528
1529
off_t         // O - New file position or -1 on error
1530
cupsFileRewind(cups_file_t *fp)   // I - CUPS file
1531
0
{
1532
  // Range check input...
1533
0
  DEBUG_printf("cupsFileRewind(fp=%p)", (void *)fp);
1534
1535
0
  if (!fp || fp->mode != 'r')
1536
0
    return (-1);
1537
1538
0
  DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1539
1540
  // Handle special cases...
1541
0
  if (fp->bufpos == 0)
1542
0
  {
1543
    // No seeking necessary...
1544
0
    fp->pos = 0;
1545
1546
0
    if (fp->ptr)
1547
0
    {
1548
0
      fp->ptr = fp->buf;
1549
0
      fp->eof = 0;
1550
0
    }
1551
1552
0
    DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1553
1554
0
    return (0);
1555
0
  }
1556
1557
  // Otherwise, seek in the file and cleanup any compression buffers...
1558
0
  if (fp->compressed)
1559
0
  {
1560
0
    inflateEnd(&fp->stream);
1561
0
    fp->compressed = 0;
1562
0
  }
1563
1564
0
  if (lseek(fp->fd, 0, SEEK_SET))
1565
0
  {
1566
0
    DEBUG_printf("1cupsFileRewind: lseek failed: %s", strerror(errno));
1567
0
    return (-1);
1568
0
  }
1569
1570
0
  fp->bufpos = 0;
1571
0
  fp->pos    = 0;
1572
0
  fp->ptr    = NULL;
1573
0
  fp->end    = NULL;
1574
0
  fp->eof    = 0;
1575
1576
0
  DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1577
1578
0
  return (0);
1579
0
}
1580
1581
1582
//
1583
// 'cupsFileSeek()' - Seek in a file.
1584
//
1585
// @since CUPS 1.2@
1586
//
1587
1588
off_t         // O - New file position or -1 on error
1589
cupsFileSeek(cups_file_t *fp,   // I - CUPS file
1590
             off_t       pos)   // I - Position in file
1591
0
{
1592
0
  ssize_t bytes;      // Number bytes in buffer
1593
1594
1595
0
  DEBUG_printf("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", (void *)fp, CUPS_LLCAST pos);
1596
1597
  // Range check input...
1598
0
  if (!fp || pos < 0 || fp->mode != 'r')
1599
0
    return (-1);
1600
1601
0
  DEBUG_printf("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1602
0
  DEBUG_printf("2cupsFileSeek: fp->ptr=%p, fp->end=%p", (void *)fp->ptr, (void *)fp->end);
1603
1604
  // Handle special cases...
1605
0
  if (pos == 0)
1606
0
    return (cupsFileRewind(fp));
1607
1608
0
  if (fp->ptr)
1609
0
  {
1610
0
    bytes = (ssize_t)(fp->end - fp->buf);
1611
1612
0
    DEBUG_printf("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes);
1613
1614
0
    if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1615
0
    {
1616
      // No seeking necessary...
1617
0
      fp->pos = pos;
1618
0
      fp->ptr = fp->buf + (pos - fp->bufpos);
1619
0
      fp->eof = 0;
1620
1621
0
      return (pos);
1622
0
    }
1623
0
  }
1624
1625
0
  if (!fp->compressed && !fp->ptr)
1626
0
  {
1627
    // Preload a buffer to determine whether the file is compressed...
1628
0
    if (cups_fill(fp) <= 0)
1629
0
      return (-1);
1630
0
  }
1631
1632
  // Seek forwards or backwards...
1633
0
  fp->eof = 0;
1634
1635
0
  if (pos < fp->bufpos)
1636
0
  {
1637
    // Need to seek backwards...
1638
0
    DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS");
1639
1640
0
    if (fp->compressed)
1641
0
    {
1642
0
      inflateEnd(&fp->stream);
1643
1644
0
      lseek(fp->fd, 0, SEEK_SET);
1645
0
      fp->bufpos = 0;
1646
0
      fp->pos    = 0;
1647
0
      fp->ptr    = NULL;
1648
0
      fp->end    = NULL;
1649
1650
0
      while ((bytes = cups_fill(fp)) > 0)
1651
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1652
0
    break;
1653
1654
0
      if (bytes <= 0)
1655
0
        return (-1);
1656
1657
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1658
0
      fp->pos = pos;
1659
0
    }
1660
0
    else
1661
0
    {
1662
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1663
0
      fp->pos    = fp->bufpos;
1664
0
      fp->ptr    = NULL;
1665
0
      fp->end    = NULL;
1666
1667
0
      DEBUG_printf("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos);
1668
0
    }
1669
0
  }
1670
0
  else
1671
0
  {
1672
    // Need to seek forwards...
1673
0
    DEBUG_puts("2cupsFileSeek: SEEK FORWARDS");
1674
1675
0
    if (fp->compressed)
1676
0
    {
1677
0
      while ((bytes = cups_fill(fp)) > 0)
1678
0
      {
1679
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1680
0
    break;
1681
0
      }
1682
1683
0
      if (bytes <= 0)
1684
0
        return (-1);
1685
1686
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1687
0
      fp->pos = pos;
1688
0
    }
1689
0
    else
1690
0
    {
1691
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1692
0
      fp->pos    = fp->bufpos;
1693
0
      fp->ptr    = NULL;
1694
0
      fp->end    = NULL;
1695
1696
0
      DEBUG_printf("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos);
1697
0
    }
1698
0
  }
1699
1700
0
  DEBUG_printf("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1701
1702
0
  return (fp->pos);
1703
0
}
1704
1705
1706
//
1707
// 'cupsFileStderr()' - Return a CUPS file associated with stderr.
1708
//
1709
// @since CUPS 1.2@
1710
//
1711
1712
cups_file_t *       // O - CUPS file
1713
cupsFileStderr(void)
1714
0
{
1715
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1716
1717
1718
  // Open file descriptor 2 as needed...
1719
0
  if (!cg->stdio_files[2])
1720
0
  {
1721
    // Flush any pending output on the stdio file...
1722
0
    fflush(stderr);
1723
1724
    // Open file descriptor 2...
1725
0
    if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1726
0
      cg->stdio_files[2]->is_stdio = 1;
1727
0
  }
1728
1729
0
  return (cg->stdio_files[2]);
1730
0
}
1731
1732
1733
//
1734
// 'cupsFileStdin()' - Return a CUPS file associated with stdin.
1735
//
1736
// @since CUPS 1.2@
1737
//
1738
1739
cups_file_t *       // O - CUPS file
1740
cupsFileStdin(void)
1741
0
{
1742
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1743
1744
1745
  // Open file descriptor 0 as needed...
1746
0
  if (!cg->stdio_files[0])
1747
0
  {
1748
    // Open file descriptor 0...
1749
0
    if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1750
0
      cg->stdio_files[0]->is_stdio = 1;
1751
0
  }
1752
1753
0
  return (cg->stdio_files[0]);
1754
0
}
1755
1756
1757
//
1758
// 'cupsFileStdout()' - Return a CUPS file associated with stdout.
1759
//
1760
// @since CUPS 1.2@
1761
//
1762
1763
cups_file_t *       // O - CUPS file
1764
cupsFileStdout(void)
1765
0
{
1766
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1767
1768
1769
  // Open file descriptor 1 as needed...
1770
0
  if (!cg->stdio_files[1])
1771
0
  {
1772
    // Flush any pending output on the stdio file...
1773
0
    fflush(stdout);
1774
1775
    // Open file descriptor 1...
1776
0
    if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
1777
0
      cg->stdio_files[1]->is_stdio = 1;
1778
0
  }
1779
1780
0
  return (cg->stdio_files[1]);
1781
0
}
1782
1783
1784
//
1785
// 'cupsFileTell()' - Return the current file position.
1786
//
1787
// @since CUPS 1.2@
1788
//
1789
1790
off_t         // O - File position
1791
cupsFileTell(cups_file_t *fp)   // I - CUPS file
1792
0
{
1793
0
  DEBUG_printf("2cupsFileTell(fp=%p)", (void *)fp);
1794
0
  DEBUG_printf("3cupsFileTell: pos=" CUPS_LLFMT, CUPS_LLCAST (fp ? fp->pos : -1));
1795
1796
0
  return (fp ? fp->pos : 0);
1797
0
}
1798
1799
1800
//
1801
// 'cupsFileUnlock()' - Unlock access to a file.
1802
//
1803
// @since CUPS 1.2@
1804
//
1805
1806
int         // O - 0 on success, -1 on error
1807
cupsFileUnlock(cups_file_t *fp)   // I - CUPS file
1808
0
{
1809
  // Range check...
1810
0
  DEBUG_printf("cupsFileUnlock(fp=%p)", (void *)fp);
1811
1812
0
  if (!fp || fp->mode == 's')
1813
0
    return (-1);
1814
1815
  // Unlock...
1816
#ifdef _WIN32
1817
  return (_locking(fp->fd, _LK_UNLCK, 0));
1818
#else
1819
0
  return (lockf(fp->fd, F_ULOCK, 0));
1820
0
#endif // _WIN32
1821
0
}
1822
1823
1824
//
1825
// 'cupsFileWrite()' - Write to a file.
1826
//
1827
// @since CUPS 1.2@
1828
//
1829
1830
ssize_t         // O - Number of bytes written or -1 on error
1831
cupsFileWrite(cups_file_t *fp,    // I - CUPS file
1832
              const char  *buf,   // I - Buffer
1833
        size_t      bytes)  // I - Number of bytes to write
1834
0
{
1835
  // Range check input...
1836
0
  DEBUG_printf("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1837
1838
0
  if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
1839
0
    return (-1);
1840
1841
0
  if (bytes == 0)
1842
0
    return (0);
1843
1844
  // Write the buffer...
1845
0
  if (fp->mode == 's')
1846
0
  {
1847
0
    if (cups_write(fp, buf, bytes) < 0)
1848
0
      return (-1);
1849
1850
0
    fp->pos += (off_t)bytes;
1851
1852
0
    DEBUG_printf("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1853
1854
0
    return ((ssize_t)bytes);
1855
0
  }
1856
1857
0
  if ((fp->ptr + bytes) > fp->end)
1858
0
    if (cupsFileFlush(fp))
1859
0
      return (-1);
1860
1861
0
  fp->pos += (off_t)bytes;
1862
1863
0
  DEBUG_printf("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1864
1865
0
  if (bytes > sizeof(fp->buf))
1866
0
  {
1867
0
    if (fp->compressed)
1868
0
      return (cups_compress(fp, buf, bytes));
1869
0
    else
1870
0
      return (cups_write(fp, buf, bytes));
1871
0
  }
1872
0
  else
1873
0
  {
1874
0
    memcpy(fp->ptr, buf, bytes);
1875
0
    fp->ptr += bytes;
1876
0
    return ((ssize_t)bytes);
1877
0
  }
1878
0
}
1879
1880
1881
//
1882
// 'cups_compress()' - Compress a buffer of data.
1883
//
1884
1885
static ssize_t        // O - Number of bytes written or -1
1886
cups_compress(cups_file_t *fp,    // I - CUPS file
1887
              const char  *buf,   // I - Buffer
1888
        size_t      bytes)  // I - Number bytes
1889
0
{
1890
0
  int status;       // Deflate status
1891
1892
1893
0
  DEBUG_printf("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1894
1895
  // Update the CRC...
1896
0
  fp->crc = crc32(fp->crc, (const Bytef *)buf, (uInt)bytes);
1897
1898
  // Deflate the bytes...
1899
0
  fp->stream.next_in  = (Bytef *)buf;
1900
0
  fp->stream.avail_in = (uInt)bytes;
1901
1902
0
  while (fp->stream.avail_in > 0)
1903
0
  {
1904
    // Flush the current buffer...
1905
0
    DEBUG_printf("9cups_compress: avail_in=%d, avail_out=%d", fp->stream.avail_in, fp->stream.avail_out);
1906
1907
0
    if (fp->stream.avail_out < (uInt)(sizeof(fp->cbuf) / 8))
1908
0
    {
1909
0
      if (cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)) < 0)
1910
0
        return (-1);
1911
1912
0
      fp->stream.next_out  = fp->cbuf;
1913
0
      fp->stream.avail_out = sizeof(fp->cbuf);
1914
0
    }
1915
1916
0
    if ((status = deflate(&(fp->stream), Z_NO_FLUSH)) < Z_OK && status != Z_BUF_ERROR)
1917
0
      return (-1);
1918
0
  }
1919
1920
0
  return ((ssize_t)bytes);
1921
0
}
1922
1923
1924
//
1925
// 'cups_fill()' - Fill the input buffer.
1926
//
1927
1928
static ssize_t        // O - Number of bytes or -1
1929
cups_fill(cups_file_t *fp)    // I - CUPS file
1930
0
{
1931
0
  ssize_t   bytes;    // Number of bytes read
1932
0
  int     status;   // Decompression status
1933
0
  const unsigned char *ptr,   // Pointer into buffer
1934
0
      *end;   // End of buffer
1935
1936
1937
0
  DEBUG_printf("7cups_fill(fp=%p)", (void *)fp);
1938
0
  DEBUG_printf("9cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, fp->bufpos=" CUPS_LLFMT ", fp->eof=%d", (void *)fp->ptr, (void *)fp->end, (void *)fp->buf, CUPS_LLCAST fp->bufpos, fp->eof);
1939
1940
0
  if (fp->ptr && fp->end)
1941
0
    fp->bufpos += fp->end - fp->buf;
1942
1943
0
  DEBUG_printf("9cups_fill: fp->compressed=%d", fp->compressed);
1944
1945
0
  while (!fp->ptr || fp->compressed)
1946
0
  {
1947
    // Check to see if we have read any data yet; if not, see if we have a
1948
    // compressed file...
1949
0
    if (!fp->ptr)
1950
0
    {
1951
      // Reset the file position in case we are seeking...
1952
0
      fp->compressed = 0;
1953
1954
      // Read the first bytes in the file to determine if we have a gzip'd file...
1955
0
      if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
1956
0
      {
1957
        // Can't read from file!
1958
0
        DEBUG_printf("9cups_fill: cups_read() returned " CUPS_LLFMT, CUPS_LLCAST bytes);
1959
1960
0
        fp->eof = 1;
1961
1962
0
  return (-1);
1963
0
      }
1964
1965
0
      if (bytes < 10 || fp->buf[0] != 0x1f ||
1966
0
          (fp->buf[1] & 255) != 0x8b ||
1967
0
          fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
1968
0
      {
1969
        // Not a gzip'd file!
1970
0
  fp->ptr = fp->buf;
1971
0
  fp->end = fp->buf + bytes;
1972
1973
0
        DEBUG_printf("9cups_fill: Returning " CUPS_LLFMT, CUPS_LLCAST bytes);
1974
1975
0
  return (bytes);
1976
0
      }
1977
1978
      // Parse header junk: extra data, original name, and comment...
1979
0
      ptr = (unsigned char *)fp->buf + 10;
1980
0
      end = (unsigned char *)fp->buf + bytes;
1981
1982
0
      if (fp->buf[3] & 0x04)
1983
0
      {
1984
        // Skip extra data...
1985
0
  if ((ptr + 2) > end)
1986
0
  {
1987
    // Can't read from file!
1988
0
    DEBUG_puts("9cups_fill: Extra gzip header data missing, returning -1.");
1989
1990
0
          fp->eof = 1;
1991
0
    errno   = EIO;
1992
1993
0
    return (-1);
1994
0
  }
1995
1996
0
  bytes = (ptr[1] << 8) | ptr[0];
1997
0
  ptr   += 2 + bytes;
1998
1999
0
  if (ptr > end)
2000
0
  {
2001
    // Can't read from file!
2002
0
    DEBUG_puts("9cups_fill: Extra gzip header data does not fit in initial buffer, returning -1.");
2003
2004
0
          fp->eof = 1;
2005
0
    errno   = EIO;
2006
2007
0
    return (-1);
2008
0
  }
2009
0
      }
2010
2011
0
      if (fp->buf[3] & 0x08)
2012
0
      {
2013
        // Skip original name data...
2014
0
  while (ptr < end && *ptr)
2015
0
          ptr ++;
2016
2017
0
  if (ptr < end)
2018
0
          ptr ++;
2019
0
  else
2020
0
  {
2021
    // Can't read from file!
2022
0
    DEBUG_puts("9cups_fill: Original filename in gzip header data does not fit in initial buffer, returning -1.");
2023
2024
0
          fp->eof = 1;
2025
0
    errno   = EIO;
2026
2027
0
    return (-1);
2028
0
  }
2029
0
      }
2030
2031
0
      if (fp->buf[3] & 0x10)
2032
0
      {
2033
        // Skip comment data...
2034
0
  while (ptr < end && *ptr)
2035
0
          ptr ++;
2036
2037
0
  if (ptr < end)
2038
0
          ptr ++;
2039
0
  else
2040
0
  {
2041
    // Can't read from file!
2042
0
    DEBUG_puts("9cups_fill: Comment in gzip header data does not fit in initial buffer, returning -1.");
2043
2044
0
          fp->eof = 1;
2045
0
    errno   = EIO;
2046
2047
0
    return (-1);
2048
0
  }
2049
0
      }
2050
2051
0
      if (fp->buf[3] & 0x02)
2052
0
      {
2053
        // Skip header CRC data...
2054
0
  ptr += 2;
2055
2056
0
  if (ptr > end)
2057
0
  {
2058
    // Can't read from file!
2059
0
    DEBUG_puts("9cups_fill: Header CRC in gzip header data does not fit in initial buffer, returning -1.");
2060
2061
0
          fp->eof = 1;
2062
0
    errno   = EIO;
2063
2064
0
    return (-1);
2065
0
  }
2066
0
      }
2067
2068
      // Copy the flate-compressed data to the compression buffer...
2069
0
      if ((bytes = end - ptr) > 0)
2070
0
        memcpy(fp->cbuf, ptr, (size_t)bytes);
2071
2072
      // Setup the decompressor data...
2073
0
      fp->stream.zalloc    = (alloc_func)0;
2074
0
      fp->stream.zfree     = (free_func)0;
2075
0
      fp->stream.opaque    = (voidpf)0;
2076
0
      fp->stream.next_in   = (Bytef *)fp->cbuf;
2077
0
      fp->stream.next_out  = NULL;
2078
0
      fp->stream.avail_in  = (uInt)bytes;
2079
0
      fp->stream.avail_out = 0;
2080
0
      fp->crc              = crc32(0L, Z_NULL, 0);
2081
2082
0
      if ((status = inflateInit2(&(fp->stream), -15)) != Z_OK)
2083
0
      {
2084
0
  DEBUG_printf("9cups_fill: inflateInit2 returned %d, returning -1.", status);
2085
2086
0
        fp->eof = 1;
2087
0
        errno   = EIO;
2088
2089
0
  return (-1);
2090
0
      }
2091
2092
0
      fp->compressed = 1;
2093
0
    }
2094
2095
0
    if (fp->compressed)
2096
0
    {
2097
      // If we have reached end-of-file, return immediately...
2098
0
      if (fp->eof)
2099
0
      {
2100
0
        DEBUG_puts("9cups_fill: EOF, returning 0.");
2101
2102
0
  return (0);
2103
0
      }
2104
2105
      // Fill the decompression buffer as needed...
2106
0
      if (fp->stream.avail_in == 0)
2107
0
      {
2108
0
  if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
2109
0
  {
2110
0
    DEBUG_printf("9cups_fill: cups_read error, returning %d.", (int)bytes);
2111
2112
0
    fp->eof = 1;
2113
2114
0
          return (bytes);
2115
0
  }
2116
2117
0
  fp->stream.next_in  = fp->cbuf;
2118
0
  fp->stream.avail_in = (uInt)bytes;
2119
0
      }
2120
2121
      // Decompress data from the buffer...
2122
0
      fp->stream.next_out  = (Bytef *)fp->buf;
2123
0
      fp->stream.avail_out = sizeof(fp->buf);
2124
2125
0
      status = inflate(&(fp->stream), Z_NO_FLUSH);
2126
2127
0
      if (fp->stream.next_out > (Bytef *)fp->buf)
2128
0
        fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
2129
0
                  (uInt)(fp->stream.next_out - (Bytef *)fp->buf));
2130
2131
0
      if (status == Z_STREAM_END)
2132
0
      {
2133
        // Read the CRC and length...
2134
0
  unsigned char trailer[8]; // Trailer bytes
2135
0
  uLong   tcrc;   // Trailer CRC
2136
0
  ssize_t   tbytes = 0; // Number of bytes
2137
2138
0
  if (fp->stream.avail_in > 0)
2139
0
  {
2140
    // Get the first N trailer bytes from the inflate stream...
2141
0
    if (fp->stream.avail_in > sizeof(trailer))
2142
0
      tbytes = (ssize_t)sizeof(trailer);
2143
0
    else
2144
0
      tbytes = (ssize_t)fp->stream.avail_in;
2145
2146
0
    memcpy(trailer, fp->stream.next_in, (size_t)tbytes);
2147
0
    fp->stream.next_in  += tbytes;
2148
0
    fp->stream.avail_in -= (size_t)tbytes;
2149
0
  }
2150
2151
        // Reset the compressed flag so that we re-read the file header...
2152
0
        inflateEnd(&fp->stream);
2153
2154
0
  fp->compressed = 0;
2155
2156
        // Get any remaining trailer bytes...
2157
0
        if (tbytes < (ssize_t)sizeof(trailer))
2158
0
  {
2159
0
    if (read(fp->fd, trailer + tbytes, sizeof(trailer) - (size_t)tbytes) < ((ssize_t)sizeof(trailer) - tbytes))
2160
0
    {
2161
      // Can't get it, so mark end-of-file...
2162
0
      DEBUG_puts("9cups_fill: Unable to read gzip CRC trailer, returning -1.");
2163
2164
0
      fp->eof = 1;
2165
0
      errno   = EIO;
2166
2167
0
      return (-1);
2168
0
    }
2169
0
  }
2170
2171
        // Calculate and compare the CRC...
2172
0
  tcrc = ((uLong)trailer[3] << 24) | ((uLong)trailer[2] << 16) | ((uLong)trailer[1] << 8) | ((uLong)trailer[0]);
2173
2174
0
  if (tcrc != fp->crc)
2175
0
  {
2176
    // Bad CRC, mark end-of-file...
2177
0
    DEBUG_printf("9cups_fill: tcrc=%08x != fp->crc=%08x, returning -1.", (unsigned int)tcrc, (unsigned int)fp->crc);
2178
2179
0
    fp->eof = 1;
2180
0
    errno   = EIO;
2181
2182
0
    return (-1);
2183
0
  }
2184
0
      }
2185
0
      else if (status < Z_OK)
2186
0
      {
2187
0
  DEBUG_printf("9cups_fill: inflate returned %d, returning -1.", status);
2188
2189
0
        fp->eof = 1;
2190
0
        errno   = EIO;
2191
2192
0
  return (-1);
2193
0
      }
2194
2195
0
      bytes = (ssize_t)sizeof(fp->buf) - (ssize_t)fp->stream.avail_out;
2196
2197
      // Return the decompressed data...
2198
0
      fp->ptr = fp->buf;
2199
0
      fp->end = fp->buf + bytes;
2200
2201
0
      if (bytes)
2202
0
      {
2203
0
        DEBUG_printf("9cups_fill: Returning %d.", (int)bytes);
2204
0
  return (bytes);
2205
0
      }
2206
0
    }
2207
0
  }
2208
2209
  // Read a buffer's full of data...
2210
0
  if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
2211
0
  {
2212
    // Can't read from file!
2213
0
    fp->eof = 1;
2214
0
    fp->ptr = fp->buf;
2215
0
    fp->end = fp->buf;
2216
0
  }
2217
0
  else
2218
0
  {
2219
    // Return the bytes we read...
2220
0
    fp->eof = 0;
2221
0
    fp->ptr = fp->buf;
2222
0
    fp->end = fp->buf + bytes;
2223
0
  }
2224
2225
0
  DEBUG_printf("9cups_fill: Not gzip, returning %d.", (int)bytes);
2226
2227
0
  return (bytes);
2228
0
}
2229
2230
2231
//
2232
// 'cups_open()' - Safely open a file for writing.
2233
//
2234
// We don't allow appending to directories or files that are hard-linked or
2235
// symlinked.
2236
//
2237
2238
static int        // O - File descriptor or -1 otherwise
2239
cups_open(const char *filename,   // I - Filename
2240
          int        oflag,   // I - Open flags
2241
    int        mode)    // I - Open permissions
2242
0
{
2243
0
  int   fd;     // File descriptor
2244
0
  struct stat fileinfo;   // File information
2245
0
#ifndef _WIN32
2246
0
  struct stat linkinfo;   // Link information
2247
0
#endif // !_WIN32
2248
2249
2250
  // Open the file...
2251
0
  if ((fd = open(filename, oflag, mode)) < 0)
2252
0
    return (-1);
2253
2254
  // Then verify that the file descriptor doesn't point to a directory or hard-linked file.
2255
0
  if (fstat(fd, &fileinfo))
2256
0
  {
2257
0
    int temp = errno;
2258
0
    close(fd);
2259
0
    errno = temp;
2260
0
    return (-1);
2261
0
  }
2262
2263
0
  if (fileinfo.st_nlink != 1)
2264
0
  {
2265
0
    close(fd);
2266
0
    errno = EPERM;
2267
0
    return (-1);
2268
0
  }
2269
2270
#ifdef _WIN32
2271
  if (fileinfo.st_mode & _S_IFDIR)
2272
#else
2273
0
  if (S_ISDIR(fileinfo.st_mode))
2274
0
#endif // _WIN32
2275
0
  {
2276
0
    close(fd);
2277
0
    errno = EISDIR;
2278
0
    return (-1);
2279
0
  }
2280
2281
0
#ifndef _WIN32
2282
  // Then use lstat to determine whether the filename is a symlink...
2283
0
  if (lstat(filename, &linkinfo))
2284
0
  {
2285
0
    int temp = errno;
2286
0
    close(fd);
2287
0
    errno = temp;
2288
0
    return (-1);
2289
0
  }
2290
2291
0
  if (S_ISLNK(linkinfo.st_mode) ||
2292
0
      fileinfo.st_dev != linkinfo.st_dev ||
2293
0
      fileinfo.st_ino != linkinfo.st_ino ||
2294
#ifdef HAVE_ST_GEN
2295
      fileinfo.st_gen != linkinfo.st_gen ||
2296
#endif // HAVE_ST_GEN
2297
0
      fileinfo.st_nlink != linkinfo.st_nlink ||
2298
0
      fileinfo.st_mode != linkinfo.st_mode)
2299
0
  {
2300
    // Yes, don't allow!
2301
0
    close(fd);
2302
0
    errno = EPERM;
2303
0
    return (-1);
2304
0
  }
2305
0
#endif // !_WIN32
2306
2307
0
  return (fd);
2308
0
}
2309
2310
2311
//
2312
// 'cups_read()' - Read from a file descriptor.
2313
//
2314
2315
static ssize_t        // O - Number of bytes read or -1
2316
cups_read(cups_file_t *fp,    // I - CUPS file
2317
          char        *buf,   // I - Buffer
2318
    size_t      bytes)    // I - Number bytes
2319
0
{
2320
0
  ssize_t total;      // Total bytes read
2321
2322
2323
0
  DEBUG_printf("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
2324
2325
  // Loop until we read at least 0 bytes...
2326
0
  for (;;)
2327
0
  {
2328
#ifdef _WIN32
2329
    if (fp->mode == 's')
2330
      total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2331
    else
2332
      total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2333
#else
2334
0
    if (fp->mode == 's')
2335
0
      total = recv(fp->fd, buf, bytes, 0);
2336
0
    else
2337
0
      total = read(fp->fd, buf, bytes);
2338
0
#endif // _WIN32
2339
2340
0
    DEBUG_printf("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total);
2341
2342
0
    if (total >= 0)
2343
0
      break;
2344
2345
    // Reads can be interrupted by signals and unavailable resources...
2346
0
    if (errno == EAGAIN || errno == EINTR)
2347
0
      continue;
2348
0
    else
2349
0
      return (-1);
2350
0
  }
2351
2352
  // Return the total number of bytes read...
2353
0
  return (total);
2354
0
}
2355
2356
2357
//
2358
// 'cups_write()' - Write to a file descriptor.
2359
//
2360
2361
static ssize_t        // O - Number of bytes written or -1
2362
cups_write(cups_file_t *fp,   // I - CUPS file
2363
           const char  *buf,    // I - Buffer
2364
     size_t      bytes)   // I - Number bytes
2365
0
{
2366
0
  size_t  total;      // Total bytes written
2367
0
  ssize_t count;      // Count this time
2368
2369
2370
0
  DEBUG_printf("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
2371
2372
  // Loop until all bytes are written...
2373
0
  total = 0;
2374
0
  while (bytes > 0)
2375
0
  {
2376
#ifdef _WIN32
2377
    if (fp->mode == 's')
2378
      count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2379
    else
2380
      count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2381
#else
2382
0
    if (fp->mode == 's')
2383
0
      count = send(fp->fd, buf, bytes, 0);
2384
0
    else
2385
0
      count = write(fp->fd, buf, bytes);
2386
0
#endif // _WIN32
2387
2388
0
    DEBUG_printf("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count);
2389
2390
0
    if (count < 0)
2391
0
    {
2392
      // Writes can be interrupted by signals and unavailable resources...
2393
0
      if (errno == EAGAIN || errno == EINTR)
2394
0
        continue;
2395
0
      else
2396
0
        return (-1);
2397
0
    }
2398
2399
    // Update the counts for the last write call...
2400
0
    bytes -= (size_t)count;
2401
0
    total += (size_t)count;
2402
0
    buf   += count;
2403
0
  }
2404
2405
  // Return the total number of bytes written...
2406
0
  return ((ssize_t)total);
2407
0
}