Coverage Report

Created: 2026-10-28 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zfile.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
38.6M
{
127
38.6M
    long i;
128
38.6M
    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
38.6M
    const char *win_sep2 = "\\";
132
38.6M
    bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
133
38.6M
    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
38.6M
    if (iodev && iodev != iodev_default(imemory)) {
139
11.9M
        return 0;
140
11.9M
    }
141
142
    /* Assuming a reduced file name. */
143
26.7M
    if (dict_find_string_with_type(&(i_ctx_p->userparams), permitgroup, &permitlist, t_array) <= 0)
144
26.7M
        return 0;       /* if Permissions not found, just allow access */
145
146
0
    for (i=0; i<r_size(permitlist); i++) {
147
0
        ref permitstring;
148
0
        const string_match_params win_filename_params = {
149
0
                '*', '?', '\\', true, true      /* ignore case & '/' == '\\' */
150
0
        };
151
0
        const byte *permstr;
152
0
        uint permlen;
153
0
        int cwd_len = 0;
154
155
0
        if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
156
0
            r_type(&permitstring) != t_string
157
0
           )
158
0
            break;      /* any problem, just fail */
159
0
        permstr = permitstring.value.bytes;
160
0
        permlen = r_size(&permitstring);
161
        /*
162
         * Check if any file name is permitted with "*".
163
         */
164
0
        if (permlen == 1 && permstr[0] == '*')
165
0
            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
0
}
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
38.6M
{
199
38.6M
    char fname_reduced[gp_file_name_sizeof];
200
38.6M
    uint rlen = sizeof(fname_reduced);
201
202
38.6M
    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
38.6M
    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
205
38.6M
}
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
9.97M
{
212
9.97M
    i_ctx_t *i_ctx_p = get_minst_from_memory(mem)->i_ctx_p;
213
9.97M
    gs_parsed_file_name_t pname;
214
9.97M
    const char *permitgroup = permission[0] == 'r' ? "PermitFileReading" : "PermitFileWriting";
215
9.97M
    int code = gs_parse_file_name(&pname, fname, len, imemory);
216
9.97M
    if (code < 0)
217
0
        return code;
218
219
9.97M
    if (pname.iodev && i_ctx_p->LockFilePermissions
220
0
         && strcmp(pname.iodev->dname, "%pipe%") == 0) {
221
0
        code = gs_note_error(gs_error_invalidfileaccess);
222
0
    }
223
9.97M
    else {
224
9.97M
        code = check_file_permissions(i_ctx_p, pname.fname, pname.len, pname.iodev, permitgroup);
225
9.97M
    }
226
9.97M
    return code;
227
9.97M
}
228
229
/* <name_string> <access_string> file <file> */
230
int                             /* exported for zsysvm.c */
231
zfile(i_ctx_t *i_ctx_p)
232
17.8M
{
233
17.8M
    os_ptr op = osp;
234
17.8M
    char file_access[4];
235
17.8M
    gs_parsed_file_name_t pname;
236
17.8M
    int code = parse_file_access_string(op, file_access);
237
17.8M
    stream *s;
238
239
17.8M
    if (code < 0)
240
33
        return code;
241
17.8M
    code = parse_file_name(op-1, &pname, i_ctx_p->LockFilePermissions, imemory);
242
17.8M
    if (code < 0)
243
6
        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
17.8M
    if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) {
250
14.2M
        bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0);
251
14.2M
        bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0);
252
14.2M
        if (pname.fname)
253
0
            return_error(gs_error_invalidfileaccess);
254
14.2M
        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
14.2M
        pname.iodev->state = i_ctx_p;
275
14.2M
        code = (*pname.iodev->procs.open_device)(pname.iodev,
276
14.2M
                                                 file_access, &s, imemory);
277
14.2M
        pname.iodev->state = NULL;
278
14.2M
    } else {
279
3.69M
        if (pname.iodev == NULL)
280
1.79M
            pname.iodev = iodev_default(imemory);
281
3.69M
        code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory);
282
3.69M
    }
283
17.8M
    if (code < 0)
284
2.81M
        return code;
285
15.0M
    if (s == NULL)
286
33
        return_error(gs_error_undefinedfilename);
287
15.0M
    code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1));
288
15.0M
    if (code < 0) {
289
0
        sclose(s);
290
0
        return_error(gs_error_VMerror);
291
0
    }
292
15.0M
    make_stream_file(op - 1, s, file_access);
293
15.0M
    pop(1);
294
15.0M
    return code;
295
15.0M
}
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
88.2k
{
321
88.2k
    ref *SAFETY;
322
88.2k
    ref *tempfiles;
323
88.2k
    ref kname, bref;
324
88.2k
    int code = 0;
325
326
88.2k
    if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
327
88.2k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0) {
328
0
        return 0;
329
0
    }
