Coverage Report

Created: 2025-11-09 06:35

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-2025 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
4.39k
{
301
4.39k
  int fd;       // File descriptor
302
4.39k
  char  mode;       // Open mode
303
4.39k
  int status;       // Return status
304
305
306
4.39k
  DEBUG_printf("cupsFileClose(fp=%p)", (void *)fp);
307
308
  // Range check...
309
4.39k
  if (!fp)
310
0
    return (-1);
311
312
  // Flush pending write data...
313
4.39k
  if (fp->mode == 'w')
314
2.19k
    status = cupsFileFlush(fp);
315
2.19k
  else
316
2.19k
    status = 0;
317
318
4.39k
  if (fp->compressed && status >= 0)
319
76
  {
320
76
    if (fp->mode == 'r')
321
76
    {
322
      // Free decompression data...
323
76
      inflateEnd(&fp->stream);
324
76
    }
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
76
  }
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
4.39k
  if (fp->is_stdio)
374
0
    return (status);
375
376
  // Save the file descriptor we used and free memory...
377
4.39k
  fd   = fp->fd;
378
4.39k
  mode = fp->mode;
379
380
4.39k
  if (fp->printf_buffer)
381
0
    free(fp->printf_buffer);
382
383
4.39k
  free(fp);
384
385
  // Close the file, returning the close status...
386
4.39k
  if (mode == 's')
387
0
  {
388
0
    if (httpAddrClose(NULL, fd) < 0)
389
0
      status = -1;
390
0
  }
391
4.39k
  else if (close(fd) < 0)
392
0
    status = -1;
393
394
4.39k
  return (status);
395
4.39k
}
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
2.34k
{
528
2.34k
  ssize_t bytes;      // Bytes to write
529
530
531
2.34k
  DEBUG_printf("cupsFileFlush(fp=%p)", (void *)fp);
532
533
  // Range check input...
534
2.34k
  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
2.34k
  bytes = (ssize_t)(fp->ptr - fp->buf);
541
542
2.34k
  DEBUG_printf("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes);
543
544
2.34k
  if (bytes > 0)
545
2.05k
  {
546
2.05k
    if (fp->compressed)
547
0
      bytes = cups_compress(fp, fp->buf, (size_t)bytes);
548
2.05k
    else
549
2.05k
      bytes = cups_write(fp, fp->buf, (size_t)bytes);
550
551
2.05k
    if (bytes < 0)
552
0
      return (-1);
553
554
2.05k
    fp->ptr = fp->buf;
555
2.05k
  }
556
557
2.34k
  return (0);
558
2.34k
}
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') ||
626
0
      !buf || buflen < 2 || !value)
627
0
  {
628
0
    if (value)
629
0
      *value = NULL;
630
631
0
    return (NULL);
632
0
  }
633
634
  // Read the next non-comment line...
635
0
  *value = NULL;
636
637
0
  while (cupsFileGets(fp, buf, buflen))
638
0
  {
639
0
    (*linenum) ++;
640
641
    // Strip any comments...
642
0
    if ((ptr = strchr(buf, '#')) != NULL)
643
0
    {
644
0
      if (ptr > buf && ptr[-1] == '\\')
645
0
      {
646
        // Unquote the #...
647
0
  _cups_strcpy(ptr - 1, ptr);
648
0
      }
649
0
      else
650
0
      {
651
        // Strip the comment and any trailing whitespace...
652
0
  while (ptr > buf)
653
0
  {
654
0
    if (!_cups_isspace(ptr[-1]))
655
0
      break;
656
657
0
    ptr --;
658
0
  }
659
660
0
  *ptr = '\0';
661
0
      }
662
0
    }
663
664
    // Strip leading whitespace...
665
0
    for (ptr = buf; _cups_isspace(*ptr); ptr ++);
666
667
0
    if (ptr > buf)
668
0
      _cups_strcpy(buf, ptr);
669
670
    // See if there is anything left...
671
0
    if (buf[0])
672
0
    {
673
      // Yes, grab any value and return...
674
0
      for (ptr = buf; *ptr; ptr ++)
675
0
        if (_cups_isspace(*ptr))
676
0
    break;
677
678
0
      if (*ptr)
679
0
      {
680
        // Have a value, skip any other spaces...
681
0
        while (_cups_isspace(*ptr))
682
0
    *ptr++ = '\0';
683
684
0
        if (*ptr)
685
0
    *value = ptr;
686
687
        // Strip trailing whitespace and > for lines that begin with <...
688
0
        ptr += strlen(ptr) - 1;
689
690
0
        if (buf[0] == '<' && *ptr == '>')
691
0
    *ptr-- = '\0';
692
0
  else if (buf[0] == '<' && *ptr != '>')
693
0
        {
694
    // Syntax error...
695
0
    *value = NULL;
696
0
    return (buf);
697
0
  }
698
699
0
        while (ptr > *value && _cups_isspace(*ptr))
700
0
    *ptr-- = '\0';
701
0
      }
702
703
      // Return the line...
704
0
      return (buf);
705
0
    }
706
0
  }
707
708
0
  return (NULL);
709
0
}
710
711
712
//
713
// 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
714
//                       contain binary data.
715
//
716
// This function differs from @link cupsFileGets@ in that the trailing CR
717
// and LF are preserved, as is any binary data on the line. The buffer is
718
// nul-terminated, however you should use the returned length to determine
719
// the number of bytes on the line.
720
//
721
// @since CUPS 1.2@
722
//
723
724
size_t          // O - Number of bytes on line or 0 on end of file
725
cupsFileGetLine(cups_file_t *fp,  // I - File to read from
726
                char        *buf, // I - Buffer
727
                size_t      buflen) // I - Size of buffer
