Coverage Report

Created: 2025-06-10 07:06

/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
2.50M
{
127
2.50M
    long i;
128
2.50M
    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
2.50M
    const char *win_sep2 = "\\";
132
2.50M
    bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
133
2.50M
    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
2.50M
    if (iodev && iodev != iodev_default(imemory)) {
139
919k
        return 0;
140
919k
    }
141
142
    /* Assuming a reduced file name. */
143
1.58M
    if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
144
0
        return 0;       /* if Permissions not found, just allow access */
145
146
1.58M
    for (i=0; i<r_size(permitlist); i++) {
147
1.58M
        ref permitstring;
148
1.58M
        const string_match_params win_filename_params = {
149
1.58M
                '*', '?', '\\', true, true      /* ignore case & '/' == '\\' */
150
1.58M
        };
151
1.58M
        const byte *permstr;
152
1.58M
        uint permlen;
153
1.58M
        int cwd_len = 0;
154
155
1.58M
        if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
156
1.58M
            r_type(&permitstring) != t_string
157
1.58M
           )
158
0
            break;      /* any problem, just fail */
159
1.58M
        permstr = permitstring.value.bytes;
160
1.58M
        permlen = r_size(&permitstring);
161
        /*
162
         * Check if any file name is permitted with "*".
163
         */
164
1.58M
        if (permlen == 1 && permstr[0] == '*')
165
1.58M
            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
1.58M
}
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
2.50M
{
199
2.50M
    char fname_reduced[gp_file_name_sizeof];
200
2.50M
    uint rlen = sizeof(fname_reduced);
201
202
2.50M
    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
2.50M
    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
205
2.50M
}
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
805k
{
212
805k
    i_ctx_t *i_ctx_p = get_minst_from_memory(mem)->i_ctx_p;
213
805k
    gs_parsed_file_name_t pname;
214
805k
    const char *permitgroup = permission[0] == 'r' ? "PermitFileReading" : "PermitFileWriting";
215
805k
    int code = gs_parse_file_name(&pname, fname, len, imemory);
216
805k
    if (code < 0)
217
0
        return code;
218
219
805k
    if (pname.iodev && i_ctx_p->LockFilePermissions
220
805k
         && strcmp(pname.iodev->dname, "%pipe%") == 0) {
221
0
        code = gs_note_error(gs_error_invalidfileaccess);
222
0
    }
223
805k
    else {
224
805k
        code = check_file_permissions(i_ctx_p, pname.fname, pname.len, pname.iodev, permitgroup);
225
805k
    }
226
805k
    return code;
227
805k
}
228
229
/* <name_string> <access_string> file <file> */
230
int                             /* exported for zsysvm.c */
231
zfile(i_ctx_t *i_ctx_p)
232
2.19M
{
233
2.19M
    os_ptr op = osp;
234
2.19M
    char file_access[4];
235
2.19M
    gs_parsed_file_name_t pname;
236
2.19M
    int code = parse_file_access_string(op, file_access);
237
2.19M
    stream *s;
238
239
2.19M
    if (code < 0)
240
3
        return code;
241
2.19M
    code = parse_file_name(op-1, &pname, i_ctx_p->LockFilePermissions, imemory);
242
2.19M
    if (code < 0)
243
0
        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
2.19M
    if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) {
250
1.98M
        bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0);
251
1.98M
        bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0);
252
1.98M
        if (pname.fname)
253
0
            return_error(gs_error_invalidfileaccess);
254
1.98M
        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
1.98M
        pname.iodev->state = i_ctx_p;
275
1.98M
        code = (*pname.iodev->procs.open_device)(pname.iodev,
276
1.98M
                                                 file_access, &s, imemory);
277
1.98M
        pname.iodev->state = NULL;
278
1.98M
    } else {
279
207k
        if (pname.iodev == NULL)
280
101k
            pname.iodev = iodev_default(imemory);
281
207k
        code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory);
282
207k
    }
283
2.19M
    if (code < 0)