330
88.2k
    if ((code = name_ref(imemory, fname, len, &kname, 1)) < 0) {
331
0
        return code;
332
0
    }
333
88.2k
    make_bool(&bref, true);
334
88.2k
    if (add)
335
88.2k
        return idict_put(tempfiles, &kname, &bref);
336
0
    else
337
0
        return idict_undef(tempfiles, &kname);
338
88.2k
}
339
340
/* ------ Level 2 extensions ------ */
341
342
/* <string> deletefile - */
343
static int
344
zdeletefile(i_ctx_t *i_ctx_p)
345
87.9k
{
346
87.9k
    os_ptr op = osp;
347
87.9k
    gs_parsed_file_name_t pname;
348
87.9k
    int code;
349
87.9k
    bool is_temp = false;
350
351
87.9k
    check_op(1);
352
87.9k
    code = parse_real_file_name(op, &pname, imemory, "deletefile");
353
87.9k
    if (code < 0)
354
3
        return code;
355
87.9k
    if (pname.iodev == iodev_default(imemory)) {
356
87.9k
        if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
357
87.9k
                pname.iodev, "PermitFileControl")) < 0 &&
358
0
                 !(is_temp = file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op)))) {
359
0
            return code;
360
0
        }
361
87.9k
    }
362
363
87.9k
    code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
364
365
87.9k
    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
87.9k
    gs_free_file_name(&pname, "deletefile");
369
87.9k
    if (code < 0)
370
9
        return code;
371
87.9k
    pop(1);
372
87.9k
    return 0;
373
87.9k
}
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
9
{
476
9
    int code;
477
9
    os_ptr op = osp;
478
9
    gs_parsed_file_name_t pname1, pname2;
479
480
9
    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.18M
{
529
2.18M
    os_ptr op = osp;
530
531
2.18M
    check_op(1);
532
2.18M
    switch (r_type(op)) {
533
218k
        case t_file:
534
218k
            {
535
218k
                stream *s;
536
537
218k
                make_bool(op, (file_is_valid(s, op) ? 1 : 0));
538
218k
            }
539
218k
            return 0;
540
1.97M
        case t_string:
541
1.97M
            {
542
1.97M
                gs_parsed_file_name_t pname;
543
1.97M
                struct stat fstat;
544
1.97M
                int code = parse_file_name(op, &pname,
545
1.97M
                                           i_ctx_p->LockFilePermissions, imemory);
546
1.97M
                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
1.97M
                code = gs_terminate_file_name(&pname, imemory, "status");
554
1.97M
                if (code < 0)
555
0
                    return code;
556
1.97M
                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
557
1.97M
                                       pname.iodev, "PermitFileReading")) >= 0) {
558
1.97M
                    code = (*pname.iodev->procs.file_status)(pname.iodev,
559
1.97M
                                                       pname.fname, &fstat);
560
1.97M
                }
561
1.97M
                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
788k
                    case gs_error_undefinedfilename:
591
788k
                        make_bool(op, 0);
592
788k
                        code = 0;
593
1.97M
                }
594
1.97M
                gs_free_file_name(&pname, "status");
595
1.97M
                return code;
596
1.97M
            }
597
8
        default:
598
8
            return_op_typecheck(op);
599
2.18M
    }
600
2.18M
}
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
3.83M
{
665
3.83M
    os_ptr op = osp;
666
3.83M
    int code;
667
3.83M
    byte cname[DEFAULT_BUFFER_SIZE];
668
3.83M
    uint clen;
669
3.83M
    gs_parsed_file_name_t pname;
670
3.83M
    stream *s;
671
3.83M
    gx_io_device *iodev_dflt;
672
673
3.83M
    check_op(1); /* Enough arguments */
674
3.83M
    check_ostack(2); /* Enough space for our results */
675
3.83M
    code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions, imemory);
676
3.83M
    if (code < 0)
677
499
        return code;
678
3.83M
    iodev_dflt = iodev_default(imemory);
679
3.83M
    if (pname.iodev == NULL)
680
2.90M
        pname.iodev = iodev_dflt;
681
3.83M
    if (pname.iodev != iodev_dflt) { /* Non-OS devices don't have search paths (yet). */
682
926k
        code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
683
926k
        if (s == NULL) code = gs_note_error(gs_error_undefinedfilename);
684
926k
        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
926k
        if (code < 0) {
692
764k
            push(1);
693
764k
            make_false(op);
694
764k
            return 0;
695
764k
        }
696
162k
        make_stream_file(op, s, "r");
697
2.90M
    } else {
698
2.90M
        ref fref;
699
700
2.90M
        code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len,
701
2.90M
                             (char *)cname, sizeof(cname), &clen, &fref);
