Coverage Report

Created: 2024-11-19 06:28

/src/libcups/cups/file.c
Line
Count
Source (jump to first uncovered line)
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, etc.
8
//
9
// Copyright © 2021-2024 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
#ifndef va_copy
23
#  define va_copy(__list1, __list2) ((void)(__list1 = __list2))
24
#endif
25
26
27
//
28
// Internal structures...
29
//
30
31
struct _cups_file_s     // CUPS file structure...
32
{
33
  int   fd;     // File descriptor
34
  bool    compressed;   // Compression used?
35
  char    mode,     // Mode ('r' or 'w')
36
    buf[4096],    // Buffer
37
    *ptr,     // Pointer into buffer
38
    *end;     // End of buffer data
39
  bool    is_stdio,   // stdin/out/err?
40
    eof;      // End of file?
41
  off_t   pos,      // Position in file
42
    bufpos;     // File position for start of buffer
43
44
  z_stream  stream;     // (De)compression stream
45
  Bytef   cbuf[4096];   // (De)compression buffer
46
  uLong   crc;      // (De)compression CRC
47
48
  char    *printf_buffer;   // cupsFilePrintf buffer
49
  size_t  printf_size;    // Size of cupsFilePrintf buffer
50
};
51
52
53
//
54
// Local functions...
55
//
56
57
static bool cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
58
static ssize_t  cups_fill(cups_file_t *fp);
59
static int  cups_open(const char *filename, int oflag, int mode);
60
static ssize_t  cups_read(cups_file_t *fp, char *buf, size_t bytes);
61
static bool cups_write(cups_file_t *fp, const char *buf, size_t bytes);
62
63
64
//
65
// 'cupsFileClose()' - Close a CUPS file.
66
//
67
68
bool          // O - `true` on success, `false` on error
69
cupsFileClose(cups_file_t *fp)    // I - CUPS file
70
7.69k
{
71
7.69k
  int fd;       // File descriptor
72
7.69k
  char  mode;       // Open mode
73
7.69k
  bool  status;       // Return status
74
75
76
  // Range check...
77
7.69k
  if (!fp)
78
0
    return (false);
79
80
  // Flush pending write data...
81
7.69k
  if (fp->mode == 'w')
82
5.13k
    status = cupsFileFlush(fp);
83
2.56k
  else
84
2.56k
    status = true;
85
86
7.69k
  if (fp->compressed && status)
87
1.39k
  {
88
1.39k
    if (fp->mode == 'r')
89
1.39k
    {
90
      // Free decompression data...
91
1.39k
      inflateEnd(&fp->stream);
92
1.39k
    }
93
0
    else
94
0
    {
95
      // Flush any remaining compressed data...
96
0
      unsigned char trailer[8]; // Trailer CRC and length
97
0
      bool    done;   // Done writing...
98
99
100
0
      fp->stream.avail_in = 0;
101
102
0
      for (done = false;;)
103
0
      {
104
0
        if (fp->stream.next_out > fp->cbuf)
105
0
  {
106
0
    status = cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf));
107
108
0
    fp->stream.next_out  = fp->cbuf;
109
0
    fp->stream.avail_out = sizeof(fp->cbuf);
110
0
  }
111
112
0
        if (done || !status)
113
0
    break;
114
115
0
        done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END && fp->stream.next_out == fp->cbuf;
116
0
      }
117
118
      // Write the CRC and length...
119
0
      trailer[0] = (unsigned char)fp->crc;
120
0
      trailer[1] = (unsigned char)(fp->crc >> 8);
121
0
      trailer[2] = (unsigned char)(fp->crc >> 16);
122
0
      trailer[3] = (unsigned char)(fp->crc >> 24);
123
0
      trailer[4] = (unsigned char)fp->pos;
124
0
      trailer[5] = (unsigned char)(fp->pos >> 8);
125
0
      trailer[6] = (unsigned char)(fp->pos >> 16);
126
0
      trailer[7] = (unsigned char)(fp->pos >> 24);
127
128
0
      status = cups_write(fp, (char *)trailer, 8);
129
130
      // Free all memory used by the compression stream...
131
0
      deflateEnd(&(fp->stream));
132
0
    }
133
1.39k
  }
134
135
  // If this is one of the cupsFileStdin/out/err files, return now and don't
136
  // actually free memory or close (these last the life of the process...)
137
7.69k
  if (fp->is_stdio)
138
0
    return (status);
139
140
  // Save the file descriptor we used and free memory...
141
7.69k
  fd   = fp->fd;
142
7.69k
  mode = fp->mode;
143
144
7.69k
  if (fp->printf_buffer)
145
0
    free(fp->printf_buffer);
146
147
7.69k
  free(fp);
148
149
  // Close the file, returning the close status...
150
7.69k
  if (mode == 's')
151
0
    status = httpAddrClose(NULL, fd);
152
7.69k
  else if (close(fd) < 0)
153
0
    status = false;
154
155
7.69k
  return (status);
156
7.69k
}
157
158
159
//
160
// 'cupsFileEOF()' - Return the end-of-file status.
161
//
162
163
bool          // O - `true` on end of file, `false` otherwise
164
cupsFileEOF(cups_file_t *fp)    // I - CUPS file
165
0
{
166
0
  return (fp ? fp->eof : true);
167
0
}
168
169
170
//
171
// 'cupsFileFind()' - Find a file using the specified path.
172
//
173
// This function allows the paths in the path string to be separated by
174
// colons (POSIX standard) or semicolons (Windows standard) and stores the
175
// result in the buffer supplied.  If the file cannot be found in any of
176
// the supplied paths, `NULL` is returned.  A `NULL` path only matches the
177
// current directory.
178
//
179
180
const char *        // O - Full path to file or `NULL` if not found
181
cupsFileFind(const char *filename,  // I - File to find
182
             const char *path,    // I - Colon/semicolon-separated path
183
             bool       executable, // I - `true` = executable files, `false` = any file/dir
184
       char       *buffer,  // I - Filename buffer
185
       size_t     bufsize)  // I - Size of filename buffer
186
0
{
187
0
  char  *bufptr,      // Current position in buffer
188
0
  *bufend;      // End of buffer
189
190
191
  // Range check input...
192
0
  if (!filename || !buffer || bufsize < 2)
193
0
    return (NULL);
194
195
0
  if (!path)
196
0
  {
197
    // No path, so check current directory...
198
0
    if (!access(filename, 0))
199
0
    {
200
0
      cupsCopyString(buffer, filename, (size_t)bufsize);
201
0
      return (buffer);
202
0
    }
203
0
    else
204
0
    {
205
0
      return (NULL);
206
0
    }
207
0
  }
208
209
  // Now check each path and return the first match...
210
0
  bufend = buffer + bufsize - 1;
211
0
  bufptr = buffer;
212
213
0
  while (*path)
214
0
  {
215
#ifdef _WIN32
216
    if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
217
#else
218
0
    if (*path == ';' || *path == ':')
219
0
#endif // _WIN32
220
0
    {
221
0
      if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
222
0
        *bufptr++ = '/';
223
224
0
      cupsCopyString(bufptr, filename, (size_t)(bufend - bufptr));
225
226
#ifdef _WIN32
227
      if (!access(buffer, 0))
228
#else
229
0
      if (!access(buffer, executable ? X_OK : 0))
230
0
#endif // _WIN32
231
0
        return (buffer);
232
233
0
      bufptr = buffer;
234
0
    }
235
0
    else if (bufptr < bufend)
236
0
      *bufptr++ = *path;
237
238
0
    path ++;
239
0
  }
240
241
  // Check the last path...
242
0
  if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
243
0
    *bufptr++ = '/';
244
245
0
  cupsCopyString(bufptr, filename, (size_t)(bufend - bufptr));
246
247
0
  if (!access(buffer, 0))
248
0
    return (buffer);
249
0
  else
250
0
    return (NULL);
251
0
}
252
253
254
//
255
// 'cupsFileFlush()' - Flush pending output.
256
//
257
258
bool          // O - `true` on success, `false` on error
259
cupsFileFlush(cups_file_t *fp)    // I - CUPS file
260
97.4k
{
261
97.4k
  ssize_t bytes;      // Bytes to write
262
97.4k
  bool    ret;      // Return value
263
264
265
  // Range check input...
266
97.4k
  if (!fp || fp->mode != 'w')
267
0
    return (false);
268
269
97.4k
  bytes = (ssize_t)(fp->ptr - fp->buf);
270
271
97.4k
  if (bytes > 0)
272
91.2k
  {
273
91.2k
    if (fp->compressed)
274
0
      ret = cups_compress(fp, fp->buf, (size_t)bytes);
275
91.2k
    else
276
91.2k
      ret = cups_write(fp, fp->buf, (size_t)bytes);
277
278
91.2k
    fp->ptr = fp->buf;
279
280
91.2k
    return (ret);
281
91.2k
  }
282
283
6.26k
  return (true);
284
97.4k
}
285
286
287
//
288
// 'cupsFileGetChar()' - Get a single character from a file.
289
//
290
291
int         // O - Character or `-1` on end of file
292
cupsFileGetChar(cups_file_t *fp)  // I - CUPS file
293
0
{
294
  // Range check input...
295
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's'))
296
0
    return (-1);