284
159k
        return code;
285
2.03M
    if (s == NULL)
286
16
        return_error(gs_error_undefinedfilename);
287
2.03M
    code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1));
288
2.03M
    if (code < 0) {
289
0
        sclose(s);
290
0
        return_error(gs_error_VMerror);
291
0
    }
292
2.03M
    make_stream_file(op - 1, s, file_access);
293
2.03M
    pop(1);
294
2.03M
    return code;
295
2.03M
}
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
5.40k
{
321
5.40k
    ref *SAFETY;
322
5.40k
    ref *tempfiles;
323
5.40k
    ref kname, bref;
324
5.40k
    int code = 0;
325
326
5.40k
    if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
327
5.40k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0) {
328
0
        return 0;
329
0
    }
330
5.40k
    if ((code = name_ref(imemory, fname, len, &kname, 1)) < 0) {
331
0
        return code;
332
0
    }
333
5.40k
    make_bool(&bref, true);
334
5.40k
    if (add)
335
5.40k
        return idict_put(tempfiles, &kname, &bref);
336
0
    else
337
0
        return idict_undef(tempfiles, &kname);
338
5.40k
}
339
340
/* ------ Level 2 extensions ------ */
341
342
/* <string> deletefile - */
343
static int
344
zdeletefile(i_ctx_t *i_ctx_p)
345
5.37k
{
346
5.37k
    os_ptr op = osp;
347
5.37k
    gs_parsed_file_name_t pname;
348
5.37k
    int code;
349
5.37k
    bool is_temp = false;
350
351
5.37k
    check_op(1);
352
5.37k
    code = parse_real_file_name(op, &pname, imemory, "deletefile");
353
5.37k
    if (code < 0)
354
1
        return code;
355
5.37k
    if (pname.iodev == iodev_default(imemory)) {
356
5.37k
        if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
357
5.37k
                pname.iodev, "PermitFileControl")) < 0 &&
358
5.37k
                 !(is_temp = file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op)))) {
359
0
            return code;
360
0
        }
361
5.37k
    }
362
363
5.37k
    code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
364
365
5.37k
    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
5.37k
    gs_free_file_name(&pname, "deletefile");
369
5.37k
    if (code < 0)
370
2
        return code;
371
5.37k
    pop(1);
372
5.37k
    return 0;