702
2.90M
        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
2.90M
        if (code < 0) {
711
2.25M
            if (code == gs_error_VMerror || code == gs_error_invalidfileaccess)
712
0
                return code;
713
2.25M
            push(1);
714
2.25M
            make_false(op);
715
2.25M
            return 0;
716
2.25M
        }
717
649k
        ref_assign(op, &fref);
718
649k
    }
719
3.83M
    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
88.2k
{
729
88.2k
    int i;
730
88.2k
    char c;
731
732
353k
    for (i = 0; (c = pstr[i]) != 0; i++) {
733
264k
        if (!(c == '-' || c == '_' || (c >= '0' && c <= '9') ||
734
176k
              (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
735
0
            return false;
736
264k
    }
737
88.2k
    return true;
738
88.2k
}
739
740
/* <prefix|null> <access_string> .tempfile <name_string> <file> */
741
static int
742
ztempfile(i_ctx_t *i_ctx_p)
743
88.2k
{
744
88.2k
    os_ptr op = osp;
745
88.2k
    const char *pstr;
746
88.2k
    char fmode[4];
747
88.2k
    char fmode_temp[4];
748
88.2k
    int code;
749
88.2k
    char *prefix = NULL;
750
88.2k
    char *fname= NULL;
751
88.2k
    uint fnlen;
752
88.2k
    gp_file *sfile;
753
88.2k
    stream *s;
754
88.2k
    byte *buf, *sbody;
755
756
88.2k
    check_op(2);
757
88.2k
    code = parse_file_access_string(op, fmode_temp);
758
88.2k
    if (code < 0)
759
0
        return code;
760
88.2k
    prefix = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(prefix)");
761
88.2k
    fname = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(fname)");
762
88.2k
    if (!prefix || !fname) {
763
0
        code = gs_note_error(gs_error_VMerror);
764
0
        goto done;
765
0
    }
766
767
88.2k
    snprintf(fmode, sizeof(fmode), "%s%s", fmode_temp, gp_fmode_binary_suffix);
768
88.2k
    if (r_has_type(op - 1, t_null))
769
88.2k
        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
88.2k
    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
88.2k
    } else if (!prefix_is_simple(pstr)) {
814
0
        code = gs_note_error(gs_error_invalidfileaccess);
815
0
        goto done;
816
0
    }
817
818
88.2k
    s = file_alloc_stream(imemory, "ztempfile(stream)");
819
88.2k
    if (s == 0) {
820
0
        code = gs_note_error(gs_error_VMerror);
821
0
        goto done;
822
0
    }
823
88.2k
    buf = gs_alloc_bytes(imemory, file_default_buffer_size,
824
88.2k
                         "ztempfile(buffer)");
825
88.2k
    if (buf == 0) {
826
0
        code = gs_note_error(gs_error_VMerror);
827
0
        goto done;
828
0
    }
829
88.2k
    sfile = gp_open_scratch_file(imemory, pstr, fname, fmode);
830
88.2k
    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
88.2k
    fnlen = strlen(fname);
836
88.2k
    sbody = ialloc_string(fnlen, ".tempfile(fname)");
837
88.2k
    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
88.2k
    memcpy(sbody, fname, fnlen);
843
88.2k
    file_init_stream(s, sfile, fmode, buf, file_default_buffer_size);
844
88.2k
    code = ssetfilename(s, (const unsigned char*) fname, fnlen);
845
88.2k
    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
88.2k
    make_string(op - 1, a_readonly | icurrent_space, fnlen, sbody);
854
88.2k
    make_stream_file(op, s, fmode);
855
88.2k
    code = record_file_is_tempfile(i_ctx_p, (unsigned char *)fname, fnlen, true);
856
857
88.2k
done:
858
88.2k
    if (prefix)
859
88.2k
        gs_free_object(imemory, prefix, "ztempfile(prefix)");
860
88.2k
    if (fname)
861
88.2k
        gs_free_object(imemory, fname, "ztempfile(fname)");
862
88.2k
    return code;
863
88.2k
}
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
2.58M
{
905
2.58M
    int code;
906
2.58M
    os_ptr op = osp;
907
2.58M
    ref nsref;
908
2.58M
    unsigned int n = -1;
909
910
2.58M
    check_op(2);
911
2.58M
    check_read_type(*op, t_string);
912
2.58M
    check_type(op[-1], t_name);
913
914
2.58M
    name_string_ref(imemory, op-1, &nsref);
915
2.58M
    if (r_size(&nsref) == 17 &&
916
2.58M
        strncmp((const char *)nsref.value.const_bytes,
917
2.58M
                "PermitFileReading", 17) == 0) {
918
2.58M
        n = gs_permit_file_reading;
919
2.58M
    } else if (r_size(&nsref) == 17 &&
920
0
               strncmp((const char *)nsref.value.const_bytes,
921
0
                       "PermitFileWriting", 17) == 0) {
922
0
        n = gs_permit_file_writing;
923
0
    } else if (r_size(&nsref) == 17 &&
924
0
               strncmp((const char *)nsref.value.const_bytes,
925
0
                       "PermitFileControl", 17) == 0) {
926
0
        n = gs_permit_file_control;
927
0
    }
928
929
2.58M
    if (n == -1)
930
0
        code = gs_note_error(gs_error_rangecheck);
931
2.58M
    else if (gs_is_path_control_active(imemory))
932
0
        code = gs_note_error(gs_error_Fatal);
933
2.58M
    else
934
2.58M
        code = gs_add_control_path_len(imemory, n,
935
2.58M
                                       (const char *)op[0].value.const_bytes,
936
2.58M
                                       (size_t)r_size(&op[0]));
937
2.58M
    pop(2);
938
2.58M
    return code;
939
2.58M
}
940
941
static int zactivatepathcontrol(i_ctx_t *i_ctx_p)
942
161k
{
943
161k
    ref *safety, *safe;
944
161k
    int code = 0;
945
946
161k
    gs_activate_path_control(imemory, 1);
947
948
    /* Set the PostScript level 'safe' parameter. This now correctly prevents
949
     * /tests_private/ps/ps3cet/27-09.ps from changing FontDir, GenericResourceDir
950
     * and GenericResourcePathSep by using setsystemparams (this is implemented
951
     * in PostScript in gs_ll2.ps and relies on systemdict->SAFETY->safe being true).
952
     */
953
161k
    if (dict_find_string(systemdict, "SAFETY", &safety) > 0 &&
954
161k
        dict_find_string(safety, "safe", &safe) > 0) {
955
161k
        make_bool(safe, true);
956
161k
        code = idict_put_string(systemdict, "safe", safe);
957
161k
    }
958
161k
    return code;
959
161k
}
960
static int zcurrentpathcontrolstate(i_ctx_t *i_ctx_p)
961
161k
{
962
161k
    os_ptr op = osp;
963
161k
    push(1);
964
161k
    if (gs_is_path_control_active(imemory)) {
965
5
        make_true(op);
966
5
    }
967
161k
    else {
968
161k
        make_false(op);
969
161k
    }
970
161k
    return 0;
971
161k
}
972
973
/* ------ Initialization procedure ------ */
974
975
const op_def zfile_op_defs[] =
976
{
977
    {"1deletefile", zdeletefile},
978
    {"1.execfile", zexecfile},
979
    {"2file", zfile},
980
    {"3filenameforall", zfilenameforall},
981
    {"0.filenamelistseparator", zfilenamelistseparator},
982
    {"1.filenamesplit", zfilenamesplit},
983
    {"1.libfile", zlibfile},
984
    {"2renamefile", zrenamefile},
985
    {"1status", zstatus},
986
    {"2.tempfile", ztempfile},
987
                /* Internal operators */
988
    {"0%file_continue", file_continue},
989
    {"0%execfile_finish", execfile_finish},
990
    {"1.getfilename", zgetfilename},
991
    /* Control path operators */
992
    {"2.addcontrolpath", zaddcontrolpath},
993
    {"0.activatepathcontrol", zactivatepathcontrol},
994
    {"0.currentpathcontrolstate", zcurrentpathcontrolstate},
995
    op_def_end(0)
996
};
997
998
/* ------ File name parsing ------ */
999
1000
/* Parse a file name into device and individual name. */
1001
/* See gsfname.c for details. */
1002
static int
1003
parse_file_name(const ref * op, gs_parsed_file_name_t * pfn, bool safemode,
1004
                gs_memory_t *memory)
1005
25.9M
{
1006
25.9M
    int code;
1007
1008
25.9M
    check_read_type(*op, t_string);
1009
25.9M
    code = gs_parse_file_name(pfn, (const char *)op->value.const_bytes,
1010
25.9M
                              r_size(op), memory);
1011
25.9M
    if (code < 0)
1012
502
        return code;
1013
    /*
1014
     * Check here for the %pipe device which is illegal when
1015
     * LockFilePermissions is true. In the future we might want to allow
1016
     * the %pipe device to be included on the PermitFile... paths, but
1017
     * for now it is simply disallowed.
1018
     */
1019
25.9M
    if (pfn->iodev && safemode && strcmp(pfn->iodev->dname, "%pipe%") == 0)
1020
0
        return gs_error_invalidfileaccess;
1021
25.9M
    return code;
1022
25.9M
}
1023
1024
/* Parse a real (non-device) file name and convert to a C string. */
1025
/* See gsfname.c for details. */
1026
static int
1027
parse_real_file_name(const ref *op, gs_parsed_file_name_t *pfn,
1028
                     gs_memory_t *mem, client_name_t cname)
1029
87.9k
{
1030
87.9k
    check_read_type(*op, t_string);
1031
87.9k
    return gs_parse_real_file_name(pfn, (const char *)op->value.const_bytes,
1032
87.9k
                                   r_size(op), mem, cname);
1033
87.9k
}
1034
1035
/* Parse the access string for opening a file. */
1036
/* [4] is for r/w, +, b, \0. */
1037
static int
1038
parse_file_access_string(const ref *op, char file_access[4])
1039
17.9M
{
1040
17.9M
    const byte *astr;
1041
1042
17.9M
    check_read_type(*op, t_string);
1043
17.9M
    astr = op->value.const_bytes;
1044
17.9M
    switch (r_size(op)) {
1045
88.2k
        case 2:
1046
88.2k
            if (astr[1] != '+')
1047
1
                return_error(gs_error_invalidfileaccess);
1048
88.2k
            file_access[1] = '+';
1049
88.2k
            file_access[2] = 0;
1050
88.2k
            break;
1051
17.8M
        case 1:
1052
17.8M
            file_access[1] = 0;
1053
17.8M
            break;
1054
7
        default:
1055
7
            return_error(gs_error_invalidfileaccess);
1056
17.9M
    }
1057
17.9M
    switch (astr[0]) {
1058
4.09M
        case 'r':
1059
17.9M
        case 'w':
1060
17.9M
        case 'a':
1061
17.9M
            break;
1062
3
        default:
1063
3
            return_error(gs_error_invalidfileaccess);
1064
17.9M
    }
1065
17.9M
    file_access[0] = astr[0];
1066
17.9M
    return 0;
1067
17.9M
}
1068
1069
/* ------ Stream opening ------ */
1070
1071
/*
1072
 * Open a file specified by a parsed file name (which may be only a
1073
 * device).
1074
 */
1075
int
1076
zopen_file(i_ctx_t *i_ctx_p, const gs_parsed_file_name_t *pfn,
1077
           const char *file_access, stream **ps, gs_memory_t *mem)
1078
4.62M
{
1079
4.62M
    gx_io_device *const iodev = pfn->iodev;
1080
4.62M
    int code = 0;
1081
1082
4.62M
    if (pfn->fname == NULL) {     /* just a device */
1083
0
        iodev->state = i_ctx_p;
1084
0
        code = iodev->procs.open_device(iodev, file_access, ps, mem);
1085
0
        iodev->state = NULL;
1086
0
        return code;
1087
0
    }
1088
4.62M
    else {                      /* file */
1089
4.62M
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
1090
1091
4.62M
        if (open_file == 0)
1092
1.79M
            open_file = iodev_os_open_file;
1093
        /* Check OS files to make sure we allow the type of access */
1094
4.62M
        if (open_file == iodev_os_open_file) {
1095
1.79M
            if (file_access[0] == 'r' || file_access[1] == '+') {
1096
1.79M
                code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev, "PermitFileReading");
1097
1.79M
                if (code < 0 && !file_is_tempfile(i_ctx_p, (const uchar *)pfn->fname, pfn->len))
1098
0
                    return code;
1099
1.79M
            }
1100
1.79M
            if (file_access[0] == 'w' || file_access[1] == '+') {
1101
0
                code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev, "PermitFileWriting");
1102
0
                if (code < 0 && !file_is_tempfile(i_ctx_p, (const uchar *)pfn->fname, pfn->len))
1103
0
                    return code;
1104
0
            }
1105
1.79M
        }
1106
4.62M
        return open_file(iodev, pfn->fname, pfn->len, file_access, ps, mem);
1107
4.62M
    }
1108
4.62M
}
1109
1110
/*
1111
 * Define the file_open procedure for the %os% IODevice (also used, as the
1112
 * default, for %pipe% and possibly others).
1113
 */