297
298
0
  if (fp->eof)
299
0
    return (-1);
300
301
  // If the input buffer is empty, try to read more data...
302
0
  if (fp->ptr >= fp->end)
303
0
  {
304
0
    if (cups_fill(fp) <= 0)
305
0
      return (-1);
306
0
  }
307
308
  // Return the next character in the buffer...
309
0
  fp->pos ++;
310
311
0
  return (*(fp->ptr)++ & 255);
312
0
}
313
314
315
//
316
// 'cupsFileGetConf()' - Get a line from a configuration file.
317
//
318
319
char *          // O  - Line read or `NULL` on end of file or error
320
cupsFileGetConf(cups_file_t *fp,  // I  - CUPS file
321
                char        *buf, // O  - String buffer
322
    size_t      buflen, // I  - Size of string buffer
323
                char        **value,  // O  - Pointer to value
324
    int         *linenum) // IO - Current line number
325
0
{
326
0
  char  *ptr;       // Pointer into line
327
328
329
  // Range check input...
330
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
331
0
      !buf || buflen < 2 || !value)
332
0
  {
333
0
    if (value)
334
0
      *value = NULL;
335
336
0
    return (NULL);
337
0
  }
338
339
  // Read the next non-comment line...
340
0
  *value = NULL;
341
342
0
  while (cupsFileGets(fp, buf, buflen))
343
0
  {
344
0
    (*linenum) ++;
345
346
    // Strip any comments...
347
0
    if ((ptr = strchr(buf, '#')) != NULL)
348
0
    {
349
0
      if (ptr > buf && ptr[-1] == '\\')
350
0
      {
351
        // Unquote the #...
352
0
  _cups_strcpy(ptr - 1, ptr);
353
0
      }
354
0
      else
355
0
      {
356
        // Strip the comment and any trailing whitespace...
357
0
  while (ptr > buf)
358
0
  {
359
0
    if (!_cups_isspace(ptr[-1]))
360
0
      break;
361
362
0
    ptr --;
363
0
  }
364
365
0
  *ptr = '\0';
366
0
      }
367
0
    }
368
369
    // Strip leading whitespace...
370
0
    for (ptr = buf; _cups_isspace(*ptr); ptr ++);
371
372
0
    if (ptr > buf)
373
0
      _cups_strcpy(buf, ptr);
374
375
    // See if there is anything left...
376
0
    if (buf[0])
377
0
    {
378
      // Yes, grab any value and return...
379
0
      for (ptr = buf; *ptr; ptr ++)
380
0
      {
381
0
        if (_cups_isspace(*ptr))
382
0
    break;
383
0
      }
384
385
0
      if (*ptr)
386
0
      {
387
        // Have a value, skip any other spaces...
388
0
        while (_cups_isspace(*ptr))
389
0
    *ptr++ = '\0';
390
391
0
        if (*ptr)
392
0
    *value = ptr;
393
394
        // Strip trailing whitespace and > for lines that begin with <...
395
0
        ptr += strlen(ptr) - 1;
396
397
0
        if (buf[0] == '<' && *ptr == '>')
398
0
        {
399
0
    *ptr-- = '\0';
400
0
  }
401
0
  else if (buf[0] == '<' && *ptr != '>')
402
0
        {
403
    // Syntax error...
404
0
    *value = NULL;
405
0
    return (buf);
406
0
  }
407
408
0
        while (ptr > *value && _cups_isspace(*ptr))
409
0
    *ptr-- = '\0';
410
0
      }
411
412
      // Return the line...
413
0
      return (buf);
414
0
    }
415
0
  }
416
417
0
  return (NULL);
418
0
}
419
420
421
//
422
// 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
423
//                       contain binary data.
424
//
425
// This function differs from @link cupsFileGets@ in that the trailing CR
426
// and LF are preserved, as is any binary data on the line. The buffer is
427
// `nul`-terminated, however you should use the returned length to determine
428
// the number of bytes on the line.
429
//
430
431
size_t          // O - Number of bytes on line or 0 on end of file
432
cupsFileGetLine(cups_file_t *fp,  // I - File to read from
433
                char        *buf, // I - Buffer
434
                size_t      buflen) // I - Size of buffer
435
0
{
436
0
  int   ch;     // Character from file
437
0
  char    *ptr,     // Current position in line buffer
438
0
    *end;     // End of line buffer
439
440
441
  // Range check input...
442
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
443
0
    return (0);
444
445
  // Now loop until we have a valid line...
446
0
  for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
447
0
  {
448
0
    if (fp->ptr >= fp->end)
449
0
    {
450
0
      if (cups_fill(fp) <= 0)
451
0
        break;
452
0
    }
453
454
0
    *ptr++ = ch = *(fp->ptr)++;
455
0
    fp->pos ++;
456
457
0
    if (ch == '\r')
458
0
    {
459
      // Check for CR LF...
460
0
      if (fp->ptr >= fp->end)
461
0
      {
462
0
  if (cups_fill(fp) <= 0)
463
0
          break;
464
0
      }
465
466
0
      if (*(fp->ptr) == '\n')
467
0
      {
468
0
        *ptr++ = *(fp->ptr)++;
469
0
  fp->pos ++;
470
0
      }
471
472
0
      break;
473
0
    }
474
0
    else if (ch == '\n')
475
0
    {
476
      // Line feed ends a line...
477
0
      break;
478
0
    }
479
0
  }
480
481
0
  *ptr = '\0';
482
483
0
  return ((size_t)(ptr - buf));
484
0
}
485
486
487
//
488
// 'cupsFileGets()' - Get a CR and/or LF-terminated line.
489
//
490
491
char *          // O - Line read or `NULL` on end of file or error
492
cupsFileGets(cups_file_t *fp,   // I - CUPS file
493
             char        *buf,    // O - String buffer
494
       size_t      buflen)  // I - Size of string buffer