373
5.37k
}
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
128k
{
381
128k
    os_ptr op = osp;
382
128k
    file_enum *pfen;
383
128k
    gx_io_device *iodev = NULL;
384
128k
    gs_parsed_file_name_t pname;
385
128k
    int code = 0;
386
387
128k
    check_op(3);
388
128k
    check_write_type(*op, t_string);
389
128k
    check_proc(op[-1]);
390
128k
    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
128k
    check_estack(7);
394
    /* Get the iodevice */
395
128k
    code = parse_file_name(op-2, &pname, i_ctx_p->LockFilePermissions, imemory);
396
128k
    if (code < 0)
397
0
        return code;
398
128k
    iodev = (pname.iodev == NULL) ? iodev_default(imemory) : pname.iodev;
399
400
    /* Check for several conditions that just cause us to return success */
401
128k
    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
128k
    pfen = iodev->procs.enumerate_files(imemory, iodev, (const char *)pname.fname,
406
128k
                pname.len);
407
128k
    if (pfen == 0)
408
0
        return_error(gs_error_VMerror);
409
128k
    push_mark_estack(es_for, file_cleanup);
410
128k
    ++esp;
411
128k
    make_istruct(esp, 0, iodev);
412
128k
    ++esp;
413
128k
    make_int(esp, r_size(op-2) - pname.len);
414
128k
    *++esp = *op;
415
128k
    ++esp;
416
128k
    make_istruct(esp, 0, pfen);
417
128k
    *++esp = op[-1];
418
128k
    ref_stack_pop(&o_stack, 3);
419
128k
    code = file_continue(i_ctx_p);
420
128k
    return code;
421
128k
}
422
/* Continuation operator for enumerating files */
423
static int
424
file_continue(i_ctx_t *i_ctx_p)
425
147k
{
426
147k
    os_ptr op = osp;
427
147k
    es_ptr pscratch = esp - 2;
428
147k
    file_enum *pfen = r_ptr(esp - 1, file_enum);
429
147k
    int devlen = esp[-3].value.intval;
430
147k
    gx_io_device *iodev = r_ptr(esp - 4, gx_io_device);
431
147k
    uint len = r_size(pscratch);
432
147k
    uint code;
433
434
147k
    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
147k
    do {
440
147k
        memcpy((char *)pscratch->value.bytes, iodev->dname, devlen);
441
147k
        code = iodev->procs.enumerate_next(imemory, pfen, (char *)pscratch->value.bytes + devlen,
442
147k
                    len - devlen);
443
147k
        if (code == ~(uint) 0) {    /* all done */
444
128k
            esp -= 6;               /* pop proc, pfen, scratch, devlen, iodev , mark */
445
128k
            return o_pop_estack;
446
128k
        } else if (code > len - devlen) {      /* overran string */
447
0
            return_error(gs_error_rangecheck);
448
0
        }
449
18.4k
        else if (iodev != iodev_default(imemory)
450
18.4k
              || (check_file_permissions(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, iodev, "PermitFileReading")) == 0) {
451
18.4k
            push(1);
452
18.4k
            ref_assign(op, pscratch);
453
18.4k
            r_set_size(op, code + devlen);
454
18.4k
            push_op_estack(file_continue);  /* come again */
455
18.4k
            *++esp = pscratch[2];   /* proc */
456
18.4k
            return o_push_estack;
457
18.4k
        }
458
147k
    } while(1);
459
147k
}
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
1
{
476
1
    int code;
477
1
    os_ptr op = osp;
478
1
    gs_parsed_file_name_t pname1, pname2;
479
480
1
    check_op(2);
481
0
    code = parse_real_file_name(op, &pname2, imemory, "renamefile(to)");
482
0
    if (code < 0)
483
0
        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
120k
{
529
120k
    os_ptr op = osp;
530
531
120k
    check_op(1);
532
120k
    switch (r_type(op)) {
533
7.11k
        case t_file:
534
7.11k
            {
535
7.11k
                stream *s;
536
537
7.11k
                make_bool(op, (file_is_valid(s, op) ? 1 : 0));
538
7.11k
            }
539
7.11k
            return 0;
540
113k
        case t_string:
541
113k
            {
542
113k
                gs_parsed_file_name_t pname;
543
113k
                struct stat fstat;
544
113k
                int code = parse_file_name(op, &pname,
545
113k
                                           i_ctx_p->LockFilePermissions, imemory);
546
113k
                if (code < 0) {
547
0
                    if (code == gs_error_undefinedfilename) {
548
0
                        make_bool(op, 0);
549
0
                        code = 0;
550
0
                    }
551
0
                    return code;
552
0
                }
553
113k
                code = gs_terminate_file_name(&pname, imemory, "status");
554
113k
                if (code < 0)
555
0
                    return code;
556
113k
                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
557
113k
                                       pname.iodev, "PermitFileReading")) >= 0) {
558
113k
                    code = (*pname.iodev->procs.file_status)(pname.iodev,
559
113k
                                                       pname.fname, &fstat);
560
113k
                }
561
113k
                switch (code) {
562
65.2k
                    case 0:
563
65.2k
                        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
65.2k
                        push(4);
570
65.2k
                        make_int(op - 4, stat_blocks(&fstat));
571
65.2k
                        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
65.2k
                        if ((double)op[-4].value.intval !=
581
65.2k
                              (double)stat_blocks(&fstat) ||
582
65.2k
                            (double)op[-3].value.intval !=
583
65.2k
                              (double)fstat.st_size
584
65.2k
                            )
585
0
                            return_error(gs_error_limitcheck);
586
65.2k
                        make_int(op - 2, fstat.st_mtime);
587
65.2k
                        make_int(op - 1, fstat.st_ctime);
588
65.2k
                        make_bool(op, 1);
589
65.2k
                        break;
590
48.3k
                    case gs_error_undefinedfilename:
591
48.3k
                        make_bool(op, 0);
592
48.3k
                        code = 0;
593
113k
                }
594
113k
                gs_free_file_name(&pname, "status");
595
113k
                return code;
596
113k
            }
