Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gpmisc.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Miscellaneous support for platform facilities */
18
19
#include "errno_.h"
20
#include "stat_.h"
21
#include "unistd_.h"
22
#include "fcntl_.h"
23
#include "stdio_.h"
24
#include "memory_.h"
25
#include "string_.h"
26
#include "gp.h"
27
#include "gpgetenv.h"
28
#include "gpmisc.h"
29
#include "gserrors.h"
30
31
/*
32
 * Get the name of the directory for temporary files, if any.  Currently
33
 * this checks the TMPDIR and TEMP environment variables, in that order.
34
 * The return value and the setting of *ptr and *plen are as for gp_getenv.
35
 */
36
int
37
gp_gettmpdir(char *ptr, int *plen)
38
145k
{
39
145k
    int max_len = *plen;
40
145k
    int code = gp_getenv("TMPDIR", ptr, plen);
41
42
145k
    if (code != 1)
43
0
        return code;
44
145k
    *plen = max_len;
45
145k
    return gp_getenv("TEMP", ptr, plen);
46
145k
}
47
48
/*
49
 * Open a temporary file, using O_EXCL and S_I*USR to prevent race
50
 * conditions and symlink attacks.
51
 */
52
FILE *
53
gp_fopentemp(const char *fname, const char *mode)
54
0
{
55
0
    int flags = O_EXCL;
56
    /* Scan the mode to construct the flags. */
57
0
    const char *p = mode;
58
0
    int fildes;
59
0
    FILE *file;
60
61
0
#if defined (O_LARGEFILE)
62
    /* It works for Linux/gcc. */
63
0
    flags |= O_LARGEFILE;
64
#else
65
    /* fixme : Not sure what to do. Unimplemented. */
66
    /* MSVC has no O_LARGEFILE, but MSVC build never calls this function. */
67
#endif
68
0
    while (*p)
69
0
        switch (*p++) {
70
0
        case 'a':
71
0
            flags |= O_CREAT | O_APPEND;
72
0
            break;
73
0
        case 'r':
74
0
            flags |= O_RDONLY;
75
0
            break;
76
0
        case 'w':
77
0
            flags |= O_CREAT | O_WRONLY | O_TRUNC;
78
0
            break;
79
#ifdef O_BINARY
80
            /* Watcom C insists on this non-ANSI flag being set. */
81
        case 'b':
82
            flags |= O_BINARY;
83
            break;
84
#endif
85
0
        case '+':
86
0
            flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
87
0
            break;
88
0
        default:    /* e.g., 'b' */
89
0
            break;
90
0
        }
91
0
    fildes = open(fname, flags, S_IRUSR | S_IWUSR);
92
0
    if (fildes < 0)
93
0
        return 0;
94
    /*
95
     * The DEC VMS C compiler incorrectly defines the second argument of
96
     * fdopen as (char *), rather than following the POSIX.1 standard,
97
     * which defines it as (const char *).  Patch this here.
98
     */
99
0
    file = fdopen(fildes, (char *)mode); /* still really const */
100
0
    if (file == 0)
101
0
        close(fildes);
102
0
    return file;
103
0
}
104
105
/* Append a string to buffer. */
106
static inline bool
107
append(char **bp, const char *bpe, const char **ip, uint len)
108
1.07G
{
109
1.07G
    if (bpe - *bp < len)
110
2
        return false;
111
1.07G
    memcpy(*bp, *ip, len);
112
1.07G
    *bp += len;
113
1.07G
    *ip += len;
114
1.07G
    return true;
115
1.07G
}
116
117
/* Search a separator forward. */
118
static inline uint
119
search_separator(const char **ip, const char *ipe, const char *item, int direction)
120
526M
{   uint slen = 0;
121
4.13G
    for (slen = 0; (*ip - ipe) * direction < 0; (*ip) += direction)
122
4.02G
        if((slen = gs_file_name_check_separator(*ip, ipe - *ip, item)) != 0)
123
416M
            break;
124
526M
    return slen;
125
526M
}
126
127
/*
128
 * Combine a file name with a prefix.
129
 * Concatenates two paths and reduce parent references and current
130
 * directory references from the concatenation when possible.
131
 * The trailing zero byte is being added.
132
 *
133
 * Returns "gp_combine_success" if OK and sets '*blen' to the length of
134
 * the combined string. If the combined string is too small for the buffer
135
 * length passed in (as defined by the initial value of *blen), then the
136
 * "gp_combine_small_buffer" code is returned.
137
 *
138
 * Also tolerates/skips leading IODevice specifiers such as %os% or %rom%
139
 * When there is a leading '%' in the 'fname' no other processing is done.
140
 *
141
 * Examples :
142
 *  "/gs/lib" + "../Resource/CMap/H" --> "/gs/Resource/CMap/H"
143
 *  "C:/gs/lib" + "../Resource/CMap/H" --> "C:/gs/Resource/CMap/H"
144
 *  "hard disk:gs:lib" + "::Resource:CMap:H" -->
145
 *    "hard disk:gs:Resource:CMap:H"
146
 *  "DUA1:[GHOSTSCRIPT.LIB" + "-.RESOURCE.CMAP]H" -->
147
 *    "DUA1:[GHOSTSCRIPT.RESOURCE.CMAP]H"
148
 *      "\\server\share/a/b///c/../d.e/./" + "../x.e/././/../../y.z/v.v" -->
149
 *    "\\server\share/a/y.z/v.v"
150
 *  "%rom%lib/" + "gs_init.ps" --> "%rom%lib/gs_init.ps
151
 *  "" + "%rom%lib/gs_init.ps" --> "%rom%lib/gs_init.ps"
152
 */
153
gp_file_name_combine_result
154
gp_file_name_combine_generic(const char *prefix, uint plen, const char *fname, uint flen,
155
                    bool no_sibling, char *buffer, uint *blen)