1114
static int
1115
iodev_os_open_file(gx_io_device * iodev, const char *fname, uint len,
1116
                   const char *file_access, stream ** ps, gs_memory_t * mem)
1117
26.6M
{
1118
26.6M
    return file_open_stream(fname, len, file_access,
1119
26.6M
                            file_default_buffer_size, ps,
1120
26.6M
                            iodev, iodev->procs.gp_fopen, mem);
1121
26.6M
}
1122
1123
/* Make a t_file reference to a stream. */
1124
void
1125
make_stream_file(ref * pfile, stream * s, const char *access)
1126
17.8M
{
1127
17.8M
    uint attrs =
1128
17.8M
        (access[1] == '+' ? a_write + a_read + a_execute : 0) |
1129
17.8M
        imemory_space((gs_ref_memory_t *) s->memory);
1130
1131
17.8M
    if (access[0] == 'r') {
1132
3.54M
        make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
1133
3.54M
        s->write_id = 0;
1134
14.3M
    } else {
1135
14.3M
        make_file(pfile, attrs | a_write, s->write_id, s);
1136
14.3M
        s->read_id = 0;
1137
14.3M
    }
1138
17.8M
}
1139
1140
/* return zero for success, -ve for error, +1 for continue */
1141
static int
1142
lib_file_open_search_with_no_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1143
                                     const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1144
                                     gx_io_device *iodev, bool starting_arg_file, char *fmode)