495
0
{
496
0
  int   ch;     // Character from file
497
0
  char    *ptr,     // Current position in line buffer
498
0
    *end;     // End of line buffer
499
500
501
  // Range check input...
502
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
503
0
    return (NULL);
504
505
  // Now loop until we have a valid line...
506
0
  for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
507
0
  {
508
0
    if (fp->ptr >= fp->end)
509
0
    {
510
0
      if (cups_fill(fp) <= 0)
511
0
      {
512
0
        if (ptr == buf)
513
0
    return (NULL);
514
0
  else
515
0
          break;
516
0
      }
517
0
    }
518
519
0
    ch = *(fp->ptr)++;
520
0
    fp->pos ++;
521
522
0
    if (ch == '\r')
523
0
    {
524
      // Check for CR LF...
525
0
      if (fp->ptr >= fp->end)
526
0
      {
527
0
  if (cups_fill(fp) <= 0)
528
0
          break;
529
0
      }
530
531
0
      if (*(fp->ptr) == '\n')
532
0
      {
533
0
        fp->ptr ++;
534
0
  fp->pos ++;
535
0
      }
536
537
0
      break;
538
0
    }
539
0
    else if (ch == '\n')
540
0
    {
541
      // Line feed ends a line...
542
0
      break;
543
0
    }
544
0
    else
545
0
    {
546
0
      *ptr++ = (char)ch;
547
0
    }
548
0
  }
549
550
0
  *ptr = '\0';
551
552
0
  return (buf);
553
0
}
554
555
556
//
557
// 'cupsFileIsCompressed()' - Return whether a file is compressed.
558
//
559
560
bool          // O - `true` if compressed, `false` if not
561
cupsFileIsCompressed(cups_file_t *fp) // I - CUPS file
562
0
{
563
0
  return (fp ? fp->compressed : false);
564
0
}
565
566
567
//
568
// 'cupsFileLock()' - Temporarily lock access to a file.
569
//
570
571
bool          // O - `true` on success, `false` on error
572
cupsFileLock(cups_file_t *fp,   // I - CUPS file
573
             bool        block)   // I - `true` to wait for the lock, `false` to fail right away
574
0
{
575
  // Range check...
576
0
  if (!fp || fp->mode == 's')
577
0
    return (false);
578
579
  // Try the lock...
580
#ifdef _WIN32
581
  return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0) == 0);
582
#else
583
0
  return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0) == 0);
584
0
#endif // _WIN32
585
0
}
586
587
588
//
589
// 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
590
//
591
592
int         // O - File descriptor
593
cupsFileNumber(cups_file_t *fp)   // I - CUPS file
594
0
{
595
0
  if (fp)
596
0
    return (fp->fd);
597
0
  else
598
0
    return (-1);
599
0
}
600
601
602
//
603
// 'cupsFileOpen()' - Open a CUPS file.
604
//
605
// This function opens a file or socket for use with the CUPS file API.
606
//
607
// The "filename" argument is a filename or socket address.
608
//
609
// The "mode" parameter can be "r" to read, "w" to write, overwriting any
610
// existing file, "a" to append to an existing file or create a new file,
611
// or "s" to open a socket connection.
612
//
613
// When opening for writing ("w"), an optional number from `1` to `9` can be
614
// supplied which enables Flate compression of the file.  Compression is
615
// not supported for the "a" (append) mode.
616
//
617
// When opening for writing ("w") or append ("a"), an optional 'm###' suffix
618
// can be used to set the permissions of the opened file.
619
//
620
// When opening a socket connection, the filename is a string of the form
621
// "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
622
// connection as needed, generally preferring IPv6 connections when there is
623
// a choice.
624
//
625
626
cups_file_t *       // O - CUPS file or `NULL` if the file or socket cannot be opened
627
cupsFileOpen(const char *filename,  // I - Name of file
628
             const char *mode)    // I - Open mode
629
7.70k
{
630
7.70k
  cups_file_t *fp;      // New CUPS file
631
7.70k
  int   fd;     // File descriptor
632
7.70k
  char    hostname[1024],   // Hostname
633
7.70k
    *portname;    // Port "name" (number or service)
634
7.70k
  http_addrlist_t *addrlist;    // Host address list
635
7.70k
  int   perm = 0664;    // Permissions for write/append
636
7.70k
  const char  *ptr;     // Pointer into mode string
637
638
639
  // Range check input...
640
7.70k
  if (!filename || !mode || (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') || (*mode == 'a' && isdigit(mode[1] & 255)))
641
0
    return (NULL);
642
643
7.70k
  if ((ptr = strchr(mode, 'm')) != NULL && ptr[1] >= '0' && ptr[1] <= '7')
644
0
  {
645
    // Get permissions from mode string...
646
0
    perm = (int)strtol(mode + 1, NULL, 8);
647
0
  }
648
649
  // Open the file...
650
7.70k
  switch (*mode)
651
7.70k
  {
652
0
    case 'a' : // Append file
653
0
        fd = cups_open(filename, O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, perm);
654
0
        break;
655
656
2.56k
    case 'r' : // Read file
657
2.56k
  fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
658
2.56k
  break;
659
660
5.13k
    case 'w' : // Write file
661
5.13k
        fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
662
5.13k
  if (fd < 0 && errno == ENOENT)
663
2.56k
  {
664
2.56k
    fd = cups_open(filename, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY, perm);
665
2.56k
    if (fd < 0 && errno == EEXIST)
666
0
      fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
667
2.56k
  }
668
669
5.13k
  if (fd >= 0)
670
#ifdef _WIN32
671
    _chsize(fd, 0);
672
#else
673
5.13k
    ftruncate(fd, 0);
674
5.13k
#endif // _WIN32
675
5.13k
        break;
676
677
0
    case 's' : // Read/write socket
678
0
        cupsCopyString(hostname, filename, sizeof(hostname));
679
0
  if ((portname = strrchr(hostname, ':')) != NULL)
680
0
    *portname++ = '\0';
681
0
  else
682
0
    return (NULL);
683
684
        // Lookup the hostname and service...
685
0
        if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
686
0
    return (NULL);
687
688
        // Connect to the server...
689
0
        if (!httpAddrConnect(addrlist, &fd, 30000, NULL))
690
0
  {
691
0
    httpAddrFreeList(addrlist);
692
0
    return (NULL);
693
0
  }
694
695
0
  httpAddrFreeList(addrlist);
696
0
  break;
697
698
0
    default : // Remove bogus compiler warning...
699
0
        return (NULL);
700
7.70k
  }
701
702
7.70k
  if (fd < 0)
703
2
    return (NULL);
704
705
  // Create the CUPS file structure...
706
7.69k
  if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
707
0
  {
708
0
    if (*mode == 's')
709
0
      httpAddrClose(NULL, fd);
710
0
    else
711
0
      close(fd);
712
0
  }
713
714
  // Return it...
715
7.69k
  return (fp);
716
7.70k
}
717
718
719
//
720
// 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
721
//
722
// This function prepares a file descriptor for use with the CUPS file API.
723
//
724
// The "fd" argument specifies the file descriptor.
725
//
726
// The "mode" argument can be "r" to read, "w" to write, "a" to append,
727
// or "s" to treat the file descriptor as a bidirectional socket connection.
728
//
729
// When opening for writing ("w"), an optional number from `1` to `9` can be
730
// supplied which enables Flate compression of the file.  Compression is
731
// not supported for the "a" (append) mode.
732
//
733
734
cups_file_t *       // O - CUPS file or `NULL` if the file could not be opened
735
cupsFileOpenFd(int        fd,   // I - File descriptor
736
         const char *mode)  // I - Open mode
737
7.69k
{
738
7.69k
  cups_file_t *fp;      // New CUPS file
739
740
741
  // Range check input...
742
7.69k
  if (fd < 0 || !mode || (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') || (*mode == 'a' && isdigit(mode[1] & 255)))
743
0
    return (NULL);
744
745
  // Allocate memory...
746
7.69k
  if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
747
0
    return (NULL);
748
749
  // Open the file...
750
7.69k
  fp->fd = fd;
751
752
7.69k
  switch (*mode)
753
7.69k
  {
754
0
    case 'a' :
755
5.13k
    case 'w' :
756
5.13k
        if (*mode == 'a')
757
0
          fp->pos = lseek(fd, 0, SEEK_END);
758
759
5.13k
  fp->mode = 'w';
760
5.13k
  fp->ptr  = fp->buf;
761
5.13k
  fp->end  = fp->buf + sizeof(fp->buf);
762
763
5.13k
  if (mode[1] >= '1' && mode[1] <= '9')
764
0
  {
765
    // Open a compressed stream, so write the standard gzip file header...
766
0
          unsigned char header[10]; // gzip file header
767
0
    time_t  curtime;  // Current time
768
769
770
0
          curtime   = time(NULL);
771
0
    header[0] = 0x1f;
772
0
    header[1] = 0x8b;
773
0
    header[2] = Z_DEFLATED;
774
0
    header[3] = 0;
775
0
    header[4] = (unsigned char)curtime;
776
0
    header[5] = (unsigned char)(curtime >> 8);
777
0
    header[6] = (unsigned char)(curtime >> 16);
778
0
    header[7] = (unsigned char)(curtime >> 24);
779
0
    header[8] = 0;
780
0
    header[9] = 0x03;
781
782
0
    cups_write(fp, (char *)header, 10);
783
784
          // Initialize the compressor...
785
0
          if (deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) < Z_OK)
786
0
          {
787
0
            free(fp);
788
0
      return (NULL);
789
0
          }
790
791
0
    fp->stream.next_out  = fp->cbuf;
792
0
    fp->stream.avail_out = sizeof(fp->cbuf);
793
0
    fp->compressed       = true;
794
0
    fp->crc              = crc32(0L, Z_NULL, 0);
795
0
  }
796
5.13k
        break;
797
798
5.13k
    case 'r' :
799
2.56k
  fp->mode = 'r';
800
2.56k
  break;
801
802
0
    case 's' :
803
0
        fp->mode = 's';
804
0
  break;
805
806
0
    default : // Remove bogus compiler warning...
807
0
        return (NULL);
808
7.69k
  }
809
810
  // Don't pass this file to child processes...
811
7.69k
#ifndef _WIN32
812
7.69k
  if (fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC))
813
0
    DEBUG_printf("cupsFileOpenFd: fcntl(F_SETFD, FD_CLOEXEC) failed - %s", strerror(errno));
814
7.69k
#endif // !_WIN32
815
816
7.69k
  return (fp);
817
7.69k
}
818
819
820
//
821
// '_cupsFilePeekAhead()' - See if the requested character is buffered up.
822
//
823
824
bool          // O - `true` if present, `false` otherwise
825
_cupsFilePeekAhead(cups_file_t *fp, // I - CUPS file
826
                   int         ch)  // I - Character
827
0
{
828
0
  return (fp && fp->ptr && memchr(fp->ptr, ch, (size_t)(fp->end - fp->ptr)));
829
0
}
830
831
832
//
833
// 'cupsFilePeekChar()' - Peek at the next character from a file.
834
//
835
836
int         // O - Character or `-1` on end of file
837
cupsFilePeekChar(cups_file_t *fp) // I - CUPS file
838
0
{
839
  // Range check input...
840
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's'))
841
0
    return (-1);
842
843
  // If the input buffer is empty, try to read more data...
844
0
  if (fp->ptr >= fp->end)
845
0
  {
846
0
    if (cups_fill(fp) <= 0)
847
0
      return (-1);
848
0
  }
849
850
  // Return the next character in the buffer...
851
0
  return (*(fp->ptr) & 255);
852
0
}
853
854
855
//
856
// 'cupsFilePrintf()' - Write a formatted string.
857
//
858
859
bool          // O - `true` on success, `false` on error
860
cupsFilePrintf(cups_file_t *fp,   // I - CUPS file
861
               const char  *format, // I - Printf-style format string
862
         ...)     // I - Additional args as necessary