597
0
        default:
598
0
            return_op_typecheck(op);
599
120k
    }
600
120k
}
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
228k
{
665
228k
    os_ptr op = osp;
666
228k
    int code;
667
228k
    byte cname[DEFAULT_BUFFER_SIZE];
668
228k
    uint clen;
669
228k
    gs_parsed_file_name_t pname;
670
228k
    stream *s;
671
228k
    gx_io_device *iodev_dflt;
672
673
228k
    check_op(1); /* Enough arguments */
674
228k
    check_ostack(2); /* Enough space for our results */
675
228k
    code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions, imemory);
676
228k
    if (code < 0)
677
9
        return code;
678
228k
    iodev_dflt = iodev_default(imemory);
679
228k
    if (pname.iodev == NULL)
680
170k
        pname.iodev = iodev_dflt;
681
228k
    if (pname.iodev != iodev_dflt) { /* Non-OS devices don't have search paths (yet). */
682
57.1k
        code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
683
57.1k
        if (s == NULL) code = gs_note_error(gs_error_undefinedfilename);
684
57.1k
        if (code >= 0) {
685
9.21k
            code = ssetfilename(s, op->value.const_bytes, r_size(op));
686
9.21k
            if (code < 0) {
687
0
                sclose(s);
688
0
                return_error(gs_error_VMerror);
689
0
            }
690
9.21k
        }
691
57.1k
        if (code < 0) {
692
47.9k
            push(1);
693
47.9k
            make_false(op);
694
47.9k
            return 0;
695
47.9k
        }
696
9.21k
        make_stream_file(op, s, "r");
697
170k
    } else {
698
170k
        ref fref;
699
700
170k
        code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len,
701
170k
                             (char *)cname, sizeof(cname), &clen, &fref);
702
170k
        if (code >= 0) {
703
36.8k
            s = fptr(&fref);
704
36.8k
            code = ssetfilename(s, cname, clen);
705
36.8k
            if (code < 0) {
706
0
                sclose(s);
707
0
                return_error(gs_error_VMerror);
708
0
            }
709
36.8k
        }
710
170k
        if (code < 0) {
711
134k
            if (code == gs_error_VMerror || code == gs_error_invalidfileaccess)
712
0
                return code;
713
134k
            push(1);
714
134k
            make_false(op);
715
134k
            return 0;
716
134k
        }
717
36.8k
        ref_assign(op, &fref);
718
36.8k
    }
719
228k
    push(1);
720
46.0k
    make_true(op);
721
46.0k
    return 0;