1145
1.00k
{
1146
1.00k
    stream *s;
1147
1.00k
    uint blen1 = blen;
1148
1.00k
    struct stat fstat;
1149
1.00k
    int code = 1;
1150
1151
1.00k
    if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success)
1152
0
      goto skip;
1153
1154
1.00k
    if (starting_arg_file || check_file_permissions(i_ctx_p, buffer, blen1, iodev, "PermitFileReading") >= 0) {
1155
1.00k
        if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1156
1.00k
                       (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1157
1.00k
            *pclen = blen1;
1158
1.00k
            make_stream_file(pfile, s, "r");
1159
1.00k
            code = 0;
1160
1.00k
        }
1161
1.00k
    }
1162
0
    else {
1163
        /* If we are not allowed to open the file by check_file_permissions_aux()
1164
         * and if the file exists, throw an error.......
1165
         * Otherwise, keep searching.
1166
         */
1167
0
        if ((*iodev->procs.file_status)(iodev,  buffer, &fstat) >= 0) {
1168
0
            code = gs_note_error(gs_error_invalidfileaccess);
1169
0
        }
1170
0
    }
1171
1172
1.00k
 skip:
1173
1.00k
    return code;
1174
1.00k
}
1175
1176
/* return zero for success, -ve for error, +1 for continue */
1177
static int
1178
lib_file_open_search_with_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1179
                                  const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1180
                                  gx_io_device *iodev, bool starting_arg_file, char *fmode)