863
0
{
864
0
  va_list ap, ap2;    // Argument list
865
0
  ssize_t bytes;      // Formatted size
866
867
868
0
  if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
869
0
    return (false);
870
871
0
  if (!fp->printf_buffer)
872
0
  {
873
    // Start with an 1k printf buffer...
874
0
    if ((fp->printf_buffer = malloc(1024)) == NULL)
875
0
      return (false);
876
877
0
    fp->printf_size = 1024;
878
0
  }
879
880
0
  va_start(ap, format);
881
0
  va_copy(ap2, ap);
882
0
  bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap2);
883
0
  va_end(ap2);
884
885
0
  if (bytes >= (ssize_t)fp->printf_size)
886
0
  {
887
    // Expand the printf buffer...
888
0
    char  *temp;      // Temporary buffer pointer
889
890
0
    if (bytes > 65535)
891
0
    {
892
0
      va_end(ap);
893
0
      return (-1);
894
0
    }
895
896
0
    if ((temp = realloc(fp->printf_buffer, (size_t)(bytes + 1))) == NULL)
897
0
    {
898
0
      va_end(ap);
899
0
      return (-1);
900
0
    }
901
902
0
    fp->printf_buffer = temp;
903
0
    fp->printf_size   = (size_t)(bytes + 1);
904
905
0
    bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
906
0
  }
907
908
0
  va_end(ap);
909
910
0
  if (fp->mode == 's')
911
0
  {
912
0
    if (!cups_write(fp, fp->printf_buffer, (size_t)bytes))
913
0
      return (false);
914
915
0
    fp->pos += bytes;
916
917
0
    return ((int)bytes);
918
0
  }
919
920
0
  if ((fp->ptr + bytes) > fp->end)
921
0
  {
922
0
    if (!cupsFileFlush(fp))
923
0
      return (false);
924
0
  }
925
926
0
  fp->pos += bytes;
927
928
0
  if ((size_t)bytes > sizeof(fp->buf))
929
0
  {
930
0
    if (fp->compressed)
931
0
      return (cups_compress(fp, fp->printf_buffer, (size_t)bytes));
932
0
    else
933
0
      return (cups_write(fp, fp->printf_buffer, (size_t)bytes));
934
0
  }
935
0
  else
936
0
  {
937
0
    memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
938
0
    fp->ptr += bytes;
939
940
0
    if (fp->is_stdio && !cupsFileFlush(fp))
941
0
      return (false);
942
0
    else
943
0
      return (true);
944
0
  }
945
0
}
946
947
948
//
949
// 'cupsFilePutChar()' - Write a character.
950
//
951
952
bool          // O - `true` on success, `false` on error
953
cupsFilePutChar(cups_file_t *fp,  // I - CUPS file
954
                int         c)    // I - Character to write
955
0
{
956
  // Range check input...
957
0
  if (!fp || (fp->mode != 'w' && fp->mode != 's'))
958
0
    return (false);
959
960
0
  if (fp->mode == 's')
961
0
  {
962
    // Send character immediately over socket...
963
0
    char ch;        // Output character
964
965
0
    ch = (char)c;
966
967
0
    if (send(fp->fd, &ch, 1, 0) < 1)
968
0
      return (false);
969
0
  }
970
0
  else
971
0
  {
972
    // Buffer it up...
973
0
    if (fp->ptr >= fp->end)
974
0
    {
975
0
      if (!cupsFileFlush(fp))
976
0
  return (false);
977
0
    }
978
979
0
    *(fp->ptr) ++ = (char)c;
980
0
  }
981
982
0
  fp->pos ++;
983
984
0
  return (true);
985
0
}
986
987
988
//
989
// 'cupsFilePutConf()' - Write a configuration line.
990
//
991
// This function handles any comment escaping of the value.
992
//
993
994
bool          // O - `true` on success, `false` on error
995
cupsFilePutConf(cups_file_t *fp,  // I - CUPS file
996
                const char *directive,  // I - Directive
997
    const char *value)  // I - Value