156
79.5M
{
157
    /*
158
     * THIS CODE IS SHARED FOR MULTIPLE PLATFORMS.
159
     * PLEASE DON'T CHANGE IT FOR A SPECIFIC PLATFORM.
160
     * Change gp_file_name_combine instead.
161
     */
162
79.5M
    char *bp = buffer, *bpe = buffer + *blen;
163
79.5M
    const char *ip, *ipe;
164
79.5M
    uint slen;
165
79.5M
    uint infix_type = 0; /* 0=none, 1=current, 2=parent. */
166
79.5M
    uint infix_len = 0;
167
79.5M
    uint rlen = gp_file_name_root(fname, flen);
168
    /* We need a special handling of infixes only immediately after a drive. */
169
170
79.5M
    if ( flen > 0 && fname[0] == '%') {
171
        /* IoDevice -- just return the fname as-is since this */
172
        /* function only handles the default file system */
173
        /* NOTE: %os% will subvert the normal processing of prefix and fname */
174
0
        ip = fname;
175
0
        *blen = flen;
176
0
        if (!append(&bp, bpe, &ip, flen))
177
0
            return gp_combine_small_buffer;
178
0
        return gp_combine_success;
179
0
    }
180
79.5M
    if (rlen != 0) {
181
        /* 'fname' is absolute, ignore the prefix. */
182
0
        ip = fname;
183
0
        ipe = fname + flen;
184
79.5M
    } else {
185
        /* Concatenate with prefix. */
186
79.5M
        ip = prefix;
187
79.5M
        ipe = prefix + plen;
188
79.5M
        rlen = gp_file_name_root(prefix, plen);
189
79.5M
    }
190
79.5M
    if (!append(&bp, bpe, &ip, rlen))
191
0
        return gp_combine_small_buffer;
192
79.5M
    slen = gs_file_name_check_separator(bp, buffer - bp, bp); /* Backward search. */
193
79.5M
    if (rlen != 0 && slen == 0) {
194
        /* Patch it against names like "c:dir" on Windows. */
195
0
        const char *sep = gp_file_name_directory_separator();
196
197
0
        slen = strlen(sep);
198
0
        if (!append(&bp, bpe, &sep, slen))
199
0
            return gp_combine_small_buffer;
200
0
        rlen += slen;
201
0
    }
202
495M
    for (;;) {
203
495M
        const char *item = ip;
204
495M
        uint ilen;
205
206
495M
        slen = search_separator(&ip, ipe, item, 1);
207
495M
        ilen = ip - item;
208
495M
        if (ilen == 0 && !gp_file_name_is_empty_item_meanful()) {
209
107k
            ip += slen;
210
107k
            slen = 0;
211
494M
        } else if (gp_file_name_is_current(item, ilen)) {
212
            /* Skip the reference to 'current', except the starting one.
213
             * We keep the starting 'current' for platforms, which
214
             * require relative paths to start with it.
215
             */
216
18.6k
            if (bp == buffer) {
217
22
                if (!append(&bp, bpe, &item, ilen))
218
0
                    return gp_combine_small_buffer;
219
22
                infix_type = 1;
220
22
                infix_len = ilen;
221
18.6k
            } else {
222
18.6k
                ip += slen;
223
18.6k
                slen = 0;
224
18.6k
            }
225
494M
        } else if (!gp_file_name_is_parent(item, ilen)) {
226
494M
            if (!append(&bp, bpe, &item, ilen))
227
0
                return gp_combine_small_buffer;
228
            /* The 'item' pointer is now broken; it may be restored using 'ilen'. */
229
494M
        } else if (bp == buffer + rlen + infix_len) {
230
            /* Input is a parent and the output only contains a root and an infix. */
231
8
            if (rlen != 0)
232
0
                return gp_combine_cant_handle;
233
8
            switch (infix_type) {
234
0
                case 1:
235
                    /* Replace the infix with parent. */
236
0
                    bp = buffer + rlen; /* Drop the old infix, if any. */
237
0
                    infix_len = 0;
238
                    /* Falls through. */
239
8
                case 0:
240
                    /* We have no infix, start with parent. */
241
8
                    if ((no_sibling && ipe == fname + flen && flen != 0) ||
242
8
                            !gp_file_name_is_parent_allowed())
243
0
                        return gp_combine_cant_handle;
244
                    /* Falls through. */
245
8
                case 2:
246
                    /* Append one more parent - falls through. */
247
8
                    DO_NOTHING;
248
8
            }
249
8
            if (!append(&bp, bpe, &item, ilen))
250
0
                return gp_combine_small_buffer;
251
8
            infix_type = 2;
252
8
            infix_len += ilen;
253
            /* Recompute the separator length. We cannot use the old slen on Mac OS. */
254
8
            slen = gs_file_name_check_separator(ip, ipe - ip, ip);
255
14.8k
        } else {
256
            /* Input is a parent and the output continues after infix. */
257
            /* Unappend the last separator and the last item. */
258
14.8k
            uint slen1 = gs_file_name_check_separator(bp, buffer + rlen - bp, bp); /* Backward search. */
259
14.8k
            char *bie = bp - slen1;
260
261
14.8k
            bp = bie;
262
14.8k
            DISCARD(search_separator((const char **)&bp, buffer + rlen, bp, -1));
263
            /* The cast above quiets a gcc warning. We believe it's a bug in the compiler. */
264
            /* Skip the input with separator. We cannot use slen on Mac OS. */
265
14.8k
            ip += gs_file_name_check_separator(ip, ipe - ip, ip);
266
14.8k
            if (no_sibling) {
267
0
                const char *p = ip;
268
269
0
                DISCARD(search_separator(&p, ipe, ip, 1));
270
0
                if (p - ip != bie - bp || memcmp(ip, bp, p - ip))
271
0
                    return gp_combine_cant_handle;
272
0
            }
273
14.8k
            slen = 0;
274
14.8k
        }
275
495M
        if (slen) {
276
397M
            if (bp == buffer + rlen + infix_len)
277
0
                infix_len += slen;
278
397M
            if (!append(&bp, bpe, &ip, slen))
279
0
                return gp_combine_small_buffer;
280
397M
        }
281
495M
        if (ip == ipe) {
282
104M
            if (ipe == fname + flen) {
283
                /* All done.
284
                 * Note that the case (prefix + plen == fname && flen == 0)
285
                 * falls here without appending a separator.
286
                 */
287
79.5M
                const char *zero="";
288
289
79.5M
                if (bp == buffer) {
290
                    /* Must not return empty path. */
291
2
                    const char *current = gp_file_name_current();
292
2
                    int clen = strlen(current);
293
294
2
                    if (!append(&bp, bpe, &current, clen))
295
0
                        return gp_combine_small_buffer;
296
2
                }
297
79.5M
                *blen = bp - buffer;
298
79.5M
                if (!append(&bp, bpe, &zero, 1))
299
2
                    return gp_combine_small_buffer;
300
79.5M
                return gp_combine_success;
301
79.5M
            } else {
302
                /* ipe == prefix + plen */
303
                /* Switch to fname. */
304
25.3M
                ip = fname;
305
25.3M
                ipe = fname + flen;
306
25.3M
                if (slen == 0) {
307
                    /* Insert a separator. */
308
23.7M
                    const char *sep;
309
310
23.7M
                    slen = search_separator(&ip, ipe, fname, 1);
311
23.7M
                    sep = (slen != 0 ? gp_file_name_directory_separator()
312
23.7M
                                    : gp_file_name_separator());
313
23.7M
                    slen = strlen(sep);
314
23.7M
                    if (bp == buffer + rlen + infix_len)
315
0
                        infix_len += slen;
316
23.7M
                    if (!append(&bp, bpe, &sep, slen))
317
0
                        return gp_combine_small_buffer;
318
23.7M
                    ip = fname; /* Switch to fname. */
319
23.7M
                }
320
25.3M
            }
321
104M
        }
322
495M
    }
323
79.5M
}
324
325
/*
326
 * Reduces parent references and current directory references when possible.
327
 * The trailing zero byte is being added.
328
 *
329
 * Examples :
330
 *  "/gs/lib/../Resource/CMap/H" --> "/gs/Resource/CMap/H"
331
 *  "C:/gs/lib/../Resource/CMap/H" --> "C:/gs/Resource/CMap/H"
332
 *  "hard disk:gs:lib::Resource:CMap:H" -->
333
 *    "hard disk:gs:Resource:CMap:H"
334
 *  "DUA1:[GHOSTSCRIPT.LIB.-.RESOURCE.CMAP]H" -->
335
 *    "DUA1:[GHOSTSCRIPT.RESOURCE.CMAP]H"
336
 *      "\\server\share/a/b///c/../d.e/./../x.e/././/../../y.z/v.v" -->
337
 *    "\\server\share/a/y.z/v.v"
338
 *
339
 */