1181
3.06M
{
1182
3.06M
    stream *s;
1183
3.06M
    const gs_file_path *pfpath = lib_path;
1184
3.06M
    uint pi;
1185
3.06M
    int code = 1;
1186
1187
33.2M
    for (pi = 0; pi < r_size(&pfpath->list) && code == 1; ++pi) {
1188
30.1M
        const ref *prdir = pfpath->list.value.refs + pi;
1189
30.1M
        const char *pstr = (const char *)prdir->value.const_bytes;
1190
30.1M
        uint plen = r_size(prdir), blen1 = blen;
1191
30.1M
        gs_parsed_file_name_t pname;
1192
30.1M
        gp_file_name_combine_result r;
1193
1194
        /* We need to concatenate and parse the file name here
1195
         * if this path has a %device% prefix.              */
1196
30.1M
        if (pstr[0] == '%') {
1197
            /* We concatenate directly since gp_file_name_combine_*
1198
             * rules are not correct for other devices such as %rom% */
1199
5.32M
            code = gs_parse_file_name(&pname, pstr, plen, mem);
1200
5.32M
            if (code < 0) {
1201
0
                code = 1;
1202
0
                continue;
1203
0
            }
1204
5.32M
            if (blen < max(pname.len, plen) + flen)
1205
0
              return_error(gs_error_limitcheck);
1206
5.32M
            memcpy(buffer, pname.fname, pname.len);
1207
5.32M
            memcpy(buffer+pname.len, fname, flen);
1208
5.32M
            if (pname.iodev->procs.open_file == NULL) {
1209
0
                code = 1;
1210
0
                continue;
1211
0
            }
1212
5.32M
            code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode,
1213
5.32M
                                          &s, (gs_memory_t *)mem);
1214
5.32M
            if (code < 0) {
1215
4.51M
                code = 1;
1216
4.51M
                continue;
1217
4.51M
            }
1218
811k
            make_stream_file(pfile, s, "r");
1219
            /* fill in the buffer with the device concatenated */
1220
811k
            memcpy(buffer, pstr, plen);
1221
811k
            memcpy(buffer+plen, fname, flen);
1222
811k
            *pclen = plen + flen;
1223
811k
            code = 0;
1224
24.8M
        } else {
1225
24.8M
            r = gp_file_name_combine(pstr, plen,
1226
24.8M
                    fname, flen, false, buffer, &blen1);
1227
24.8M
            if (r != gp_combine_success)
1228
0
                continue;
1229
24.8M
            if (starting_arg_file || check_file_permissions(i_ctx_p, buffer,
1230
24.8M
                                      blen1, iodev, "PermitFileReading") >= 0) {
1231
1232
24.8M
                if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1233
24.8M
                            (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1234
0
                    *pclen = blen1;
1235
0
                    make_stream_file(pfile, s, "r");
1236
0
                    code = 0;
1237
0
                }
1238
24.8M
            }
1239
0
            else {
1240
0
                struct stat fstat;
1241
                /* If we are not allowed to open the file by check_file_permissions_aux()
1242
                 * and if the file exists, throw an error.......
1243
                 * Otherwise, keep searching.
1244
                 */
1245
0
                if ((*iodev->procs.file_status)(iodev,  (const char *)buffer, &fstat) >= 0) {
1246
0
                    code = gs_note_error(gs_error_invalidfileaccess);
1247
0
                }
1248
0
            }
1249
24.8M
        }
1250
30.1M
    }