998
0
{
999
0
  const char  *ptr;     // Pointer into value
1000
1001
1002
0
  if (!fp || !directive || !*directive)
1003
0
    return (false);
1004
1005
0
  if (!cupsFilePuts(fp, directive))
1006
0
    return (false);
1007
1008
0
  if (!cupsFilePutChar(fp, ' '))
1009
0
    return (false);
1010
1011
0
  if (value && *value)
1012
0
  {
1013
0
    if ((ptr = strchr(value, '#')) != NULL)
1014
0
    {
1015
      // Need to quote the first # in the info string...
1016
0
      if (!cupsFileWrite(fp, value, (size_t)(ptr - value)))
1017
0
        return (false);
1018
1019
0
      if (!cupsFilePutChar(fp, '\\'))
1020
0
        return (false);
1021
1022
0
      if (!cupsFilePuts(fp, ptr))
1023
0
        return (false);
1024
0
    }
1025
0
    else if (!cupsFilePuts(fp, value))
1026
0
    {
1027
0
      return (false);
1028
0
    }
1029
0
  }
1030
1031
0
  return (cupsFilePutChar(fp, '\n'));
1032
0
}
1033
1034
1035
//
1036
// 'cupsFilePuts()' - Write a string.
1037
//
1038
// Like the `fputs` function, no newline is appended to the string.
1039
//
1040
1041
bool          // O - `true` on success, `false` on error
1042
cupsFilePuts(cups_file_t *fp,   // I - CUPS file
1043
             const char  *s)    // I - String to write
1044
0
{
1045
0
  size_t  bytes;      // Bytes to write
1046
1047
1048
  // Range check input...
1049
0
  if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1050
0
    return (false);
1051
1052
  // Write the string...
1053
0
  bytes = strlen(s);
1054
1055
0
  if (fp->mode == 's')
1056
0
  {
1057
0
    if (!cups_write(fp, s, bytes))
1058
0
      return (false);
1059
1060
0
    fp->pos += bytes;
1061
1062
0
    return (true);
1063
0
  }
1064
1065
0
  if ((fp->ptr + bytes) > fp->end)
1066
0
  {
1067
0
    if (!cupsFileFlush(fp))
1068
0
      return (false);
1069
0
  }
1070
1071
0
  fp->pos += bytes;
1072
1073
0
  if (bytes > sizeof(fp->buf))
1074
0
  {
1075
0
    if (fp->compressed)
1076
0
      return (cups_compress(fp, s, bytes) > 0);
1077
0
    else
1078
0
      return (cups_write(fp, s, bytes) > 0);
1079
0
  }
1080
0
  else
1081
0
  {
1082
0
    memcpy(fp->ptr, s, bytes);
1083
0
    fp->ptr += bytes;
1084
1085
0
    if (fp->is_stdio && !cupsFileFlush(fp))
1086
0
      return (false);
1087
0
    else
1088
0
      return (true);
1089
0
  }
1090
0
}
1091
1092
1093
//
1094
// 'cupsFileRead()' - Read from a file.
1095
//
1096
1097
ssize_t         // O - Number of bytes read or -1 on error
1098
cupsFileRead(cups_file_t *fp,   // I - CUPS file
1099
             char        *buf,    // O - Buffer
1100
       size_t      bytes)   // I - Number of bytes to read
1101
26.9M
{
1102
26.9M
  size_t  total;      // Total bytes read
1103
26.9M
  ssize_t count;      // Bytes read
1104
1105
1106
  // Range check input...
1107
26.9M
  if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
1108
0
    return (-1);
1109
1110
26.9M
  if (bytes == 0)
1111
0
    return (0);
1112
1113
26.9M
  if (fp->eof)
1114
0
    return (-1);
1115
1116
  // Loop until all bytes are read...
1117
26.9M
  total = 0;
1118
53.9M
  while (bytes > 0)
1119
27.0M
  {
1120
27.0M
    if (fp->ptr >= fp->end)
1121
113k
    {
1122
113k
      if (cups_fill(fp) <= 0)
1123
1.94k
      {
1124
1.94k
        if (total > 0)
1125
909
          return ((ssize_t)total);
1126
1.03k
  else
1127
1.03k
    return (-1);
1128
1.94k
      }
1129
113k
    }
1130
1131
27.0M
    count = (ssize_t)(fp->end - fp->ptr);
1132
27.0M
    if (count > (ssize_t)bytes)
1133
26.8M
      count = (ssize_t)bytes;
1134
1135
27.0M
    memcpy(buf, fp->ptr,(size_t) count);
1136
27.0M
    fp->ptr += count;
1137
27.0M
    fp->pos += count;
1138
1139
    // Update the counts for the last read...
1140
27.0M
    bytes -= (size_t)count;
1141
27.0M
    total += (size_t)count;
1142
27.0M
    buf   += count;
1143
27.0M
  }
1144
1145
  // Return the total number of bytes read...
1146
26.8M
  return ((ssize_t)total);
1147
26.9M
}
1148
1149
1150
//
1151
// 'cupsFileRewind()' - Set the current file position to the beginning of the file.
1152
//
1153
1154
off_t         // O - New file position or `-1` on error
1155
cupsFileRewind(cups_file_t *fp)   // I - CUPS file
1156
0
{
1157
  // Range check input...
1158
0
  if (!fp || fp->mode != 'r')
1159
0
    return (-1);
1160
1161
  // Handle special cases...
1162
0
  if (fp->bufpos == 0)
1163
0
  {
1164
    // No seeking necessary...
1165
0
    fp->pos = 0;
1166
1167
0
    if (fp->ptr)
1168
0
    {
1169
0
      fp->ptr = fp->buf;
1170
0
      fp->eof = false;
1171
0
    }
1172
1173
0
    return (0);
1174
0
  }
1175
1176
  // Otherwise, seek in the file and cleanup any compression buffers...
1177
0
  if (fp->compressed)
1178
0
  {
1179
0
    inflateEnd(&fp->stream);
1180
0
    fp->compressed = false;
1181
0
  }
1182
1183
0
  if (lseek(fp->fd, 0, SEEK_SET))
1184
0
    return (-1);
1185
1186
0
  fp->bufpos = 0;
1187
0
  fp->pos    = 0;
1188
0
  fp->ptr    = NULL;
1189
0
  fp->end    = NULL;
1190
0
  fp->eof    = false;
1191
1192
0
  return (0);
1193
0
}
1194
1195
1196
//
1197
// 'cupsFileSeek()' - Seek in a file.
1198
//
1199
1200
off_t         // O - New file position or `-1` on error
1201
cupsFileSeek(cups_file_t *fp,   // I - CUPS file
1202
             off_t       pos)   // I - Position in file
