Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zfile.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Non-I/O file operators */
18
#include "memory_.h"
19
#include "string_.h"
20
#include "unistd_.h"
21
#include "stat_.h" /* get system header early to avoid name clash on Cygwin */
22
#include "ghost.h"
23
#include "gscdefs.h"            /* for gx_io_device_table */
24
#include "gsutil.h"             /* for bytes_compare */
25
#include "gp.h"
26
#include "gpmisc.h"
27
#include "gsfname.h"
28
#include "gsstruct.h"           /* for registering root */
29
#include "gxalloc.h"            /* for streams */
30
#include "oper.h"
31
#include "dstack.h"             /* for systemdict */
32
#include "estack.h"             /* for filenameforall, .execfile */
33
#include "ialloc.h"
34
#include "ilevel.h"             /* %names only work in Level 2 */
35
#include "iname.h"
36
#include "isave.h"              /* for restore */
37
#include "idict.h"
38
#include "iddict.h"
39
#include "iutil.h"
40
#include "stream.h"
41
#include "strimpl.h"
42
#include "sfilter.h"
43
#include "gxiodev.h"            /* must come after stream.h */
44
                                /* and before files.h */
45
#include "files.h"
46
#include "main.h"               /* for gs_lib_paths */
47
#include "store.h"
48
#include "zfile.h"
49
50
/* Import the IODevice table. */
51
extern_gx_io_device_table();
52
53
/* Import the dtype of the stdio IODevices. */
54
extern const char iodev_dtype_stdio[];
55
56
/* Forward references: file name parsing. */
57
static int parse_file_name(const ref * op, gs_parsed_file_name_t * pfn,
58
                           bool safemode, gs_memory_t *memory);
59
static int parse_real_file_name(const ref * op,
60
                                 gs_parsed_file_name_t * pfn,
61
                                 gs_memory_t *mem, client_name_t cname);
62
static int parse_file_access_string(const ref *op, char file_access[4]);
63
64
/* Forward references: other. */
65
static int execfile_finish(i_ctx_t *);
66
static int execfile_cleanup(i_ctx_t *);
67
static iodev_proc_open_file(iodev_os_open_file);
68
stream_proc_report_error(filter_report_error);
69
70
/*
71
 * Since there can be many file objects referring to the same file/stream,
72
 * we can't simply free a stream when we close it.  On the other hand,
73
 * we don't want freed streams to clutter up memory needlessly.
74
 * Our solution is to retain the freed streams, and reuse them.
75
 * To prevent an old file object from being able to access a reused stream,
76
 * we keep a serial number in each stream, and check it against a serial
77
 * number stored in the file object (as the "size"); when we close a file,
78
 * we increment its serial number.  If the serial number ever overflows,
79
 * we leave it at zero, and do not reuse the stream.
80
 * (This will never happen.)
81
 *
82
 * Storage management for this scheme is a little tricky.  We maintain an
83
 * invariant that says that a stream opened at a given save level always
84
 * uses a stream structure allocated at that level.  By doing this, we don't
85
 * need to keep track separately of streams open at a level vs. streams
86
 * allocated at a level.  To make this interact properly with save and
87
 * restore, we maintain a list of all streams allocated at this level, both
88
 * open and closed.  We store this list in the allocator: this is a hack,
89
 * but it simplifies bookkeeping (in particular, it guarantees the list is
90
 * restored properly by a restore).
91
 *
92
 * We want to close streams freed by restore and by garbage collection.  We
93
 * use the finalization procedure for this.  For restore, we don't have to
94
 * do anything special to make this happen.  For garbage collection, we do
95
 * something more drastic: we simply clear the list of known streams (at all
96
 * save levels).  Any streams open at the time of garbage collection will no
97
 * longer participate in the list of known streams, but this does no harm;
98
 * it simply means that they won't get reused, and can only be reclaimed by
99
 * a future garbage collection or restore.
100
 */
101
102
/*
103
 * Define the default stream buffer sizes.  For file streams,
104
 * this is arbitrary, since the C library or operating system
105
 * does its own buffering in addition.
106
 * However, a buffer size of at least 2K bytes is necessary to prevent
107
 * JPEG decompression from running very slow. When less than 2K, an
108
 * intermediate filter is installed that transfers 1 byte at a time
109
 * causing many aborted roundtrips through the JPEG filter code.
110
 */
111
#define DEFAULT_BUFFER_SIZE 2048
112
extern const uint file_default_buffer_size;
113
114
/* Make an invalid file object. */
115
void
116
make_invalid_file(i_ctx_t *i_ctx_p, ref * fp)
117
0
{
118
0
    make_file(fp, avm_invalid_file_entry, ~0, i_ctx_p->invalid_file_stream);
119
0
}
120
121
/* Check a file name for permission by stringmatch on one of the */
122
/* strings of the permitgroup array. */
123
static int
124
check_file_permissions_reduced(i_ctx_t *i_ctx_p, const char *fname, int len,
125
                        gx_io_device *iodev, const char *permitgroup)
126
53.1M
{
127
53.1M
    long i;
128
53.1M
    ref *permitlist = NULL;
129
    /* an empty string (first character == 0) if '\' character is */
130
    /* recognized as a file name separator as on DOS & Windows    */
131
53.1M
    const char *win_sep2 = "\\";
132
53.1M
    bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
133
53.1M
    uint plen = gp_file_name_parents(fname, len);
134
135
    /* we're protecting arbitrary file system accesses, not Postscript device accesses.
136
     * Although, note that %pipe% is explicitly checked for and disallowed elsewhere
137
     */
138
53.1M
    if (iodev && iodev != iodev_default(imemory)) {
139
15.9M
        return 0;
140
15.9M
    }
141
142
    /* Assuming a reduced file name. */
143
37.2M
    if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
144
0
        return 0;       /* if Permissions not found, just allow access */
145
146
37.2M
    for (i=0; i<r_size(permitlist); i++) {
147
37.2M
        ref permitstring;
148
37.2M
        const string_match_params win_filename_params = {
149
37.2M
                '*', '?', '\\', true, true      /* ignore case & '/' == '\\' */
150
37.2M
        };
151
37.2M
        const byte *permstr;
152
37.2M
        uint permlen;
153
37.2M
        int cwd_len = 0;
154
155
37.2M
        if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
156
37.2M
            r_type(&permitstring) != t_string
157
37.2M
           )
158
0
            break;      /* any problem, just fail */
159
37.2M
        permstr = permitstring.value.bytes;
160
37.2M
        permlen = r_size(&permitstring);
161
        /*
162
         * Check if any file name is permitted with "*".
163
         */
164
37.2M
        if (permlen == 1 && permstr[0] == '*')
165
37.2M
            return 0;           /* success */
166
        /*
167
         * If the filename starts with parent references,
168
         * the permission element must start with same number of parent references.
169
         */
170
0
        if (plen != 0 && plen != gp_file_name_parents((const char *)permstr, permlen))
171
0
            continue;
172
0
        cwd_len = gp_file_name_cwds((const char *)permstr, permlen);
173
        /*
174
         * If the permission starts with "./", absolute paths
175
         * are not permitted.
176
         */
177
0
        if (cwd_len > 0 && gp_file_name_is_absolute(fname, len))
178
0
            continue;
179
        /*
180
         * If the permission starts with "./", relative paths
181
         * with no "./" are allowed as well as with "./".
182
         * 'fname' has no "./" because it is reduced.
183
         */
184
0
        if (string_match( (const unsigned char*) fname, len,
185
0
                          permstr + cwd_len, permlen - cwd_len,
186
0
                use_windows_pathsep ? &win_filename_params : NULL))
187
0
            return 0;           /* success */
188
0
    }