1251
3.06M
    return code;
1252
3.06M
}
1253
1254
/* Return a file object of of the file searched for using the search paths. */
1255
/* The fname cannot contain a device part (%...%) but the lib paths might. */
1256
/* The startup code calls this to open the initialization file gs_init.ps. */
1257
/* The startup code also calls this to open @-files. */
1258
int
1259
lib_file_open(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1260
                       const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile)
1261
3.06M
{   /* i_ctx_p is NULL running arg (@) files.
1262
     * lib_path and mem are never NULL
1263
     */
1264
3.06M
    bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file;
1265
3.06M
    bool search_with_no_combine = false;
1266
3.06M
    bool search_with_combine = false;
1267
3.06M
    char fmode[2] = { 'r', 0};
1268
3.06M
    gx_io_device *iodev = iodev_default(mem);
1269
3.06M
    gs_main_instance *minst = get_minst_from_memory(mem);
1270
3.06M
    int code;
1271
1272
3.06M
    if (i_ctx_p && starting_arg_file)
1273
1.00k
        i_ctx_p->starting_arg_file = false;
1274
1275
    /* when starting arg files (@ files) iodev_default is not yet set */
1276
3.06M
    if (iodev == 0)
1277
0
        iodev = (gx_io_device *)gx_io_device_table[0];
1278
1279
3.06M
    if (gp_file_name_is_absolute(fname, flen)) {
1280
1.00k
       search_with_no_combine = true;
1281
1.00k
       search_with_combine = false;
1282
3.06M
    } else {
1283
3.06M
       search_with_no_combine = starting_arg_file;
1284
3.06M
       search_with_combine = true;
1285
3.06M
    }
1286
3.06M
    if (minst->search_here_first) {
1287
0
      if (search_with_no_combine) {
1288
0
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1289
0
                                                    fname, flen, buffer, blen, pclen, pfile,
1290
0
                                                    iodev, starting_arg_file, fmode);
1291
0
        if (code <= 0) /* +ve means continue continue */
1292
0
          return code;
1293
0
      }
1294
0
      if (search_with_combine) {
1295
0
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1296
0
                                                 fname, flen, buffer, blen, pclen, pfile,
1297
0
                                                 iodev, starting_arg_file, fmode);
1298
0
        if (code <= 0) /* +ve means continue searching */
1299
0
          return code;
1300
0
      }
1301
3.06M
    } else {
1302
3.06M
      if (search_with_combine) {
1303
3.06M
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1304
3.06M
                                                 fname, flen, buffer, blen, pclen, pfile,
1305
3.06M
                                                 iodev, starting_arg_file, fmode);
1306
3.06M
        if (code <= 0) /* +ve means continue searching */
1307
811k
          return code;
1308
3.06M
      }
1309
2.25M
      if (search_with_no_combine) {
1310
1.00k
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1311
1.00k
                                                    fname, flen, buffer, blen, pclen, pfile,
1312
1.00k
                                                    iodev, starting_arg_file, fmode);
1313
1.00k
        if (code <= 0) /* +ve means continue searching */
1314
1.00k
          return code;
1315
1.00k
      }
1316
2.25M
    }
1317
3.06M
    return_error(gs_error_undefinedfilename);