722
46.0k
}
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
5.40k
{
729
5.40k
    int i;
730
5.40k
    char c;
731
732
21.6k
    for (i = 0; (c = pstr[i]) != 0; i++) {
733
16.2k
        if (!(c == '-' || c == '_' || (c >= '0' && c <= '9') ||
734
16.2k
              (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
735
0
            return false;
736
16.2k
    }
737
5.40k
    return true;
738
5.40k
}
739
740
/* <prefix|null> <access_string> .tempfile <name_string> <file> */
741
static int
742
ztempfile(i_ctx_t *i_ctx_p)
743
5.40k
{
744
5.40k
    os_ptr op = osp;
745
5.40k
    const char *pstr;
746
5.40k
    char fmode[4];
747
5.40k
    char fmode_temp[4];
748
5.40k
    int code;
749
5.40k
    char *prefix = NULL;
750
5.40k
    char *fname= NULL;
751
5.40k
    uint fnlen;
752
5.40k
    gp_file *sfile;
753
5.40k
    stream *s;
754
5.40k
    byte *buf, *sbody;
755
756
5.40k
    check_op(2);
757
5.40k
    code = parse_file_access_string(op, fmode_temp);
758
5.40k
    if (code < 0)
759
0
        return code;
760
5.40k
    prefix = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(prefix)");
761
5.40k
    fname = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(fname)");
762
5.40k
    if (!prefix || !fname) {
763
0
        code = gs_note_error(gs_error_VMerror);
764
0
        goto done;
765
0
    }
766
767
5.40k
    snprintf(fmode, sizeof(fmode), "%s%s", fmode_temp, gp_fmode_binary_suffix);
768
5.40k
    if (r_has_type(op - 1, t_null))
769
5.40k
        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
5.40k
    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
5.40k
    } else if (!prefix_is_simple(pstr)) {
814
0
        code = gs_note_error(gs_error_invalidfileaccess);
815
0
        goto done;
816
0
    }
817
818
5.40k
    s = file_alloc_stream(imemory, "ztempfile(stream)");
819
5.40k
    if (s == 0) {
820
0
        code = gs_note_error(gs_error_VMerror);
821
0
        goto done;
822
0
    }
823
5.40k
    buf = gs_alloc_bytes(imemory, file_default_buffer_size,
824
5.40k
                         "ztempfile(buffer)");
825
5.40k
    if (buf == 0) {
826
0
        code = gs_note_error(gs_error_VMerror);
827
0
        goto done;
828
0
    }
829
5.40k
    sfile = gp_open_scratch_file(imemory, pstr, fname, fmode);
830
5.40k
    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
5.40k
    fnlen = strlen(fname);
836
5.40k
    sbody = ialloc_string(fnlen, ".tempfile(fname)");
837
5.40k
    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
5.40k
    memcpy(sbody, fname, fnlen);
843
5.40k
    file_init_stream(s, sfile, fmode, buf, file_default_buffer_size);
844
5.40k
    code = ssetfilename(s, (const unsigned char*) fname, fnlen);
845
5.40k
    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
5.40k
    make_string(op - 1, a_readonly | icurrent_space, fnlen, sbody);
854
5.40k
    make_stream_file(op, s, fmode);
855
5.40k
    code = record_file_is_tempfile(i_ctx_p, (unsigned char *)fname, fnlen, true);
856
857
5.40k
done:
858
5.40k
    if (prefix)
859
5.40k
        gs_free_object(imemory, prefix, "ztempfile(prefix)");
860
5.40k
    if (fname)
861
5.40k
        gs_free_object(imemory, fname, "ztempfile(fname)");
862
5.40k
    return code;
863
5.40k
}
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
202k
{
905
202k
    int code;
906
202k
    os_ptr op = osp;
907
202k
    ref nsref;
908
202k
    unsigned int n = -1;
909
910
202k
    check_op(2);
911
202k
    check_read_type(*op, t_string);
912
202k
    check_type(op[-1], t_name);
913
914
202k
    name_string_ref(imemory, op-1, &nsref);
915
202k
    if (r_size(&nsref) == 17 &&
916
202k
        strncmp((const char *)nsref.value.const_bytes,
917
202k
                "PermitFileReading", 17) == 0) {
918
165k
        n = gs_permit_file_reading;
919
165k
    } else if (r_size(&nsref) == 17 &&
920
36.8k
               strncmp((const char *)nsref.value.const_bytes,
921
36.8k
                       "PermitFileWriting", 17) == 0) {
922
18.4k
        n = gs_permit_file_writing;
923
18.4k
    } else if (r_size(&nsref) == 17 &&
924
18.4k
               strncmp((const char *)nsref.value.const_bytes,
925
18.4k
                       "PermitFileControl", 17) == 0) {
926
18.4k
        n = gs_permit_file_control;
927
18.4k
    }
928
929
202k
    if (n == -1)
930
0
        code = gs_note_error(gs_error_rangecheck);
931
202k
    else if (gs_is_path_control_active(imemory))
932
0
        code = gs_note_error(gs_error_Fatal);
933
202k
    else
934
202k
        code = gs_add_control_path_len(imemory, n,
935
202k
                                       (const char *)op[0].value.const_bytes,
936
202k
                                       (size_t)r_size(&op[0]));
937
202k
    pop(2);
938
202k
    return code;
939
202k
}
940
941
static int zactivatepathcontrol(i_ctx_t *i_ctx_p)
942
9.21k
{
943
9.21k
    gs_activate_path_control(imemory, 1);
944
9.21k
    return 0;
945
9.21k
}
946
static int zcurrentpathcontrolstate(i_ctx_t *i_ctx_p)
947
9.21k
{
948
9.21k
    os_ptr op = osp;
949
9.21k
    push(1);
950
9.21k
    if (gs_is_path_control_active(imemory)) {
951
0
        make_true(op);
952
0
    }
953
9.21k
    else {
954
9.21k
        make_false(op);
955
9.21k
    }
956
9.21k
    return 0;
957
9.21k
}
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
2.66M
{
992
2.66M
    int code;
993
994
2.66M
    check_read_type(*op, t_string);
995
2.66M
    code = gs_parse_file_name(pfn, (const char *)op->value.const_bytes,
996
2.66M
                              r_size(op), memory);
997
2.66M
    if (code < 0)
998
9
        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
2.66M
    if (pfn->iodev && safemode && strcmp(pfn->iodev->dname, "%pipe%") == 0)
1006
0
        return gs_error_invalidfileaccess;
1007
2.66M
    return code;
1008
2.66M
}
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
5.37k
{
1016
5.37k
    check_read_type(*op, t_string);
1017
5.37k
    return gs_parse_real_file_name(pfn, (const char *)op->value.const_bytes,
1018
5.37k
                                   r_size(op), mem, cname);
1019
5.37k
}
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
2.20M
{
1026
2.20M
    const byte *astr;
1027
1028
2.20M
    check_read_type(*op, t_string);
1029
2.20M
    astr = op->value.const_bytes;
1030
2.20M
    switch (r_size(op)) {
1031
5.40k
        case 2:
1032
5.40k
            if (astr[1] != '+')
1033
0
                return_error(gs_error_invalidfileaccess);
1034
5.40k
            file_access[1] = '+';
1035
5.40k
            file_access[2] = 0;
1036
5.40k
            break;
1037
2.19M
        case 1:
1038
2.19M
            file_access[1] = 0;
1039
2.19M
            break;
1040
1
        default:
1041
1
            return_error(gs_error_invalidfileaccess);
1042
2.20M
    }
1043
2.20M
    switch (astr[0]) {
1044
231k
        case 'r':
1045
2.20M
        case 'w':
1046
2.20M
        case 'a':
1047
2.20M
            break;
1048
1
        default:
1049
1
            return_error(gs_error_invalidfileaccess);
1050
2.20M
    }
1051
2.20M
    file_access[0] = astr[0];
1052
2.20M
    return 0;
1053
2.20M
}
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
264k
{
1065
264k
    gx_io_device *const iodev = pfn->iodev;
1066
264k
    int code = 0;
1067
1068
264k
    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
264k
    else {                      /* file */
1075
264k
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
1076
1077
264k
        if (open_file == 0)
1078
101k
            open_file = iodev_os_open_file;
1079
        /* Check OS files to make sure we allow the type of access */
1080
264k
        if (open_file == iodev_os_open_file) {
1081
101k
            code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev,
1082
101k
                file_access[0] == 'r' ? "PermitFileReading" : "PermitFileWriting");
1083
1084
101k
            if (code < 0 && !file_is_tempfile(i_ctx_p,
1085
0
                                          (const uchar *)pfn->fname, pfn->len))
1086
0
                return code;
1087
101k
        }
1088
264k
        return open_file(iodev, pfn->fname, pfn->len, file_access, ps, mem);
1089
264k
    }
1090
264k
}
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
1.57M
{
1100
1.57M
    return file_open_stream(fname, len, file_access,
1101
1.57M
                            file_default_buffer_size, ps,
1102
1.57M
                            iodev, iodev->procs.gp_fopen, mem);
1103
1.57M
}
1104
1105
/* Make a t_file reference to a stream. */
1106
void
1107
make_stream_file(ref * pfile, stream * s, const char *access)
1108
2.20M
{
1109
2.20M
    uint attrs =
1110
2.20M
        (access[1] == '+' ? a_write + a_read + a_execute : 0) |
1111
2.20M
        imemory_space((gs_ref_memory_t *) s->memory);
1112
1113
2.20M
    if (access[0] == 'r') {
1114
210k
        make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
1115
210k
        s->write_id = 0;
1116
1.99M
    } else {
1117
1.99M
        make_file(pfile, attrs | a_write, s->write_id, s);
1118
1.99M
        s->read_id = 0;
1119
1.99M
    }
1120
2.20M
}
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
0
{
1128
0
    stream *s;
1129
0
    uint blen1 = blen;
1130
0
    struct stat fstat;
1131
0
    int code = 1;
1132
1133
0
    if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success)
1134
0
      goto skip;
1135
1136
0
    if (starting_arg_file || check_file_permissions(i_ctx_p, buffer, blen1, iodev, "PermitFileReading") >= 0) {
1137
0
        if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1138
0
                       (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
0
    }
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
0
 skip:
1155
0
    return code;
1156
0
}
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
180k
{
1164
180k
    stream *s;
1165
180k
    const gs_file_path *pfpath = lib_path;
1166
180k
    uint pi;
1167
180k
    int code = 1;
1168
1169
1.96M
    for (pi = 0; pi < r_size(&pfpath->list) && code == 1; ++pi) {
1170
1.78M
        const ref *prdir = pfpath->list.value.refs + pi;
1171
1.78M
        const char *pstr = (const char *)prdir->value.const_bytes;
1172
1.78M
        uint plen = r_size(prdir), blen1 = blen;
1173
1.78M
        gs_parsed_file_name_t pname;
1174
1.78M
        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
1.78M
        if (pstr[0] == '%') {
1179
            /* We concatenate directly since gp_file_name_combine_*
1180
             * rules are not correct for other devices such as %rom% */
1181
314k
            code = gs_parse_file_name(&pname, pstr, plen, mem);
1182
314k
            if (code < 0) {
1183
0
                code = 1;
1184
0
                continue;
1185
0
            }
1186
314k
            if (blen < max(pname.len, plen) + flen)
1187
0
              return_error(gs_error_limitcheck);
1188
314k
            memcpy(buffer, pname.fname, pname.len);
1189
314k
            memcpy(buffer+pname.len, fname, flen);
1190
314k
            if (pname.iodev->procs.open_file == NULL) {
1191
0
                code = 1;
1192
0
                continue;
1193
0
            }
1194
314k
            code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode,
1195
314k
                                          &s, (gs_memory_t *)mem);
1196
314k
            if (code < 0) {
1197
268k
                code = 1;
1198
268k
                continue;
1199
268k
            }
1200
46.0k
            make_stream_file(pfile, s, "r");
1201
            /* fill in the buffer with the device concatenated */
1202
46.0k
            memcpy(buffer, pstr, plen);
1203
46.0k
            memcpy(buffer+plen, fname, flen);
1204
46.0k
            *pclen = plen + flen;
1205
46.0k
            code = 0;
1206
1.47M
        } else {
1207
1.47M
            r = gp_file_name_combine(pstr, plen,
1208
1.47M
                    fname, flen, false, buffer, &blen1);
1209
1.47M
            if (r != gp_combine_success)
1210
0
                continue;
1211
1.47M
            if (starting_arg_file || check_file_permissions(i_ctx_p, buffer,
1212
1.47M
                                      blen1, iodev, "PermitFileReading") >= 0) {
1213
1214
1.47M
                if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1215
1.47M
                            (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
1.47M
            }
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
1.47M
        }
1232
1.78M
    }
1233
180k
    return code;
1234
180k
}
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
180k
{   /* i_ctx_p is NULL running arg (@) files.
1244
     * lib_path and mem are never NULL
1245
     */
1246
180k
    bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file;
1247
180k
    bool search_with_no_combine = false;
1248
180k
    bool search_with_combine = false;
1249
180k
    char fmode[2] = { 'r', 0};
1250
180k
    gx_io_device *iodev = iodev_default(mem);
1251
180k
    gs_main_instance *minst = get_minst_from_memory(mem);
1252
180k
    int code;
1253
1254
180k
    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
180k
    if (iodev == 0)
1259
0
        iodev = (gx_io_device *)gx_io_device_table[0];
1260
1261
180k
    if (gp_file_name_is_absolute(fname, flen)) {
1262
0
       search_with_no_combine = true;
1263
0
       search_with_combine = false;
1264
180k
    } else {
1265
180k
       search_with_no_combine = starting_arg_file;
1266
180k
       search_with_combine = true;
1267
180k
    }
1268
180k
    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
180k
    } else {
1284
180k
      if (search_with_combine) {
1285
180k
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1286
180k
                                                 fname, flen, buffer, blen, pclen, pfile,
1287
180k
                                                 iodev, starting_arg_file, fmode);
1288
180k
        if (code <= 0) /* +ve means continue searching */
1289
46.0k
          return code;
1290
180k
      }
1291
134k
      if (search_with_no_combine) {
1292
0
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1293
0
                                                    fname, flen, buffer, blen, pclen, pfile,
1294
0
                                                    iodev, starting_arg_file, fmode);
1295
0
        if (code <= 0) /* +ve means continue searching */
1296
0
          return code;
1297
0
      }