340
gp_file_name_combine_result
341
gp_file_name_reduce(const char *fname, uint flen, char *buffer, uint *blen)
342
54.2M
{
343
54.2M
    return gp_file_name_combine(fname, flen, fname + flen, 0, false, buffer, blen);
344
54.2M
}
345
346
/*
347
 * Answers whether a file name is absolute (starts from a root).
348
 */
349
bool
350
gp_file_name_is_absolute(const char *fname, uint flen)
351
20.9M
{
352
20.9M
    return (gp_file_name_root(fname, flen) > 0);
353
20.9M
}
354
355
/*
356
 * Returns length of all starting parent references.
357
 */
358
static uint
359
gp_file_name_prefix(const char *fname, uint flen,
360
                bool (*test)(const char *fname, uint flen))
361
25.2M
{
362
25.2M
    uint plen = gp_file_name_root(fname, flen), slen;
363
25.2M
    const char *ip, *ipe;
364
25.2M
    const char *item = fname; /* plen == flen could cause an indeterminizm. */
365
366
25.2M
    if (plen > 0)
367
17.7M
        return 0;
368
7.46M
    ip = fname + plen;
369
7.46M
    ipe = fname + flen;
370
7.46M
    for (; ip < ipe; ) {
371
7.46M
        item = ip;
372
7.46M
        slen = search_separator(&ip, ipe, item, 1);
373
7.46M
        if (!(*test)(item, ip - item))
374
7.46M
            break;
375
4
        ip += slen;
376
4
    }
377
7.46M
    return item - fname;
378
25.2M
}
379
380
/*
381
 * Returns length of all starting parent references.
382
 */
383
uint
384
gp_file_name_parents(const char *fname, uint flen)
385
25.2M
{
386
25.2M
    return gp_file_name_prefix(fname, flen, gp_file_name_is_parent);
387
25.2M
}
388
389
/*
390
 * Returns length of all starting cwd references.
391
 */