1318
3.06M
}
1319
1320
/* The startup code calls this to open @-files. */
1321
stream *
1322
lib_sopen(const gs_file_path_ptr pfpath, const gs_memory_t *mem, const char *fname)
1323
0
{
1324
    /* We need a buffer to hold the expanded file name. */
1325
0
    char filename_found[DEFAULT_BUFFER_SIZE];
1326
0
    uint fnamelen;
1327
0
    ref obj;
1328
0
    int code;
1329
1330
    /* open the usual 'stream', then if successful, return the file */
1331
0
    code = lib_file_open(pfpath, mem, NULL, fname, strlen(fname),
1332
0
                            filename_found, sizeof(filename_found), &fnamelen, &obj);
1333
1334
0
    if (code < 0)
1335
0
        return NULL;
1336
1337
0
    return((stream *)(obj.value.pfile));
1338
0
}
1339
1340
/* Open a file stream that reads a string. */
1341
/* (This is currently used only by the ccinit feature.) */
1342
/* The string must be allocated in non-garbage-collectable (foreign) space. */
1343
int
1344
file_read_string(const byte *str, uint len, ref *pfile, gs_ref_memory_t *imem)
1345
0
{
1346
0
    stream *s = file_alloc_stream((gs_memory_t *)imem, "file_read_string");
1347
1348
0
    if (s == 0)
1349
0
        return_error(gs_error_VMerror);
1350
0
    sread_string(s, str, len);
1351
0
    s->foreign = 1;
1352
0
    s->write_id = 0;
1353
0
    make_file(pfile, a_readonly | imemory_space(imem), s->read_id, s);
1354
0
    s->save_close = s->procs.close;
1355
0
    s->procs.close = file_close_disable;
1356
0
    return 0;
1357
0
}
1358
1359
/* Report an error by storing it in the stream's error_string. */
1360
int
1361
filter_report_error(stream_state * st, const char *str)
1362
0
{
1363
0
    if_debug1m('s', st->memory, "[s]stream error: %s\n", str);
1364
0
    strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING);
1365
    /* Ensure null termination. */
1366
0
    st->error_string[STREAM_MAX_ERROR_STRING] = 0;
1367
0
    return 0;
1368
0
}
1369
1370
/* Open a file stream for a filter. */
1371
int
1372
filter_open(const char *file_access, uint buffer_size, ref * pfile,
1373
            const stream_procs * procs, const stream_template * templat,
1374
            const stream_state * st, gs_memory_t *mem)
1375
1.37M
{
1376
1.37M
    stream *s;
1377
1.37M
    uint ssize = gs_struct_type_size(templat->stype);
1378
1.37M
    stream_state *sst = 0;
1379
1.37M
    int code;
1380
1381
1.37M
    if (templat->stype != &st_stream_state) {
1382
1.29M
        sst = s_alloc_state(mem, templat->stype, "filter_open(stream_state)");
1383
1.29M
        if (sst == 0)
1384
0
            return_error(gs_error_VMerror);
1385
1.29M
    }
1386
1.37M
    code = file_open_stream((char *)0, 0, file_access, buffer_size, &s,
1387
1.37M
                                (gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
1388
1.37M
    if (code < 0) {
1389
0
        gs_free_object(mem, sst, "filter_open(stream_state)");
1390
0
        return code;
1391
0
    }
1392
1.37M
    s_std_init(s, s->cbuf, s->bsize, procs,
1393
1.37M
               (*file_access == 'r' ? s_mode_read : s_mode_write));
1394
1.37M
    s->procs.process = templat->process;
1395
1.37M
    s->save_close = s->procs.close;
1396
1.37M
    s->procs.close = file_close_file;
1397
1.37M
    if (sst == 0) {
1398
        /* This stream doesn't have any state of its own. */
1399
        /* Hack: use the stream itself as the state. */
1400
74.5k
        sst = (stream_state *) s;
1401
1.29M
    } else if (st != 0)         /* might not have client parameters */
1402
1.29M
        memcpy(sst, st, ssize);
1403
1.37M
    s->state = sst;
1404
1.37M
    s_init_state(sst, templat, mem);
1405
1.37M
    sst->report_error = filter_report_error;
1406
1407
1.37M
    if (templat->init != 0) {
1408
1.29M
        code = (*templat->init)(sst);
1409
1.29M
        if (code < 0) {
1410
0
            gs_free_object(mem, sst, "filter_open(stream_state)");
1411
0
            gs_free_object(mem, s->cbuf, "filter_open(buffer)");
1412
0
            return code;
1413
0
        }
1414
1.29M
    }
1415
1.37M
    make_stream_file(pfile, s, file_access);
1416
1.37M
    return 0;
1417
1.37M
}
1418
1419
/* Close a file object. */
1420
/* This is exported only for gsmain.c. */
1421
int
1422
file_close(ref * pfile)
1423
0
{
1424
0
    stream *s;
1425
1426
0
    if (file_is_valid(s, pfile)) {      /* closing a closed file is a no-op */
1427
0
        if (sclose(s))
1428
0
            return_error(gs_error_ioerror);
1429
0
    }
1430
0
    return 0;
1431
0
}