189
    /* not found */
190
0
    return gs_error_invalidfileaccess;
191
37.2M
}
192
193
/* Check a file name for permission by stringmatch on one of the */
194
/* strings of the permitgroup array */
195
static int
196
check_file_permissions(i_ctx_t *i_ctx_p, const char *fname, int len,
197
                        gx_io_device *iodev, const char *permitgroup)
198
53.1M
{
199
53.1M
    char fname_reduced[gp_file_name_sizeof];
200
53.1M
    uint rlen = sizeof(fname_reduced);
201
202
53.1M
    if (gp_file_name_reduce(fname, len, fname_reduced, &rlen) != gp_combine_success)
203
0
        return gs_error_invalidaccess;         /* fail if we couldn't reduce */
204
53.1M
    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
205
53.1M
}
206
207
/* z_check_file_permissions: see zfile.h for explanation
208
 */
209
int
210
z_check_file_permissions(gs_memory_t *mem, const char *fname, const int len, const char *permission)
211
13.4M
{
212
13.4M
    i_ctx_t *i_ctx_p = get_minst_from_memory(mem)->i_ctx_p;
213
13.4M
    gs_parsed_file_name_t pname;
214
13.4M
    const char *permitgroup = permission[0] == 'r' ? "PermitFileReading" : "PermitFileWriting";
215
13.4M
    int code = gs_parse_file_name(&pname, fname, len, imemory);
216
13.4M
    if (code < 0)
217
0
        return code;
218
219
13.4M
    if (pname.iodev && i_ctx_p->LockFilePermissions
220
13.4M
         && strcmp(pname.iodev->dname, "%pipe%") == 0) {
221
0
        code = gs_note_error(gs_error_invalidfileaccess);
222
0
    }
223
13.4M
    else {
224
13.4M
        code = check_file_permissions(i_ctx_p, pname.fname, pname.len, pname.iodev, permitgroup);
225
13.4M
    }
226
13.4M
    return code;
227
13.4M
}
228
229
/* <name_string> <access_string> file <file> */
230
int                             /* exported for zsysvm.c */
231
zfile(i_ctx_t *i_ctx_p)
232
43.1M
{
233
43.1M
    os_ptr op = osp;
234
43.1M
    char file_access[4];
235
43.1M
    gs_parsed_file_name_t pname;
236
43.1M
    int code = parse_file_access_string(op, file_access);
237
43.1M
    stream *s;
238
239
43.1M
    if (code < 0)
240
44
        return code;
241
43.1M
    code = parse_file_name(op-1, &pname, i_ctx_p->LockFilePermissions, imemory);
242
43.1M
    if (code < 0)
243
7
        return code;
244
        /*
245
         * HACK: temporarily patch the current context pointer into the
246
         * state pointer for stdio-related devices.  See ziodev.c for
247
         * more information.
248
         */
249
43.1M
    if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) {
250
38.8M
        bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0);
251
38.8M
        bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0);
252
38.8M
        if (pname.fname)
253
0
            return_error(gs_error_invalidfileaccess);
254
38.8M
        if (statement || lineedit) {
255
            /* These need special code to support callouts */
256
0
            gx_io_device *indev = gs_findiodevice(imemory,
257
0
                                                  (const byte *)"%stdin", 6);
258
0
            stream *ins;
259
0
            if (strcmp(file_access, "r"))
260
0
                return_error(gs_error_invalidfileaccess);
261
0
            indev->state = i_ctx_p;
262
0
            code = (indev->procs.open_device)(indev, file_access, &ins, imemory);
263
0
            indev->state = 0;
264
0
            if (code < 0)
265
0
                return code;
266
0
            check_ostack(2);
267
0
            push(2);
268
0
            make_stream_file(op - 3, ins, file_access);
269
0
            make_bool(op-2, statement);
270
0
            make_int(op-1, 0);
271
0
            make_string(op, icurrent_space, 0, NULL);
272
0
            return zfilelineedit(i_ctx_p);
273
0
        }
274
38.8M
        pname.iodev->state = i_ctx_p;
275
38.8M
        code = (*pname.iodev->procs.open_device)(pname.iodev,
276
38.8M
                                                 file_access, &s, imemory);
277
38.8M
        pname.iodev->state = NULL;
278
38.8M
    } else {
279
4.28M
        if (pname.iodev == NULL)
280
1.79M
            pname.iodev = iodev_default(imemory);
281
4.28M
        code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory);
282
4.28M
    }
283
43.1M
    if (code < 0)
284
3.39M
        return code;
285
39.7M
    if (s == NULL)
286
43
        return_error(gs_error_undefinedfilename);
287
39.7M
    code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1));
288
39.7M
    if (code < 0) {
289
0
        sclose(s);
290
0
        return_error(gs_error_VMerror);
291
0
    }
292
39.7M
    make_stream_file(op - 1, s, file_access);
293
39.7M
    pop(1);
294
39.7M
    return code;
295
39.7M
}
296
297
/*
298
 * Files created with .tempfile permit some operations even if the
299
 * temp directory is not explicitly named on the PermitFile... path
300
 * The names 'SAFETY' and 'tempfiles' are defined by gs_init.ps
301
*/
302
static bool
303
file_is_tempfile(i_ctx_t *i_ctx_p, const uchar *fname, int len)
304
0
{
305
0
    ref *SAFETY;
306
0
    ref *tempfiles;
307
0
    ref kname;
308
309
0
    if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
310
0
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0)
311
0
        return false;
312
0
    if (name_ref(imemory, fname, len, &kname, -1) < 0 ||
313
0
            dict_find(tempfiles, &kname, &SAFETY) <= 0)
314
0
        return false;
315
0
    return true;
316
0
}
317
318
static int
319
record_file_is_tempfile(i_ctx_t *i_ctx_p, const uchar *fname, int len, bool add)
320
94.5k
{
321
94.5k
    ref *SAFETY;
322
94.5k
    ref *tempfiles;
323
94.5k
    ref kname, bref;
324
94.5k
    int code = 0;
325
326
94.5k
    if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
327
94.5k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0) {
328
0
        return 0;
329
0
    }
330
94.5k
    if ((code = name_ref(imemory, fname, len, &kname, 1)) < 0) {
331
0
        return code;
332
0
    }
333
94.5k
    make_bool(&bref, true);
334
94.5k
    if (add)
335
94.5k
        return idict_put(tempfiles, &kname, &bref);
336
0
    else
337
0
        return idict_undef(tempfiles, &kname);
338
94.5k
}
339
340
/* ------ Level 2 extensions ------ */
341
342
/* <string> deletefile - */
343
static int
344
zdeletefile(i_ctx_t *i_ctx_p)
345
94.2k
{
346
94.2k
    os_ptr op = osp;
347
94.2k
    gs_parsed_file_name_t pname;
348
94.2k
    int code;
349
94.2k
    bool is_temp = false;
350
351
94.2k
    check_op(1);
352
94.2k
    code = parse_real_file_name(op, &pname, imemory, "deletefile");
353
94.2k
    if (code < 0)
354
4
        return code;
355
94.1k
    if (pname.iodev == iodev_default(imemory)) {
356
94.1k
        if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
357
94.1k
                pname.iodev, "PermitFileControl")) < 0 &&
358
94.1k
                 !(is_temp = file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op)))) {
359
0
            return code;
360
0
        }
361
94.1k
    }
362
363
94.1k
    code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
364
365
94.1k
    if (code >= 0 && is_temp)
366
0
        code = record_file_is_tempfile(i_ctx_p, (unsigned char *)pname.fname, strlen(pname.fname), false);