392
uint
393
gp_file_name_cwds(const char *fname, uint flen)
394
0
{
395
0
    return gp_file_name_prefix(fname, flen, gp_file_name_is_current);
396
0
}
397
398
static int
399
generic_pread(gp_file *f, size_t count, gs_offset_t offset, void *buf)
400
0
{
401
0
    int c;
402
0
    int64_t os, curroff = gp_ftell(f);
403
0
    if (curroff < 0) return curroff;
404
405
0
    os = gp_fseek(f, offset, 0);
406
0
    if (os < 0) return os;
407
408
0
    c = gp_fread(buf, 1, count, f);
409
0
    if (c < 0) return c;
410
411
0
    os = gp_fseek(f, curroff, 0);
412
0
    if (os < 0) return os;
413
414
0
    return c;
415
0
}
416
417
static int
418
generic_pwrite(gp_file *f, size_t count, gs_offset_t offset, const void *buf)
419
0
{
420
0
    int c;
421
0
    int64_t os, curroff = gp_ftell(f);
422
0
    if (curroff < 0) return curroff;
423
424
0
    os = gp_fseek(f, offset, 0);
425
0
    if (os < 0) return os;
426
427
0
    c = gp_fwrite(buf, 1, count, f);
428
0
    if (c < 0) return c;
429
430
0
    os = gp_fseek(f, curroff, 0);
431
0
    if (os < 0) return os;
432
433
0
    return c;
434
0
}
435
436
gp_file *gp_file_alloc(const gs_memory_t *mem, const gp_file_ops_t *prototype, size_t size, const char *cname)
437
21.3M
{
438
21.3M
    gp_file *file = (gp_file *)gs_alloc_bytes(mem->thread_safe_memory, size, cname ? cname : "gp_file");
439
21.3M
    if (file == NULL)
440
0
        return NULL;
441
442
21.3M
    if (prototype)
443
21.3M
        file->ops = *prototype;
444
21.3M
    if (file->ops.pread == NULL)
445
0
        file->ops.pread = generic_pread;
446
21.3M
    if (file->ops.pwrite == NULL)
447
0
        file->ops.pwrite = generic_pwrite;
448
21.3M
    if (size > sizeof(*prototype))
449
21.3M
        memset(((char *)file)+sizeof(*prototype),
450
21.3M
               0,
451
21.3M
               size - sizeof(*prototype));
452
21.3M
    file->memory = mem->thread_safe_memory;
453
454
21.3M
    return file;
455
21.3M
}
456
457
void gp_file_dealloc(gp_file *file)
458
21.3M
{
459
21.3M
    if (file == NULL)
460
0
        return;
461
462
21.3M
    if (file->buffer)
463
0
        gs_free_object(file->memory, file->buffer, "gp_file");
464
21.3M
    gs_free_object(file->memory, file, "gp_file");
465
21.3M
}
466
467
int gp_fprintf(gp_file *f, const char *fmt, ...)
468
0
{
469
0
    va_list args;
470
0
    int n;
471
472
0
    if (f->buffer)
473
0
        goto mid;
474
0
    do {
475
0
        n = f->buffer_size * 2;
476
0
        if (n == 0)
477
0
            n = 256;
478
0
        gs_free_object(f->memory, f->buffer, "gp_file(buffer)");
479
0
        f->buffer = (char *)gs_alloc_bytes(f->memory, n, "gp_file(buffer)");
480
0
        if (f->buffer == NULL)
481
0
            return -1;
482
0
        f->buffer_size = n;
483
0
mid:
484
0
        va_start(args, fmt);
485
0
        n = vsnprintf(f->buffer, f->buffer_size, fmt, args);
486
0
        va_end(args);
487
0
    } while (n >= f->buffer_size);
488
0
    return (f->ops.write)(f, 1, n, f->buffer);
489
0
}
490
typedef struct {
491
    gp_file base;
492
    FILE *file;
493
    int (*close)(FILE *file);
494
} gp_file_FILE;
495
496
static int
497
gp_file_FILE_close(gp_file *file_)
498
287k
{
499
287k
    gp_file_FILE *file = (gp_file_FILE *)file_;
500
501
287k
    return (file->close)(file->file);
502
287k
}
503
504
static int
505
gp_file_FILE_getc(gp_file *file_)
506
0
{
507
0
    gp_file_FILE *file = (gp_file_FILE *)file_;
508
509
0
    return fgetc(file->file);
510
0
}
511
512
static int
513
gp_file_FILE_putc(gp_file *file_, int c)
514
7.92k
{
515
7.92k
    gp_file_FILE *file = (gp_file_FILE *)file_;
516
517
7.92k
    return fputc(c, file->file);
518
7.92k
}
519
520
static int
521
gp_file_FILE_read(gp_file *file_, size_t size, unsigned int count, void *buf)
522
882M
{
523
882M
    gp_file_FILE *file = (gp_file_FILE *)file_;
524
525
882M
    return fread(buf, size, count, file->file);
526
882M
}
527
528
static int
529
gp_file_FILE_write(gp_file *file_, size_t size, unsigned int count, const void *buf)
530
96.7M
{
531
96.7M
    gp_file_FILE *file = (gp_file_FILE *)file_;
532
533
96.7M
    return fwrite(buf, size, count, file->file);
534
96.7M
}
535
536
static int
537
gp_file_FILE_seek(gp_file *file_, gs_offset_t offset, int whence)
538
7.60M
{
539
7.60M
    gp_file_FILE *file = (gp_file_FILE *)file_;
540
541
7.60M
    return gp_fseek_impl(file->file, offset, whence);
542
7.60M
}
543
544
static gs_offset_t
545
gp_file_FILE_tell(gp_file *file_)
546
890k
{
547
890k
    gp_file_FILE *file = (gp_file_FILE *)file_;
548
549
890k
    return gp_ftell_impl(file->file);
550
890k
}
551
552
static int
553
gp_file_FILE_eof(gp_file *file_)
554
880M
{
555
880M
    gp_file_FILE *file = (gp_file_FILE *)file_;
556
557
880M
    return feof(file->file);
558
880M
}
559
560
static gp_file *
561
gp_file_FILE_dup(gp_file *file_, const char *mode)
562
0
{
563
0
    gp_file_FILE *file = (gp_file_FILE *)file_;
564
0
    gp_file *file2 = gp_file_FILE_alloc(file->base.memory);
565
566
0
    if (gp_file_FILE_set(file2, gp_fdup_impl(file->file, mode), NULL))
567
0
        file2 = NULL;
568
569
0
    return file2;
570
0
}
571
572
static int
573
gp_file_FILE_seekable(gp_file *file_)
574
0
{
575
0
    gp_file_FILE *file = (gp_file_FILE *)file_;
576
577
0
    return gp_fseekable_impl(file->file);
578
0
}
579
580
static int
581
gp_file_FILE_pread(gp_file *file_, size_t count, gs_offset_t offset, void *buf)
582
1.02M
{
583
1.02M
    gp_file_FILE *file = (gp_file_FILE *)file_;
584
585
1.02M
    return gp_pread_impl(buf, count, offset, file->file);
586
1.02M
}
587
588
static int
589
gp_file_FILE_pwrite(gp_file *file_, size_t count, gs_offset_t offset, const void *buf)
590
6.28M
{
591
6.28M
    gp_file_FILE *file = (gp_file_FILE *)file_;
592
593
6.28M
    return gp_pwrite_impl(buf, count, offset, file->file);
594
6.28M
}
595
596
static int
597
gp_file_FILE_is_char_buffered(gp_file *file_)
598
0
{
599
0
    gp_file_FILE *file = (gp_file_FILE *)file_;
600
0
    struct stat rstat;
601
602
0
    if (fstat(fileno(file->file), &rstat) != 0)
603
0
        return ERRC;
604
0
    return S_ISCHR(rstat.st_mode);
605
0
}
606
607
static void
608
gp_file_FILE_fflush(gp_file *file_)
609
79.2M
{
610
79.2M
    gp_file_FILE *file = (gp_file_FILE *)file_;
611
612
79.2M
    fflush(file->file);
613
79.2M
}
614
615
static int
616
gp_file_FILE_ferror(gp_file *file_)
617
33.4M
{
618
33.4M
    gp_file_FILE *file = (gp_file_FILE *)file_;
619
620
33.4M
    return ferror(file->file);
621
33.4M
}
622
623
static FILE *
624
gp_file_FILE_get_file(gp_file *file_)
625
312k
{
626
312k
    gp_file_FILE *file = (gp_file_FILE *)file_;
627
628
312k
    return file->file;
629
312k
}
630
631
static void
632
gp_file_FILE_clearerr(gp_file *file_)
633
40.8k
{
634
40.8k
    gp_file_FILE *file = (gp_file_FILE *)file_;
635
636
40.8k
    clearerr(file->file);
637
40.8k
}
638
639
static gp_file *
640
gp_file_FILE_reopen(gp_file *file_, const char *fname, const char *mode)
641
0
{
642
0
    gp_file_FILE *file = (gp_file_FILE *)file_;
643
644
0
    file->file = freopen(fname, mode, file->file);
645
0
    if (file->file == NULL) {
646
0
        gp_file_dealloc(file_);
647
0
        return NULL;
648
0
    }
649
0
    return file_;
650
0
}
651
652
static const gp_file_ops_t gp_file_FILE_prototype =
653
{
654
    gp_file_FILE_close,
655
    gp_file_FILE_getc,
656
    gp_file_FILE_putc,
657
    gp_file_FILE_read,
658
    gp_file_FILE_write,
659
    gp_file_FILE_seek,
660
    gp_file_FILE_tell,
661
    gp_file_FILE_eof,
662
    gp_file_FILE_dup,
663
    gp_file_FILE_seekable,
664
    gp_file_FILE_pread,
665
    gp_file_FILE_pwrite,
666
    gp_file_FILE_is_char_buffered,
667
    gp_file_FILE_fflush,
668
    gp_file_FILE_ferror,
669
    gp_file_FILE_get_file,
670
    gp_file_FILE_clearerr,
671
    gp_file_FILE_reopen
672
};
673
674
gp_file *gp_file_FILE_alloc(const gs_memory_t *mem)
675
21.3M
{
676
21.3M
    return gp_file_alloc(mem->non_gc_memory,
677
21.3M
                         &gp_file_FILE_prototype,
678
21.3M
                         sizeof(gp_file_FILE),
679
21.3M
                         "gp_file_FILE");
680
21.3M
}
681
682
int gp_file_FILE_set(gp_file *file_, FILE *f, int (*close)(FILE *))
683
21.3M
{
684
21.3M
    gp_file_FILE *file = (gp_file_FILE *)file_;
685
686
21.3M
    if (f == NULL) {
687
21.1M
        gp_file_dealloc(file_);
688
21.1M
        return 1;
689
21.1M
    }
690
691
287k
    file->file = f;
692
287k
    file->close = close ? close : fclose;
693
694
287k
    return 0;
695
21.3M
}
696
697
char *gp_fgets(char *buffer, size_t n, gp_file *f)
698
0
{
699
0
    int c = EOF;
700
0
    char *b = buffer;
701
0
    while (n > 1) {
702
0
        c = gp_fgetc(f);
703
0
  if (c == 0)
704
0
            break;
705
0
  *b++ = c;
706
0
  n--;
707
0
    }
708
0
    if (c == EOF && b == buffer)
709
0
        return NULL;
710
0
    if (gp_ferror(f))
711
0
        return NULL;
712
0
    if (n > 0)
713
0
        *b++ = 0;
714
0
    return buffer;
715
0
}
716
717
gp_file *
718
gp_fopen(const gs_memory_t *mem, const char *fname, const char *mode)
719
24.0M
{
720
24.0M
    gp_file *file = NULL;
721
24.0M
    gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
722
24.0M
    gs_fs_list_t *fs = ctx->core->fs;
723
724
24.0M
    if (gp_validate_path(mem, fname, mode) != 0)
725
2.83M
        return NULL;
726
727
21.2M
    for (fs = ctx->core->fs; fs != NULL; fs = fs->next)
728
21.2M
    {
729
21.2M
        int code = 0;
730
21.2M
        if (fs->fs.open_file)
731
21.2M
            code = fs->fs.open_file(mem, fs->secret, fname, mode, &file);
732
21.2M
        if (code < 0)
733
21.1M
            return NULL;
734
106k
        if (file != NULL)
735
106k
            break;
736
106k
    }
737
738
106k
    return file;
739
21.2M
}
740
741
gp_file *
742
gp_open_printer(const gs_memory_t *mem,
743
                      char         fname[gp_file_name_sizeof],
744
                      int          binary_mode)
