Coverage Report

Created: 2025-07-11 06:22

/src/cups/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, 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
10.0k
{
301
10.0k
  int fd;       // File descriptor
302
10.0k
  char  mode;       // Open mode
303
10.0k
  int status;       // Return status
304
305
306
10.0k
  DEBUG_printf("cupsFileClose(fp=%p)", (void *)fp);
307
308
  // Range check...
309
10.0k
  if (!fp)
310
0
    return (-1);
311
312
  // Flush pending write data...
313
10.0k
  if (fp->mode == 'w')
314
0
    status = cupsFileFlush(fp);
315
10.0k
  else
316
10.0k
    status = 0;
317
318
10.0k
  if (fp->compressed && status >= 0)
319
74
  {
320
74
    if (fp->mode == 'r')
321
74
    {
322
      // Free decompression data...
323
74
      inflateEnd(&fp->stream);
324
74
    }
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
74
  }
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
10.0k
  if (fp->is_stdio)
374
0
    return (status);
375
376
  // Save the file descriptor we used and free memory...
377
10.0k
  fd   = fp->fd;
378
10.0k
  mode = fp->mode;
379
380
10.0k
  if (fp->printf_buffer)
381
0
    free(fp->printf_buffer);
382
383
10.0k
  free(fp);
384
385
  // Close the file, returning the close status...
386
10.0k
  if (mode == 's')
387
0
  {
388
0
    if (httpAddrClose(NULL, fd) < 0)
389
0
      status = -1;
390
0
  }
391
10.0k
  else if (close(fd) < 0)
392
0
    status = -1;
393
394
10.0k
  return (status);
395
10.0k
}
396
397
398
//
399
// 'cupsFileCompression()' - Return whether a file is compressed.
400
//
401
// @deprecated@ @exclude all@
402
//
403
404
int         // O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@
405
cupsFileCompression(cups_file_t *fp)  // I - CUPS file
406
0
{
407
0
  return (fp ? fp->compressed : CUPS_FILE_NONE);
408
0
}
409
410
411
//
412
// 'cupsFileEOF()' - Return the end-of-file status.
413
//
414
// @since CUPS 1.2@
415
//
416
417
int         // O - 1 on end of file, 0 otherwise
418
cupsFileEOF(cups_file_t *fp)    // I - CUPS file
419
0
{
420
0
  return (fp ? fp->eof : 1);
421
0
}
422
423
424
//
425
// 'cupsFileFind()' - Find a file using the specified path.
426
//
427
// This function allows the paths in the path string to be separated by
428
// colons (UNIX standard) or semicolons (Windows standard) and stores the
429
// result in the buffer supplied.  If the file cannot be found in any of
430
// the supplied paths, @code NULL@ is returned. A @code NULL@ path only
431
// matches the current directory.
432
//
433
// @since CUPS 1.2@
434
//
435
436
const char *        // O - Full path to file or @code NULL@ if not found
437
cupsFileFind(const char *filename,  // I - File to find
438
             const char *path,    // I - Colon/semicolon-separated path
439
             int        executable, // I - 1 = executable files, 0 = any file/dir
440
       char       *buffer,  // I - Filename buffer
441
       int        bufsize)  // I - Size of filename buffer