367
368
94.1k
    gs_free_file_name(&pname, "deletefile");
369
94.1k
    if (code < 0)
370
15
        return code;
371
94.1k
    pop(1);
372
94.1k
    return 0;
373
94.1k
}
374
375
/* <template> <proc> <scratch> filenameforall - */
376
static int file_continue(i_ctx_t *);
377
static int file_cleanup(i_ctx_t *);
378
static int
379
zfilenameforall(i_ctx_t *i_ctx_p)
380
2.27M
{
381
2.27M
    os_ptr op = osp;
382
2.27M
    file_enum *pfen;
383
2.27M
    gx_io_device *iodev = NULL;
384
2.27M
    gs_parsed_file_name_t pname;
385
2.27M
    int code = 0;
386
387
2.27M
    check_op(3);
388
2.27M
    check_write_type(*op, t_string);
389
2.27M
    check_proc(op[-1]);
390
2.27M
    check_read_type(op[-2], t_string);
391
    /* Push a mark, the iodev, devicenamelen, the scratch string, the enumerator, */
392
    /* and the procedure, and invoke the continuation. */
393
2.27M
    check_estack(7);
394
    /* Get the iodevice */
395
2.27M
    code = parse_file_name(op-2, &pname, i_ctx_p->LockFilePermissions, imemory);
396
2.27M
    if (code < 0)
397
0
        return code;
398
2.27M
    iodev = (pname.iodev == NULL) ? iodev_default(imemory) : pname.iodev;
399
400
    /* Check for several conditions that just cause us to return success */
401
2.27M
    if (pname.len == 0 || iodev->procs.enumerate_files == iodev_no_enumerate_files) {
402
0
        pop(3);
403
0
        return 0;       /* no pattern, or device not found -- just return */
404
0
    }
405
2.27M
    pfen = iodev->procs.enumerate_files(imemory, iodev, (const char *)pname.fname,
406
2.27M
                pname.len);
407
2.27M
    if (pfen == 0)
408
0
        return_error(gs_error_VMerror);
409
2.27M
    push_mark_estack(es_for, file_cleanup);
410
2.27M
    ++esp;
411
2.27M
    make_istruct(esp, 0, iodev);
412
2.27M
    ++esp;
413
2.27M
    make_int(esp, r_size(op-2) - pname.len);
414
2.27M
    *++esp = *op;
415
2.27M
    ++esp;
416
2.27M
    make_istruct(esp, 0, pfen);
417
2.27M
    *++esp = op[-1];
418
2.27M
    ref_stack_pop(&o_stack, 3);
419
2.27M
    code = file_continue(i_ctx_p);
420
2.27M
    return code;
421
2.27M
}
422
/* Continuation operator for enumerating files */
423
static int
424
file_continue(i_ctx_t *i_ctx_p)
425
2.59M
{
426
2.59M
    os_ptr op = osp;
427
2.59M
    es_ptr pscratch = esp - 2;
428
2.59M
    file_enum *pfen = r_ptr(esp - 1, file_enum);
429
2.59M
    int devlen = esp[-3].value.intval;
430
2.59M
    gx_io_device *iodev = r_ptr(esp - 4, gx_io_device);
431
2.59M
    uint len = r_size(pscratch);
432
2.59M
    uint code;
433
434
2.59M
    if (len < devlen) {
435
0
        esp -= 6;               /* pop proc, pfen, scratch, devlen, iodev , mark */
436
0
        return_error(gs_error_rangecheck);     /* not even room for device len */
437
0
    }
438
439
2.59M
    do {
440
2.59M
        memcpy((char *)pscratch->value.bytes, iodev->dname, devlen);
441
2.59M
        code = iodev->procs.enumerate_next(imemory, pfen, (char *)pscratch->value.bytes + devlen,
442
2.59M
                    len - devlen);
443
2.59M
        if (code == ~(uint) 0) {    /* all done */
444
2.27M
            esp -= 6;               /* pop proc, pfen, scratch, devlen, iodev , mark */
445
2.27M
            return o_pop_estack;
446
2.27M
        } else if (code > len - devlen) {      /* overran string */
447
0
            return_error(gs_error_rangecheck);
448
0
        }
449
324k
        else if (iodev != iodev_default(imemory)
450
324k
              || (check_file_permissions(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, iodev, "PermitFileReading")) == 0) {
451
324k
            push(1);
452
324k
            ref_assign(op, pscratch);
453
324k
            r_set_size(op, code + devlen);
454
324k
            push_op_estack(file_continue);  /* come again */
455
324k
            *++esp = pscratch[2];   /* proc */
456
324k
            return o_push_estack;
457
324k
        }
458
2.59M
    } while(1);
459
2.59M
}
460
/* Cleanup procedure for enumerating files */
461
static int
462
file_cleanup(i_ctx_t *i_ctx_p)
463
0
{
464
0
    gx_io_device *iodev = r_ptr(esp + 2, gx_io_device);
465
466
0
    iodev->procs.enumerate_close(imemory, r_ptr(esp + 5, file_enum));
467
    /* See bug #707007, gp_enumerate_file_close() explicitly frees the file enumerator */
468
0
    make_null(esp + 5);
469
0
    return 0;
470
0
}
471
472
/* <string1> <string2> renamefile - */
473
static int
474
zrenamefile(i_ctx_t *i_ctx_p)
475
12
{
476
12
    int code;
477
12
    os_ptr op = osp;
478
12
    gs_parsed_file_name_t pname1, pname2;
479
480
12
    check_op(2);
481
2
    code = parse_real_file_name(op, &pname2, imemory, "renamefile(to)");
482
2
    if (code < 0)
483
2
        return code;
484
485
0
    pname1.fname = 0;
486
0
    code = parse_real_file_name(op - 1, &pname1, imemory, "renamefile(from)");
487
0
    if (code >= 0) {
488
0
        gx_io_device *iodev_dflt = iodev_default(imemory);
489
0
        if (pname1.iodev != pname2.iodev ) {
490
0
            if (pname1.iodev == iodev_dflt)
491
0
                pname1.iodev = pname2.iodev;
492
0
            if (pname2.iodev == iodev_dflt)
493
0
                pname2.iodev = pname1.iodev;
494
0
        }
495
0
        if (pname1.iodev != pname2.iodev ||
496
0
            (pname1.iodev == iodev_dflt &&
497
                /*
498
                 * We require FileControl permissions on the source path
499
                 * unless it is a temporary file. Also, we require FileControl
500
                 * and FileWriting permissions to the destination file/path.
501
                 */
502
0
              ((check_file_permissions(i_ctx_p, pname1.fname, pname1.len,
503
0
                                        pname1.iodev, "PermitFileControl") < 0 &&
504
0
                  !file_is_tempfile(i_ctx_p, op[-1].value.bytes, r_size(op - 1))) ||
505
0
              (check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
506
0
                                        pname2.iodev, "PermitFileControl") < 0 ||
507
0
              check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
508
0
                                        pname2.iodev, "PermitFileWriting") < 0 )))) {
509
0
            code = gs_note_error(gs_error_invalidfileaccess);
510
0
        } else {
511
0
            code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
512
0
                            pname1.fname, pname2.fname);
513
0
        }
514
0
    }
515
0
    gs_free_file_name(&pname2, "renamefile(to)");
516
0
    gs_free_file_name(&pname1, "renamefile(from)");
517
0
    if (code < 0)
518
0
        return code;
519
0
    pop(2);
520
0
    return 0;