728
0
{
729
0
  int   ch;     // Character from file
730
0
  char    *ptr,     // Current position in line buffer
731
0
    *end;     // End of line buffer
732
733
734
  // Range check input...
735
0
  DEBUG_printf("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST buflen);
736
737
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
738
0
    return (0);
739
740
  // Now loop until we have a valid line...
741
0
  for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
742
0
  {
743
0
    if (fp->ptr >= fp->end)
744
0
      if (cups_fill(fp) <= 0)
745
0
        break;
746
747
0
    *ptr++ = ch = *(fp->ptr)++;
748
0
    fp->pos ++;
749
750
0
    if (ch == '\r')
751
0
    {
752
      // Check for CR LF...
753
0
      if (fp->ptr >= fp->end)
754
0
  if (cups_fill(fp) <= 0)
755
0
          break;
756
757
0
      if (*(fp->ptr) == '\n')
758
0
      {
759
0
        *ptr++ = *(fp->ptr)++;
760
0
  fp->pos ++;
761
0
      }
762
763
0
      break;
764
0
    }
765
0
    else if (ch == '\n')
766
0
    {
767
      // Line feed ends a line...
768
0
      break;
769
0
    }
770
0
  }
771
772
0
  *ptr = '\0';
773
774
0
  DEBUG_printf("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
775
776
0
  return ((size_t)(ptr - buf));
777
0
}
778
779
780
//
781
// 'cupsFileGets()' - Get a CR and/or LF-terminated line.
782
//
783
// @since CUPS 1.2@
784
//
785
786
char *          // O - Line read or @code NULL@ on end of file or error
787
cupsFileGets(cups_file_t *fp,   // I - CUPS file
788
             char        *buf,    // O - String buffer
789
       size_t      buflen)  // I - Size of string buffer
790
0
{
791
0
  int   ch;     // Character from file
792
0
  char    *ptr,     // Current position in line buffer
793
0
    *end;     // End of line buffer
794
795
796
  // Range check input...
797
0
  DEBUG_printf("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST buflen);
798
799
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
800
0
    return (NULL);
801
802
  // Now loop until we have a valid line...
803
0
  for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
804
0
  {
805
0
    if (fp->ptr >= fp->end)
806
0
      if (cups_fill(fp) <= 0)
807
0
      {
808
0
        if (ptr == buf)
809
0
    return (NULL);
810
0
  else
811
0
          break;
812
0
      }
813
814
0
    ch = *(fp->ptr)++;
815
0
    fp->pos ++;
816
817
0
    if (ch == '\r')
818
0
    {
819
      // Check for CR LF...
820
0
      if (fp->ptr >= fp->end)
821
0
  if (cups_fill(fp) <= 0)
822
0
          break;
823
824
0
      if (*(fp->ptr) == '\n')
825
0
      {
826
0
        fp->ptr ++;
827
0
  fp->pos ++;
828
0
      }
829
830
0
      break;
831
0
    }
832
0
    else if (ch == '\n')
833
0
    {
834
      // Line feed ends a line...
835
0
      break;
836
0
    }
837
0
    else
838
0
      *ptr++ = (char)ch;
839
0
  }
840
841
0
  *ptr = '\0';
842
843
0
  DEBUG_printf("4cupsFileGets: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
844
845
0
  return (buf);
846
0
}
847
848
849
//
850
// 'cupsFileIsCompressed()' - Return whether a file is compressed.
851
//
852
// @since CUPS 2.5@
853
//
854
855
bool          // O - `true` if file is compressed, `false` otherwise
856
cupsFileIsCompressed(cups_file_t *fp) // I - CUPS file
857
0
{
858
0
  return (fp ? fp->compressed != 0 : false);
859
0
}
860
861
862
//
863
// 'cupsFileLock()' - Temporarily lock access to a file.
864
//
865
// @since CUPS 1.2@
866
//
867
868
int         // O - 0 on success, -1 on error
869
cupsFileLock(cups_file_t *fp,   // I - CUPS file
870
             int         block)   // I - 1 to wait for the lock, 0 to fail right away
871
0
{
872
  // Range check...
873
0
  if (!fp || fp->mode == 's')
874
0
    return (-1);
875
876
  // Try the lock...
877
#ifdef _WIN32
878
  return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
879
#else
880
0
  return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
881
0
#endif // _WIN32
882
0
}
883
884
885
//
886
// 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
887
//
888
// @since CUPS 1.2@
889
//
890
891
int         // O - File descriptor
892
cupsFileNumber(cups_file_t *fp)   // I - CUPS file
893
0
{
894
0
  if (fp)
895
0
    return (fp->fd);
896
0
  else
897
0
    return (-1);
898
0
}
899
900
901
//
902
// 'cupsFileOpen()' - Open a CUPS file.
903
//
904
// The "mode" parameter can be "r" to read, "w" to write, overwriting any
905
// existing file, "a" to append to an existing file or create a new file,
906
// or "s" to open a socket connection.
907
//
908
// When opening for writing ("w"), an optional number from 1 to 9 can be
909
// supplied which enables Flate compression of the file.  Compression is
910
// not supported for the "a" (append) mode.
911
//
912
// When opening for writing ("w") or append ("a"), an optional 'm###' suffix
913
// can be used to set the permissions of the opened file.
914
//
915
// When opening a socket connection, the filename is a string of the form
916
// "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
917
// connection as needed, generally preferring IPv6 connections when there is
918
// a choice.
919
//
920
// @since CUPS 1.2@
921
//
922
923
cups_file_t *       // O - CUPS file or @code NULL@ if the file or socket cannot be opened
924
cupsFileOpen(const char *filename,  // I - Name of file
925
             const char *mode)    // I - Open mode
926
4.40k
{
927
4.40k
  cups_file_t *fp;      // New CUPS file
928
4.40k
  int   fd;     // File descriptor
929
4.40k
  char    hostname[1024],   // Hostname
930
4.40k
    *portname;    // Port "name" (number or service)
931
4.40k
  http_addrlist_t *addrlist;    // Host address list
932
4.40k
  int   perm = 0664;    // Permissions for write/append
933
4.40k
  const char  *ptr;     // Pointer into mode string
934
935
936
4.40k
  DEBUG_printf("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename, mode);
937
938
  // Range check input...
939
4.40k
  if (!filename || !mode ||
940
4.40k
      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
941
4.40k
      (*mode == 'a' && isdigit(mode[1] & 255)))
942
0
    return (NULL);
943
944
4.40k
  if ((ptr = strchr(mode, 'm')) != NULL && ptr[1] >= '0' && ptr[1] <= '7')
945
0
  {
946
    // Get permissions from mode string...
947
0
    perm = (int)strtol(mode + 1, NULL, 8);
948
0
  }
949
950
  // Open the file...
951
4.40k
  switch (*mode)
952
4.40k
  {
953
0
    case 'a' : // Append file
954
0
        fd = cups_open(filename, O_WRONLY | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, perm);
955
0
        break;
956
957
2.20k
    case 'r' : // Read file
958
2.20k
  fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
959
2.20k
  break;
960
961
2.19k
    case 'w' : // Write file
962
2.19k
        fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
963
2.19k
  if (fd < 0 && errno == ENOENT)
964
2.19k
  {
965
2.19k
    fd = cups_open(filename, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY, perm);
966
2.19k
    if (fd < 0 && errno == EEXIST)
967
0
      fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
968
2.19k
  }
969
970
2.19k
  if (fd >= 0)
971
#ifdef _WIN32
972
    _chsize(fd, 0);
973
#else
974
2.19k
    ftruncate(fd, 0);
975
2.19k
#endif // _WIN32
976
2.19k
        break;
977
978
0
    case 's' : // Read/write socket
979
0
        cupsCopyString(hostname, filename, sizeof(hostname));
980
0
  if ((portname = strrchr(hostname, ':')) != NULL)
981
0
    *portname++ = '\0';
982
0
  else
983
0
    return (NULL);
984
985
        // Lookup the hostname and service...
986
0
        if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
987
0
    return (NULL);
988
989
        // Connect to the server...
990
0
        if (!httpAddrConnect(addrlist, &fd))
991
0
  {
992
0
    httpAddrFreeList(addrlist);
993
0
    return (NULL);
994
0
  }
995
996
0
  httpAddrFreeList(addrlist);
997
0
  break;
998
999
0
    default : // Remove bogus compiler warning...
1000
0
        return (NULL);
1001
4.40k
  }
1002
1003
4.40k
  if (fd < 0)
1004
3
    return (NULL);
1005
1006
  // Create the CUPS file structure...
1007
4.39k
  if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
1008
0
  {
1009
0
    if (*mode == 's')
1010
0
      httpAddrClose(NULL, fd);
1011
0
    else
1012
0
      close(fd);
1013
0
  }
1014
1015
  // Return it...
1016
4.39k
  return (fp);
1017
4.40k
}
1018
1019
//
1020
// 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
1021
//
1022
// The "mode" parameter can be "r" to read, "w" to write, "a" to append,
1023
// or "s" to treat the file descriptor as a bidirectional socket connection.
1024
//
1025
// When opening for writing ("w"), an optional number from 1 to 9 can be
1026
// supplied which enables Flate compression of the file.  Compression is
1027
// not supported for the "a" (append) mode.
1028
//
1029
// @since CUPS 1.2@
1030
//
1031
1032
cups_file_t *       // O - CUPS file or @code NULL@ if the file could not be opened
1033
cupsFileOpenFd(int        fd,   // I - File descriptor
1034
         const char *mode)  // I - Open mode
1035
4.39k
{
1036
4.39k
  cups_file_t *fp;      // New CUPS file
1037
1038
1039
4.39k
  DEBUG_printf("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode);
1040
1041
  // Range check input...
1042
4.39k
  if (fd < 0 || !mode ||
1043
4.39k
      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
1044
4.39k
      (*mode == 'a' && isdigit(mode[1] & 255)))
1045
0
    return (NULL);
1046
1047
  // Allocate memory...
1048
4.39k
  if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
1049
0
    return (NULL);
1050
1051
  // Open the file...
1052
4.39k
  fp->fd = fd;
1053
1054
4.39k
  switch (*mode)
1055
4.39k
  {
1056
0
    case 'a' :
1057
0
        fp->pos = lseek(fd, 0, SEEK_END);
1058
1059
2.19k
    case 'w' :
1060
2.19k
  fp->mode = 'w';
1061
2.19k
  fp->ptr  = fp->buf;
1062
2.19k
  fp->end  = fp->buf + sizeof(fp->buf);
1063
1064
2.19k
  if (mode[1] >= '1' && mode[1] <= '9')
1065
0
  {
1066
    // Open a compressed stream, so write the standard gzip file header...
1067
0
          unsigned char header[10]; // gzip file header
1068
0
    time_t  curtime;  // Current time
1069
1070
1071
0
          curtime   = time(NULL);
1072
0
    header[0] = 0x1f;
1073
0
    header[1] = 0x8b;
1074
0
    header[2] = Z_DEFLATED;
1075
0
    header[3] = 0;
1076
0
    header[4] = (unsigned char)curtime;
1077
0
    header[5] = (unsigned char)(curtime >> 8);
1078
0
    header[6] = (unsigned char)(curtime >> 16);
1079
0
    header[7] = (unsigned char)(curtime >> 24);
1080
0
    header[8] = 0;
1081
0
    header[9] = 0x03;
1082
1083
0
    if (cups_write(fp, (char *)header, 10) < 10)
1084
0
    {
1085
0
            free(fp);
1086
0
      return (NULL);
1087
0
    }
1088
1089
          // Initialize the compressor...
1090
0
          if (deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) < Z_OK)
1091
0
          {
1092
0
            free(fp);
1093
0
      return (NULL);
1094
0
          }
1095
1096
0
    fp->stream.next_out  = fp->cbuf;
1097
0
    fp->stream.avail_out = sizeof(fp->cbuf);
1098
0
    fp->compressed       = 1;
1099
0
    fp->crc              = crc32(0L, Z_NULL, 0);
1100
0
  }
1101
2.19k
        break;
1102
1103
2.19k
    case 'r' :
1104
2.19k
  fp->mode = 'r';
1105
2.19k
  break;
1106
1107
0
    case 's' :
1108
0
        fp->mode = 's';
1109
0
  break;
1110
1111
0
    default : // Remove bogus compiler warning...
1112
0
        return (NULL);
1113
4.39k
  }
1114
1115
  // Don't pass this file to child processes...
1116
4.39k
#ifndef _WIN32
1117
4.39k
  fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
1118
4.39k
#endif // !_WIN32
1119
1120
4.39k
  return (fp);
1121
4.39k
}
1122
1123
1124
//
1125
// '_cupsFilePeekAhead()' - See if the requested character is buffered up.
1126
//
1127
1128
int         // O - 1 if present, 0 otherwise
1129
_cupsFilePeekAhead(cups_file_t *fp, // I - CUPS file
1130
                   int         ch)  // I - Character
1131
0
{
1132
0
  return (fp && fp->ptr && memchr(fp->ptr, ch, (size_t)(fp->end - fp->ptr)));
1133
0
}
1134
1135
1136
//
1137
// 'cupsFilePeekChar()' - Peek at the next character from a file.
1138
//
1139
// @since CUPS 1.2@
1140
//
1141
1142
int         // O - Character or -1 on end of file
1143
cupsFilePeekChar(cups_file_t *fp) // I - CUPS file
1144
0
{
1145
  // Range check input...
1146
0
  if (!fp || (fp->mode != 'r' && fp->mode != 's'))
1147
0
    return (-1);
1148
1149
  // If the input buffer is empty, try to read more data...
1150
0
  if (fp->ptr >= fp->end)
1151
0
    if (cups_fill(fp) <= 0)
1152
0
      return (-1);
1153
1154
  // Return the next character in the buffer...
1155
0
  return (*(fp->ptr) & 255);
1156
0
}
1157
1158
1159
//
1160
// 'cupsFilePrintf()' - Write a formatted string.
1161
//
1162
// @since CUPS 1.2@
1163
//
1164
1165
int         // O - Number of bytes written or -1 on error
1166
cupsFilePrintf(cups_file_t *fp,   // I - CUPS file
1167
               const char  *format, // I - Printf-style format string
1168
         ...)     // I - Additional args as necessary
1169
0
{
1170
0
  va_list ap;     // Argument list
1171
0
  ssize_t bytes;      // Formatted size
1172
1173
1174
0
  DEBUG_printf("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", (void *)fp, format);
1175
1176
0
  if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
1177
0
    return (-1);
1178
1179
0
  if (!fp->printf_buffer)
1180
0
  {
1181
    // Start with a 1k printf buffer...
1182
0
    if ((fp->printf_buffer = malloc(1024)) == NULL)
1183
0
      return (-1);
1184
1185
0
    fp->printf_size = 1024;
1186
0
  }
1187
1188
0
  va_start(ap, format);
1189
0
  bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1190
0
  va_end(ap);
1191
1192
0
  if (bytes >= (ssize_t)fp->printf_size)
1193
0
  {
1194
    // Expand the printf buffer...
1195
0
    char  *temp;      // Temporary buffer pointer
1196
1197
1198
0
    if (bytes > 65535)
1199
0
      return (-1);
1200
1201
0
    if ((temp = realloc(fp->printf_buffer, (size_t)(bytes + 1))) == NULL)
1202
0
      return (-1);
1203
1204
0
    fp->printf_buffer = temp;
1205
0
    fp->printf_size   = (size_t)(bytes + 1);
1206
1207
0
    va_start(ap, format);
1208
0
    bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1209
0
    va_end(ap);
1210
0
  }
1211
1212
0
  if (fp->mode == 's')
1213
0
  {
1214
0
    if (cups_write(fp, fp->printf_buffer, (size_t)bytes) < 0)
1215
0
      return (-1);
1216
1217
0
    fp->pos += bytes;
1218
1219
0
    DEBUG_printf("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1220
1221
0
    return ((int)bytes);
1222
0
  }
1223
1224
0
  if ((fp->ptr + bytes) > fp->end)
1225
0
    if (cupsFileFlush(fp))
1226
0
      return (-1);
1227
1228
0
  fp->pos += bytes;
1229
1230
0
  DEBUG_printf("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1231
1232
0
  if ((size_t)bytes > sizeof(fp->buf))
1233
0
  {
1234
0
    if (fp->compressed)
1235
0
      return ((int)cups_compress(fp, fp->printf_buffer, (size_t)bytes));
1236
0
    else
1237
0
      return ((int)cups_write(fp, fp->printf_buffer, (size_t)bytes));
1238
0
  }
1239
0
  else
1240
0
  {
1241
0
    memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
1242
0
    fp->ptr += bytes;
1243
1244
0
    if (fp->is_stdio && cupsFileFlush(fp))
1245
0
      return (-1);
1246
0
    else
1247
0
      return ((int)bytes);
1248
0
  }
1249
0
}
1250
1251
1252
//
1253
// 'cupsFilePutChar()' - Write a character.
1254
//
1255
// @since CUPS 1.2@
1256
//
1257
1258
int         // O - 0 on success, -1 on error
1259
cupsFilePutChar(cups_file_t *fp,  // I - CUPS file
1260
                int         c)    // I - Character to write
1261
0
{
1262
  // Range check input...
1263
0
  if (!fp || (fp->mode != 'w' && fp->mode != 's'))
1264
0
    return (-1);
1265
1266
0
  if (fp->mode == 's')
1267
0
  {
1268
    // Send character immediately over socket...
1269
0
    char ch;        // Output character
1270
1271
1272
0
    ch = (char)c;
1273
1274
0
    if (send(fp->fd, &ch, 1, 0) < 1)
1275
0
      return (-1);
1276
0
  }
1277
0
  else
1278
0
  {
1279
    // Buffer it up...
1280
0
    if (fp->ptr >= fp->end)
1281
0
      if (cupsFileFlush(fp))
1282
0
  return (-1);
1283
1284
0
    *(fp->ptr) ++ = (char)c;
1285
0
  }
1286
1287
0
  fp->pos ++;
1288
1289
0
  DEBUG_printf("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1290
1291
0
  return (0);
1292
0
}
1293
1294
1295
//
1296
// 'cupsFilePutConf()' - Write a configuration line.
1297
//
1298
// This function handles any comment escaping of the value.
1299
//
1300
// @since CUPS 1.4@
1301
//
1302
1303
ssize_t         // O - Number of bytes written or -1 on error
1304
cupsFilePutConf(cups_file_t *fp,  // I - CUPS file
1305
                const char *directive,  // I - Directive
1306
    const char *value)  // I - Value
1307
0
{
1308
0
  ssize_t bytes,      // Number of bytes written
1309
0
    temp;     // Temporary byte count
1310
0
  const char  *ptr;     // Pointer into value
1311
1312
1313
0
  if (!fp || !directive || !*directive)
1314
0
    return (-1);
1315
1316
0
  if ((bytes = cupsFilePuts(fp, directive)) < 0)
1317
0
    return (-1);
1318
1319
0
  if (cupsFilePutChar(fp, ' ') < 0)
1320
0
    return (-1);
1321
0
  bytes ++;
1322
1323
0
  if (value && *value)
1324
0
  {
1325
0
    if ((ptr = strchr(value, '#')) != NULL)
1326
0
    {
1327
      // Need to quote the first # in the info string...
1328
0
      if ((temp = cupsFileWrite(fp, value, (size_t)(ptr - value))) < 0)
1329
0
        return (-1);
1330
0
      bytes += temp;
1331
1332
0
      if (cupsFilePutChar(fp, '\\') < 0)
1333
0
        return (-1);
1334
0
      bytes ++;
1335
1336
0
      if ((temp = cupsFilePuts(fp, ptr)) < 0)
1337
0
        return (-1);
1338
0
      bytes += temp;
1339
0
    }
1340
0
    else if ((temp = cupsFilePuts(fp, value)) < 0)
1341
0
      return (-1);
1342
0
    else
1343
0
      bytes += temp;
1344
0
  }
1345
1346
0
  if (cupsFilePutChar(fp, '\n') < 0)
1347
0
    return (-1);
1348
0
  else
1349
0
    return (bytes + 1);
1350
0
}
1351
1352
1353
//
1354
// 'cupsFilePuts()' - Write a string.
1355
//
1356
// Like the @code fputs@ function, no newline is appended to the string.
1357
//
1358
// @since CUPS 1.2@
1359
//
1360
1361
int         // O - Number of bytes written or -1 on error
1362
cupsFilePuts(cups_file_t *fp,   // I - CUPS file
1363
             const char  *s)    // I - String to write
1364
0
{
1365
0
  ssize_t bytes;      // Bytes to write
1366
1367
1368
  // Range check input...
1369
0
  if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1370
0
    return (-1);
1371
1372
  // Write the string...
1373
0
  bytes = (ssize_t)strlen(s);
1374
1375
0
  if (fp->mode == 's')
1376
0
  {
1377
0
    if (cups_write(fp, s, (size_t)bytes) < 0)
1378
0
      return (-1);
1379
1380
0
    fp->pos += bytes;
1381
1382
0
    DEBUG_printf("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1383
1384
0
    return ((int)bytes);
1385
0
  }
1386
1387
0
  if ((fp->ptr + bytes) > fp->end)
1388
0
    if (cupsFileFlush(fp))
1389
0
      return (-1);
1390
1391
0
  fp->pos += bytes;
1392
1393
0
  DEBUG_printf("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1394
1395
0
  if ((size_t)bytes > sizeof(fp->buf))
1396
0
  {
1397
0
    if (fp->compressed)
1398
0
      return ((int)cups_compress(fp, s, (size_t)bytes));
1399
0
    else
1400
0
      return ((int)cups_write(fp, s, (size_t)bytes));
1401
0
  }
1402
0
  else
1403
0
  {
1404
0
    memcpy(fp->ptr, s, (size_t)bytes);
1405
0
    fp->ptr += bytes;
1406
1407
0
    if (fp->is_stdio && cupsFileFlush(fp))
1408
0
      return (-1);
1409
0
    else
1410
0
      return ((int)bytes);
1411
0
  }
1412
0
}
1413
1414
1415
//
1416
// 'cupsFileRead()' - Read from a file.
1417
//
1418
// @since CUPS 1.2@
1419
//
1420
1421
ssize_t         // O - Number of bytes read or -1 on error
1422
cupsFileRead(cups_file_t *fp,   // I - CUPS file
1423
             char        *buf,    // O - Buffer
1424
       size_t      bytes)   // I - Number of bytes to read
1425
2.16M
{
1426
2.16M
  size_t  total;      // Total bytes read
1427
2.16M
  ssize_t count;      // Bytes read
1428
1429
1430
2.16M
  DEBUG_printf("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1431
1432
  // Range check input...
1433
2.16M
  if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
1434
0
    return (-1);
1435
1436
2.16M
  if (bytes == 0)
1437
0
    return (0);
1438
1439
2.16M
  if (fp->eof)
1440
0
  {
1441
0
    DEBUG_puts("5cupsFileRead: End-of-file!");
1442
0
    return (-1);
1443
0
  }
1444
1445
  // Loop until all bytes are read...
1446
2.16M
  total = 0;
1447
4.33M
  while (bytes > 0)
1448
2.16M
  {
1449
2.16M
    if (fp->ptr >= fp->end)
1450
5.08k
      if (cups_fill(fp) <= 0)
1451
1.43k
      {
1452
1.43k
        DEBUG_printf("4cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT, CUPS_LLCAST total);
1453
1454
1.43k
        if (total > 0)
1455
220
          return ((ssize_t)total);
1456
1.21k
  else
1457
1.21k
    return (-1);
1458
1.43k
      }
1459
1460
2.16M
    count = (ssize_t)(fp->end - fp->ptr);
1461
2.16M
    if (count > (ssize_t)bytes)
1462
2.16M
      count = (ssize_t)bytes;
1463
1464
2.16M
    memcpy(buf, fp->ptr,(size_t) count);
1465
2.16M
    fp->ptr += count;
1466
2.16M
    fp->pos += count;
1467
1468
2.16M
    DEBUG_printf("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1469
1470
    // Update the counts for the last read...
1471
2.16M
    bytes -= (size_t)count;
1472
2.16M
    total += (size_t)count;
1473
2.16M
    buf   += count;
1474
2.16M
  }
1475
1476
  // Return the total number of bytes read...
1477
2.16M
  DEBUG_printf("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total);
1478
1479
2.16M
  return ((ssize_t)total);
1480
2.16M
}
1481
1482
1483
//
1484
// 'cupsFileRewind()' - Set the current file position to the beginning of the
1485
//                      file.
1486
//
1487
// @since CUPS 1.2@
1488
//
1489
1490
off_t         // O - New file position or -1 on error
1491
cupsFileRewind(cups_file_t *fp)   // I - CUPS file
1492
0
{
1493
  // Range check input...
1494
0
  DEBUG_printf("cupsFileRewind(fp=%p)", (void *)fp);
1495
1496
0
  if (!fp || fp->mode != 'r')
1497
0
    return (-1);
1498
1499
0
  DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1500
1501
  // Handle special cases...
1502
0
  if (fp->bufpos == 0)
1503
0
  {
1504
    // No seeking necessary...
1505
0
    fp->pos = 0;
1506
1507
0
    if (fp->ptr)
1508
0
    {
1509
0
      fp->ptr = fp->buf;
1510
0
      fp->eof = 0;
1511
0
    }
1512
1513
0
    DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1514
1515
0
    return (0);
1516
0
  }
1517
1518
  // Otherwise, seek in the file and cleanup any compression buffers...
1519
0
  if (fp->compressed)
1520
0
  {
1521
0
    inflateEnd(&fp->stream);
1522
0
    fp->compressed = 0;
1523
0
  }
1524
1525
0
  if (lseek(fp->fd, 0, SEEK_SET))
1526
0
  {
1527
0
    DEBUG_printf("1cupsFileRewind: lseek failed: %s", strerror(errno));
1528
0
    return (-1);
1529
0
  }
1530
1531
0
  fp->bufpos = 0;
1532
0
  fp->pos    = 0;
1533
0
  fp->ptr    = NULL;
1534
0
  fp->end    = NULL;
1535
0
  fp->eof    = 0;
1536
1537
0
  DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1538
1539
0
  return (0);
1540
0
}
1541
1542
1543
//
1544
// 'cupsFileSeek()' - Seek in a file.
1545
//
1546
// @since CUPS 1.2@
1547
//
1548
1549
off_t         // O - New file position or -1 on error
1550
cupsFileSeek(cups_file_t *fp,   // I - CUPS file
1551
             off_t       pos)   // I - Position in file
1552
0
{
1553
0
  ssize_t bytes;      // Number bytes in buffer
1554
1555
1556
0
  DEBUG_printf("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", (void *)fp, CUPS_LLCAST pos);
1557
1558
  // Range check input...
1559
0
  if (!fp || pos < 0 || fp->mode != 'r')
1560
0
    return (-1);
1561
1562
0
  DEBUG_printf("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1563
0
  DEBUG_printf("2cupsFileSeek: fp->ptr=%p, fp->end=%p", (void *)fp->ptr, (void *)fp->end);
1564
1565
  // Handle special cases...
1566
0
  if (pos == 0)
1567
0
    return (cupsFileRewind(fp));
1568
1569
0
  if (fp->ptr)
1570
0
  {
1571
0
    bytes = (ssize_t)(fp->end - fp->buf);
1572
1573
0
    DEBUG_printf("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes);
1574
1575
0
    if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1576
0
    {
1577
      // No seeking necessary...
1578
0
      fp->pos = pos;
1579
0
      fp->ptr = fp->buf + (pos - fp->bufpos);
1580
0
      fp->eof = 0;
1581
1582
0
      return (pos);
1583
0
    }
1584
0
  }
1585
1586
0
  if (!fp->compressed && !fp->ptr)
1587
0
  {
1588
    // Preload a buffer to determine whether the file is compressed...
1589
0
    if (cups_fill(fp) <= 0)
1590
0
      return (-1);
1591
0
  }
1592
1593
  // Seek forwards or backwards...
1594
0
  fp->eof = 0;
1595
1596
0
  if (pos < fp->bufpos)
1597
0
  {
1598
    // Need to seek backwards...
1599
0
    DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS");
1600
1601
0
    if (fp->compressed)
1602
0
    {
1603
0
      inflateEnd(&fp->stream);
1604
1605
0
      lseek(fp->fd, 0, SEEK_SET);
1606
0
      fp->bufpos = 0;
1607
0
      fp->pos    = 0;
1608
0
      fp->ptr    = NULL;
1609
0
      fp->end    = NULL;
1610
1611
0
      while ((bytes = cups_fill(fp)) > 0)
1612
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1613
0
    break;
1614
1615
0
      if (bytes <= 0)
1616
0
        return (-1);
1617
1618
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1619
0
      fp->pos = pos;
1620
0
    }
1621
0
    else
1622
0
    {
1623
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1624
0
      fp->pos    = fp->bufpos;
1625
0
      fp->ptr    = NULL;
1626
0
      fp->end    = NULL;
1627
1628
0
      DEBUG_printf("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos);
1629
0
    }
1630
0
  }
1631
0
  else
1632
0
  {
1633
    // Need to seek forwards...
1634
0
    DEBUG_puts("2cupsFileSeek: SEEK FORWARDS");
1635
1636
0
    if (fp->compressed)
1637
0
    {
1638
0
      while ((bytes = cups_fill(fp)) > 0)
1639
0
      {
1640
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1641
0
    break;
1642
0
      }
1643
1644
0
      if (bytes <= 0)
1645
0
        return (-1);
1646
1647
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1648
0
      fp->pos = pos;
1649
0
    }
1650
0
    else
1651
0
    {
1652
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1653
0
      fp->pos    = fp->bufpos;
1654
0
      fp->ptr    = NULL;
1655
0
      fp->end    = NULL;
1656
1657
0
      DEBUG_printf("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos);
1658
0
    }
1659
0
  }
1660
1661
0
  DEBUG_printf("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1662
1663
0
  return (fp->pos);
1664
0
}
1665
1666
1667
//
1668
// 'cupsFileStderr()' - Return a CUPS file associated with stderr.
1669
//
1670
// @since CUPS 1.2@
1671
//
1672
1673
cups_file_t *       // O - CUPS file
1674
cupsFileStderr(void)
1675
0
{
1676
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1677
1678
1679
  // Open file descriptor 2 as needed...
1680
0
  if (!cg->stdio_files[2])
1681
0
  {
1682
    // Flush any pending output on the stdio file...
1683
0
    fflush(stderr);
1684
1685
    // Open file descriptor 2...
1686
0
    if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1687
0
      cg->stdio_files[2]->is_stdio = 1;
1688
0
  }
1689
1690
0
  return (cg->stdio_files[2]);
1691
0
}
1692
1693
1694
//
1695
// 'cupsFileStdin()' - Return a CUPS file associated with stdin.
1696
//
1697
// @since CUPS 1.2@
1698
//
1699
1700
cups_file_t *       // O - CUPS file
1701
cupsFileStdin(void)
1702
0
{
1703
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1704
1705
1706
  // Open file descriptor 0 as needed...
1707
0
  if (!cg->stdio_files[0])
1708
0
  {
1709
    // Open file descriptor 0...
1710
0
    if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1711
0
      cg->stdio_files[0]->is_stdio = 1;
1712
0
  }
1713
1714
0
  return (cg->stdio_files[0]);
1715
0
}
1716
1717
1718
//
1719
// 'cupsFileStdout()' - Return a CUPS file associated with stdout.
1720
//
1721
// @since CUPS 1.2@
1722
//
1723
1724
cups_file_t *       // O - CUPS file
1725
cupsFileStdout(void)
1726
0
{
1727
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1728
1729
1730
  // Open file descriptor 1 as needed...
1731
0
  if (!cg->stdio_files[1])
1732
0
  {
1733
    // Flush any pending output on the stdio file...
1734
0
    fflush(stdout);
1735
1736
    // Open file descriptor 1...
1737
0
    if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
1738
0
      cg->stdio_files[1]->is_stdio = 1;
1739
0
  }
1740
1741
0
  return (cg->stdio_files[1]);
1742
0
}
1743
1744
1745
//
1746
// 'cupsFileTell()' - Return the current file position.
1747
//
1748
// @since CUPS 1.2@
1749
//
1750
1751
off_t         // O - File position
1752
cupsFileTell(cups_file_t *fp)   // I - CUPS file
1753
0
{
1754
0
  DEBUG_printf("2cupsFileTell(fp=%p)", (void *)fp);
1755
0
  DEBUG_printf("3cupsFileTell: pos=" CUPS_LLFMT, CUPS_LLCAST (fp ? fp->pos : -1));
1756
1757
0
  return (fp ? fp->pos : 0);
1758
0
}
1759
1760
1761
//
1762
// 'cupsFileUnlock()' - Unlock access to a file.
1763
//
1764
// @since CUPS 1.2@
1765
//
1766
1767
int         // O - 0 on success, -1 on error
1768
cupsFileUnlock(cups_file_t *fp)   // I - CUPS file
1769
0
{
1770
  // Range check...
1771
0
  DEBUG_printf("cupsFileUnlock(fp=%p)", (void *)fp);
1772
1773
0
  if (!fp || fp->mode == 's')
1774
0
    return (-1);
1775
1776
  // Unlock...
1777
#ifdef _WIN32
1778
  return (_locking(fp->fd, _LK_UNLCK, 0));
1779
#else
1780
0
  return (lockf(fp->fd, F_ULOCK, 0));
1781
0
#endif // _WIN32
1782
0
}
1783
1784
1785
//
1786
// 'cupsFileWrite()' - Write to a file.
1787
//
1788
// @since CUPS 1.2@
1789
//
1790
1791
ssize_t         // O - Number of bytes written or -1 on error
1792
cupsFileWrite(cups_file_t *fp,    // I - CUPS file
1793
              const char  *buf,   // I - Buffer
1794
        size_t      bytes)  // I - Number of bytes to write
1795
2.19k
{
1796
  // Range check input...
1797
2.19k
  DEBUG_printf("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1798
1799
2.19k
  if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
1800
0
    return (-1);
1801
1802
2.19k
  if (bytes == 0)
1803
0
    return (0);
1804
1805
  // Write the buffer...
1806
2.19k
  if (fp->mode == 's')
1807
0
  {
1808
0
    if (cups_write(fp, buf, bytes) < 0)
1809
0
      return (-1);
1810
1811
0
    fp->pos += (off_t)bytes;
1812
1813
0
    DEBUG_printf("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1814
1815
0
    return ((ssize_t)bytes);
1816
0
  }
1817
1818
2.19k
  if ((fp->ptr + bytes) > fp->end)
1819
142
    if (cupsFileFlush(fp))
1820
0
      return (-1);
1821
1822
2.19k
  fp->pos += (off_t)bytes;
1823
1824
2.19k
  DEBUG_printf("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1825
1826
2.19k
  if (bytes > sizeof(fp->buf))
1827
142
  {
1828
142
    if (fp->compressed)
1829
0
      return (cups_compress(fp, buf, bytes));
1830
142
    else
1831
142
      return (cups_write(fp, buf, bytes));
1832
142
  }
1833
2.05k
  else
1834
2.05k
  {
1835
2.05k
    memcpy(fp->ptr, buf, bytes);
1836
2.05k
    fp->ptr += bytes;
1837
2.05k
    return ((ssize_t)bytes);
1838
2.05k
  }
1839
2.19k
}
1840
1841
1842
//
1843
// 'cups_compress()' - Compress a buffer of data.
1844
//
1845
1846
static ssize_t        // O - Number of bytes written or -1
1847
cups_compress(cups_file_t *fp,    // I - CUPS file
1848
              const char  *buf,   // I - Buffer
1849
        size_t      bytes)  // I - Number bytes
1850
0
{
1851
0
  int status;       // Deflate status
1852
1853
1854
0
  DEBUG_printf("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1855
1856
  // Update the CRC...
1857
0
  fp->crc = crc32(fp->crc, (const Bytef *)buf, (uInt)bytes);
1858
1859
  // Deflate the bytes...
1860
0
  fp->stream.next_in  = (Bytef *)buf;
1861
0
  fp->stream.avail_in = (uInt)bytes;
1862
1863
0
  while (fp->stream.avail_in > 0)
1864
0
  {
1865
    // Flush the current buffer...
1866
0
    DEBUG_printf("9cups_compress: avail_in=%d, avail_out=%d", fp->stream.avail_in, fp->stream.avail_out);
1867
1868
0
    if (fp->stream.avail_out < (uInt)(sizeof(fp->cbuf) / 8))
1869
0
    {
1870
0
      if (cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)) < 0)
1871
0
        return (-1);
1872
1873
0
      fp->stream.next_out  = fp->cbuf;
1874
0
      fp->stream.avail_out = sizeof(fp->cbuf);
1875
0
    }
1876
1877
0
    if ((status = deflate(&(fp->stream), Z_NO_FLUSH)) < Z_OK && status != Z_BUF_ERROR)
1878
0
      return (-1);
1879
0
  }
1880
1881
0
  return ((ssize_t)bytes);
1882
0
}
1883
1884
1885
//
1886
// 'cups_fill()' - Fill the input buffer.
1887
//
1888
1889
static ssize_t        // O - Number of bytes or -1
1890
cups_fill(cups_file_t *fp)    // I - CUPS file
1891
5.08k
{
1892
5.08k
  ssize_t   bytes;    // Number of bytes read
1893
5.08k
  int     status;   // Decompression status
1894
5.08k
  const unsigned char *ptr,   // Pointer into buffer
1895
5.08k
      *end;   // End of buffer
1896
1897
1898
5.08k
  DEBUG_printf("7cups_fill(fp=%p)", (void *)fp);
1899
5.08k
  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);
1900
1901
5.08k
  if (fp->ptr && fp->end)
1902
2.89k
    fp->bufpos += fp->end - fp->buf;
1903
1904
5.08k
  DEBUG_printf("9cups_fill: fp->compressed=%d", fp->compressed);
1905
1906
5.10k
  while (!fp->ptr || fp->compressed)
1907
2.49k
  {
1908
    // Check to see if we have read any data yet; if not, see if we have a
1909
    // compressed file...
1910
2.49k
    if (!fp->ptr)
1911
2.19k
    {
1912
      // Reset the file position in case we are seeking...
1913
2.19k
      fp->compressed = 0;
1914
1915
      // Read the first bytes in the file to determine if we have a gzip'd file...
1916
2.19k
      if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
1917
0
      {
1918
        // Can't read from file!
1919
0
        DEBUG_printf("9cups_fill: cups_read() returned " CUPS_LLFMT, CUPS_LLCAST bytes);
1920
1921
0
        fp->eof = 1;
1922
1923
0
  return (-1);
1924
0
      }
1925
1926
2.19k
      if (bytes < 10 || fp->buf[0] != 0x1f ||
1927
258
          (fp->buf[1] & 255) != 0x8b ||
1928
246
          fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
1929
1.96k
      {
1930
        // Not a gzip'd file!
1931
1.96k
  fp->ptr = fp->buf;
1932
1.96k
  fp->end = fp->buf + bytes;
1933
1934
1.96k
        DEBUG_printf("9cups_fill: Returning " CUPS_LLFMT, CUPS_LLCAST bytes);
1935
1936
1.96k
  return (bytes);
1937
1.96k
      }
1938
1939
      // Parse header junk: extra data, original name, and comment...
1940
235
      ptr = (unsigned char *)fp->buf + 10;
1941
235
      end = (unsigned char *)fp->buf + bytes;
1942
1943
235
      if (fp->buf[3] & 0x04)
1944
60
      {
1945
        // Skip extra data...
1946
60
  if ((ptr + 2) > end)
1947
6
  {
1948
    // Can't read from file!
1949
6
    DEBUG_puts("9cups_fill: Extra gzip header data missing, returning -1.");
1950
1951
6
          fp->eof = 1;
1952
6
    errno   = EIO;
1953
1954
6
    return (-1);
1955
6
  }
1956
1957
54
  bytes = (ptr[1] << 8) | ptr[0];
1958
54
  ptr   += 2 + bytes;
1959
1960
54
  if (ptr > end)
1961
31
  {
1962
    // Can't read from file!
1963
31
    DEBUG_puts("9cups_fill: Extra gzip header data does not fit in initial buffer, returning -1.");
1964
1965
31
          fp->eof = 1;
1966
31
    errno   = EIO;
1967
1968
31
    return (-1);
1969
31
  }
1970
54
      }
1971
1972
198
      if (fp->buf[3] & 0x08)
1973
66
      {
1974
        // Skip original name data...
1975
499
  while (ptr < end && *ptr)
1976
433
          ptr ++;
1977
1978
66
  if (ptr < end)
1979
50
          ptr ++;
1980
16
  else
1981
16
  {
1982
    // Can't read from file!
1983
16
    DEBUG_puts("9cups_fill: Original filename in gzip header data does not fit in initial buffer, returning -1.");
1984
1985
16
          fp->eof = 1;
1986
16
    errno   = EIO;
1987
1988
16
    return (-1);
1989
16
  }
1990
66
      }
1991
1992
182
      if (fp->buf[3] & 0x10)
1993
52
      {
1994
        // Skip comment data...
1995
709
  while (ptr < end && *ptr)
1996
657
          ptr ++;
1997
1998
52
  if (ptr < end)
1999
34
          ptr ++;
2000
18
  else
2001
18
  {
2002
    // Can't read from file!
2003
18
    DEBUG_puts("9cups_fill: Comment in gzip header data does not fit in initial buffer, returning -1.");
2004
2005
18
          fp->eof = 1;
2006
18
    errno   = EIO;
2007
2008
18
    return (-1);
2009
18
  }
2010
52
      }
2011
2012
164
      if (fp->buf[3] & 0x02)
2013
39
      {
2014
        // Skip header CRC data...
2015
39
  ptr += 2;
2016
2017
39
  if (ptr > end)
2018
8
  {
2019
    // Can't read from file!
2020
8
    DEBUG_puts("9cups_fill: Header CRC in gzip header data does not fit in initial buffer, returning -1.");
2021
2022
8
          fp->eof = 1;
2023
8
    errno   = EIO;
2024
2025
8
    return (-1);
2026
8
  }
2027
39
      }
2028
2029
      // Copy the flate-compressed data to the compression buffer...
2030
156
      if ((bytes = end - ptr) > 0)
2031
153
        memcpy(fp->cbuf, ptr, (size_t)bytes);
2032
2033
      // Setup the decompressor data...
2034
156
      fp->stream.zalloc    = (alloc_func)0;
2035
156
      fp->stream.zfree     = (free_func)0;
2036
156
      fp->stream.opaque    = (voidpf)0;
2037
156
      fp->stream.next_in   = (Bytef *)fp->cbuf;
2038
156
      fp->stream.next_out  = NULL;
2039
156
      fp->stream.avail_in  = (uInt)bytes;
2040
156
      fp->stream.avail_out = 0;
2041
156
      fp->crc              = crc32(0L, Z_NULL, 0);
2042
2043
156
      if ((status = inflateInit2(&(fp->stream), -15)) != Z_OK)
2044
0
      {
2045
0
  DEBUG_printf("9cups_fill: inflateInit2 returned %d, returning -1.", status);
2046
2047
0
        fp->eof = 1;
2048
0
        errno   = EIO;
2049
2050
0
  return (-1);
2051
0
      }
2052
2053
156
      fp->compressed = 1;
2054
156
    }
2055
2056
447
    if (fp->compressed)
2057
447
    {
2058
      // If we have reached end-of-file, return immediately...
2059
447
      if (fp->eof)
2060
0
      {
2061
0
        DEBUG_puts("9cups_fill: EOF, returning 0.");
2062
2063
0
  return (0);
2064
0
      }
2065
2066
      // Fill the decompression buffer as needed...
2067
447
      if (fp->stream.avail_in == 0)
2068
247
      {
2069
247
  if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
2070
48
  {
2071
48
    DEBUG_printf("9cups_fill: cups_read error, returning %d.", (int)bytes);
2072
2073
48
    fp->eof = 1;
2074
2075
48
          return (bytes);
2076
48
  }
2077
2078
199
  fp->stream.next_in  = fp->cbuf;
2079
199
  fp->stream.avail_in = (uInt)bytes;
2080
199
      }
2081
2082
      // Decompress data from the buffer...
2083
399
      fp->stream.next_out  = (Bytef *)fp->buf;
2084
399
      fp->stream.avail_out = sizeof(fp->buf);
2085
2086
399
      status = inflate(&(fp->stream), Z_NO_FLUSH);
2087
2088
399
      if (fp->stream.next_out > (Bytef *)fp->buf)
2089
308
        fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
2090
308
                  (uInt)(fp->stream.next_out - (Bytef *)fp->buf));
2091
2092
399
      if (status == Z_STREAM_END)
2093
80
      {
2094
        // Read the CRC and length...
2095
80
  unsigned char trailer[8]; // Trailer bytes
2096
80
  uLong   tcrc;   // Trailer CRC
2097
80
  ssize_t   tbytes = 0; // Number of bytes
2098
2099
80
  if (fp->stream.avail_in > 0)
2100
79
  {
2101
    // Get the first N trailer bytes from the inflate stream...
2102
79
    if (fp->stream.avail_in > sizeof(trailer))
2103
25
      tbytes = (ssize_t)sizeof(trailer);
2104
54
    else
2105
54
      tbytes = (ssize_t)fp->stream.avail_in;
2106
2107
79
    memcpy(trailer, fp->stream.next_in, (size_t)tbytes);
2108
79
    fp->stream.next_in  += tbytes;
2109
79
    fp->stream.avail_in -= (size_t)tbytes;
2110
79
  }
2111
2112
        // Reset the compressed flag so that we re-read the file header...
2113
80
        inflateEnd(&fp->stream);
2114
2115
80
  fp->compressed = 0;
2116
2117
        // Get any remaining trailer bytes...
2118
80
        if (tbytes < (ssize_t)sizeof(trailer))
2119
7
  {
2120
7
    if (read(fp->fd, trailer + tbytes, sizeof(trailer) - (size_t)tbytes) < ((ssize_t)sizeof(trailer) - tbytes))
2121
6
    {
2122
      // Can't get it, so mark end-of-file...
2123
6
      DEBUG_puts("9cups_fill: Unable to read gzip CRC trailer, returning -1.");
2124
2125
6
      fp->eof = 1;
2126
6
      errno   = EIO;
2127
2128
6
      return (-1);
2129
6
    }
2130
7
  }
2131
2132
        // Calculate and compare the CRC...
2133
74
  tcrc = ((uLong)trailer[3] << 24) | ((uLong)trailer[2] << 16) | ((uLong)trailer[1] << 8) | ((uLong)trailer[0]);
2134
2135
74
  if (tcrc != fp->crc)
2136
69
  {
2137
    // Bad CRC, mark end-of-file...
2138
69
    DEBUG_printf("9cups_fill: tcrc=%08x != fp->crc=%08x, returning -1.", (unsigned int)tcrc, (unsigned int)fp->crc);
2139
2140
69
    fp->eof = 1;
2141
69
    errno   = EIO;
2142
2143
69
    return (-1);
2144
69
  }
2145
74
      }
2146
319
      else if (status < Z_OK)
2147
6
      {
2148
6
  DEBUG_printf("9cups_fill: inflate returned %d, returning -1.", status);
2149
2150
6
        fp->eof = 1;
2151
6
        errno   = EIO;
2152
2153
6
  return (-1);
2154
6
      }
2155
2156
318
      bytes = (ssize_t)sizeof(fp->buf) - (ssize_t)fp->stream.avail_out;
2157
2158
      // Return the decompressed data...
2159
318
      fp->ptr = fp->buf;
2160
318
      fp->end = fp->buf + bytes;
2161
2162
318
      if (bytes)
2163
304
      {
2164
304
        DEBUG_printf("9cups_fill: Returning %d.", (int)bytes);
2165
304
  return (bytes);
2166
304
      }
2167
318
    }
2168
447
  }
2169
2170
  // Read a buffer's full of data...
2171
2.61k
  if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
2172
1.22k
  {
2173
    // Can't read from file!
2174
1.22k
    fp->eof = 1;
2175
1.22k
    fp->ptr = fp->buf;
2176
1.22k
    fp->end = fp->buf;
2177
1.22k
  }
2178
1.38k
  else
2179
1.38k
  {
2180
    // Return the bytes we read...
2181
1.38k
    fp->eof = 0;
2182
1.38k
    fp->ptr = fp->buf;
2183
1.38k
    fp->end = fp->buf + bytes;
2184
1.38k
  }
2185
2186
2.61k
  DEBUG_printf("9cups_fill: Not gzip, returning %d.", (int)bytes);
2187
2188
2.61k
  return (bytes);
2189
5.08k
}
2190
2191
2192
//
2193
// 'cups_open()' - Safely open a file for writing.
2194
//
2195
// We don't allow appending to directories or files that are hard-linked or
2196
// symlinked.
2197
//
2198
2199
static int        // O - File descriptor or -1 otherwise
2200
cups_open(const char *filename,   // I - Filename
2201
          int        oflag,   // I - Open flags
2202
    int        mode)    // I - Open permissions
2203
4.39k
{
2204
4.39k
  int   fd;     // File descriptor
2205
4.39k
  struct stat fileinfo;   // File information
2206
4.39k
#ifndef _WIN32
2207
4.39k
  struct stat linkinfo;   // Link information
2208
4.39k
#endif // !_WIN32
2209
2210
2211
  // Open the file...
2212
4.39k
  if ((fd = open(filename, oflag, mode)) < 0)
2213
2.19k
    return (-1);
2214
2215
  // Then verify that the file descriptor doesn't point to a directory or hard-linked file.
2216
2.19k
  if (fstat(fd, &fileinfo))
2217
0
  {
2218
0
    int temp = errno;
2219
0
    close(fd);
2220
0
    errno = temp;
2221
0
    return (-1);
2222
0
  }
2223
2224
2.19k
  if (fileinfo.st_nlink != 1)
2225
0
  {
2226
0
    close(fd);
2227
0
    errno = EPERM;
2228
0
    return (-1);
2229
0
  }
2230
2231
#ifdef _WIN32
2232
  if (fileinfo.st_mode & _S_IFDIR)
2233
#else
2234
2.19k
  if (S_ISDIR(fileinfo.st_mode))
2235
0
#endif // _WIN32
2236
0
  {
2237
0
    close(fd);
2238
0
    errno = EISDIR;
2239
0
    return (-1);
2240
0
  }
2241
2242
2.19k
#ifndef _WIN32
2243
  // Then use lstat to determine whether the filename is a symlink...
2244
2.19k
  if (lstat(filename, &linkinfo))
2245
0
  {
2246
0
    int temp = errno;
2247
0
    close(fd);
2248
0
    errno = temp;
2249
0
    return (-1);
2250
0
  }
2251
2252
2.19k
  if (S_ISLNK(linkinfo.st_mode) ||
2253
2.19k
      fileinfo.st_dev != linkinfo.st_dev ||
2254
2.19k
      fileinfo.st_ino != linkinfo.st_ino ||
2255
#ifdef HAVE_ST_GEN
2256
      fileinfo.st_gen != linkinfo.st_gen ||
2257
#endif // HAVE_ST_GEN
2258
2.19k
      fileinfo.st_nlink != linkinfo.st_nlink ||
2259
2.19k
      fileinfo.st_mode != linkinfo.st_mode)
2260
0
  {
2261
    // Yes, don't allow!
2262
0
    close(fd);
2263
0
    errno = EPERM;
2264
0
    return (-1);
2265
0
  }
2266
2.19k
#endif // !_WIN32
2267
2268
2.19k
  return (fd);
2269
2.19k
}
2270
2271
2272
//
2273
// 'cups_read()' - Read from a file descriptor.
2274
//
2275
2276
static ssize_t        // O - Number of bytes read or -1
2277
cups_read(cups_file_t *fp,    // I - CUPS file
2278
          char        *buf,   // I - Buffer
2279
    size_t      bytes)    // I - Number bytes
2280
5.05k
{
2281
5.05k
  ssize_t total;      // Total bytes read
2282
2283
2284
5.05k
  DEBUG_printf("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
2285
2286
  // Loop until we read at least 0 bytes...
2287
5.05k
  for (;;)
2288
5.05k
  {
2289
#ifdef _WIN32
2290
    if (fp->mode == 's')
2291
      total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2292
    else
2293
      total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2294
#else
2295
5.05k
    if (fp->mode == 's')
2296
0
      total = recv(fp->fd, buf, bytes, 0);
2297
5.05k
    else
2298
5.05k
      total = read(fp->fd, buf, bytes);
2299
5.05k
#endif // _WIN32
2300
2301
5.05k
    DEBUG_printf("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total);
2302
2303
5.05k
    if (total >= 0)
2304
5.05k
      break;
2305
2306
    // Reads can be interrupted by signals and unavailable resources...
2307
0
    if (errno == EAGAIN || errno == EINTR)
2308
0
      continue;
2309
0
    else
2310
0
      return (-1);
2311
0
  }
2312
2313
  // Return the total number of bytes read...
2314
5.05k
  return (total);
2315
5.05k
}
2316
2317
2318
//
2319
// 'cups_write()' - Write to a file descriptor.
2320
//
2321
2322
static ssize_t        // O - Number of bytes written or -1
2323
cups_write(cups_file_t *fp,   // I - CUPS file
2324
           const char  *buf,    // I - Buffer
2325
     size_t      bytes)   // I - Number bytes
2326
2.19k
{
2327
2.19k
  size_t  total;      // Total bytes written
2328
2.19k
  ssize_t count;      // Count this time
2329
2330
2331
2.19k
  DEBUG_printf("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
2332
2333
  // Loop until all bytes are written...
2334
2.19k
  total = 0;
2335
4.39k
  while (bytes > 0)
2336
2.19k
  {
2337
#ifdef _WIN32
2338
    if (fp->mode == 's')
2339
      count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2340
    else
2341
      count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2342
#else
2343
2.19k
    if (fp->mode == 's')
2344
0
      count = send(fp->fd, buf, bytes, 0);
2345
2.19k
    else
2346
2.19k
      count = write(fp->fd, buf, bytes);
2347
2.19k
#endif // _WIN32
2348
2349
2.19k
    DEBUG_printf("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count);
2350
2351
2.19k
    if (count < 0)
2352
0
    {
2353
      // Writes can be interrupted by signals and unavailable resources...
2354
0
      if (errno == EAGAIN || errno == EINTR)
2355
0
        continue;
2356
0
      else
2357
0
        return (-1);
2358
0
    }
2359
2360
    // Update the counts for the last write call...
2361
2.19k
    bytes -= (size_t)count;
2362
2.19k
    total += (size_t)count;
2363
2.19k
    buf   += count;
2364
2.19k
  }
2365
2366
  // Return the total number of bytes written...
2367
2.19k
  return ((ssize_t)total);
2368
2.19k
}