745
34.9k
{
746
34.9k
    gp_file *file = NULL;
747
34.9k
    gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
748
34.9k
    gs_fs_list_t *fs = ctx->core->fs;
749
750
34.9k
    if (gp_validate_path(mem, fname, binary_mode ? "wb" : "w") != 0)
751
0
        return NULL;
752
753
34.9k
    for (fs = ctx->core->fs; fs != NULL; fs = fs->next)
754
34.9k
    {
755
34.9k
        int code = 0;
756
34.9k
        if (fs->fs.open_printer)
757
34.9k
            code = fs->fs.open_printer(mem, fs->secret, fname, binary_mode, &file);
758
34.9k
        if (code < 0)
759
0
            return NULL;
760
34.9k
        if (file != NULL)
761
34.9k
            break;
762
34.9k
    }
763
764
34.9k
    return file;
765
34.9k
}
766
767
static gp_file *
768
do_open_scratch_file(const gs_memory_t *mem,
769
                     const char        *prefix,
770
                     char              *fname,
771
                     const char        *mode,
772
                     int                rm)
773
145k
{
774
145k
    gp_file *file = NULL;
775
145k
    gs_lib_ctx_t *ctx = mem->gs_lib_ctx;
776
145k
    gs_fs_list_t *fs = ctx->core->fs;
777
145k
    int code = 0;
778
779
    /* If the prefix is absolute, then we must check it's a permissible
780
     * path. If not, we're OK. */
781
145k
    if (gp_file_name_is_absolute(prefix, strlen(prefix)) &&
782
145k
        gp_validate_path(mem, prefix, mode) != 0)
783
0
            return NULL;
784
785
145k
    for (fs = ctx->core->fs; fs != NULL; fs = fs->next)
786
145k
    {
787
145k
        if (fs->fs.open_scratch)
788
145k
            code = fs->fs.open_scratch(mem, fs->secret, prefix, fname, mode, rm, &file);
789
145k
        if (code < 0)
790
0
            return NULL;
791
145k
        if (file != NULL)
792
145k
            break;
793
145k
    }
794
795
145k
    if (file == NULL) {
796
        /* The file failed to open. Don't add it to the list. */
797
145k
    } else if (rm) {
798
        /* This file has already been deleted by the underlying system.
799
         * We don't need to add it to the lists as it will never be
800
         * deleted manually, nor do we need to tidy it up on closedown. */
801
105k
    } else {
802
         /* This file was not requested to be deleted. We add it to the
803
          * list so that it will either be deleted by any future call to
804
          * zdeletefile, OR on closedown. */
805
         /* Add the scratch file name to the lists. We can't do this any
806
          * earlier as we didn't know the name until now! Unfortunately
807
          * that makes cleanup harder. */
808
105k
        code = gs_add_control_path_flags(mem, gs_permit_file_control, fname,
809
105k
                                         gs_path_control_flag_is_scratch_file);
810
105k
        if (code >= 0)
811
105k
            code = gs_add_control_path_flags(mem, gs_permit_file_reading, fname,
812
105k
                                             gs_path_control_flag_is_scratch_file);
813
105k
        if (code >= 0)
814
105k
            code = gs_add_control_path_flags(mem, gs_permit_file_writing, fname,
815
105k
                                         gs_path_control_flag_is_scratch_file);
816
817
105k
        if (code < 0) {
818
0
            gp_fclose(file);
819
0
            file = NULL;
820
            /* Call directly through to the unlink implementation. We know
821
             * we're 'permitted' to do this, but we might not be on all the
822
             * required permit lists because of the failure. The only bad
823
             * thing here, is that we're deleting an fname that might not
824
             * have come from the filing system itself. */
825
0
            if (fname && fname[0])
826
0
                gp_unlink_impl(ctx->memory, fname);
827
0
            (void)gs_remove_control_path_flags(mem, gs_permit_file_control, fname,
828
0
                                               gs_path_control_flag_is_scratch_file);
829
0
            (void)gs_remove_control_path_flags(mem, gs_permit_file_reading, fname,
830
0
                                               gs_path_control_flag_is_scratch_file);
831
0
            (void)gs_remove_control_path_flags(mem, gs_permit_file_writing, fname,
832
0
                                               gs_path_control_flag_is_scratch_file);
833
0
        }
834
105k
    }
835
836
145k
    return file;
837
145k
}
838
839
gp_file *
840
gp_open_scratch_file(const gs_memory_t *mem,
841
                     const char        *prefix,
842
                     char              *fname,
843
                     const char        *mode)