521
0
}
522
523
/* <file> status <open_bool> */
524
/* <string> status <pages> <bytes> <ref_time> <creation_time> true */
525
/* <string> status false */
526
static int
527
zstatus(i_ctx_t *i_ctx_p)
528
2.80M
{
529
2.80M
    os_ptr op = osp;
530
531
2.80M
    check_op(1);
532
2.80M
    switch (r_type(op)) {
533
346k
        case t_file:
534
346k
            {
535
346k
                stream *s;
536
537
346k
                make_bool(op, (file_is_valid(s, op) ? 1 : 0));
538
346k
            }
539
346k
            return 0;
540
2.45M
        case t_string:
541
2.45M
            {
542
2.45M
                gs_parsed_file_name_t pname;
543
2.45M
                struct stat fstat;
544
2.45M
                int code = parse_file_name(op, &pname,
545
2.45M
                                           i_ctx_p->LockFilePermissions, imemory);
546
2.45M
                if (code < 0) {
547
2
                    if (code == gs_error_undefinedfilename) {
548
2
                        make_bool(op, 0);
549
2
                        code = 0;
550
2
                    }
551
2
                    return code;
552
2
                }
553
2.45M
                code = gs_terminate_file_name(&pname, imemory, "status");
554
2.45M
                if (code < 0)
555
0
                    return code;
556
2.45M
                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
557
2.45M
                                       pname.iodev, "PermitFileReading")) >= 0) {
558
2.45M
                    code = (*pname.iodev->procs.file_status)(pname.iodev,
559
2.45M
                                                       pname.fname, &fstat);
560
2.45M
                }
561
2.45M
                switch (code) {
562
1.18M
                    case 0:
563
1.18M
                        check_ostack(4);
564
                        /*
565
                         * Check to make sure that the file size fits into
566
                         * a PostScript integer.  (On some systems, long is
567
                         * 32 bits, but file sizes are 64 bits.)
568
                         */
569
1.18M
                        push(4);
570
1.18M
                        make_int(op - 4, stat_blocks(&fstat));
571
1.18M
                        make_int(op - 3, fstat.st_size);
572
                        /*
573
                         * We can't check the value simply by using ==,
574
                         * because signed/unsigned == does the wrong thing.
575
                         * Instead, since integer assignment only keeps the
576
                         * bottom bits, we convert the values to double
577
                         * and then test for equality.  This handles all
578
                         * cases of signed/unsigned or width mismatch.
579
                         */
580
1.18M
                        if ((double)op[-4].value.intval !=
581
1.18M
                              (double)stat_blocks(&fstat) ||
582
1.18M
                            (double)op[-3].value.intval !=
583
1.18M
                              (double)fstat.st_size
584
1.18M
                            )
585
0
                            return_error(gs_error_limitcheck);
586
1.18M
                        make_int(op - 2, fstat.st_mtime);
587
1.18M
                        make_int(op - 1, fstat.st_ctime);
588
1.18M
                        make_bool(op, 1);
589
1.18M
                        break;
590
1.26M
                    case gs_error_undefinedfilename:
591
1.26M
                        make_bool(op, 0);
592
1.26M
                        code = 0;
593
2.45M
                }
594
2.45M
                gs_free_file_name(&pname, "status");
595
2.45M
                return code;
596
2.45M
            }
597
7
        default:
598
7
            return_op_typecheck(op);
599
2.80M
    }
600
2.80M
}
601
602
/* ------ Non-standard extensions ------ */
603
604
/* <executable_file> .execfile - */
605
static int
606
zexecfile(i_ctx_t *i_ctx_p)
607
0
{
608
0
    os_ptr op = osp;
609
610
0
    check_op(1);
611
0
    check_type_access(*op, t_file, a_executable | a_read | a_execute);
612
0
    check_estack(4);            /* cleanup, file, finish, file */
613
0
    push_mark_estack(es_other, execfile_cleanup);
614
0
    *++esp = *op;
615
0
    push_op_estack(execfile_finish);
616
0
    return zexec(i_ctx_p);
617
0
}
618
/* Finish normally. */
619
static int
620
execfile_finish(i_ctx_t *i_ctx_p)
621
0
{
622
0
    check_ostack(1);
623
0
    esp -= 2;
624
0
    execfile_cleanup(i_ctx_p);
625
0
    return o_pop_estack;
626
0
}
627
/* Clean up by closing the file. */
628
static int
629
execfile_cleanup(i_ctx_t *i_ctx_p)
630
0
{
631
0
    check_ostack(1);
632
0
    *++osp = esp[2];
633
0
    return zclosefile(i_ctx_p);
634
0
}
635
636
/* - .filenamelistseparator <string> */
637
static int
638
zfilenamelistseparator(i_ctx_t *i_ctx_p)
639
0
{
640
0
    os_ptr op = osp;
641
642
0
    push(1);
643
0
    make_const_string(op, avm_foreign | a_readonly, 1,
644
0
                      (const byte *)&gp_file_name_list_separator);
645
0
    return 0;
646
0
}
647
648
/* <name> .filenamesplit <dir> <base> <extension> */
649
static int
650
zfilenamesplit(i_ctx_t *i_ctx_p)
651
0
{
652
0
    os_ptr op = osp;
653
654
0
    check_op(1);
655
0
    check_read_type(*op, t_string);
656
/****** NOT IMPLEMENTED YET ******/
657
0
    return_error(gs_error_undefined);
658
0
}
659
660
/* <string> .libfile <file> true */
661
/* <string> .libfile <string> false */
662
int                             /* exported for zsysvm.c */
663
zlibfile(i_ctx_t *i_ctx_p)
664
5.25M
{
665
5.25M
    os_ptr op = osp;
666
5.25M
    int code;
667
5.25M
    byte cname[DEFAULT_BUFFER_SIZE];
668
5.25M
    uint clen;
669
5.25M
    gs_parsed_file_name_t pname;
670
5.25M
    stream *s;
671
5.25M
    gx_io_device *iodev_dflt;
672
673
5.25M
    check_op(1); /* Enough arguments */
674
5.25M
    check_ostack(2); /* Enough space for our results */
675
5.25M
    code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions, imemory);
676
5.25M
    if (code < 0)
677
766
        return code;
678
5.25M
    iodev_dflt = iodev_default(imemory);
679
5.25M
    if (pname.iodev == NULL)
680
3.86M
        pname.iodev = iodev_dflt;
681
5.25M
    if (pname.iodev != iodev_dflt) { /* Non-OS devices don't have search paths (yet). */
682
1.39M
        code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
683
1.39M
        if (s == NULL) code = gs_note_error(gs_error_undefinedfilename);
684
1.39M
        if (code >= 0) {
685
162k
            code = ssetfilename(s, op->value.const_bytes, r_size(op));
686
162k
            if (code < 0) {
687
0
                sclose(s);
688
0
                return_error(gs_error_VMerror);
689
0
            }
690
162k
        }
691
1.39M
        if (code < 0) {
692
1.23M
            push(1);
693
1.23M
            make_false(op);
694
1.23M
            return 0;
695
1.23M
        }
696
162k
        make_stream_file(op, s, "r");
697
3.86M
    } else {
698
3.86M
        ref fref;
699
700
3.86M
        code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len,
701
3.86M
                             (char *)cname, sizeof(cname), &clen, &fref);
702
3.86M
        if (code >= 0) {
703
649k
            s = fptr(&fref);
704
649k
            code = ssetfilename(s, cname, clen);
705
649k
            if (code < 0) {
706
0
                sclose(s);
707
0
                return_error(gs_error_VMerror);
708
0
            }
709
649k
        }
710
3.86M
        if (code < 0) {
711
3.21M
            if (code == gs_error_VMerror || code == gs_error_invalidfileaccess)
712
0
                return code;
713
3.21M
            push(1);
714
3.21M
            make_false(op);
715
3.21M
            return 0;
716
3.21M
        }