1203
0
{
1204
0
  ssize_t bytes;      // Number bytes in buffer
1205
1206
1207
  // Range check input...
1208
0
  if (!fp || pos < 0 || fp->mode != 'r')
1209
0
    return (-1);
1210
1211
  // Handle special cases...
1212
0
  if (pos == 0)
1213
0
    return (cupsFileRewind(fp));
1214
1215
0
  if (fp->ptr)
1216
0
  {
1217
0
    bytes = (ssize_t)(fp->end - fp->buf);
1218
1219
0
    if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1220
0
    {
1221
      // No seeking necessary...
1222
0
      fp->pos = pos;
1223
0
      fp->ptr = fp->buf + (pos - fp->bufpos);
1224
0
      fp->eof = false;
1225
1226
0
      return (pos);
1227
0
    }
1228
0
  }
1229
1230
0
  if (!fp->compressed && !fp->ptr)
1231
0
  {
1232
    // Preload a buffer to determine whether the file is compressed...
1233
0
    if (cups_fill(fp) <= 0)
1234
0
      return (-1);
1235
0
  }
1236
1237
  // Seek forwards or backwards...
1238
0
  fp->eof = false;
1239
1240
0
  if (pos < fp->bufpos)
1241
0
  {
1242
    // Need to seek backwards...
1243
0
    if (fp->compressed)
1244
0
    {
1245
0
      inflateEnd(&fp->stream);
1246
1247
0
      lseek(fp->fd, 0, SEEK_SET);
1248
0
      fp->bufpos = 0;
1249
0
      fp->pos    = 0;
1250
0
      fp->ptr    = NULL;
1251
0
      fp->end    = NULL;
1252
1253
0
      while ((bytes = cups_fill(fp)) > 0)
1254
0
      {
1255
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1256
0
    break;
1257
0
      }
1258
1259
0
      if (bytes <= 0)
1260
0
        return (-1);
1261
1262
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1263
0
      fp->pos = pos;
1264
0
    }
1265
0
    else
1266
0
    {
1267
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1268
0
      fp->pos    = fp->bufpos;
1269
0
      fp->ptr    = NULL;
1270
0
      fp->end    = NULL;
1271
0
    }
1272
0
  }
1273
0
  else
1274
0
  {
1275
    // Need to seek forwards...
1276
0
    if (fp->compressed)
1277
0
    {
1278
0
      while ((bytes = cups_fill(fp)) > 0)
1279
0
      {
1280
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1281
0
    break;
1282
0
      }
1283
1284
0
      if (bytes <= 0)
1285
0
        return (-1);
1286
1287
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1288
0
      fp->pos = pos;
1289
0
    }
1290
0
    else
1291
0
    {
1292
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1293
0
      fp->pos    = fp->bufpos;
1294
0
      fp->ptr    = NULL;
1295
0
      fp->end    = NULL;
1296
0
    }
1297
0
  }
1298
1299
0
  return (fp->pos);
1300
0
}
1301
1302
1303
//
1304
// 'cupsFileStderr()' - Return a CUPS file associated with stderr.
1305
//
1306
1307
cups_file_t *       // O - CUPS file
1308
cupsFileStderr(void)
1309
0
{
1310
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1311
1312
1313
  // Open file descriptor 2 as needed...
1314
0
  if (!cg->stdio_files[2])
1315
0
  {
1316
    // Flush any pending output on the stdio file...
1317
0
    fflush(stderr);
1318
1319
    // Open file descriptor 2...
1320
0
    if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1321
0
      cg->stdio_files[2]->is_stdio = true;
1322
0
  }
1323
1324
0
  return (cg->stdio_files[2]);
1325
0
}
1326
1327
1328
//
1329
// 'cupsFileStdin()' - Return a CUPS file associated with stdin.
1330
//
1331
1332
cups_file_t *       // O - CUPS file
1333
cupsFileStdin(void)
1334
0
{
1335
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1336
1337
1338
  // Open file descriptor 0 as needed...
1339
0
  if (!cg->stdio_files[0])
1340
0
  {
1341
    // Open file descriptor 0...
1342
0
    if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1343
0
      cg->stdio_files[0]->is_stdio = true;
1344
0
  }
1345
1346
0
  return (cg->stdio_files[0]);
1347
0
}
1348
1349
1350
//
1351
// 'cupsFileStdout()' - Return a CUPS file associated with stdout.
1352
//
1353
1354
cups_file_t *       // O - CUPS file
1355
cupsFileStdout(void)
1356
0
{
1357
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1358
1359
1360
  // Open file descriptor 1 as needed...
1361
0
  if (!cg->stdio_files[1])
1362
0
  {
1363
    // Flush any pending output on the stdio file...
1364
0
    fflush(stdout);
1365
1366
    // Open file descriptor 1...
1367
0
    if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
1368
0
      cg->stdio_files[1]->is_stdio = true;
1369
0
  }
1370
1371
0
  return (cg->stdio_files[1]);
1372
0
}
1373
1374
1375
//
1376
// 'cupsFileTell()' - Return the current file position.
1377
//
1378
1379
off_t         // O - File position
1380
cupsFileTell(cups_file_t *fp)   // I - CUPS file
1381
0
{
1382
0
  return (fp ? fp->pos : 0);
1383
0
}
1384
1385
1386
//
1387
// 'cupsFileUnlock()' - Unlock access to a file.
1388
//
1389
1390
bool          // O - `true` on success, `false` on error
1391
cupsFileUnlock(cups_file_t *fp)   // I - CUPS file
1392
0
{
1393
  // Range check...
1394
0
  if (!fp || fp->mode == 's')
1395
0
    return (false);
1396
1397
  // Unlock...
1398
#ifdef _WIN32
1399
  return (_locking(fp->fd, _LK_UNLCK, 0) == 0);
1400
#else
1401
0
  return (lockf(fp->fd, F_ULOCK, 0) == 0);
1402
0
#endif // _WIN32
1403
0
}
1404
1405
1406
//
1407
// 'cupsFileWrite()' - Write to a file.
1408
//
1409
1410
bool          // O - `true` on success, `false` on error
1411
cupsFileWrite(cups_file_t *fp,    // I - CUPS file
1412
              const char  *buf,   // I - Buffer
1413
        size_t      bytes)  // I - Number of bytes to write
1414
1.71M
{
1415
  // Range check input...
1416
1.71M
  if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
1417
0
    return (false);
1418
1419
1.71M
  if (bytes == 0)
1420
0
    return (true);
1421
1422
  // Write the buffer...
1423
1.71M
  if (fp->mode == 's')
1424
0
  {
1425
0
    if (!cups_write(fp, buf, bytes))
1426
0
      return (false);
1427
1428
0
    fp->pos += (off_t)bytes;
1429
1430
0
    return (true);
1431
0
  }
1432
1433
1.71M
  if ((fp->ptr + bytes) > fp->end)
1434
92.3k
  {
1435
92.3k
    if (!cupsFileFlush(fp))
1436
0
      return (false);
1437
92.3k
  }
1438
1439
1.71M
  fp->pos += (off_t)bytes;
1440
1441
1.71M
  if (bytes > sizeof(fp->buf))
1442
22.6k
  {
1443
22.6k
    if (fp->compressed)
1444
0
      return (cups_compress(fp, buf, bytes));
1445
22.6k
    else
1446
22.6k
      return (cups_write(fp, buf, bytes));
1447
22.6k
  }
1448
1.69M
  else
1449
1.69M
  {
1450
1.69M
    memcpy(fp->ptr, buf, bytes);
1451
1.69M
    fp->ptr += bytes;
1452
1.69M
    return (true);
1453
1.69M
  }
1454
1.71M
}
1455
1456
1457
//
1458
// 'cups_compress()' - Compress a buffer of data.
1459
//
1460
1461
static bool       // O - `true` on success, `false` on error
1462
cups_compress(cups_file_t *fp,    // I - CUPS file
1463
              const char  *buf,   // I - Buffer
1464
        size_t      bytes)  // I - Number bytes
1465
0
{
1466
0
  int status;       // Deflate status
1467
1468
1469
  // Update the CRC...
1470
0
  fp->crc = crc32(fp->crc, (const Bytef *)buf, (uInt)bytes);
1471
1472
  // Deflate the bytes...
1473
0
  fp->stream.next_in  = (Bytef *)buf;
1474
0
  fp->stream.avail_in = (uInt)bytes;
1475
1476
0
  while (fp->stream.avail_in > 0)
1477
0
  {
1478
    // Flush the current buffer...
1479
0
    if (fp->stream.avail_out < (uInt)(sizeof(fp->cbuf) / 8))
1480
0
    {
1481
0
      if (!cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)))
1482
0
        return (false);
1483
1484
0
      fp->stream.next_out  = fp->cbuf;
1485
0
      fp->stream.avail_out = sizeof(fp->cbuf);
1486
0
    }
1487
1488
0
    if ((status = deflate(&(fp->stream), Z_NO_FLUSH)) < Z_OK && status != Z_BUF_ERROR)
1489
0
      return (false);
1490
0
  }
1491
1492
0
  return (true);