844
105k
{
845
105k
    return do_open_scratch_file(mem, prefix, fname, mode, 0);
846
105k
}
847
848
gp_file *
849
gp_open_scratch_file_rm(const gs_memory_t *mem,
850
                        const char        *prefix,
851
                        char              *fname,
852
                        const char        *mode)
853
40.7k
{
854
40.7k
    return do_open_scratch_file(mem, prefix, fname, mode, 1);
855
40.7k
}
856
857
int
858
gp_stat(const gs_memory_t *mem, const char *path, struct stat *buf)
859
1
{
860
1
    if (gp_validate_path(mem, path, "r") != 0) {
861
1
        return -1;
862
1
    }
863
864
0
    return gp_stat_impl(mem, path, buf);
865
1
}
866
867
file_enum *
868
gp_enumerate_files_init(gs_memory_t *mem, const char *pat, uint patlen)
869
981k
{
870
981k
    return gp_enumerate_files_init_impl(mem, pat, patlen);
871
981k
}
872
873
uint
874
gp_enumerate_files_next(gs_memory_t *mem, file_enum * pfen, char *ptr, uint maxlen)
875
981k
{
876
981k
    uint code = 0;
877
878
981k
    while (code == 0) {
879
981k
        code = gp_enumerate_files_next_impl(mem, pfen, ptr, maxlen);
880
981k
        if (code == ~0) break;
881
0
        if (code > 0) {
882
0
            if (gp_validate_path_len(mem, ptr, code, "r") != 0)
883
0
                code = 0;
884
0
        }
885
0
    }
886
981k
    return code;
887
981k
}
888
void
889
gp_enumerate_files_close(gs_memory_t *mem, file_enum * pfen)
890
981k
{
891
981k
    gp_enumerate_files_close_impl(mem, pfen);
892
981k
}
893
894
/* Path validation: (FIXME: Move this somewhere better)
895
 *
896
 * The only wildcard we accept is '*'.
897
 *
898
 * A '*' at the end of the path means "in this directory,
899
 * or any subdirectory". Anywhere else it means "a sequence of
900
 * characters not including a director separator".
901
 *
902
 * A sequence of multiple '*'s is equivalent to a single one.
903
 *
904
 * Matching on '*' is simplistic; the matching sequence will end
905
 * as soon as we meet an instance of a character that follows
906
 * the '*' in a pattern. i.e. "foo*bar" will fail to match "fooabbar"
907
 * as the '*' will be held to match just 'a'.
908
 *
909
 * There is no way of specifying a literal '*'; if you find yourself
910
 * wanting to do this, slap yourself until you come to your senses.
911
 *
912
 * Due to the difficulties of using both * and / in writing C comments,
913
 * I shall use \ as the directory separator in the examples below, but
914
 * in practice it means "the directory separator for the current
915
 * platform".
916
 *
917
 * Pattern           Match example
918
 *  *                 any file, in any directory at all.
919
 *  foo\bar           a file, foo\bar.
920
 *  foo\bar\          any file within foo\bar\, but no subdirectories.
921
 *  foo\bar\*         any file within foo\bar\ or any subdirectory thereof.
922
 *  foo\*\bar         any file 'bar' within any single subdirectory of foo
923
 *                    (i.e. foo\baz\bar, but not foo\baz\whoop\bar)
924
 *  foo\out*.tif      e.g. foo\out1.tif
925
 *  foo\out*.*.tif*   e.g. foo\out1.(Red).tif
926
 */
927
928
static int
929
validate(const gs_memory_t *mem,
930
         const char        *path,
931
         gs_path_control_t  type)