717
649k
        ref_assign(op, &fref);
718
649k
    }
719
5.25M
    push(1);
720
812k
    make_true(op);
721
812k
    return 0;
722
812k
}
723
724
/* A "simple" prefix is defined as a (possibly empty) string of
725
   alphanumeric, underscore, and hyphen characters. */
726
static bool
727
prefix_is_simple(const char *pstr)
728
94.5k
{
729
94.5k
    int i;
730
94.5k
    char c;
731
732
378k
    for (i = 0; (c = pstr[i]) != 0; i++) {
733
283k
        if (!(c == '-' || c == '_' || (c >= '0' && c <= '9') ||
734
283k
              (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
735
0
            return false;
736
283k
    }
737
94.5k
    return true;
738
94.5k
}
739
740
/* <prefix|null> <access_string> .tempfile <name_string> <file> */
741
static int
742
ztempfile(i_ctx_t *i_ctx_p)
743
94.5k
{
744
94.5k
    os_ptr op = osp;
745
94.5k
    const char *pstr;
746
94.5k
    char fmode[4];
747
94.5k
    char fmode_temp[4];
748
94.5k
    int code;
749
94.5k
    char *prefix = NULL;
750
94.5k
    char *fname= NULL;
751
94.5k
    uint fnlen;
752
94.5k
    gp_file *sfile;
753
94.5k
    stream *s;
754
94.5k
    byte *buf, *sbody;
755
756
94.5k
    check_op(2);
757
94.5k
    code = parse_file_access_string(op, fmode_temp);
758
94.5k
    if (code < 0)
759
0
        return code;
760
94.5k
    prefix = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(prefix)");
761
94.5k
    fname = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(fname)");
762
94.5k
    if (!prefix || !fname) {
763
0
        code = gs_note_error(gs_error_VMerror);
764
0
        goto done;
765
0
    }
766
767
94.5k
    snprintf(fmode, sizeof(fmode), "%s%s", fmode_temp, gp_fmode_binary_suffix);
768
94.5k
    if (r_has_type(op - 1, t_null))
769
94.5k
        pstr = gp_scratch_file_name_prefix;
770
0
    else {
771
0
        uint psize;
772
773
0
        check_read_type(op[-1], t_string);
774
0
        psize = r_size(op - 1);
775
0
        if (psize >= gp_file_name_sizeof) {
776
0
            code = gs_note_error(gs_error_rangecheck);
777
0
            goto done;
778
0
        }
779
0
        memcpy(prefix, op[-1].value.const_bytes, psize);
780
0
        prefix[psize] = 0;
781
0
        pstr = prefix;
782
0
    }
783
784
94.5k
    if (gp_file_name_is_absolute(pstr, strlen(pstr))) {
785
0
        int plen = strlen(pstr);
786
0
        const char *sep = gp_file_name_separator();
787
0
        int seplen = strlen(sep);
788
789
        /* This should not be possible if gp_file_name_is_absolute is true I think
790
         * But let's avoid the problem.
791
         */
792
0
        if (plen < seplen)
793
0
            return_error(gs_error_Fatal);
794
795
0
        plen -= seplen;
796
        /* strip off the file name prefix, leave just the directory name
797
         * so we can check if we are allowed to write to it
798
         */
799
0
        for ( ; plen >=0; plen--) {
800
0
            if ( gs_file_name_check_separator(&pstr[plen], seplen, &pstr[plen]))
801
0
                break;
802
0
        }
803
0
        if (plen < 0)
804
0
            return_error(gs_error_Fatal);
805
806
0
        memcpy(fname, pstr, plen);
807
0
        fname[plen] = '\0';
808
0
        if (check_file_permissions(i_ctx_p, fname, strlen(fname),
809
0
                                   NULL, "PermitFileWriting") < 0) {
810
0
            code = gs_note_error(gs_error_invalidfileaccess);
811
0
            goto done;
812
0
        }
813
94.5k
    } else if (!prefix_is_simple(pstr)) {
814
0
        code = gs_note_error(gs_error_invalidfileaccess);
815
0
        goto done;
816
0
    }
817
818
94.5k
    s = file_alloc_stream(imemory, "ztempfile(stream)");
819
94.5k
    if (s == 0) {
820
0
        code = gs_note_error(gs_error_VMerror);
821
0
        goto done;
822
0
    }
823
94.5k
    buf = gs_alloc_bytes(imemory, file_default_buffer_size,
824
94.5k
                         "ztempfile(buffer)");
825
94.5k
    if (buf == 0) {
826
0
        code = gs_note_error(gs_error_VMerror);
827
0
        goto done;
828
0
    }
829
94.5k
    sfile = gp_open_scratch_file(imemory, pstr, fname, fmode);
830
94.5k
    if (sfile == 0) {
831
0
        gs_free_object(imemory, buf, "ztempfile(buffer)");
832
0
        code = gs_note_error(gs_error_invalidfileaccess);
833
0
        goto done;
834
0
    }
835
94.5k
    fnlen = strlen(fname);
836
94.5k
    sbody = ialloc_string(fnlen, ".tempfile(fname)");
837
94.5k
    if (sbody == 0) {
838
0
        gs_free_object(imemory, buf, "ztempfile(buffer)");
839
0
        code = gs_note_error(gs_error_VMerror);
840
0
        goto done;
841
0
    }
842
94.5k
    memcpy(sbody, fname, fnlen);
843
94.5k
    file_init_stream(s, sfile, fmode, buf, file_default_buffer_size);
844
94.5k
    code = ssetfilename(s, (const unsigned char*) fname, fnlen);
845
94.5k
    if (code < 0) {
846
0
        gx_io_device *iodev_dflt = iodev_default(imemory);
847
0
        sclose(s);
848
0
        iodev_dflt->procs.delete_file(iodev_dflt, fname);
849
0
        ifree_string(sbody, fnlen, ".tempfile(fname)");
850
0
        code = gs_note_error(gs_error_VMerror);
851
0
        goto done;
852
0
    }
853
94.5k
    make_string(op - 1, a_readonly | icurrent_space, fnlen, sbody);
854
94.5k
    make_stream_file(op, s, fmode);
855
94.5k
    code = record_file_is_tempfile(i_ctx_p, (unsigned char *)fname, fnlen, true);
856
857
94.5k
done:
858
94.5k
    if (prefix)
859
94.5k
        gs_free_object(imemory, prefix, "ztempfile(prefix)");
860
94.5k
    if (fname)
861
94.5k
        gs_free_object(imemory, fname, "ztempfile(fname)");
862
94.5k
    return code;
863
94.5k
}
864
865
/* Return the filename used to open a file object
866
 * this is currently only used by the PDF interpreter to
867
 * get a filename corresponding to the PDF file being
868
 * executed. Since we always execute PDF files from disk
869
 * this will always be OK.
870
 */
871
static int zgetfilename(i_ctx_t *i_ctx_p)
872
0
{
873
0
    os_ptr op = osp;
874
0
    uint fnlen;
875
0
    gs_const_string pfname;
876
0
    stream *s;
877
0
    byte *sbody;
878
0
    int code;
879
880
0
    check_op(1);
881
0
    check_ostack(1);
882
0
    check_read_type(*op, t_file);
883
884
0
    s = (op)->value.pfile;
885
886
0
    code = sfilename(s, &pfname);
887
0
    if (code < 0) {
888
0
        pfname.size = 0;
889
0
    }
890
891
0
    fnlen = pfname.size;
892
0
    sbody = ialloc_string(fnlen, ".getfilename");
893
0
    if (sbody == 0) {
894
0
        code = gs_note_error(gs_error_VMerror);
895
0
        return code;
896
0
    }
897
0
    memcpy(sbody, pfname.data, fnlen);
898
0
    make_string(op, a_readonly | icurrent_space, fnlen, sbody);
899
900
0
    return 0;
901
0
}
902
903
static int zaddcontrolpath(i_ctx_t *i_ctx_p)
904
3.57M
{
905
3.57M
    int code;
906
3.57M
    os_ptr op = osp;
907
3.57M
    ref nsref;
908
3.57M
    unsigned int n = -1;
909
910
3.57M
    check_op(2);
911
3.57M
    check_read_type(*op, t_string);
912
3.57M
    check_type(op[-1], t_name);
913
914
3.57M
    name_string_ref(imemory, op-1, &nsref);
915
3.57M
    if (r_size(&nsref) == 17 &&
916
3.57M
        strncmp((const char *)nsref.value.const_bytes,
917
3.57M
                "PermitFileReading", 17) == 0) {
918
2.92M
        n = gs_permit_file_reading;
919
2.92M
    } else if (r_size(&nsref) == 17 &&
920
649k
               strncmp((const char *)nsref.value.const_bytes,
921
649k
                       "PermitFileWriting", 17) == 0) {
922
324k
        n = gs_permit_file_writing;
923
324k
    } else if (r_size(&nsref) == 17 &&
924
324k
               strncmp((const char *)nsref.value.const_bytes,
925
324k
                       "PermitFileControl", 17) == 0) {
926
324k
        n = gs_permit_file_control;
927
324k
    }
928
929
3.57M
    if (n == -1)
930
0
        code = gs_note_error(gs_error_rangecheck);
931
3.57M
    else if (gs_is_path_control_active(imemory))
932
0
        code = gs_note_error(gs_error_Fatal);
933
3.57M
    else
934
3.57M
        code = gs_add_control_path_len(imemory, n,
935
3.57M
                                       (const char *)op[0].value.const_bytes,
936
3.57M
                                       (size_t)r_size(&op[0]));
937
3.57M
    pop(2);
938
3.57M
    return code;
939
3.57M
}
940
941
static int zactivatepathcontrol(i_ctx_t *i_ctx_p)
942
162k
{
943
162k
    gs_activate_path_control(imemory, 1);
944
162k
    return 0;
945
162k
}
946
static int zcurrentpathcontrolstate(i_ctx_t *i_ctx_p)
947
162k
{
948
162k
    os_ptr op = osp;
949
162k
    push(1);
950
162k
    if (gs_is_path_control_active(imemory)) {
951
1
        make_true(op);
952
1
    }
953
162k
    else {
954
162k
        make_false(op);
955
162k
    }
956
162k
    return 0;
957
162k
}
958
959
/* ------ Initialization procedure ------ */
960
961
const op_def zfile_op_defs[] =
962
{
963
    {"1deletefile", zdeletefile},
964
    {"1.execfile", zexecfile},
965
    {"2file", zfile},
966
    {"3filenameforall", zfilenameforall},
967
    {"0.filenamelistseparator", zfilenamelistseparator},
968
    {"1.filenamesplit", zfilenamesplit},
969
    {"1.libfile", zlibfile},
970
    {"2renamefile", zrenamefile},
971
    {"1status", zstatus},
972
    {"2.tempfile", ztempfile},
973
                /* Internal operators */
974
    {"0%file_continue", file_continue},
975
    {"0%execfile_finish", execfile_finish},
976
    {"1.getfilename", zgetfilename},
977
    /* Control path operators */
978
    {"2.addcontrolpath", zaddcontrolpath},
979
    {"0.activatepathcontrol", zactivatepathcontrol},
980
    {"0.currentpathcontrolstate", zcurrentpathcontrolstate},
981
    op_def_end(0)
982
};
983
984
/* ------ File name parsing ------ */
985
986
/* Parse a file name into device and individual name. */
987
/* See gsfname.c for details. */
988
static int
989
parse_file_name(const ref * op, gs_parsed_file_name_t * pfn, bool safemode,
990
                gs_memory_t *memory)
991
53.1M
{
992
53.1M
    int code;
993
994
53.1M
    check_read_type(*op, t_string);
995
53.1M
    code = gs_parse_file_name(pfn, (const char *)op->value.const_bytes,
996
53.1M
                              r_size(op), memory);
997
53.1M
    if (code < 0)
998
769
        return code;
999
    /*
1000
     * Check here for the %pipe device which is illegal when
1001
     * LockFilePermissions is true. In the future we might want to allow
1002
     * the %pipe device to be included on the PermitFile... paths, but
1003
     * for now it is simply disallowed.
1004
     */
1005
53.1M
    if (pfn->iodev && safemode && strcmp(pfn->iodev->dname, "%pipe%") == 0)
1006
0
        return gs_error_invalidfileaccess;
1007
53.1M
    return code;
1008
53.1M
}
1009
1010
/* Parse a real (non-device) file name and convert to a C string. */
1011
/* See gsfname.c for details. */
1012
static int
1013
parse_real_file_name(const ref *op, gs_parsed_file_name_t *pfn,
1014
                     gs_memory_t *mem, client_name_t cname)
1015
94.2k
{
1016
94.2k
    check_read_type(*op, t_string);
1017
94.1k
    return gs_parse_real_file_name(pfn, (const char *)op->value.const_bytes,
1018
94.1k
                                   r_size(op), mem, cname);
1019
94.2k
}
1020
1021
/* Parse the access string for opening a file. */
1022
/* [4] is for r/w, +, b, \0. */
1023
static int
1024
parse_file_access_string(const ref *op, char file_access[4])
1025
43.2M
{
1026
43.2M
    const byte *astr;
1027
1028
43.2M
    check_read_type(*op, t_string);
1029
43.2M
    astr = op->value.const_bytes;
1030
43.2M
    switch (r_size(op)) {
1031
94.5k
        case 2:
1032
94.5k
            if (astr[1] != '+')
1033
0
                return_error(gs_error_invalidfileaccess);
1034
94.5k
            file_access[1] = '+';
1035
94.5k
            file_access[2] = 0;
1036
94.5k
            break;
1037
43.1M
        case 1:
1038
43.1M
            file_access[1] = 0;
1039
43.1M
            break;
1040
10
        default:
1041
10
            return_error(gs_error_invalidfileaccess);
1042
43.2M
    }
1043
43.2M
    switch (astr[0]) {
1044
4.70M
        case 'r':
1045
43.2M
        case 'w':
1046
43.2M
        case 'a':
1047
43.2M
            break;
1048
4
        default:
1049
4
            return_error(gs_error_invalidfileaccess);
1050
43.2M
    }
1051
43.2M
    file_access[0] = astr[0];
1052
43.2M
    return 0;
1053
43.2M
}
1054
1055
/* ------ Stream opening ------ */
1056
1057
/*
1058
 * Open a file specified by a parsed file name (which may be only a
1059
 * device).
1060
 */
1061
int
1062
zopen_file(i_ctx_t *i_ctx_p, const gs_parsed_file_name_t *pfn,
1063
           const char *file_access, stream **ps, gs_memory_t *mem)
1064
5.68M
{
1065
5.68M
    gx_io_device *const iodev = pfn->iodev;
1066
5.68M
    int code = 0;
1067
1068
5.68M
    if (pfn->fname == NULL) {     /* just a device */
1069
0
        iodev->state = i_ctx_p;
1070
0
        code = iodev->procs.open_device(iodev, file_access, ps, mem);
1071
0
        iodev->state = NULL;
1072
0
        return code;
1073
0
    }
1074
5.68M
    else {                      /* file */
1075
5.68M
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
1076
1077
5.68M
        if (open_file == 0)
1078
1.79M
            open_file = iodev_os_open_file;
1079
        /* Check OS files to make sure we allow the type of access */
1080
5.68M
        if (open_file == iodev_os_open_file) {
1081
1.79M
            code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev,
1082
1.79M
                file_access[0] == 'r' ? "PermitFileReading" : "PermitFileWriting");
1083
1084
1.79M
            if (code < 0 && !file_is_tempfile(i_ctx_p,
1085
0
                                          (const uchar *)pfn->fname, pfn->len))
1086
0
                return code;
1087
1.79M
        }
1088
5.68M
        return open_file(iodev, pfn->fname, pfn->len, file_access, ps, mem);
1089
5.68M
    }
1090
5.68M
}
1091
1092
/*
1093
 * Define the file_open procedure for the %os% IODevice (also used, as the
1094
 * default, for %pipe% and possibly others).
1095
 */
1096
static int
1097
iodev_os_open_file(gx_io_device * iodev, const char *fname, uint len,
1098
                   const char *file_access, stream ** ps, gs_memory_t * mem)
1099
37.1M
{
1100
37.1M
    return file_open_stream(fname, len, file_access,
1101
37.1M
                            file_default_buffer_size, ps,
1102
37.1M
                            iodev, iodev->procs.gp_fopen, mem);
1103
37.1M
}
1104
1105
/* Make a t_file reference to a stream. */
1106
void
1107
make_stream_file(ref * pfile, stream * s, const char *access)
1108
42.7M
{
1109
42.7M
    uint attrs =
1110
42.7M
        (access[1] == '+' ? a_write + a_read + a_execute : 0) |
1111
42.7M
        imemory_space((gs_ref_memory_t *) s->memory);
1112
1113
42.7M
    if (access[0] == 'r') {
1114
3.76M
        make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
1115
3.76M
        s->write_id = 0;
1116
38.9M
    } else {
1117
38.9M
        make_file(pfile, attrs | a_write, s->write_id, s);
1118
38.9M
        s->read_id = 0;
1119
38.9M
    }
1120
42.7M
}
1121
1122
/* return zero for success, -ve for error, +1 for continue */
1123
static int
1124
lib_file_open_search_with_no_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1125
                                     const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1126
                                     gx_io_device *iodev, bool starting_arg_file, char *fmode)
1127
8
{
1128
8
    stream *s;
1129
8
    uint blen1 = blen;
1130
8
    struct stat fstat;
1131
8
    int code = 1;
1132
1133
8
    if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success)
1134
0
      goto skip;
1135
1136
8
    if (starting_arg_file || check_file_permissions(i_ctx_p, buffer, blen1, iodev, "PermitFileReading") >= 0) {
1137
8
        if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1138
8
                       (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1139
0
            *pclen = blen1;
1140
0
            make_stream_file(pfile, s, "r");
1141
0
            code = 0;
1142
0
        }
1143
8
    }
1144
0
    else {
1145
        /* If we are not allowed to open the file by check_file_permissions_aux()
1146
         * and if the file exists, throw an error.......
1147
         * Otherwise, keep searching.
1148
         */
1149
0
        if ((*iodev->procs.file_status)(iodev,  buffer, &fstat) >= 0) {
1150
0
            code = gs_note_error(gs_error_invalidfileaccess);
1151
0
        }
1152
0
    }
1153
1154
8
 skip:
1155
8
    return code;
1156
8
}
1157
1158
/* return zero for success, -ve for error, +1 for continue */
1159
static int
1160
lib_file_open_search_with_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1161
                                  const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1162
                                  gx_io_device *iodev, bool starting_arg_file, char *fmode)