1493
0
}
1494
1495
1496
//
1497
// 'cups_fill()' - Fill the input buffer.
1498
//
1499
1500
static ssize_t        // O - Number of bytes or -1
1501
cups_fill(cups_file_t *fp)    // I - CUPS file
1502
113k
{
1503
113k
  ssize_t   bytes;    // Number of bytes read
1504
113k
  int     status;   // Decompression status
1505
113k
  const unsigned char *ptr,   // Pointer into buffer
1506
113k
      *end;   // End of buffer
1507
1508
1509
113k
  if (fp->ptr && fp->end)
1510
110k
    fp->bufpos += fp->end - fp->buf;
1511
1512
113k
  while (!fp->ptr || fp->compressed)
1513
112k
  {
1514
    // Check to see if we have read any data yet; if not, see if we have a compressed file...
1515
112k
    if (!fp->ptr)
1516
2.56k
    {
1517
      // Reset the file position in case we are seeking...
1518
2.56k
      fp->compressed = false;
1519
1520
      // Read the first bytes in the file to determine if we have a gzip'd file...
1521
2.56k
      if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
1522
0
      {
1523
        // Can't read from file!
1524
0
        fp->eof = true;
1525
1526
0
  return (-1);
1527
0
      }
1528
1529
2.56k
      if (bytes < 10 || fp->buf[0] != 0x1f || (fp->buf[1] & 255) != 0x8b || fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
1530
1.03k
      {
1531
        // Not a gzip'd file!
1532
1.03k
  fp->ptr = fp->buf;
1533
1.03k
  fp->end = fp->buf + bytes;
1534
1535
1.03k
  return (bytes);
1536
1.03k
      }
1537
1538
      // Parse header junk: extra data, original name, and comment...
1539
1.52k
      ptr = (unsigned char *)fp->buf + 10;
1540
1.52k
      end = (unsigned char *)fp->buf + bytes;
1541
1542
1.52k
      if (fp->buf[3] & 0x04)
1543
20
      {
1544
        // Skip extra data...
1545
20
  if ((ptr + 2) > end)
1546
5
  {
1547
    // Can't read from file!
1548
5
          fp->eof = true;
1549
5
    errno   = EIO;
1550
1551
5
    return (-1);
1552
5
  }
1553
1554
15
  bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
1555
15
  ptr   += 2 + bytes;
1556
1557
15
  if (ptr > end)
1558
9
  {
1559
    // Can't read from file!
1560
9
          fp->eof = true;
1561
9
    errno   = EIO;
1562
1563
9
    return (-1);
1564
9
  }
1565
15
      }
1566
1567
1.51k
      if (fp->buf[3] & 0x08)
1568
24
      {
1569
        // Skip original name data...
1570
447
  while (ptr < end && *ptr)
1571
423
          ptr ++;
1572
1573
24
  if (ptr < end)
1574
8
  {
1575
8
          ptr ++;
1576
8
  }
1577
16
  else
1578
16
  {
1579
    // Can't read from file!
1580
16
          fp->eof = true;
1581
16
    errno   = EIO;
1582
1583
16
    return (-1);
1584
16
  }
1585
24
      }
1586
1587
1.49k
      if (fp->buf[3] & 0x10)
1588
23
      {
1589
        // Skip comment data...
1590
1.22k
  while (ptr < end && *ptr)
1591
1.20k
          ptr ++;
1592
1593
23
  if (ptr < end)
1594
6
  {
1595
6
          ptr ++;
1596
6
  }
1597
17
  else
1598
17
  {
1599
    // Can't read from file!
1600
17
          fp->eof = true;
1601
17
    errno   = EIO;
1602
1603
17
    return (-1);
1604
17
  }
1605
23
      }
1606
1607
1.48k
      if (fp->buf[3] & 0x02)
1608
10
      {
1609
        // Skip header CRC data...
1610
10
  ptr += 2;
1611
1612
10
  if (ptr > end)
1613
7
  {
1614
    // Can't read from file!
1615
7
          fp->eof = true;
1616
7
    errno   = EIO;
1617
1618
7
    return (-1);
1619
7
  }
1620
10
      }
1621
1622
      // Copy the flate-compressed data to the compression buffer...
1623
1.47k
      if ((bytes = end - ptr) > 0)
1624
1.46k
        memcpy(fp->cbuf, ptr, (size_t)bytes);
1625
1626
      // Setup the decompressor data...
1627
1.47k
      fp->stream.zalloc    = (alloc_func)0;
1628
1.47k
      fp->stream.zfree     = (free_func)0;
1629
1.47k
      fp->stream.opaque    = (voidpf)0;
1630
1.47k
      fp->stream.next_in   = (Bytef *)fp->cbuf;
1631
1.47k
      fp->stream.next_out  = NULL;
1632
1.47k
      fp->stream.avail_in  = (uInt)bytes;
1633
1.47k
      fp->stream.avail_out = 0;
1634
1.47k
      fp->crc              = crc32(0L, Z_NULL, 0);
1635
1636
1.47k
      if (inflateInit2(&(fp->stream), -15) != Z_OK)
1637
0
      {
1638
0
        fp->eof = true;
1639
0
        errno   = EIO;
1640
1641
0
  return (-1);
1642
0
      }
1643
1644
1.47k
      fp->compressed = true;
1645
1.47k
    }
1646
1647
111k
    if (fp->compressed)
1648
111k
    {
1649
      // If we have reached end-of-file, return immediately...
1650
111k
      if (fp->eof)
1651
0
  return (0);
1652
1653
      // Fill the decompression buffer as needed...
1654
111k
      if (fp->stream.avail_in == 0)
1655
2.35k
      {
1656
2.35k
  if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
1657
1.03k
  {
1658
1.03k
    fp->eof = true;
1659
1660
1.03k
          return (bytes);
1661
1.03k
  }
1662
1663
1.31k
  fp->stream.next_in  = fp->cbuf;
1664
1.31k
  fp->stream.avail_in = (uInt)bytes;
1665
1.31k
      }
1666
1667
      // Decompress data from the buffer...
1668
110k
      fp->stream.next_out  = (Bytef *)fp->buf;
1669
110k
      fp->stream.avail_out = sizeof(fp->buf);
1670
1671
110k
      status = inflate(&(fp->stream), Z_NO_FLUSH);
1672
1673
110k
      if (fp->stream.next_out > (Bytef *)fp->buf)
1674
110k
        fp->crc = crc32(fp->crc, (Bytef *)fp->buf, (uInt)(fp->stream.next_out - (Bytef *)fp->buf));
1675
1676
110k
      if (status == Z_STREAM_END)
1677
82
      {
1678
        // Read the CRC and length...
1679
82
  unsigned char trailer[8]; // Trailer bytes
1680
82
  uLong   tcrc;   // Trailer CRC
1681
82
  ssize_t   tbytes = 0; // Number of bytes
1682
1683
82
  if (fp->stream.avail_in > 0)
1684
80
  {
1685
    // Get the first N trailer bytes from the inflate stream...
1686
80
    if (fp->stream.avail_in > sizeof(trailer))
1687
24
      tbytes = (ssize_t)sizeof(trailer);
1688
56
    else
1689
56
      tbytes = (ssize_t)fp->stream.avail_in;
1690
1691
80
    memcpy(trailer, fp->stream.next_in, (size_t)tbytes);
1692
80
    fp->stream.next_in  += tbytes;
1693
80
    fp->stream.avail_in -= (size_t)tbytes;
1694
80
  }
1695
1696
        // Reset the compressed flag so that we re-read the file header...
1697
82
        inflateEnd(&fp->stream);
1698
1699
82
  fp->compressed = false;
1700
1701
        // Get any remaining trailer bytes...
1702
82
        if (tbytes < (ssize_t)sizeof(trailer))
1703
8
  {
1704
8
    if (read(fp->fd, trailer + tbytes, sizeof(trailer) - (size_t)tbytes) < ((ssize_t)sizeof(trailer) - tbytes))
1705
7
    {
1706
      // Can't get it, so mark end-of-file...
1707
7
      fp->eof = true;
1708
7
      errno   = EIO;
1709
1710
7
      return (-1);
1711
7
    }
1712
8
  }
1713
1714
        // Calculate and compare the CRC...
1715
75
  tcrc = ((((((uLong)trailer[3] << 8) | (uLong)trailer[2]) << 8) | (uLong)trailer[1]) << 8) | (uLong)trailer[0];
1716
1717
75
  if (tcrc != fp->crc)
1718
72
  {
1719
    // Bad CRC, mark end-of-file...
1720
72
    fp->eof = true;
1721
72
    errno   = EIO;
1722
1723
72
    return (-1);
1724
72
  }
1725
75
      }
1726
110k
      else if (status < Z_OK)
1727
20
      {
1728
20
        fp->eof = true;
1729
20
        errno   = EIO;
1730
1731
20
  return (-1);
1732
20
      }
1733
1734
110k
      bytes = (ssize_t)sizeof(fp->buf) - (ssize_t)fp->stream.avail_out;
1735
1736
      // Return the decompressed data...
1737
110k
      fp->ptr = fp->buf;
1738
110k
      fp->end = fp->buf + bytes;
1739
1740
110k
      if (bytes)
1741
110k
  return (bytes);
1742
110k
    }
1743
111k
  }
1744
1745
  // Read a buffer's full of data...
1746
898
  if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
1747
749
  {
1748
    // Can't read from file!
1749
749
    fp->eof = true;
1750
749
    fp->ptr = fp->buf;
1751
749
    fp->end = fp->buf;
1752
749
  }
1753
149
  else
1754
149
  {
1755
    // Return the bytes we read...
1756
149
    fp->eof = false;
1757
149
    fp->ptr = fp->buf;
1758
149
    fp->end = fp->buf + bytes;
1759
149
  }
1760
1761
898
  return (bytes);
1762
113k
}
1763
1764
1765
//
1766
// 'cups_open()' - Safely open a file for writing.
1767
//
1768
// We don't allow appending to directories or files that are hard-linked or
1769
// symlinked.
1770
//
1771
1772
static int        // O - File descriptor or -1 otherwise
1773
cups_open(const char *filename,   // I - Filename
1774
          int        oflag,   // I - Open flags
1775
    int        mode)    // I - Open permissions
1776
7.69k
{
1777
7.69k
  int   fd;     // File descriptor
1778
7.69k
  struct stat fileinfo;   // File information
1779
7.69k
#ifndef _WIN32
1780
7.69k
  struct stat linkinfo;   // Link information
1781
7.69k
#endif // !_WIN32
1782
1783
1784
  // Open the file...
1785
7.69k
  if ((fd = open(filename, oflag, mode)) < 0)
1786
2.56k
    return (-1);
1787
1788
  // Then verify that the file descriptor doesn't point to a directory or hard-linked file.
1789
5.13k
  if (fstat(fd, &fileinfo))
1790
0
  {
1791
0
    close(fd);
1792
0
    return (-1);
1793
0
  }
1794
1795
5.13k
  if (fileinfo.st_nlink != 1)
1796
0
  {
1797
0
    close(fd);
1798
0
    errno = EPERM;
1799
0
    return (-1);
1800
0
  }
1801
1802
#ifdef _WIN32
1803
  if (fileinfo.st_mode & _S_IFDIR)
1804
#else
1805
5.13k
  if (S_ISDIR(fileinfo.st_mode))
1806
0
#endif // _WIN32
1807
0
  {
1808
0
    close(fd);
1809
0
    errno = EISDIR;
1810
0
    return (-1);
1811
0
  }
1812
1813
5.13k
#ifndef _WIN32
1814
  // Then use lstat to determine whether the filename is a symlink...
1815
5.13k
  if (lstat(filename, &linkinfo))
1816
0
  {
1817
0
    close(fd);
1818
0
    return (-1);
1819
0
  }
1820
1821
5.13k
  if (S_ISLNK(linkinfo.st_mode) ||
1822
5.13k
      fileinfo.st_dev != linkinfo.st_dev ||
1823
5.13k
      fileinfo.st_ino != linkinfo.st_ino ||
1824
#ifdef HAVE_ST_GEN
1825
      fileinfo.st_gen != linkinfo.st_gen ||
1826
#endif // HAVE_ST_GEN
1827
5.13k
      fileinfo.st_nlink != linkinfo.st_nlink ||
1828
5.13k
      fileinfo.st_mode != linkinfo.st_mode)
1829
0
  {
1830
    // Yes, don't allow!
1831
0
    close(fd);
1832
0
    errno = EPERM;
1833
0
    return (-1);
1834
0
  }
1835
5.13k
#endif // !_WIN32
1836
1837
5.13k
  return (fd);
1838
5.13k
}
1839
1840
1841
//
1842
// 'cups_read()' - Read from a file descriptor.
1843
//
1844
1845
static ssize_t        // O - Number of bytes read or -1
1846
cups_read(cups_file_t *fp,    // I - CUPS file
1847
          char        *buf,   // I - Buffer
1848
    size_t      bytes)    // I - Number bytes
1849
5.82k
{
1850
5.82k
  ssize_t total;      // Total bytes read
1851
1852
1853
  // Loop until we read at least 0 bytes...
1854
5.82k
  for (;;)
1855
5.82k
  {
1856
#ifdef _WIN32
1857
    if (fp->mode == 's')
1858
      total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
1859
    else
1860
      total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
1861
#else
1862
5.82k
    if (fp->mode == 's')
1863
0
      total = recv(fp->fd, buf, bytes, 0);
1864
5.82k
    else
1865
5.82k
      total = read(fp->fd, buf, bytes);
1866
5.82k
#endif // _WIN32
1867
1868
5.82k
    if (total >= 0)
1869
5.82k
      break;
1870
1871
    // Reads can be interrupted by signals and unavailable resources...
1872
0
    if (errno == EAGAIN || errno == EINTR)
1873
0
      continue;
1874
0
    else
1875
0
      return (-1);
1876
0
  }
1877
1878
  // Return the total number of bytes read...
1879
5.82k
  return (total);
1880
5.82k
}
1881
1882
1883
//
1884
// 'cups_write()' - Write to a file descriptor.
1885
//
1886
1887
static bool       // O - `true` on success, `false` on error
1888
cups_write(cups_file_t *fp,   // I - CUPS file
1889
           const char  *buf,    // I - Buffer
1890
     size_t      bytes)   // I - Number bytes
1891
113k
{
1892
113k
  ssize_t count;      // Count this time
1893
1894
1895
  // Loop until all bytes are written...
1896
227k
  while (bytes > 0)
1897
113k
  {
1898
#ifdef _WIN32
1899
    if (fp->mode == 's')
1900
      count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
1901
    else
1902
      count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
1903
#else
1904
113k
    if (fp->mode == 's')
1905
0
      count = send(fp->fd, buf, bytes, 0);
1906
113k
    else
1907
113k
      count = write(fp->fd, buf, bytes);
1908
113k
#endif // _WIN32
1909
1910
113k
    if (count < 0)
1911
0
    {
1912
      // Writes can be interrupted by signals and unavailable resources...
1913
0
      if (errno == EAGAIN || errno == EINTR)
1914
0
        continue;
1915
0
      else
1916
0
        return (false);
1917
0
    }
1918
1919
    // Update the counts for the last write call...
1920
113k
    bytes -= (size_t)count;
1921
113k
    buf   += count;
1922
113k
  }
1923
1924
  // Return the total number of bytes written...
1925
113k
  return (true);
1926
113k
}