932
19.9M
{
933
19.9M
    gs_lib_ctx_core_t *core = mem->gs_lib_ctx->core;
934
19.9M
    gs_path_control_set_t *control;
935
19.9M
    unsigned int i, n;
936
937
19.9M
    switch (type) {
938
19.8M
        case gs_permit_file_reading:
939
19.8M
            control = &core->permit_reading;
940
19.8M
            break;
941
15.1k
        case gs_permit_file_writing:
942
15.1k
            control = &core->permit_writing;
943
15.1k
            break;
944
82.3k
        case gs_permit_file_control:
945
82.3k
            control = &core->permit_control;
946
82.3k
            break;
947
0
        default:
948
0
            return gs_error_unknownerror;
949
19.9M
    }
950
951
19.9M
    n = control->num;
952
545M
    for (i = 0; i < n; i++) {
953
540M
        const char *a = path;
954
540M
        const char *b = control->entry[i].path;
955
4.22G
        while (1) {
956
4.22G
            if (*a == 0) {
957
32.9k
                if (*b == 0)
958
                    /* PATH=abc pattern=abc */
959
14.9k
                    goto found; /* Bingo! */
960
17.9k
                else
961
                    /* PATH=abc pattern=abcd */
962
17.9k
                    break; /* No match */
963
4.22G
            } else if (*b == '*') {
964
14.3M
                if (b[1] == '*') {
965
                    /* Multiple '*'s are taken to mean the
966
                     * output from a printf. */
967
0
                    b++;
968
0
                    while (b[1] == '*')
969
0
                        b++;
970
                    /* Skip over the permissible matching chars */
971
0
                    while (*a &&
972
0
                           ((*a == ' ' || *a == '-' || *a == '+' ||
973
0
                             (*a >= '0' && *a <= '9') ||
974
0
                             (*a >= 'a' && *a <= 'f') ||
975
0
                             (*a >= 'A' && *a <= 'F'))))
976
0
                            a++;
977
0
                    if (b[1] == 0 && *a == 0)
978
                        /* PATH=abc<%d> pattern=abc** */
979
0
                        goto found;
980
0
                    if (*a == 0)
981
0
                        break; /* No match */
982
14.3M
                } else {
983
14.3M
                    if (b[1] == 0)
984
                        /* PATH=abc???? pattern=abc* */
985
14.3M
                        goto found;
986
                    /* Skip over anything except NUL, directory
987
                     * separator, and the next char to match. */
988
0
                    while (*a && !gs_file_name_check_separator(a, 1, a) && *a != b[1])
989
0
                        a++;
990
0
                    if (*a == 0 || *a == gs_file_name_check_separator(a, 1, a))
991
0
                        break; /* No match */
992
0
                }
993
                /* Continue matching */
994
0
                a--; /* Subtract 1 as the loop will increment it again later */
995
4.21G
            } else if (*b == 0) {
996
14.2M
                if (b != control->entry[i].path &&
997
14.2M
                    gs_file_name_check_separator(b, -1, b)) {
998
0
                    const char *a2 = a;
999
0
                    const char *aend = path + strlen(path);
1000
0
                    while (aend != a2 && !gs_file_name_check_separator(a2, 1, a2))
1001
0
                      a2++;
1002
                    /* If the control path ends in a directory separator and we've scanned
1003
                       to the end of the candidate path with no further directory separators
1004
                       found, we have a match
1005
                     */
1006
0
                    if (aend == a2)
1007
                      /* PATH=abc/? pattern=abc/ */
1008
0
                      goto found; /* Bingo! */
1009
0
                 }
1010
                /* PATH=abcd pattern=abc */
1011
14.2M
                break; /* No match */
1012
4.19G
            } else if (gs_file_name_check_separator(a, 1, a) == 1
1013
4.19G
                        && gs_file_name_check_separator(b, 1, b) == 1) {
1014
                /* On Windows we can get random combinations of "/" and "\" as directory
1015
                 * separators, and we want "C:\" to match C:/" hence using the pair of
1016
                 * gs_file_name_check_separator() calls above */
1017
                 /* Annoyingly, we can also end up with a combination of explicitly escaped
1018
                  * '\' characters, and not escaped. So we also need "C:\\" to match "C:\"
1019
                  * and "C:/" - hence we need to check for, and skip over the
1020
                  * the extra '\' character - I'm reticent to change the upstream code that
1021
                  * adds the explicit escape, because that could have unforeseen side effects
1022
                  * elsewhere. */
1023
843M
                 if (*(a + 1) != 0 && gs_file_name_check_separator(a + 1, 1, a + 1) == 1)
1024
0
                     a++;
1025
843M
                 if (*(b + 1) != 0 && gs_file_name_check_separator(b + 1, 1, b + 1) == 1)
1026
0
                     b++;
1027
3.35G
            } else if (*a != *b) {
1028
511M
                break;
1029
511M
            }
1030
3.68G
            a++, b++;
1031
3.68G
        }
1032
540M
    }
1033
5.65M
    return gs_error_invalidfileaccess;
1034
1035
14.3M
found:
1036
14.3M
    return control->entry[i].flags;
1037
19.9M
}
1038
1039
int
1040
gp_validate_path_len(const gs_memory_t *mem,
1041
                     const char        *path,
1042
                     const uint         len,
1043
                     const char        *mode)