442
0
{
443
0
  char  *bufptr,      // Current position in buffer
444
0
  *bufend;      // End of buffer
445
446
447
  // Range check input...
448
0
  DEBUG_printf("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, buffer=%p, bufsize=%d)", filename, path, executable, (void *)buffer, bufsize);
449
450
0
  if (!filename || !buffer || bufsize < 2)
451
0
    return (NULL);
452
453
0
  if (!path)
454
0
  {
455
    // No path, so check current directory...
456
0
    if (!access(filename, 0))
457
0
    {
458
0
      cupsCopyString(buffer, filename, (size_t)bufsize);
459
0
      return (buffer);
460
0
    }
461
0
    else
462
0
      return (NULL);
463
0
  }
464
465
  // Now check each path and return the first match...
466
0
  bufend = buffer + bufsize - 1;
467
0
  bufptr = buffer;
468
469
0
  while (*path)
470
0
  {
471
#ifdef _WIN32
472
    if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
473
#else
474
0
    if (*path == ';' || *path == ':')
475
0
#endif // _WIN32
476
0
    {
477
0
      if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
478
0
        *bufptr++ = '/';
479
480
0
      cupsCopyString(bufptr, filename, (size_t)(bufend - bufptr));
481
482
#ifdef _WIN32
483
      if (!access(buffer, 0))
484
#else
485
0
      if (!access(buffer, executable ? X_OK : 0))
486
0
#endif // _WIN32
487
0
      {
488
0
        DEBUG_printf("1cupsFileFind: Returning \"%s\"", buffer);
489
0
        return (buffer);
490
0
      }
491
492
0
      bufptr = buffer;
493
0
    }
494
0
    else if (bufptr < bufend)
495
0
      *bufptr++ = *path;
496
497
0
    path ++;
498
0
  }
499
500
  // Check the last path...
501
0
  if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
502
0
    *bufptr++ = '/';
503
504
0
  cupsCopyString(bufptr, filename, (size_t)(bufend - bufptr));
505
506
0
  if (!access(buffer, 0))
507
0
  {
508
0
    DEBUG_printf("1cupsFileFind: Returning \"%s\"", buffer);
509
0
    return (buffer);
510
0
  }
511
0
  else
512
0
  {
513
0
    DEBUG_puts("1cupsFileFind: Returning NULL");
514
0
    return (NULL);
515
0
  }
516
0
}
517
518
519
//
520
// 'cupsFileFlush()' - Flush pending output.
521
//
522
// @since CUPS 1.2@
523
//
524
525
int         // O - 0 on success, -1 on error
526
cupsFileFlush(cups_file_t *fp)    // I - CUPS file
527
0
{
528
0
  ssize_t bytes;      // Bytes to write
529
530
531
0
  DEBUG_printf("cupsFileFlush(fp=%p)", (void *)fp);
532
533
  // Range check input...
534
0
  if (!fp || fp->mode != 'w')
535
0
  {
536
0
    DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file...");
537
0
    return (-1);
538
0
  }
539
540
0
  bytes = (ssize_t)(fp->ptr - fp->buf);
541
542
0
  DEBUG_printf("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes);
543
544
0
  if (bytes > 0)
545
0
  {
546
0
    if (fp->compressed)
547
0
      bytes = cups_compress(fp, fp->buf, (size_t)bytes);
548
0
    else
549
0
      bytes = cups_write(fp, fp->buf, (size_t)bytes);
550
551
0
    if (bytes < 0)
552
0
      return (-1);
553
554
0
    fp->ptr = fp->buf;
555
0
  }
556
557
0
  return (0);
558
0
}
559
560
561
//
562
// 'cupsFileGetChar()' - Get a single character from a file.
563
//
564
// @since CUPS 1.2@
565
//
566
567
int         // O - Character or -1 on end of file
568
cupsFileGetChar(cups_file_t *fp)  // I - CUPS file
569
30.9M
{
570
  // Range check input...
571
30.9M
  DEBUG_printf("4cupsFileGetChar(fp=%p)", (void *)fp);
572
573
30.9M
  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
30.9M
  if (fp->eof)
580
24.7k
  {
581
24.7k
    DEBUG_puts("5cupsFileGetChar: End-of-file!");
582
24.7k
    return (-1);
583
24.7k
  }
584
585
  // If the input buffer is empty, try to read more data...
586
30.9M
  DEBUG_printf("5cupsFileGetChar: fp->eof=%d, fp->ptr=%p, fp->end=%p", fp->eof, (void *)fp->ptr, (void *)fp->end);
587
588
30.9M
  if (fp->ptr >= fp->end)
589
25.8k
    if (cups_fill(fp) <= 0)
590
9.42k
    {
591
9.42k
      DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!");
592
9.42k
      return (-1);
593
9.42k
    }
594
595
  // Return the next character in the buffer...
596
30.9M
  DEBUG_printf("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255);
597
598
30.9M
  fp->pos ++;
599
600
30.9M
  DEBUG_printf("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
601
602
30.9M
  return (*(fp->ptr)++ & 255);
603
30.9M
}
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
10.0k
{
927
10.0k
  cups_file_t *fp;      // New CUPS file
928
10.0k
  int   fd;     // File descriptor
929
10.0k
  char    hostname[1024],   // Hostname
930
10.0k
    *portname;    // Port "name" (number or service)
931
10.0k
  http_addrlist_t *addrlist;    // Host address list
932
10.0k
  int   perm = 0664;    // Permissions for write/append
933
10.0k
  const char  *ptr;     // Pointer into mode string
934
935
936
10.0k
  DEBUG_printf("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename, mode);
937
938
  // Range check input...
939
10.0k
  if (!filename || !mode ||
940
10.0k
      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
941
10.0k
      (*mode == 'a' && isdigit(mode[1] & 255)))
942
0
    return (NULL);
943
944
10.0k
  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
10.0k
  switch (*mode)
952
10.0k
  {
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
10.0k
    case 'r' : // Read file
958
10.0k
  fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
959
10.0k
  break;
960
961
0
    case 'w' : // Write file
962
0
        fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
963
0
  if (fd < 0 && errno == ENOENT)
964
0
  {
965
0
    fd = cups_open(filename, O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY, perm);
966
0
    if (fd < 0 && errno == EEXIST)
967
0
      fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY, perm);
968
0
  }
969
970
0
  if (fd >= 0)
971
#ifdef _WIN32
972
    _chsize(fd, 0);
973
#else
974
0
    ftruncate(fd, 0);
975
0
#endif // _WIN32
976
0
        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
10.0k
  }
1002
1003
10.0k
  if (fd < 0)
1004
0
    return (NULL);
1005
1006
  // Create the CUPS file structure...
1007
10.0k
  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
10.0k
  return (fp);
1017
10.0k
}
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
10.0k
{
1036
10.0k
  cups_file_t *fp;      // New CUPS file
1037
1038
1039
10.0k
  DEBUG_printf("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode);
1040
1041
  // Range check input...
1042
10.0k
  if (fd < 0 || !mode ||
1043
10.0k
      (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
1044
10.0k
      (*mode == 'a' && isdigit(mode[1] & 255)))
1045
0
    return (NULL);
1046
1047
  // Allocate memory...
1048
10.0k
  if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
1049
0
    return (NULL);
1050
1051
  // Open the file...
1052
10.0k
  fp->fd = fd;
1053
1054
10.0k
  switch (*mode)
1055
10.0k
  {
1056
0
    case 'a' :
1057
0
        fp->pos = lseek(fd, 0, SEEK_END);
1058
1059
0
    case 'w' :
1060
0
  fp->mode = 'w';
1061
0
  fp->ptr  = fp->buf;
1062
0
  fp->end  = fp->buf + sizeof(fp->buf);
1063
1064
0
  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
    cups_write(fp, (char *)header, 10);
1084
1085
          // Initialize the compressor...
1086
0
          if (deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) < Z_OK)
1087
0
          {
1088
0
            close(fd);
1089
0
            free(fp);
1090
0
      return (NULL);
1091
0
          }
1092
1093
0
    fp->stream.next_out  = fp->cbuf;
1094
0
    fp->stream.avail_out = sizeof(fp->cbuf);
1095
0
    fp->compressed       = 1;
1096
0
    fp->crc              = crc32(0L, Z_NULL, 0);
1097
0
  }
1098
0
        break;
1099
1100
10.0k
    case 'r' :
1101
10.0k
  fp->mode = 'r';
1102
10.0k
  break;
1103
1104
0
    case 's' :
1105
0
        fp->mode = 's';
1106
0
  break;
1107
1108
0
    default : // Remove bogus compiler warning...
1109
0
        return (NULL);
1110
10.0k
  }
1111
1112
  // Don't pass this file to child processes...
1113
10.0k
#ifndef _WIN32
1114
10.0k
  fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
1115
10.0k
#endif // !_WIN32
1116
1117
10.0k
  return (fp);
1118
10.0k
}
1119
1120
1121
//
1122
// '_cupsFilePeekAhead()' - See if the requested character is buffered up.
1123
//
1124
1125
int         // O - 1 if present, 0 otherwise
1126
_cupsFilePeekAhead(cups_file_t *fp, // I - CUPS file
1127
                   int         ch)  // I - Character
1128
0
{
1129
0
  return (fp && fp->ptr && memchr(fp->ptr, ch, (size_t)(fp->end - fp->ptr)));
1130
0
}
1131
1132
1133
//
1134
// 'cupsFilePeekChar()' - Peek at the next character from a file.
1135
//
1136
// @since CUPS 1.2@
1137
//
1138
1139
int         // O - Character or -1 on end of file
1140
cupsFilePeekChar(cups_file_t *fp) // I - CUPS file
1141
1.57M
{
1142
  // Range check input...
1143
1.57M
  if (!fp || (fp->mode != 'r' && fp->mode != 's'))
1144
0
    return (-1);
1145
1146
  // If the input buffer is empty, try to read more data...
1147
1.57M
  if (fp->ptr >= fp->end)
1148
554
    if (cups_fill(fp) <= 0)
1149
155
      return (-1);
1150
1151
  // Return the next character in the buffer...
1152
1.57M
  return (*(fp->ptr) & 255);
1153
1.57M
}
1154
1155
1156
//
1157
// 'cupsFilePrintf()' - Write a formatted string.
1158
//
1159
// @since CUPS 1.2@
1160
//
1161
1162
int         // O - Number of bytes written or -1 on error
1163
cupsFilePrintf(cups_file_t *fp,   // I - CUPS file
1164
               const char  *format, // I - Printf-style format string
1165
         ...)     // I - Additional args as necessary
1166
0
{
1167
0
  va_list ap;     // Argument list
1168
0
  ssize_t bytes;      // Formatted size
1169
1170
1171
0
  DEBUG_printf("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", (void *)fp, format);
1172
1173
0
  if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
1174
0
    return (-1);
1175
1176
0
  if (!fp->printf_buffer)
1177
0
  {
1178
    // Start with a 1k printf buffer...
1179
0
    if ((fp->printf_buffer = malloc(1024)) == NULL)
1180
0
      return (-1);
1181
1182
0
    fp->printf_size = 1024;
1183
0
  }
1184
1185
0
  va_start(ap, format);
1186
0
  bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1187
0
  va_end(ap);
1188
1189
0
  if (bytes >= (ssize_t)fp->printf_size)
1190
0
  {
1191
    // Expand the printf buffer...
1192
0
    char  *temp;      // Temporary buffer pointer
1193
1194
1195
0
    if (bytes > 65535)
1196
0
      return (-1);
1197
1198
0
    if ((temp = realloc(fp->printf_buffer, (size_t)(bytes + 1))) == NULL)
1199
0
      return (-1);
1200
1201
0
    fp->printf_buffer = temp;
1202
0
    fp->printf_size   = (size_t)(bytes + 1);
1203
1204
0
    va_start(ap, format);
1205
0
    bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1206
0
    va_end(ap);
1207
0
  }
1208
1209
0
  if (fp->mode == 's')
1210
0
  {
1211
0
    if (cups_write(fp, fp->printf_buffer, (size_t)bytes) < 0)
1212
0
      return (-1);
1213
1214
0
    fp->pos += bytes;
1215
1216
0
    DEBUG_printf("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1217
1218
0
    return ((int)bytes);
1219
0
  }
1220
1221
0
  if ((fp->ptr + bytes) > fp->end)
1222
0
    if (cupsFileFlush(fp))
1223
0
      return (-1);
1224
1225
0
  fp->pos += bytes;
1226
1227
0
  DEBUG_printf("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1228
1229
0
  if ((size_t)bytes > sizeof(fp->buf))
1230
0
  {
1231
0
    if (fp->compressed)
1232
0
      return ((int)cups_compress(fp, fp->printf_buffer, (size_t)bytes));
1233
0
    else
1234
0
      return ((int)cups_write(fp, fp->printf_buffer, (size_t)bytes));
1235
0
  }
1236
0
  else
1237
0
  {
1238
0
    memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
1239
0
    fp->ptr += bytes;
1240
1241
0
    if (fp->is_stdio && cupsFileFlush(fp))
1242
0
      return (-1);
1243
0
    else
1244
0
      return ((int)bytes);
1245
0
  }
1246
0
}
1247
1248
1249
//
1250
// 'cupsFilePutChar()' - Write a character.
1251
//
1252
// @since CUPS 1.2@
1253
//
1254
1255
int         // O - 0 on success, -1 on error
1256
cupsFilePutChar(cups_file_t *fp,  // I - CUPS file
1257
                int         c)    // I - Character to write
1258
0
{
1259
  // Range check input...
1260
0
  if (!fp || (fp->mode != 'w' && fp->mode != 's'))
1261
0
    return (-1);
1262
1263
0
  if (fp->mode == 's')
1264
0
  {
1265
    // Send character immediately over socket...
1266
0
    char ch;        // Output character
1267
1268
1269
0
    ch = (char)c;
1270
1271
0
    if (send(fp->fd, &ch, 1, 0) < 1)
1272
0
      return (-1);
1273
0
  }
1274
0
  else
1275
0
  {
1276
    // Buffer it up...
1277
0
    if (fp->ptr >= fp->end)
1278
0
      if (cupsFileFlush(fp))
1279
0
  return (-1);
1280
1281
0
    *(fp->ptr) ++ = (char)c;
1282
0
  }
1283
1284
0
  fp->pos ++;
1285
1286
0
  DEBUG_printf("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1287
1288
0
  return (0);
1289
0
}
1290
1291
1292
//
1293
// 'cupsFilePutConf()' - Write a configuration line.
1294
//
1295
// This function handles any comment escaping of the value.
1296
//
1297
// @since CUPS 1.4@
1298
//
1299
1300
ssize_t         // O - Number of bytes written or -1 on error
1301
cupsFilePutConf(cups_file_t *fp,  // I - CUPS file
1302
                const char *directive,  // I - Directive
1303
    const char *value)  // I - Value
1304
0
{
1305
0
  ssize_t bytes,      // Number of bytes written
1306
0
    temp;     // Temporary byte count
1307
0
  const char  *ptr;     // Pointer into value
1308
1309
1310
0
  if (!fp || !directive || !*directive)
1311
0
    return (-1);
1312
1313
0
  if ((bytes = cupsFilePuts(fp, directive)) < 0)
1314
0
    return (-1);
1315
1316
0
  if (cupsFilePutChar(fp, ' ') < 0)
1317
0
    return (-1);
1318
0
  bytes ++;
1319
1320
0
  if (value && *value)
1321
0
  {
1322
0
    if ((ptr = strchr(value, '#')) != NULL)
1323
0
    {
1324
      // Need to quote the first # in the info string...
1325
0
      if ((temp = cupsFileWrite(fp, value, (size_t)(ptr - value))) < 0)
1326
0
        return (-1);
1327
0
      bytes += temp;
1328
1329
0
      if (cupsFilePutChar(fp, '\\') < 0)
1330
0
        return (-1);
1331
0
      bytes ++;
1332
1333
0
      if ((temp = cupsFilePuts(fp, ptr)) < 0)
1334
0
        return (-1);
1335
0
      bytes += temp;
1336
0
    }
1337
0
    else if ((temp = cupsFilePuts(fp, value)) < 0)
1338
0
      return (-1);
1339
0
    else
1340
0
      bytes += temp;
1341
0
  }
1342
1343
0
  if (cupsFilePutChar(fp, '\n') < 0)
1344
0
    return (-1);
1345
0
  else
1346
0
    return (bytes + 1);
1347
0
}
1348
1349
1350
//
1351
// 'cupsFilePuts()' - Write a string.
1352
//
1353
// Like the @code fputs@ function, no newline is appended to the string.
1354
//
1355
// @since CUPS 1.2@
1356
//
1357
1358
int         // O - Number of bytes written or -1 on error
1359
cupsFilePuts(cups_file_t *fp,   // I - CUPS file
1360
             const char  *s)    // I - String to write
1361
0
{
1362
0
  ssize_t bytes;      // Bytes to write
1363
1364
1365
  // Range check input...
1366
0
  if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1367
0
    return (-1);
1368
1369
  // Write the string...
1370
0
  bytes = (ssize_t)strlen(s);
1371
1372
0
  if (fp->mode == 's')
1373
0
  {
1374
0
    if (cups_write(fp, s, (size_t)bytes) < 0)
1375
0
      return (-1);
1376
1377
0
    fp->pos += bytes;
1378
1379
0
    DEBUG_printf("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1380
1381
0
    return ((int)bytes);
1382
0
  }
1383
1384
0
  if ((fp->ptr + bytes) > fp->end)
1385
0
    if (cupsFileFlush(fp))
1386
0
      return (-1);
1387
1388
0
  fp->pos += bytes;
1389
1390
0
  DEBUG_printf("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1391
1392
0
  if ((size_t)bytes > sizeof(fp->buf))
1393
0
  {
1394
0
    if (fp->compressed)
1395
0
      return ((int)cups_compress(fp, s, (size_t)bytes));
1396
0
    else
1397
0
      return ((int)cups_write(fp, s, (size_t)bytes));
1398
0
  }
1399
0
  else
1400
0
  {
1401
0
    memcpy(fp->ptr, s, (size_t)bytes);
1402
0
    fp->ptr += bytes;
1403
1404
0
    if (fp->is_stdio && cupsFileFlush(fp))
1405
0
      return (-1);
1406
0
    else
1407
0
      return ((int)bytes);
1408
0
  }
1409
0
}
1410
1411
1412
//
1413
// 'cupsFileRead()' - Read from a file.
1414
//
1415
// @since CUPS 1.2@
1416
//
1417
1418
ssize_t         // O - Number of bytes read or -1 on error
1419
cupsFileRead(cups_file_t *fp,   // I - CUPS file
1420
             char        *buf,    // O - Buffer
1421
       size_t      bytes)   // I - Number of bytes to read
1422
0
{
1423
0
  size_t  total;      // Total bytes read
1424
0
  ssize_t count;      // Bytes read
1425
1426
1427
0
  DEBUG_printf("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1428
1429
  // Range check input...
1430
0
  if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
1431
0
    return (-1);
1432
1433
0
  if (bytes == 0)
1434
0
    return (0);
1435
1436
0
  if (fp->eof)
1437
0
  {
1438
0
    DEBUG_puts("5cupsFileRead: End-of-file!");
1439
0
    return (-1);
1440
0
  }
1441
1442
  // Loop until all bytes are read...
1443
0
  total = 0;
1444
0
  while (bytes > 0)
1445
0
  {
1446
0
    if (fp->ptr >= fp->end)
1447
0
      if (cups_fill(fp) <= 0)
1448
0
      {
1449
0
        DEBUG_printf("4cupsFileRead: cups_fill() returned -1, total=" CUPS_LLFMT, CUPS_LLCAST total);
1450
1451
0
        if (total > 0)
1452
0
          return ((ssize_t)total);
1453
0
  else
1454
0
    return (-1);
1455
0
      }
1456
1457
0
    count = (ssize_t)(fp->end - fp->ptr);
1458
0
    if (count > (ssize_t)bytes)
1459
0
      count = (ssize_t)bytes;
1460
1461
0
    memcpy(buf, fp->ptr,(size_t) count);
1462
0
    fp->ptr += count;
1463
0
    fp->pos += count;
1464
1465
0
    DEBUG_printf("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1466
1467
    // Update the counts for the last read...
1468
0
    bytes -= (size_t)count;
1469
0
    total += (size_t)count;
1470
0
    buf   += count;
1471
0
  }
1472
1473
  // Return the total number of bytes read...
1474
0
  DEBUG_printf("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total);
1475
1476
0
  return ((ssize_t)total);
1477
0
}
1478
1479
1480
//
1481
// 'cupsFileRewind()' - Set the current file position to the beginning of the
1482
//                      file.
1483
//
1484
// @since CUPS 1.2@
1485
//
1486
1487
off_t         // O - New file position or -1 on error
1488
cupsFileRewind(cups_file_t *fp)   // I - CUPS file
1489
0
{
1490
  // Range check input...
1491
0
  DEBUG_printf("cupsFileRewind(fp=%p)", (void *)fp);
1492
1493
0
  if (!fp || fp->mode != 'r')
1494
0
    return (-1);
1495
1496
0
  DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1497
1498
  // Handle special cases...
1499
0
  if (fp->bufpos == 0)
1500
0
  {
1501
    // No seeking necessary...
1502
0
    fp->pos = 0;
1503
1504
0
    if (fp->ptr)
1505
0
    {
1506
0
      fp->ptr = fp->buf;
1507
0
      fp->eof = 0;
1508
0
    }
1509
1510
0
    DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1511
1512
0
    return (0);
1513
0
  }
1514
1515
  // Otherwise, seek in the file and cleanup any compression buffers...
1516
0
  if (fp->compressed)
1517
0
  {
1518
0
    inflateEnd(&fp->stream);
1519
0
    fp->compressed = 0;
1520
0
  }
1521
1522
0
  if (lseek(fp->fd, 0, SEEK_SET))
1523
0
  {
1524
0
    DEBUG_printf("1cupsFileRewind: lseek failed: %s", strerror(errno));
1525
0
    return (-1);
1526
0
  }
1527
1528
0
  fp->bufpos = 0;
1529
0
  fp->pos    = 0;
1530
0
  fp->ptr    = NULL;
1531
0
  fp->end    = NULL;
1532
0
  fp->eof    = 0;
1533
1534
0
  DEBUG_printf("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1535
1536
0
  return (0);
1537
0
}
1538
1539
1540
//
1541
// 'cupsFileSeek()' - Seek in a file.
1542
//
1543
// @since CUPS 1.2@
1544
//
1545
1546
off_t         // O - New file position or -1 on error
1547
cupsFileSeek(cups_file_t *fp,   // I - CUPS file
1548
             off_t       pos)   // I - Position in file
1549
0
{
1550
0
  ssize_t bytes;      // Number bytes in buffer
1551
1552
1553
0
  DEBUG_printf("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", (void *)fp, CUPS_LLCAST pos);
1554
1555
  // Range check input...
1556
0
  if (!fp || pos < 0 || fp->mode != 'r')
1557
0
    return (-1);
1558
1559
0
  DEBUG_printf("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1560
0
  DEBUG_printf("2cupsFileSeek: fp->ptr=%p, fp->end=%p", (void *)fp->ptr, (void *)fp->end);
1561
1562
  // Handle special cases...
1563
0
  if (pos == 0)
1564
0
    return (cupsFileRewind(fp));
1565
1566
0
  if (fp->ptr)
1567
0
  {
1568
0
    bytes = (ssize_t)(fp->end - fp->buf);
1569
1570
0
    DEBUG_printf("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes);
1571
1572
0
    if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1573
0
    {
1574
      // No seeking necessary...
1575
0
      fp->pos = pos;
1576
0
      fp->ptr = fp->buf + (pos - fp->bufpos);
1577
0
      fp->eof = 0;
1578
1579
0
      return (pos);
1580
0
    }
1581
0
  }
1582
1583
0
  if (!fp->compressed && !fp->ptr)
1584
0
  {
1585
    // Preload a buffer to determine whether the file is compressed...
1586
0
    if (cups_fill(fp) <= 0)
1587
0
      return (-1);
1588
0
  }
1589
1590
  // Seek forwards or backwards...
1591
0
  fp->eof = 0;
1592
1593
0
  if (pos < fp->bufpos)
1594
0
  {
1595
    // Need to seek backwards...
1596
0
    DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS");
1597
1598
0
    if (fp->compressed)
1599
0
    {
1600
0
      inflateEnd(&fp->stream);
1601
1602
0
      lseek(fp->fd, 0, SEEK_SET);
1603
0
      fp->bufpos = 0;
1604
0
      fp->pos    = 0;
1605
0
      fp->ptr    = NULL;
1606
0
      fp->end    = NULL;
1607
1608
0
      while ((bytes = cups_fill(fp)) > 0)
1609
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1610
0
    break;
1611
1612
0
      if (bytes <= 0)
1613
0
        return (-1);
1614
1615
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1616
0
      fp->pos = pos;
1617
0
    }
1618
0
    else
1619
0
    {
1620
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1621
0
      fp->pos    = fp->bufpos;
1622
0
      fp->ptr    = NULL;
1623
0
      fp->end    = NULL;
1624
1625
0
      DEBUG_printf("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos);
1626
0
    }
1627
0
  }
1628
0
  else
1629
0
  {
1630
    // Need to seek forwards...
1631
0
    DEBUG_puts("2cupsFileSeek: SEEK FORWARDS");
1632
1633
0
    if (fp->compressed)
1634
0
    {
1635
0
      while ((bytes = cups_fill(fp)) > 0)
1636
0
      {
1637
0
        if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
1638
0
    break;
1639
0
      }
1640
1641
0
      if (bytes <= 0)
1642
0
        return (-1);
1643
1644
0
      fp->ptr = fp->buf + pos - fp->bufpos;
1645
0
      fp->pos = pos;
1646
0
    }
1647
0
    else
1648
0
    {
1649
0
      fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1650
0
      fp->pos    = fp->bufpos;
1651
0
      fp->ptr    = NULL;
1652
0
      fp->end    = NULL;
1653
1654
0
      DEBUG_printf("2cupsFileSeek: lseek() returned " CUPS_LLFMT, CUPS_LLCAST fp->pos);
1655
0
    }
1656
0
  }
1657
1658
0
  DEBUG_printf("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1659
1660
0
  return (fp->pos);
1661
0
}
1662
1663
1664
//
1665
// 'cupsFileStderr()' - Return a CUPS file associated with stderr.
1666
//
1667
// @since CUPS 1.2@
1668
//
1669
1670
cups_file_t *       // O - CUPS file
1671
cupsFileStderr(void)
1672
0
{
1673
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1674
1675
1676
  // Open file descriptor 2 as needed...
1677
0
  if (!cg->stdio_files[2])
1678
0
  {
1679
    // Flush any pending output on the stdio file...
1680
0
    fflush(stderr);
1681
1682
    // Open file descriptor 2...
1683
0
    if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1684
0
      cg->stdio_files[2]->is_stdio = 1;
1685
0
  }
1686
1687
0
  return (cg->stdio_files[2]);
1688
0
}
1689
1690
1691
//
1692
// 'cupsFileStdin()' - Return a CUPS file associated with stdin.
1693
//
1694
// @since CUPS 1.2@
1695
//
1696
1697
cups_file_t *       // O - CUPS file
1698
cupsFileStdin(void)
1699
0
{
1700
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1701
1702
1703
  // Open file descriptor 0 as needed...
1704
0
  if (!cg->stdio_files[0])
1705
0
  {
1706
    // Open file descriptor 0...
1707
0
    if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1708
0
      cg->stdio_files[0]->is_stdio = 1;
1709
0
  }
1710
1711
0
  return (cg->stdio_files[0]);
1712
0
}
1713
1714
1715
//
1716
// 'cupsFileStdout()' - Return a CUPS file associated with stdout.
1717
//
1718
// @since CUPS 1.2@
1719
//
1720
1721
cups_file_t *       // O - CUPS file
1722
cupsFileStdout(void)
1723
0
{
1724
0
  _cups_globals_t *cg = _cupsGlobals(); // Pointer to library globals...
1725
1726
1727
  // Open file descriptor 1 as needed...
1728
0
  if (!cg->stdio_files[1])
1729
0
  {
1730
    // Flush any pending output on the stdio file...
1731
0
    fflush(stdout);
1732
1733
    // Open file descriptor 1...
1734
0
    if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
1735
0
      cg->stdio_files[1]->is_stdio = 1;
1736
0
  }
1737
1738
0
  return (cg->stdio_files[1]);
1739
0
}
1740
1741
1742
//
1743
// 'cupsFileTell()' - Return the current file position.
1744
//
1745
// @since CUPS 1.2@
1746
//
1747
1748
off_t         // O - File position
1749
cupsFileTell(cups_file_t *fp)   // I - CUPS file
1750
0
{
1751
0
  DEBUG_printf("2cupsFileTell(fp=%p)", (void *)fp);
1752
0
  DEBUG_printf("3cupsFileTell: pos=" CUPS_LLFMT, CUPS_LLCAST (fp ? fp->pos : -1));
1753
1754
0
  return (fp ? fp->pos : 0);
1755
0
}
1756
1757
1758
//
1759
// 'cupsFileUnlock()' - Unlock access to a file.
1760
//
1761
// @since CUPS 1.2@
1762
//
1763
1764
int         // O - 0 on success, -1 on error
1765
cupsFileUnlock(cups_file_t *fp)   // I - CUPS file
1766
0
{
1767
  // Range check...
1768
0
  DEBUG_printf("cupsFileUnlock(fp=%p)", (void *)fp);
1769
1770
0
  if (!fp || fp->mode == 's')
1771
0
    return (-1);
1772
1773
  // Unlock...
1774
#ifdef _WIN32
1775
  return (_locking(fp->fd, _LK_UNLCK, 0));
1776
#else
1777
0
  return (lockf(fp->fd, F_ULOCK, 0));
1778
0
#endif // _WIN32
1779
0
}
1780
1781
1782
//
1783
// 'cupsFileWrite()' - Write to a file.
1784
//
1785
// @since CUPS 1.2@
1786
//
1787
1788
ssize_t         // O - Number of bytes written or -1 on error
1789
cupsFileWrite(cups_file_t *fp,    // I - CUPS file
1790
              const char  *buf,   // I - Buffer
1791
        size_t      bytes)  // I - Number of bytes to write
1792
0
{
1793
  // Range check input...
1794
0
  DEBUG_printf("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1795
1796
0
  if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
1797
0
    return (-1);
1798
1799
0
  if (bytes == 0)
1800
0
    return (0);
1801
1802
  // Write the buffer...
1803
0
  if (fp->mode == 's')
1804
0
  {
1805
0
    if (cups_write(fp, buf, bytes) < 0)
1806
0
      return (-1);
1807
1808
0
    fp->pos += (off_t)bytes;
1809
1810
0
    DEBUG_printf("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1811
1812
0
    return ((ssize_t)bytes);
1813
0
  }
1814
1815
0
  if ((fp->ptr + bytes) > fp->end)
1816
0
    if (cupsFileFlush(fp))
1817
0
      return (-1);
1818
1819
0
  fp->pos += (off_t)bytes;
1820
1821
0
  DEBUG_printf("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos);
1822
1823
0
  if (bytes > sizeof(fp->buf))
1824
0
  {
1825
0
    if (fp->compressed)
1826
0
      return (cups_compress(fp, buf, bytes));
1827
0
    else
1828
0
      return (cups_write(fp, buf, bytes));
1829
0
  }
1830
0
  else
1831
0
  {
1832
0
    memcpy(fp->ptr, buf, bytes);
1833
0
    fp->ptr += bytes;
1834
0
    return ((ssize_t)bytes);
1835
0
  }
1836
0
}
1837
1838
1839
//
1840
// 'cups_compress()' - Compress a buffer of data.
1841
//
1842
1843
static ssize_t        // O - Number of bytes written or -1
1844
cups_compress(cups_file_t *fp,    // I - CUPS file
1845
              const char  *buf,   // I - Buffer
1846
        size_t      bytes)  // I - Number bytes
1847
0
{
1848
0
  int status;       // Deflate status
1849
1850
1851
0
  DEBUG_printf("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
1852
1853
  // Update the CRC...
1854
0
  fp->crc = crc32(fp->crc, (const Bytef *)buf, (uInt)bytes);
1855
1856
  // Deflate the bytes...
1857
0
  fp->stream.next_in  = (Bytef *)buf;
1858
0
  fp->stream.avail_in = (uInt)bytes;
1859
1860
0
  while (fp->stream.avail_in > 0)
1861
0
  {
1862
    // Flush the current buffer...
1863
0
    DEBUG_printf("9cups_compress: avail_in=%d, avail_out=%d", fp->stream.avail_in, fp->stream.avail_out);
1864
1865
0
    if (fp->stream.avail_out < (uInt)(sizeof(fp->cbuf) / 8))
1866
0
    {
1867
0
      if (cups_write(fp, (char *)fp->cbuf, (size_t)(fp->stream.next_out - fp->cbuf)) < 0)
1868
0
        return (-1);
1869
1870
0
      fp->stream.next_out  = fp->cbuf;
1871
0
      fp->stream.avail_out = sizeof(fp->cbuf);
1872
0
    }
1873
1874
0
    if ((status = deflate(&(fp->stream), Z_NO_FLUSH)) < Z_OK && status != Z_BUF_ERROR)
1875
0
      return (-1);
1876
0
  }
1877
1878
0
  return ((ssize_t)bytes);
1879
0
}
1880
1881
1882
//
1883
// 'cups_fill()' - Fill the input buffer.
1884
//
1885
1886
static ssize_t        // O - Number of bytes or -1
1887
cups_fill(cups_file_t *fp)    // I - CUPS file
1888
26.4k
{
1889
26.4k
  ssize_t   bytes;    // Number of bytes read
1890
26.4k
  int     status;   // Decompression status
1891
26.4k
  const unsigned char *ptr,   // Pointer into buffer
1892
26.4k
      *end;   // End of buffer
1893
1894
1895
26.4k
  DEBUG_printf("7cups_fill(fp=%p)", (void *)fp);
1896
26.4k
  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);
1897
1898
26.4k
  if (fp->ptr && fp->end)
1899
16.3k
    fp->bufpos += fp->end - fp->buf;
1900
1901
26.4k
  DEBUG_printf("9cups_fill: fp->compressed=%d", fp->compressed);
1902
1903
26.4k
  while (!fp->ptr || fp->compressed)
1904
10.6k
  {
1905
    // Check to see if we have read any data yet; if not, see if we have a
1906
    // compressed file...
1907
10.6k
    if (!fp->ptr)
1908
10.0k
    {
1909
      // Reset the file position in case we are seeking...
1910
10.0k
      fp->compressed = 0;
1911
1912
      // Read the first bytes in the file to determine if we have a gzip'd file...
1913
10.0k
      if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
1914
0
      {
1915
        // Can't read from file!
1916
0
        DEBUG_printf("9cups_fill: cups_read() returned " CUPS_LLFMT, CUPS_LLCAST bytes);
1917
1918
0
        fp->eof = 1;
1919
1920
0
  return (-1);
1921
0
      }
1922
1923
10.0k
      if (bytes < 10 || fp->buf[0] != 0x1f ||
1924
10.0k
          (fp->buf[1] & 255) != 0x8b ||
1925
10.0k
          fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
1926
9.89k
      {
1927
        // Not a gzip'd file!
1928
9.89k
  fp->ptr = fp->buf;
1929
9.89k
  fp->end = fp->buf + bytes;
1930
1931
9.89k
        DEBUG_printf("9cups_fill: Returning " CUPS_LLFMT, CUPS_LLCAST bytes);
1932
1933
9.89k
  return (bytes);
1934
9.89k
      }
1935
1936
      // Parse header junk: extra data, original name, and comment...
1937
181
      ptr = (unsigned char *)fp->buf + 10;
1938
181
      end = (unsigned char *)fp->buf + bytes;
1939
1940
181
      if (fp->buf[3] & 0x04)
1941
22
      {
1942
        // Skip extra data...
1943
22
  if ((ptr + 2) > end)
1944
3
  {
1945
    // Can't read from file!
1946
3
    DEBUG_puts("9cups_fill: Extra gzip header data missing, returning -1.");
1947
1948
3
          fp->eof = 1;
1949
3
    errno   = EIO;
1950
1951
3
    return (-1);
1952
3
  }
1953
1954
19
  bytes = (ptr[1] << 8) | ptr[0];
1955
19
  ptr   += 2 + bytes;
1956
1957
19
  if (ptr > end)
1958
6
  {
1959
    // Can't read from file!
1960
6
    DEBUG_puts("9cups_fill: Extra gzip header data does not fit in initial buffer, returning -1.");
1961
1962
6
          fp->eof = 1;
1963
6
    errno   = EIO;
1964
1965
6
    return (-1);
1966
6
  }
1967
19
      }
1968
1969
172
      if (fp->buf[3] & 0x08)
1970
49
      {
1971
        // Skip original name data...
1972
4.15k
  while (ptr < end && *ptr)
1973
4.10k
          ptr ++;
1974
1975
49
  if (ptr < end)
1976
35
          ptr ++;
1977
14
  else
1978
14
  {
1979
    // Can't read from file!
1980
14
    DEBUG_puts("9cups_fill: Original filename in gzip header data does not fit in initial buffer, returning -1.");
1981
1982
14
          fp->eof = 1;
1983
14
    errno   = EIO;
1984
1985
14
    return (-1);
1986
14
  }
1987
49
      }
1988
1989
158
      if (fp->buf[3] & 0x10)
1990
40
      {
1991
        // Skip comment data...
1992
6.00k
  while (ptr < end && *ptr)
1993
5.96k
          ptr ++;
1994
1995
40
  if (ptr < end)
1996
24
          ptr ++;
1997
16
  else
1998
16
  {
1999
    // Can't read from file!
2000
16
    DEBUG_puts("9cups_fill: Comment in gzip header data does not fit in initial buffer, returning -1.");
2001
2002
16
          fp->eof = 1;
2003
16
    errno   = EIO;
2004
2005
16
    return (-1);
2006
16
  }
2007
40
      }
2008
2009
142
      if (fp->buf[3] & 0x02)
2010
28
      {
2011
        // Skip header CRC data...
2012
28
  ptr += 2;
2013
2014
28
  if (ptr > end)
2015
6
  {
2016
    // Can't read from file!
2017
6
    DEBUG_puts("9cups_fill: Header CRC in gzip header data does not fit in initial buffer, returning -1.");
2018
2019
6
          fp->eof = 1;
2020
6
    errno   = EIO;
2021
2022
6
    return (-1);
2023
6
  }
2024
28
      }
2025
2026
      // Copy the flate-compressed data to the compression buffer...
2027
136
      if ((bytes = end - ptr) > 0)
2028
133
        memcpy(fp->cbuf, ptr, (size_t)bytes);
2029
2030
      // Setup the decompressor data...
2031
136
      fp->stream.zalloc    = (alloc_func)0;
2032
136
      fp->stream.zfree     = (free_func)0;
2033
136
      fp->stream.opaque    = (voidpf)0;
2034
136
      fp->stream.next_in   = (Bytef *)fp->cbuf;
2035
136
      fp->stream.next_out  = NULL;
2036
136
      fp->stream.avail_in  = (uInt)bytes;
2037
136
      fp->stream.avail_out = 0;
2038
136
      fp->crc              = crc32(0L, Z_NULL, 0);
2039
2040
136
      if ((status = inflateInit2(&(fp->stream), -15)) != Z_OK)
2041
0
      {
2042
0
  DEBUG_printf("9cups_fill: inflateInit2 returned %d, returning -1.", status);
2043
2044
0
        fp->eof = 1;
2045
0
        errno   = EIO;
2046
2047
0
  return (-1);
2048
0
      }
2049
2050
136
      fp->compressed = 1;
2051
136
    }
2052
2053
710
    if (fp->compressed)
2054
710
    {
2055
      // If we have reached end-of-file, return immediately...
2056
710
      if (fp->eof)
2057
0
      {
2058
0
        DEBUG_puts("9cups_fill: EOF, returning 0.");
2059
2060
0
  return (0);
2061
0
      }
2062
2063
      // Fill the decompression buffer as needed...
2064
710
      if (fp->stream.avail_in == 0)
2065
201
      {
2066
201
  if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
2067
47
  {
2068
47
    DEBUG_printf("9cups_fill: cups_read error, returning %d.", (int)bytes);
2069
2070
47
    fp->eof = 1;
2071
2072
47
          return (bytes);
2073
47
  }
2074
2075
154
  fp->stream.next_in  = fp->cbuf;
2076
154
  fp->stream.avail_in = (uInt)bytes;
2077
154
      }
2078
2079
      // Decompress data from the buffer...
2080
663
      fp->stream.next_out  = (Bytef *)fp->buf;
2081
663
      fp->stream.avail_out = sizeof(fp->buf);
2082
2083
663
      status = inflate(&(fp->stream), Z_NO_FLUSH);
2084
2085
663
      if (fp->stream.next_out > (Bytef *)fp->buf)
2086
602
        fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
2087
602
                  (uInt)(fp->stream.next_out - (Bytef *)fp->buf));
2088
2089
663
      if (status == Z_STREAM_END)
2090
62
      {
2091
        // Read the CRC and length...
2092
62
  unsigned char trailer[8]; // Trailer bytes
2093
62
  uLong   tcrc;   // Trailer CRC
2094
62
  ssize_t   tbytes = 0; // Number of bytes
2095
2096
62
  if (fp->stream.avail_in > 0)
2097
61
  {
2098
    // Get the first N trailer bytes from the inflate stream...
2099
61
    if (fp->stream.avail_in > sizeof(trailer))
2100
27
      tbytes = (ssize_t)sizeof(trailer);
2101
34
    else
2102
34
      tbytes = (ssize_t)fp->stream.avail_in;
2103
2104
61
    memcpy(trailer, fp->stream.next_in, (size_t)tbytes);
2105
61
    fp->stream.next_in  += tbytes;
2106
61
    fp->stream.avail_in -= (size_t)tbytes;
2107
61
  }
2108
2109
        // Reset the compressed flag so that we re-read the file header...
2110
62
        inflateEnd(&fp->stream);
2111
2112
62
  fp->compressed = 0;
2113
2114
        // Get any remaining trailer bytes...
2115
62
        if (tbytes < (ssize_t)sizeof(trailer))
2116
6
  {
2117
6
    if (read(fp->fd, trailer + tbytes, sizeof(trailer) - (size_t)tbytes) < ((ssize_t)sizeof(trailer) - tbytes))
2118
5
    {
2119
      // Can't get it, so mark end-of-file...
2120
5
      DEBUG_puts("9cups_fill: Unable to read gzip CRC trailer, returning -1.");
2121
2122
5
      fp->eof = 1;
2123
5
      errno   = EIO;
2124
2125
5
      return (-1);
2126
5
    }
2127
6
  }
2128
2129
        // Calculate and compare the CRC...
2130
57
  tcrc = ((uLong)trailer[3] << 24) | ((uLong)trailer[2] << 16) | ((uLong)trailer[1] << 8) | ((uLong)trailer[0]);
2131
2132
57
  if (tcrc != fp->crc)
2133
55
  {
2134
    // Bad CRC, mark end-of-file...
2135
55
    DEBUG_printf("9cups_fill: tcrc=%08x != fp->crc=%08x, returning -1.", (unsigned int)tcrc, (unsigned int)fp->crc);
2136
2137
55
    fp->eof = 1;
2138
55
    errno   = EIO;
2139
2140
55
    return (-1);
2141
55
  }
2142
57
      }
2143
601
      else if (status < Z_OK)
2144
15
      {
2145
15
  DEBUG_printf("9cups_fill: inflate returned %d, returning -1.", status);
2146
2147
15
        fp->eof = 1;
2148
15
        errno   = EIO;
2149
2150
15
  return (-1);
2151
15
      }
2152
2153
588
      bytes = (ssize_t)sizeof(fp->buf) - (ssize_t)fp->stream.avail_out;
2154
2155
      // Return the decompressed data...
2156
588
      fp->ptr = fp->buf;
2157
588
      fp->end = fp->buf + bytes;
2158
2159
588
      if (bytes)
2160
583
      {
2161
583
        DEBUG_printf("9cups_fill: Returning %d.", (int)bytes);
2162
583
  return (bytes);
2163
583
      }
2164
588
    }
2165
710
  }
2166
2167
  // Read a buffer's full of data...
2168
15.7k
  if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
2169
9.41k
  {
2170
    // Can't read from file!
2171
9.41k
    fp->eof = 1;
2172
9.41k
    fp->ptr = fp->buf;
2173
9.41k
    fp->end = fp->buf;
2174
9.41k
  }
2175
6.35k
  else
2176
6.35k
  {
2177
    // Return the bytes we read...
2178
6.35k
    fp->eof = 0;
2179
6.35k
    fp->ptr = fp->buf;
2180
6.35k
    fp->end = fp->buf + bytes;
2181
6.35k
  }
2182
2183
15.7k
  DEBUG_printf("9cups_fill: Not gzip, returning %d.", (int)bytes);
2184
2185
15.7k
  return (bytes);
2186
26.4k
}
2187
2188
2189
//
2190
// 'cups_open()' - Safely open a file for writing.
2191
//
2192
// We don't allow appending to directories or files that are hard-linked or
2193
// symlinked.
2194
//
2195
2196
static int        // O - File descriptor or -1 otherwise
2197
cups_open(const char *filename,   // I - Filename
2198
          int        oflag,   // I - Open flags
2199
    int        mode)    // I - Open permissions
2200
0
{
2201
0
  int   fd;     // File descriptor
2202
0
  struct stat fileinfo;   // File information
2203
0
#ifndef _WIN32
2204
0
  struct stat linkinfo;   // Link information
2205
0
#endif // !_WIN32
2206
2207
2208
  // Open the file...
2209
0
  if ((fd = open(filename, oflag, mode)) < 0)
2210
0
    return (-1);
2211
2212
  // Then verify that the file descriptor doesn't point to a directory or hard-linked file.
2213
0
  if (fstat(fd, &fileinfo))
2214
0
  {
2215
0
    close(fd);
2216
0
    return (-1);
2217
0
  }
2218
2219
0
  if (fileinfo.st_nlink != 1)
2220
0
  {
2221
0
    close(fd);
2222
0
    errno = EPERM;
2223
0
    return (-1);
2224
0
  }
2225
2226
#ifdef _WIN32
2227
  if (fileinfo.st_mode & _S_IFDIR)
2228
#else
2229
0
  if (S_ISDIR(fileinfo.st_mode))
2230
0
#endif // _WIN32
2231
0
  {
2232
0
    close(fd);
2233
0
    errno = EISDIR;
2234
0
    return (-1);
2235
0
  }
2236
2237
0
#ifndef _WIN32
2238
  // Then use lstat to determine whether the filename is a symlink...
2239
0
  if (lstat(filename, &linkinfo))
2240
0
  {
2241
0
    close(fd);
2242
0
    return (-1);
2243
0
  }
2244
2245
0
  if (S_ISLNK(linkinfo.st_mode) ||
2246
0
      fileinfo.st_dev != linkinfo.st_dev ||
2247
0
      fileinfo.st_ino != linkinfo.st_ino ||
2248
#ifdef HAVE_ST_GEN
2249
      fileinfo.st_gen != linkinfo.st_gen ||
2250
#endif // HAVE_ST_GEN
2251
0
      fileinfo.st_nlink != linkinfo.st_nlink ||
2252
0
      fileinfo.st_mode != linkinfo.st_mode)
2253
0
  {
2254
    // Yes, don't allow!
2255
0
    close(fd);
2256
0
    errno = EPERM;
2257
0
    return (-1);
2258
0
  }
2259
0
#endif // !_WIN32
2260
2261
0
  return (fd);
2262
0
}
2263
2264
2265
//
2266
// 'cups_read()' - Read from a file descriptor.
2267
//
2268
2269
static ssize_t        // O - Number of bytes read or -1
2270
cups_read(cups_file_t *fp,    // I - CUPS file
2271
          char        *buf,   // I - Buffer
2272
    size_t      bytes)    // I - Number bytes
2273
26.0k
{
2274
26.0k
  ssize_t total;      // Total bytes read
2275
2276
2277
26.0k
  DEBUG_printf("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
2278
2279
  // Loop until we read at least 0 bytes...
2280
26.0k
  for (;;)
2281
26.0k
  {
2282
#ifdef _WIN32
2283
    if (fp->mode == 's')
2284
      total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2285
    else
2286
      total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2287
#else
2288
26.0k
    if (fp->mode == 's')
2289
0
      total = recv(fp->fd, buf, bytes, 0);
2290
26.0k
    else
2291
26.0k
      total = read(fp->fd, buf, bytes);
2292
26.0k
#endif // _WIN32
2293
2294
26.0k
    DEBUG_printf("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total);
2295
2296
26.0k
    if (total >= 0)
2297
26.0k
      break;
2298
2299
    // Reads can be interrupted by signals and unavailable resources...
2300
0
    if (errno == EAGAIN || errno == EINTR)
2301
0
      continue;
2302
0
    else
2303
0
      return (-1);
2304
0
  }
2305
2306
  // Return the total number of bytes read...
2307
26.0k
  return (total);
2308
26.0k
}
2309
2310
2311
//
2312
// 'cups_write()' - Write to a file descriptor.
2313
//
2314
2315
static ssize_t        // O - Number of bytes written or -1
2316
cups_write(cups_file_t *fp,   // I - CUPS file
2317
           const char  *buf,    // I - Buffer
2318
     size_t      bytes)   // I - Number bytes
2319
0
{
2320
0
  size_t  total;      // Total bytes written
2321
0
  ssize_t count;      // Count this time
2322
2323
2324
0
  DEBUG_printf("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", (void *)fp, (void *)buf, CUPS_LLCAST bytes);
2325
2326
  // Loop until all bytes are written...
2327
0
  total = 0;
2328
0
  while (bytes > 0)
2329
0
  {
2330
#ifdef _WIN32
2331
    if (fp->mode == 's')
2332
      count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2333
    else
2334
      count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2335
#else
2336
0
    if (fp->mode == 's')
2337
0
      count = send(fp->fd, buf, bytes, 0);
2338
0
    else
2339
0
      count = write(fp->fd, buf, bytes);
2340
0
#endif // _WIN32
2341
2342
0
    DEBUG_printf("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count);
2343
2344
0
    if (count < 0)
2345
0
    {
2346
      // Writes can be interrupted by signals and unavailable resources...
2347
0
      if (errno == EAGAIN || errno == EINTR)
2348
0
        continue;
2349
0
      else
2350
0
        return (-1);
2351
0
    }
2352
2353
    // Update the counts for the last write call...
2354
0
    bytes -= (size_t)count;
2355
0
    total += (size_t)count;
2356
0
    buf   += count;
2357
0
  }
2358
2359
  // Return the total number of bytes written...
2360
0
  return ((ssize_t)total);
2361
0
}