1163
4.02M
{
1164
4.02M
    stream *s;
1165
4.02M
    const gs_file_path *pfpath = lib_path;
1166
4.02M
    uint pi;
1167
4.02M
    int code = 1;
1168
1169
46.5M
    for (pi = 0; pi < r_size(&pfpath->list) && code == 1; ++pi) {
1170
42.5M
        const ref *prdir = pfpath->list.value.refs + pi;
1171
42.5M
        const char *pstr = (const char *)prdir->value.const_bytes;
1172
42.5M
        uint plen = r_size(prdir), blen1 = blen;
1173
42.5M
        gs_parsed_file_name_t pname;
1174
42.5M
        gp_file_name_combine_result r;
1175
1176
        /* We need to concatenate and parse the file name here
1177
         * if this path has a %device% prefix.              */
1178
42.5M
        if (pstr[0] == '%') {
1179
            /* We concatenate directly since gp_file_name_combine_*
1180
             * rules are not correct for other devices such as %rom% */
1181
7.23M
            code = gs_parse_file_name(&pname, pstr, plen, mem);
1182
7.23M
            if (code < 0) {
1183
0
                code = 1;
1184
0
                continue;
1185
0
            }
1186
7.23M
            if (blen < max(pname.len, plen) + flen)
1187
0
              return_error(gs_error_limitcheck);
1188
7.23M
            memcpy(buffer, pname.fname, pname.len);
1189
7.23M
            memcpy(buffer+pname.len, fname, flen);
1190
7.23M
            if (pname.iodev->procs.open_file == NULL) {
1191
0
                code = 1;
1192
0
                continue;
1193
0
            }
1194
7.23M
            code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode,
1195
7.23M
                                          &s, (gs_memory_t *)mem);
1196
7.23M
            if (code < 0) {
1197
6.42M
                code = 1;
1198
6.42M
                continue;
1199
6.42M
            }
1200
812k
            make_stream_file(pfile, s, "r");
1201
            /* fill in the buffer with the device concatenated */
1202
812k
            memcpy(buffer, pstr, plen);
1203
812k
            memcpy(buffer+plen, fname, flen);
1204
812k
            *pclen = plen + flen;
1205
812k
            code = 0;
1206
35.3M
        } else {
1207
35.3M
            r = gp_file_name_combine(pstr, plen,
1208
35.3M
                    fname, flen, false, buffer, &blen1);
1209
35.3M
            if (r != gp_combine_success)
1210
0
                continue;
1211
35.3M
            if (starting_arg_file || check_file_permissions(i_ctx_p, buffer,
1212
35.3M
                                      blen1, iodev, "PermitFileReading") >= 0) {
1213
1214
35.3M
                if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1215
35.3M
                            (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1216
0
                    *pclen = blen1;
1217
0
                    make_stream_file(pfile, s, "r");
1218
0
                    code = 0;
1219
0
                }
1220
35.3M
            }
1221
0
            else {
1222
0
                struct stat fstat;
1223
                /* If we are not allowed to open the file by check_file_permissions_aux()
1224
                 * and if the file exists, throw an error.......
1225
                 * Otherwise, keep searching.
1226
                 */
1227
0
                if ((*iodev->procs.file_status)(iodev,  (const char *)buffer, &fstat) >= 0) {
1228
0
                    code = gs_note_error(gs_error_invalidfileaccess);
1229
0
                }
1230
0
            }
1231
35.3M
        }
1232
42.5M
    }