1044
24.1M
{
1045
24.1M
    char *buffer, *bufferfull;
1046
24.1M
    uint rlen;
1047
24.1M
    int code = 0;
1048
24.1M
    const char *cdirstr = gp_file_name_current();
1049
24.1M
    int cdirstrl = strlen(cdirstr);
1050
24.1M
    const char *dirsepstr = gp_file_name_separator();
1051
24.1M
    int dirsepstrl = strlen(dirsepstr);
1052
24.1M
    int prefix_len = cdirstrl + dirsepstrl;
1053
1054
    /* mem->gs_lib_ctx can be NULL when we're called from mkromfs */
1055
24.1M
    if (mem->gs_lib_ctx == NULL ||
1056
24.1M
        mem->gs_lib_ctx->core->path_control_active == 0)
1057
6.99M
        return 0;
1058
1059
    /* For current directory accesses, we need handle both a "bare" name,
1060
     * and one with a cwd prefix (in Unix terms, both "myfile.ps" and
1061
     * "./myfile.ps".
1062
     *
1063
     * So we check up front if it's absolute, then just use that.
1064
     * If it includes cwd prefix, we try that, then remove the prefix
1065
     * and try again.
1066
     * If it doesn't include the cwd prefix, we try it, then add the
1067
     * prefix and try again.
1068
     * To facilitate that, we allocate a large enough buffer to take
1069
     * the path *and* the prefix up front.
1070
     */
1071
17.1M
    if (gp_file_name_is_absolute(path, len)) {
1072
       /* Absolute path, we don't need anything extra */
1073
14.3M
       prefix_len = cdirstrl = dirsepstrl = 0;
1074
14.3M
    }
1075
2.81M
    else if (len > prefix_len && !memcmp(path, cdirstr, cdirstrl)
1076
2.81M
             && !memcmp(path + cdirstrl, dirsepstr, dirsepstrl)) {
1077
0
          prefix_len = 0;
1078
0
    }
1079
17.1M
    rlen = len+1;
1080
17.1M
    bufferfull = (char *)gs_alloc_bytes(mem->thread_safe_memory, rlen + prefix_len, "gp_validate_path");
1081
17.1M
    if (bufferfull == NULL)
1082
0
        return gs_error_VMerror;
1083
1084
17.1M
    buffer = bufferfull + prefix_len;
1085
17.1M
    if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
1086
2
        return gs_error_invalidfileaccess;
1087
17.1M
    buffer[rlen] = 0;
1088
1089
19.9M
    while (1) {
1090
19.9M
        switch (mode[0])
1091
19.9M
        {
1092
19.8M
        case 'r': /* Read */
1093
19.8M
            code = validate(mem, buffer, gs_permit_file_reading);
1094
19.8M
            break;
1095
15.1k
        case 'w': /* Write */
1096
15.1k
            code = validate(mem, buffer, gs_permit_file_writing);
1097
15.1k
            break;
1098
0
        case 'a': /* Append needs reading and writing */
1099
0
            code = (validate(mem, buffer, gs_permit_file_reading) |
1100
0
                    validate(mem, buffer, gs_permit_file_writing));
1101
0
            break;
1102
0
        case 'c': /* "Control" */
1103
0
            code =  validate(mem, buffer, gs_permit_file_control);
1104
0
            break;
1105
82.3k
        case 'd': /* "Delete" (special case of control) */
1106
82.3k
            code =  validate(mem, buffer, gs_permit_file_control);
1107
82.3k
            break;
1108
0
        case 'f': /* "Rename from" */
1109
0
            code = (validate(mem, buffer, gs_permit_file_writing) |
1110
0
                    validate(mem, buffer, gs_permit_file_control));
1111
0
            break;
1112
0
        case 't': /* "Rename to" */
1113
0
            code = (validate(mem, buffer, gs_permit_file_writing) |
1114
0
                    validate(mem, buffer, gs_permit_file_control));
1115
0
            break;
1116
0
        default:
1117
0
            errprintf(mem, "gp_validate_path: Unknown mode='%s'\n", mode);
1118
0
            code = gs_note_error(gs_error_invalidfileaccess);
1119
19.9M
        }
1120
19.9M
        if (code < 0 && prefix_len > 0 && buffer > bufferfull) {
1121
2.81M
            buffer = bufferfull;
1122
2.81M
            memcpy(buffer, cdirstr, cdirstrl);
1123
2.81M
            memcpy(buffer + cdirstrl, dirsepstr, dirsepstrl);
1124
2.81M
            continue;
1125
2.81M
        }
1126
17.1M
        else if (code < 0 && cdirstrl > 0 && prefix_len == 0 && buffer == bufferfull) {
1127
0
            buffer = bufferfull + cdirstrl + dirsepstrl;
1128
0
            continue;
1129
0
        }
1130
17.1M
        break;
1131
19.9M
    }
1132
17.1M
    if (code > 0 && (mode[0] == 'd' || mode[0] == 'f') &&
1133
17.1M
        (code & gs_path_control_flag_is_scratch_file) != 0) {
1134
0
        (void)gs_remove_control_path_flags(mem, gs_permit_file_reading, buffer,
1135
0
                                           gs_path_control_flag_is_scratch_file);
1136
0
        (void)gs_remove_control_path_flags(mem, gs_permit_file_writing, buffer,
1137
0
                                           gs_path_control_flag_is_scratch_file);
1138
0
        (void)gs_remove_control_path_flags(mem, gs_permit_file_control, buffer,
1139
0
                                           gs_path_control_flag_is_scratch_file);
1140
0
    }
1141
1142
17.1M
    gs_free_object(mem->thread_safe_memory, bufferfull, "gp_validate_path");
1143
17.1M
#ifdef EACCES
1144
17.1M
    if (code == gs_error_invalidfileaccess)
1145
2.83M
        errno = EACCES;
1146
17.1M
#endif
1147
1148
17.1M
    return code < 0 ? code : 0;
1149
17.1M
}
1150
1151
int
1152
gp_validate_path(const gs_memory_t *mem,
1153
                 const char        *path,
1154
                 const char        *mode)
1155
24.1M
{
1156
24.1M
    return gp_validate_path_len(mem, path, strlen(path), mode);
1157
24.1M
}
1158
1159
int
1160
gp_unlink(gs_memory_t *mem, const char *fname)
1161
82.3k
{
1162
82.3k
    if (gp_validate_path(mem, fname, "d") != 0)
1163
6
        return gs_error_invalidaccess;
1164
1165
82.3k
    return gp_unlink_impl(mem, fname);
1166
82.3k
}
1167
1168
int
1169
gp_rename(gs_memory_t *mem, const char *from, const char *to)
1170
0
{
1171
    /* Always check 'to' before 'from', in case 'from' is a tempfile,
1172
     * and testing it might remove it from the list! */
1173
0
    if (gp_validate_path(mem, to, "t") != 0)
1174
0
        return gs_error_invalidaccess;
1175
0
    if (gp_validate_path(mem, from, "f") != 0)
1176
0
        return gs_error_invalidaccess;
1177
1178
0
    return gp_rename_impl(mem, from, to);
1179
0
}