1298
134k
    }
1299
180k
    return_error(gs_error_undefinedfilename);
1300
180k
}
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
83.4k
{
1358
83.4k
    stream *s;
1359
83.4k
    uint ssize = gs_struct_type_size(templat->stype);
1360
83.4k
    stream_state *sst = 0;
1361
83.4k
    int code;
1362
1363
83.4k
    if (templat->stype != &st_stream_state) {
1364
83.3k
        sst = s_alloc_state(mem, templat->stype, "filter_open(stream_state)");
1365
83.3k
        if (sst == 0)
1366
0
            return_error(gs_error_VMerror);
1367
83.3k
    }
1368
83.4k
    code = file_open_stream((char *)0, 0, file_access, buffer_size, &s,
1369
83.4k
                                (gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
1370
83.4k
    if (code < 0) {
1371
0
        gs_free_object(mem, sst, "filter_open(stream_state)");
1372
0
        return code;
1373
0
    }
1374
83.4k
    s_std_init(s, s->cbuf, s->bsize, procs,
1375
83.4k
               (*file_access == 'r' ? s_mode_read : s_mode_write));
1376
83.4k
    s->procs.process = templat->process;
1377
83.4k
    s->save_close = s->procs.close;
1378
83.4k
    s->procs.close = file_close_file;
1379
83.4k
    if (sst == 0) {
1380
        /* This stream doesn't have any state of its own. */
1381
        /* Hack: use the stream itself as the state. */
1382
100
        sst = (stream_state *) s;
1383
83.3k
    } else if (st != 0)         /* might not have client parameters */
1384
83.3k
        memcpy(sst, st, ssize);
1385
83.4k
    s->state = sst;
1386
83.4k
    s_init_state(sst, templat, mem);
1387
83.4k
    sst->report_error = filter_report_error;
1388
1389
83.4k
    if (templat->init != 0) {
1390
83.3k
        code = (*templat->init)(sst);
1391
83.3k
        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
83.3k
    }
1397
83.4k
    make_stream_file(pfile, s, file_access);
1398
83.4k
    return 0;
1399
83.4k
}
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
}