1233
4.02M
    return code;
1234
4.02M
}
1235
1236
/* Return a file object of of the file searched for using the search paths. */
1237
/* The fname cannot contain a device part (%...%) but the lib paths might. */
1238
/* The startup code calls this to open the initialization file gs_init.ps. */
1239
/* The startup code also calls this to open @-files. */
1240
int
1241
lib_file_open(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1242
                       const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile)
1243
4.02M
{   /* i_ctx_p is NULL running arg (@) files.
1244
     * lib_path and mem are never NULL
1245
     */
1246
4.02M
    bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file;
1247
4.02M
    bool search_with_no_combine = false;
1248
4.02M
    bool search_with_combine = false;
1249
4.02M
    char fmode[2] = { 'r', 0};
1250
4.02M
    gx_io_device *iodev = iodev_default(mem);
1251
4.02M
    gs_main_instance *minst = get_minst_from_memory(mem);
1252
4.02M
    int code;
1253
1254
4.02M
    if (i_ctx_p && starting_arg_file)
1255
0
        i_ctx_p->starting_arg_file = false;
1256
1257
    /* when starting arg files (@ files) iodev_default is not yet set */
1258
4.02M
    if (iodev == 0)
1259
0
        iodev = (gx_io_device *)gx_io_device_table[0];
1260
1261
4.02M
    if (gp_file_name_is_absolute(fname, flen)) {
1262
8
       search_with_no_combine = true;
1263
8
       search_with_combine = false;
1264
4.02M
    } else {
1265
4.02M
       search_with_no_combine = starting_arg_file;
1266
4.02M
       search_with_combine = true;
1267
4.02M
    }
1268
4.02M
    if (minst->search_here_first) {
1269
0
      if (search_with_no_combine) {
1270
0
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1271
0
                                                    fname, flen, buffer, blen, pclen, pfile,
1272
0
                                                    iodev, starting_arg_file, fmode);
1273
0
        if (code <= 0) /* +ve means continue continue */
1274
0
          return code;
1275
0
      }
1276
0
      if (search_with_combine) {
1277
0
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1278
0
                                                 fname, flen, buffer, blen, pclen, pfile,
1279
0
                                                 iodev, starting_arg_file, fmode);
1280
0
        if (code <= 0) /* +ve means continue searching */
1281
0
          return code;
1282
0
      }
1283
4.02M
    } else {
1284
4.02M
      if (search_with_combine) {
1285
4.02M
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1286
4.02M
                                                 fname, flen, buffer, blen, pclen, pfile,
1287
4.02M
                                                 iodev, starting_arg_file, fmode);
1288
4.02M
        if (code <= 0) /* +ve means continue searching */
1289
812k
          return code;
1290
4.02M
      }
1291
3.21M
      if (search_with_no_combine) {
1292
8
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1293
8
                                                    fname, flen, buffer, blen, pclen, pfile,
1294
8
                                                    iodev, starting_arg_file, fmode);
1295
8
        if (code <= 0) /* +ve means continue searching */
1296
0
          return code;
1297
8
      }
1298
3.21M
    }
1299
4.02M
    return_error(gs_error_undefinedfilename);
1300
4.02M
}
1301
1302
/* The startup code calls this to open @-files. */
1303
stream *
1304
lib_sopen(const gs_file_path_ptr pfpath, const gs_memory_t *mem, const char *fname)
1305
0
{
1306
    /* We need a buffer to hold the expanded file name. */
1307
0
    char filename_found[DEFAULT_BUFFER_SIZE];
1308
0
    uint fnamelen;
1309
0
    ref obj;
1310
0
    int code;
1311
1312
    /* open the usual 'stream', then if successful, return the file */
1313
0
    code = lib_file_open(pfpath, mem, NULL, fname, strlen(fname),
1314
0
                            filename_found, sizeof(filename_found), &fnamelen, &obj);
1315
1316
0
    if (code < 0)
1317
0
        return NULL;
1318
1319
0
    return((stream *)(obj.value.pfile));
1320
0
}
1321
1322
/* Open a file stream that reads a string. */
1323
/* (This is currently used only by the ccinit feature.) */
1324
/* The string must be allocated in non-garbage-collectable (foreign) space. */
1325
int
1326
file_read_string(const byte *str, uint len, ref *pfile, gs_ref_memory_t *imem)
1327
0
{
1328
0
    stream *s = file_alloc_stream((gs_memory_t *)imem, "file_read_string");
1329
1330
0
    if (s == 0)
1331
0
        return_error(gs_error_VMerror);
1332
0
    sread_string(s, str, len);
1333
0
    s->foreign = 1;
1334
0
    s->write_id = 0;
1335
0
    make_file(pfile, a_readonly | imemory_space(imem), s->read_id, s);
1336
0
    s->save_close = s->procs.close;
1337
0
    s->procs.close = file_close_disable;
1338
0
    return 0;
1339
0
}
1340
1341
/* Report an error by storing it in the stream's error_string. */
1342
int
1343
filter_report_error(stream_state * st, const char *str)
1344
0
{
1345
0
    if_debug1m('s', st->memory, "[s]stream error: %s\n", str);
1346
0
    strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING);
1347
    /* Ensure null termination. */
1348
0
    st->error_string[STREAM_MAX_ERROR_STRING] = 0;
1349
0
    return 0;
1350
0
}
1351
1352
/* Open a file stream for a filter. */
1353
int
1354
filter_open(const char *file_access, uint buffer_size, ref * pfile,
1355
            const stream_procs * procs, const stream_template * templat,
1356
            const stream_state * st, gs_memory_t *mem)
1357
1.54M
{
1358
1.54M
    stream *s;
1359
1.54M
    uint ssize = gs_struct_type_size(templat->stype);
1360
1.54M
    stream_state *sst = 0;
1361
1.54M
    int code;
1362
1363
1.54M
    if (templat->stype != &st_stream_state) {
1364
1.47M
        sst = s_alloc_state(mem, templat->stype, "filter_open(stream_state)");
1365
1.47M
        if (sst == 0)
1366
0
            return_error(gs_error_VMerror);
1367
1.47M
    }
1368
1.54M
    code = file_open_stream((char *)0, 0, file_access, buffer_size, &s,
1369
1.54M
                                (gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
1370
1.54M
    if (code < 0) {
1371
0
        gs_free_object(mem, sst, "filter_open(stream_state)");
1372
0
        return code;
1373
0
    }
1374
1.54M
    s_std_init(s, s->cbuf, s->bsize, procs,
1375
1.54M
               (*file_access == 'r' ? s_mode_read : s_mode_write));
1376
1.54M
    s->procs.process = templat->process;
1377
1.54M
    s->save_close = s->procs.close;
1378
1.54M
    s->procs.close = file_close_file;
1379
1.54M
    if (sst == 0) {
1380
        /* This stream doesn't have any state of its own. */
1381
        /* Hack: use the stream itself as the state. */
1382
67.2k
        sst = (stream_state *) s;
1383
1.47M
    } else if (st != 0)         /* might not have client parameters */
1384
1.47M
        memcpy(sst, st, ssize);
1385
1.54M
    s->state = sst;
1386
1.54M
    s_init_state(sst, templat, mem);
1387
1.54M
    sst->report_error = filter_report_error;
1388
1389
1.54M
    if (templat->init != 0) {
1390
1.47M
        code = (*templat->init)(sst);
1391
1.47M
        if (code < 0) {
1392
0
            gs_free_object(mem, sst, "filter_open(stream_state)");
1393
0
            gs_free_object(mem, s->cbuf, "filter_open(buffer)");
1394
0
            return code;
1395
0
        }
1396
1.47M
    }
1397
1.54M
    make_stream_file(pfile, s, file_access);
1398
1.54M
    return 0;
1399
1.54M
}
1400
1401
/* Close a file object. */
1402
/* This is exported only for gsmain.c. */
1403
int
1404
file_close(ref * pfile)
1405
0
{
1406
0
    stream *s;
1407
1408
0
    if (file_is_valid(s, pfile)) {      /* closing a closed file is a no-op */
1409
0
        if (sclose(s))
1410
0
            return_error(gs_error_ioerror);
1411
0
    }
1412
0
    return 0;
1413
0
}