Coverage Report

Created: 2022-04-16 11:23

/src/ghostpdl/psi/zfile.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* 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
580k
{
127
580k
    long i;
128
580k
    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
580k
    const char *win_sep2 = "\\";
132
580k
    bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
133
580k
    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
580k
    if (iodev && iodev != iodev_default(imemory)) {
139
243k
        return 0;
140
243k
    }
141
142
    /* Assuming a reduced file name. */
143
337k
    if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
144
0
        return 0;       /* if Permissions not found, just allow access */
145
146
337k
    for (i=0; i<r_size(permitlist); i++) {
147
337k
        ref permitstring;
148
337k
        const string_match_params win_filename_params = {
149
                '*', '?', '\\', true, true      /* ignore case & '/' == '\\' */
150
337k
        };
151
337k
        const byte *permstr;
152
337k
        uint permlen;
153
337k
        int cwd_len = 0;
154
155
337k
        if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
156
337k
            r_type(&permitstring) != t_string
157
337k
           )
158
0
            break;      /* any problem, just fail */
159
337k
        permstr = permitstring.value.bytes;
160
337k
        permlen = r_size(&permitstring);
161
        /*
162
         * Check if any file name is permitted with "*".
163
         */
164
337k
        if (permlen == 1 && permstr[0] == '*')
165
337k
            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
337k
}
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
580k
{
199
580k
    char fname_reduced[gp_file_name_sizeof];
200
580k
    uint rlen = sizeof(fname_reduced);
201
202
580k
    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
580k
    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
205
580k
}
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
464k
{
212
464k
    i_ctx_t *i_ctx_p = get_minst_from_memory(mem)->i_ctx_p;
213
464k
    gs_parsed_file_name_t pname;
214
464k
    const char *permitgroup = permission[0] == 'r' ? "PermitFileReading" : "PermitFileWriting";
215
464k
    int code = gs_parse_file_name(&pname, fname, len, imemory);
216
464k
    if (code < 0)
217
0
        return code;
218
219
464k
    if (pname.iodev && i_ctx_p->LockFilePermissions
220
464k
         && strcmp(pname.iodev->dname, "%pipe%") == 0) {
221
0
        code = gs_note_error(gs_error_invalidfileaccess);
222
0
    }
223
464k
    else {
224
464k
        code = check_file_permissions(i_ctx_p, pname.fname, pname.len, pname.iodev, permitgroup);
225
464k
    }
226
464k
    return code;
227
464k
}
228
229
/* <name_string> <access_string> file <file> */
230
int                             /* exported for zsysvm.c */
231
zfile(i_ctx_t *i_ctx_p)
232
93.7k
{
233
93.7k
    os_ptr op = osp;
234
93.7k
    char file_access[4];
235
93.7k
    gs_parsed_file_name_t pname;
236
93.7k
    int code = parse_file_access_string(op, file_access);
237
93.7k
    stream *s;
238
239
93.7k
    if (code < 0)
240
0
        return code;
241
93.7k
    code = parse_file_name(op-1, &pname, i_ctx_p->LockFilePermissions, imemory);
242
93.7k
    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
93.7k
    if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) {
250
78.9k
        bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0);
251
78.9k
        bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0);
252
78.9k
        if (pname.fname)
253
0
            return_error(gs_error_invalidfileaccess);
254
78.9k
        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
78.9k
        pname.iodev->state = i_ctx_p;
275
78.9k
        code = (*pname.iodev->procs.open_device)(pname.iodev,
276
78.9k
                                                 file_access, &s, imemory);
277
78.9k
        pname.iodev->state = NULL;
278
78.9k
    } else {
279
14.7k
        if (pname.iodev == NULL)
280
7.51k
            pname.iodev = iodev_default(imemory);
281
14.7k
        code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory);
282
14.7k
    }
283
93.7k
    if (code < 0)
284
11.3k
        return code;
285
82.4k
    if (s == NULL)
286
0
        return_error(gs_error_undefinedfilename);
287
82.4k
    code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1));
288
82.4k
    if (code < 0) {
289
0
        sclose(s);
290
0
        return_error(gs_error_VMerror);
291
0
    }
292
82.4k
    make_stream_file(op - 1, s, file_access);
293
82.4k
    pop(1);
294
82.4k
    return code;
295
82.4k
}
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
669
{
321
669
    ref *SAFETY;
322
669
    ref *tempfiles;
323
669
    ref kname, bref;
324
669
    int code = 0;
325
326
669
    if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
327
669
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0) {
328
0
        return 0;
329
0
    }
330
669
    if ((code = name_ref(imemory, fname, len, &kname, 1)) < 0) {
331
0
        return code;
332
0
    }
333
669
    make_bool(&bref, true);
334
669
    if (add)
335
669
        return idict_put(tempfiles, &kname, &bref);
336
0
    else
337
0
        return idict_undef(tempfiles, &kname);
338
669
}
339
340
/* ------ Level 2 extensions ------ */
341
342
/* <string> deletefile - */
343
static int
344
zdeletefile(i_ctx_t *i_ctx_p)
345
668
{
346
668
    os_ptr op = osp;
347
668
    gs_parsed_file_name_t pname;
348
668
    int code = parse_real_file_name(op, &pname, imemory, "deletefile");
349
668
    bool is_temp = false;
350
351
668
    if (code < 0)
352
0
        return code;
353
668
    if (pname.iodev == iodev_default(imemory)) {
354
668
        if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
355
668
                pname.iodev, "PermitFileControl")) < 0 &&
356
668
                 !(is_temp = file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op)))) {
357
0
            return code;
358
0
        }
359
668
    }
360
361
668
    code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
362
363
668
    if (code >= 0 && is_temp)
364
0
        code = record_file_is_tempfile(i_ctx_p, (unsigned char *)pname.fname, strlen(pname.fname), false);
365
366
668
    gs_free_file_name(&pname, "deletefile");
367
668
    if (code < 0)
368
0
        return code;
369
668
    pop(1);
370
668
    return 0;
371
668
}
372
373
/* <template> <proc> <scratch> filenameforall - */
374
static int file_continue(i_ctx_t *);
375
static int file_cleanup(i_ctx_t *);
376
static int
377
zfilenameforall(i_ctx_t *i_ctx_p)
378
9.56k
{
379
9.56k
    os_ptr op = osp;
380
9.56k
    file_enum *pfen;
381
9.56k
    gx_io_device *iodev = NULL;
382
9.56k
    gs_parsed_file_name_t pname;
383
9.56k
    int code = 0;
384
385
9.56k
    check_write_type(*op, t_string);
386
9.56k
    check_proc(op[-1]);
387
9.56k
    check_read_type(op[-2], t_string);
388
    /* Push a mark, the iodev, devicenamelen, the scratch string, the enumerator, */
389
    /* and the procedure, and invoke the continuation. */
390
9.56k
    check_estack(7);
391
    /* Get the iodevice */
392
9.56k
    code = parse_file_name(op-2, &pname, i_ctx_p->LockFilePermissions, imemory);
393
9.56k
    if (code < 0)
394
0
        return code;
395
9.56k
    iodev = (pname.iodev == NULL) ? iodev_default(imemory) : pname.iodev;
396
397
    /* Check for several conditions that just cause us to return success */
398
9.56k
    if (pname.len == 0 || iodev->procs.enumerate_files == iodev_no_enumerate_files) {
399
0
        pop(3);
400
0
        return 0;       /* no pattern, or device not found -- just return */
401
0
    }
402
9.56k
    pfen = iodev->procs.enumerate_files(imemory, iodev, (const char *)pname.fname,
403
9.56k
                pname.len);
404
9.56k
    if (pfen == 0)
405
0
        return_error(gs_error_VMerror);
406
9.56k
    push_mark_estack(es_for, file_cleanup);
407
9.56k
    ++esp;
408
9.56k
    make_istruct(esp, 0, iodev);
409
9.56k
    ++esp;
410
9.56k
    make_int(esp, r_size(op-2) - pname.len);
411
9.56k
    *++esp = *op;
412
9.56k
    ++esp;
413
9.56k
    make_istruct(esp, 0, pfen);
414
9.56k
    *++esp = op[-1];
415
9.56k
    ref_stack_pop(&o_stack, 3);
416
9.56k
    code = file_continue(i_ctx_p);
417
9.56k
    return (code == o_pop_estack ? o_push_estack : code);
418
9.56k
}
419
/* Continuation operator for enumerating files */
420
static int
421
file_continue(i_ctx_t *i_ctx_p)
422
10.9k
{
423
10.9k
    os_ptr op = osp;
424
10.9k
    es_ptr pscratch = esp - 2;
425
10.9k
    file_enum *pfen = r_ptr(esp - 1, file_enum);
426
10.9k
    int devlen = esp[-3].value.intval;
427
10.9k
    gx_io_device *iodev = r_ptr(esp - 4, gx_io_device);
428
10.9k
    uint len = r_size(pscratch);
429
10.9k
    uint code;
430
431
10.9k
    if (len < devlen) {
432
0
        esp -= 5;               /* pop proc, pfen, devlen, iodev , mark */
433
0
        return_error(gs_error_rangecheck);     /* not even room for device len */
434
0
    }
435
436
10.9k
    do {
437
10.9k
        memcpy((char *)pscratch->value.bytes, iodev->dname, devlen);
438
10.9k
        code = iodev->procs.enumerate_next(imemory, pfen, (char *)pscratch->value.bytes + devlen,
439
10.9k
                    len - devlen);
440
10.9k
        if (code == ~(uint) 0) {    /* all done */
441
9.56k
            esp -= 5;               /* pop proc, pfen, devlen, iodev , mark */
442
9.56k
            return o_pop_estack;
443
9.56k
        } else if (code > len) {      /* overran string */
444
0
            return_error(gs_error_rangecheck);
445
0
        }
446
1.36k
        else if (iodev != iodev_default(imemory)
447
1.36k
              || (check_file_permissions(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, iodev, "PermitFileReading")) == 0) {
448
1.36k
            push(1);
449
1.36k
            ref_assign(op, pscratch);
450
1.36k
            r_set_size(op, code + devlen);
451
1.36k
            push_op_estack(file_continue);  /* come again */
452
1.36k
            *++esp = pscratch[2];   /* proc */
453
1.36k
            return o_push_estack;
454
1.36k
        }
455
10.9k
    } while(1);
456
10.9k
}
457
/* Cleanup procedure for enumerating files */
458
static int
459
file_cleanup(i_ctx_t *i_ctx_p)
460
0
{
461
0
    gx_io_device *iodev = r_ptr(esp + 2, gx_io_device);
462
463
0
    iodev->procs.enumerate_close(imemory, r_ptr(esp + 5, file_enum));
464
0
    return 0;
465
0
}
466
467
/* <string1> <string2> renamefile - */
468
static int
469
zrenamefile(i_ctx_t *i_ctx_p)
470
0
{
471
0
    int code;
472
0
    os_ptr op = osp;
473
0
    gs_parsed_file_name_t pname1, pname2;
474
475
0
    code = parse_real_file_name(op, &pname2, imemory, "renamefile(to)");
476
0
    if (code < 0)
477
0
        return code;
478
479
0
    pname1.fname = 0;
480
0
    code = parse_real_file_name(op - 1, &pname1, imemory, "renamefile(from)");
481
0
    if (code >= 0) {
482
0
        gx_io_device *iodev_dflt = iodev_default(imemory);
483
0
        if (pname1.iodev != pname2.iodev ) {
484
0
            if (pname1.iodev == iodev_dflt)
485
0
                pname1.iodev = pname2.iodev;
486
0
            if (pname2.iodev == iodev_dflt)
487
0
                pname2.iodev = pname1.iodev;
488
0
        }
489
0
        if (pname1.iodev != pname2.iodev ||
490
0
            (pname1.iodev == iodev_dflt &&
491
                /*
492
                 * We require FileControl permissions on the source path
493
                 * unless it is a temporary file. Also, we require FileControl
494
                 * and FileWriting permissions to the destination file/path.
495
                 */
496
0
              ((check_file_permissions(i_ctx_p, pname1.fname, pname1.len,
497
0
                                        pname1.iodev, "PermitFileControl") < 0 &&
498
0
                  !file_is_tempfile(i_ctx_p, op[-1].value.bytes, r_size(op - 1))) ||
499
0
              (check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
500
0
                                        pname2.iodev, "PermitFileControl") < 0 ||
501
0
              check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
502
0
                                        pname2.iodev, "PermitFileWriting") < 0 )))) {
503
0
            code = gs_note_error(gs_error_invalidfileaccess);
504
0
        } else {
505
0
            code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
506
0
                            pname1.fname, pname2.fname);
507
0
        }
508
0
    }
509
0
    gs_free_file_name(&pname2, "renamefile(to)");
510
0
    gs_free_file_name(&pname1, "renamefile(from)");
511
0
    if (code < 0)
512
0
        return code;
513
0
    pop(2);
514
0
    return 0;
515
0
}
516
517
/* <file> status <open_bool> */
518
/* <string> status <pages> <bytes> <ref_time> <creation_time> true */
519
/* <string> status false */
520
static int
521
zstatus(i_ctx_t *i_ctx_p)
522
9.31k
{
523
9.31k
    os_ptr op = osp;
524
525
9.31k
    switch (r_type(op)) {
526
704
        case t_file:
527
704
            {
528
704
                stream *s;
529
530
704
                make_bool(op, (file_is_valid(s, op) ? 1 : 0));
531
704
            }
532
704
            return 0;
533
8.60k
        case t_string:
534
8.60k
            {
535
8.60k
                gs_parsed_file_name_t pname;
536
8.60k
                struct stat fstat;
537
8.60k
                int code = parse_file_name(op, &pname,
538
8.60k
                                           i_ctx_p->LockFilePermissions, imemory);
539
8.60k
                if (code < 0) {
540
0
                    if (code == gs_error_undefinedfilename) {
541
0
                        make_bool(op, 0);
542
0
                        code = 0;
543
0
                    }
544
0
                    return code;
545
0
                }
546
8.60k
                code = gs_terminate_file_name(&pname, imemory, "status");
547
8.60k
                if (code < 0)
548
0
                    return code;
549
8.60k
                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
550
8.60k
                                       pname.iodev, "PermitFileReading")) >= 0) {
551
8.60k
                    code = (*pname.iodev->procs.file_status)(pname.iodev,
552
8.60k
                                                       pname.fname, &fstat);
553
8.60k
                }
554
8.60k
                switch (code) {
555
4.78k
                    case 0:
556
4.78k
                        check_ostack(4);
557
                        /*
558
                         * Check to make sure that the file size fits into
559
                         * a PostScript integer.  (On some systems, long is
560
                         * 32 bits, but file sizes are 64 bits.)
561
                         */
562
4.78k
                        push(4);
563
4.78k
                        make_int(op - 4, stat_blocks(&fstat));
564
4.78k
                        make_int(op - 3, fstat.st_size);
565
                        /*
566
                         * We can't check the value simply by using ==,
567
                         * because signed/unsigned == does the wrong thing.
568
                         * Instead, since integer assignment only keeps the
569
                         * bottom bits, we convert the values to double
570
                         * and then test for equality.  This handles all
571
                         * cases of signed/unsigned or width mismatch.
572
                         */
573
4.78k
                        if ((double)op[-4].value.intval !=
574
4.78k
                              (double)stat_blocks(&fstat) ||
575
4.78k
                            (double)op[-3].value.intval !=
576
4.78k
                              (double)fstat.st_size
577
4.78k
                            )
578
0
                            return_error(gs_error_limitcheck);
579
4.78k
                        make_int(op - 2, fstat.st_mtime);
580
4.78k
                        make_int(op - 1, fstat.st_ctime);
581
4.78k
                        make_bool(op, 1);
582
4.78k
                        break;
583
3.82k
                    case gs_error_undefinedfilename:
584
3.82k
                        make_bool(op, 0);
585
3.82k
                        code = 0;
586
8.60k
                }
587
8.60k
                gs_free_file_name(&pname, "status");
588
8.60k
                return code;
589
8.60k
            }
590
0
        default:
591
0
            return_op_typecheck(op);
592
9.31k
    }
593
9.31k
}
594
595
/* ------ Non-standard extensions ------ */
596
597
/* <executable_file> .execfile - */
598
static int
599
zexecfile(i_ctx_t *i_ctx_p)
600
0
{
601
0
    os_ptr op = osp;
602
603
0
    check_type_access(*op, t_file, a_executable | a_read | a_execute);
604
0
    check_estack(4);            /* cleanup, file, finish, file */
605
0
    push_mark_estack(es_other, execfile_cleanup);
606
0
    *++esp = *op;
607
0
    push_op_estack(execfile_finish);
608
0
    return zexec(i_ctx_p);
609
0
}
610
/* Finish normally. */
611
static int
612
execfile_finish(i_ctx_t *i_ctx_p)
613
0
{
614
0
    check_ostack(1);
615
0
    esp -= 2;
616
0
    execfile_cleanup(i_ctx_p);
617
0
    return o_pop_estack;
618
0
}
619
/* Clean up by closing the file. */
620
static int
621
execfile_cleanup(i_ctx_t *i_ctx_p)
622
0
{
623
0
    check_ostack(1);
624
0
    *++osp = esp[2];
625
0
    return zclosefile(i_ctx_p);
626
0
}
627
628
/* - .filenamelistseparator <string> */
629
static int
630
zfilenamelistseparator(i_ctx_t *i_ctx_p)
631
0
{
632
0
    os_ptr op = osp;
633
634
0
    push(1);
635
0
    make_const_string(op, avm_foreign | a_readonly, 1,
636
0
                      (const byte *)&gp_file_name_list_separator);
637
0
    return 0;
638
0
}
639
640
/* <name> .filenamesplit <dir> <base> <extension> */
641
static int
642
zfilenamesplit(i_ctx_t *i_ctx_p)
643
0
{
644
0
    os_ptr op = osp;
645
646
0
    check_read_type(*op, t_string);
647
/****** NOT IMPLEMENTED YET ******/
648
0
    return_error(gs_error_undefined);
649
0
}
650
651
/* <string> .libfile <file> true */
652
/* <string> .libfile <string> false */
653
int                             /* exported for zsysvm.c */
654
zlibfile(i_ctx_t *i_ctx_p)
655
15.5k
{
656
15.5k
    os_ptr op = osp;
657
15.5k
    int code;
658
15.5k
    byte cname[DEFAULT_BUFFER_SIZE];
659
15.5k
    uint clen;
660
15.5k
    gs_parsed_file_name_t pname;
661
15.5k
    stream *s;
662
15.5k
    gx_io_device *iodev_dflt;
663
664
15.5k
    check_ostack(2);
665
15.5k
    code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions, imemory);
666
15.5k
    if (code < 0)
667
0
        return code;
668
15.5k
    iodev_dflt = iodev_default(imemory);
669
15.5k
    if (pname.iodev == NULL)
670
11.7k
        pname.iodev = iodev_dflt;
671
15.5k
    if (pname.iodev != iodev_dflt) { /* Non-OS devices don't have search paths (yet). */
672
3.82k
        code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
673
3.82k
        if (s == NULL) code = gs_note_error(gs_error_undefinedfilename);
674
3.82k
        if (code >= 0) {
675
683
            code = ssetfilename(s, op->value.const_bytes, r_size(op));
676
683
            if (code < 0) {
677
0
                sclose(s);
678
0
                return_error(gs_error_VMerror);
679
0
            }
680
683
        }
681
3.82k
        if (code < 0) {
682
3.14k
            push(1);
683
3.14k
            make_false(op);
684
3.14k
            return 0;
685
3.14k
        }
686
683
        make_stream_file(op, s, "r");
687
11.7k
    } else {
688
11.7k
        ref fref;
689
690
11.7k
        code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len,
691
11.7k
                             (char *)cname, sizeof(cname), &clen, &fref);
692
11.7k
        if (code >= 0) {
693
2.73k
            s = fptr(&fref);
694
2.73k
            code = ssetfilename(s, cname, clen);
695
2.73k
            if (code < 0) {
696
0
                sclose(s);
697
0
                return_error(gs_error_VMerror);
698
0
            }
699
2.73k
        }
700
11.7k
        if (code < 0) {
701
9.01k
            if (code == gs_error_VMerror || code == gs_error_invalidfileaccess)
702
0
                return code;
703
9.01k
            push(1);
704
9.01k
            make_false(op);
705
9.01k
            return 0;
706
9.01k
        }
707
2.73k
        ref_assign(op, &fref);
708
2.73k
    }
709
15.5k
    push(1);
710
3.41k
    make_true(op);
711
3.41k
    return 0;
712
3.41k
}
713
714
/* A "simple" prefix is defined as a (possibly empty) string of
715
   alphanumeric, underscore, and hyphen characters. */
716
static bool
717
prefix_is_simple(const char *pstr)
718
669
{
719
669
    int i;
720
669
    char c;
721
722
2.67k
    for (i = 0; (c = pstr[i]) != 0; i++) {
723
2.00k
        if (!(c == '-' || c == '_' || (c >= '0' && c <= '9') ||
724
2.00k
              (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
725
0
            return false;
726
2.00k
    }
727
669
    return true;
728
669
}
729
730
/* <prefix|null> <access_string> .tempfile <name_string> <file> */
731
static int
732
ztempfile(i_ctx_t *i_ctx_p)
733
669
{
734
669
    os_ptr op = osp;
735
669
    const char *pstr;
736
669
    char fmode[4];
737
669
    char fmode_temp[4];
738
669
    int code = parse_file_access_string(op, fmode_temp);
739
669
    char *prefix = NULL;
740
669
    char *fname= NULL;
741
669
    uint fnlen;
742
669
    gp_file *sfile;
743
669
    stream *s;
744
669
    byte *buf, *sbody;
745
746
669
    if (code < 0)
747
0
        return code;
748
669
    prefix = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(prefix)");
749
669
    fname = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(fname)");
750
669
    if (!prefix || !fname) {
751
0
        code = gs_note_error(gs_error_VMerror);
752
0
        goto done;
753
0
    }
754
755
669
    snprintf(fmode, sizeof(fmode), "%s%s", fmode_temp, gp_fmode_binary_suffix);
756
669
    if (r_has_type(op - 1, t_null))
757
669
        pstr = gp_scratch_file_name_prefix;
758
0
    else {
759
0
        uint psize;
760
761
0
        check_read_type(op[-1], t_string);
762
0
        psize = r_size(op - 1);
763
0
        if (psize >= gp_file_name_sizeof) {
764
0
            code = gs_note_error(gs_error_rangecheck);
765
0
            goto done;
766
0
        }
767
0
        memcpy(prefix, op[-1].value.const_bytes, psize);
768
0
        prefix[psize] = 0;
769
0
        pstr = prefix;
770
0
    }
771
772
669
    if (gp_file_name_is_absolute(pstr, strlen(pstr))) {
773
0
        int plen = strlen(pstr);
774
0
        const char *sep = gp_file_name_separator();
775
#ifdef DEBUG
776
        int seplen = strlen(sep);
777
        if (seplen != 1)
778
            return_error(gs_error_Fatal);
779
#endif
780
        /* strip off the file name prefix, leave just the directory name
781
         * so we can check if we are allowed to write to it
782
         */
783
0
        for ( ; plen >=0; plen--) {
784
0
            if (pstr[plen] == sep[0])
785
0
                break;
786
0
        }
787
0
        memcpy(fname, pstr, plen);
788
0
        fname[plen] = '\0';
789
0
        if (check_file_permissions(i_ctx_p, fname, strlen(fname),
790
0
                                   NULL, "PermitFileWriting") < 0) {
791
0
            code = gs_note_error(gs_error_invalidfileaccess);
792
0
            goto done;
793
0
        }
794
669
    } else if (!prefix_is_simple(pstr)) {
795
0
        code = gs_note_error(gs_error_invalidfileaccess);
796
0
        goto done;
797
0
    }
798
799
669
    s = file_alloc_stream(imemory, "ztempfile(stream)");
800
669
    if (s == 0) {
801
0
        code = gs_note_error(gs_error_VMerror);
802
0
        goto done;
803
0
    }
804
669
    buf = gs_alloc_bytes(imemory, file_default_buffer_size,
805
669
                         "ztempfile(buffer)");
806
669
    if (buf == 0) {
807
0
        code = gs_note_error(gs_error_VMerror);
808
0
        goto done;
809
0
    }
810
669
    sfile = gp_open_scratch_file(imemory, pstr, fname, fmode);
811
669
    if (sfile == 0) {
812
0
        gs_free_object(imemory, buf, "ztempfile(buffer)");
813
0
        code = gs_note_error(gs_error_invalidfileaccess);
814
0
        goto done;
815
0
    }
816
669
    fnlen = strlen(fname);
817
669
    sbody = ialloc_string(fnlen, ".tempfile(fname)");
818
669
    if (sbody == 0) {
819
0
        gs_free_object(imemory, buf, "ztempfile(buffer)");
820
0
        code = gs_note_error(gs_error_VMerror);
821
0
        goto done;
822
0
    }
823
669
    memcpy(sbody, fname, fnlen);
824
669
    file_init_stream(s, sfile, fmode, buf, file_default_buffer_size);
825
669
    code = ssetfilename(s, (const unsigned char*) fname, fnlen);
826
669
    if (code < 0) {
827
0
        gx_io_device *iodev_dflt = iodev_default(imemory);
828
0
        sclose(s);
829
0
        iodev_dflt->procs.delete_file(iodev_dflt, fname);
830
0
        ifree_string(sbody, fnlen, ".tempfile(fname)");
831
0
        code = gs_note_error(gs_error_VMerror);
832
0
        goto done;
833
0
    }
834
669
    make_string(op - 1, a_readonly | icurrent_space, fnlen, sbody);
835
669
    make_stream_file(op, s, fmode);
836
669
    code = record_file_is_tempfile(i_ctx_p, (unsigned char *)fname, fnlen, true);
837
838
669
done:
839
669
    if (prefix)
840
669
        gs_free_object(imemory, prefix, "ztempfile(prefix)");
841
669
    if (fname)
842
669
        gs_free_object(imemory, fname, "ztempfile(fname)");
843
669
    return code;
844
669
}
845
846
/* Return the filename used to open a file object
847
 * this is currently only used by the PDF interpreter to
848
 * get a filename corresponding to the PDF file being
849
 * executed. Since we always execute PDF files from disk
850
 * this will always be OK.
851
 */
852
static int zgetfilename(i_ctx_t *i_ctx_p)
853
0
{
854
0
    os_ptr op = osp;
855
0
    uint fnlen;
856
0
    gs_const_string pfname;
857
0
    stream *s;
858
0
    byte *sbody;
859
0
    int code;
860
861
0
    check_ostack(1);
862
0
    check_read_type(*op, t_file);
863
864
0
    s = (op)->value.pfile;
865
866
0
    code = sfilename(s, &pfname);
867
0
    if (code < 0) {
868
0
        pfname.size = 0;
869
0
    }
870
871
0
    fnlen = pfname.size;
872
0
    sbody = ialloc_string(fnlen, ".getfilename");
873
0
    if (sbody == 0) {
874
0
        code = gs_note_error(gs_error_VMerror);
875
0
        return code;
876
0
    }
877
0
    memcpy(sbody, pfname.data, fnlen);
878
0
    make_string(op, a_readonly | icurrent_space, fnlen, sbody);
879
880
0
    return 0;
881
0
}
882
883
static int zaddcontrolpath(i_ctx_t *i_ctx_p)
884
15.0k
{
885
15.0k
    int code;
886
15.0k
    os_ptr op = osp;
887
15.0k
    ref nsref;
888
15.0k
    unsigned int n = -1;
889
890
15.0k
    check_ostack(2);
891
15.0k
    check_read_type(*op, t_string);
892
15.0k
    check_type(op[-1], t_name);
893
894
15.0k
    name_string_ref(imemory, op-1, &nsref);
895
15.0k
    if (r_size(&nsref) == 17 &&
896
15.0k
        strncmp((const char *)nsref.value.const_bytes,
897
15.0k
                "PermitFileReading", 17) == 0) {
898
12.2k
        n = gs_permit_file_reading;
899
12.2k
    } else if (r_size(&nsref) == 17 &&
900
2.73k
               strncmp((const char *)nsref.value.const_bytes,
901
2.73k
                       "PermitFileWriting", 17) == 0) {
902
1.36k
        n = gs_permit_file_writing;
903
1.36k
    } else if (r_size(&nsref) == 17 &&
904
1.36k
               strncmp((const char *)nsref.value.const_bytes,
905
1.36k
                       "PermitFileControl", 17) == 0) {
906
1.36k
        n = gs_permit_file_control;
907
1.36k
    }
908
909
15.0k
    if (n == -1)
910
0
        code = gs_note_error(gs_error_rangecheck);
911
15.0k
    else if (gs_is_path_control_active(imemory))
912
0
        code = gs_note_error(gs_error_Fatal);
913
15.0k
    else
914
15.0k
        code = gs_add_control_path_len(imemory, n,
915
15.0k
                                       (const char *)op[0].value.const_bytes,
916
15.0k
                                       (size_t)r_size(&op[0]));
917
15.0k
    pop(2);
918
15.0k
    return code;
919
15.0k
}
920
921
static int zactivatepathcontrol(i_ctx_t *i_ctx_p)
922
683
{
923
683
    gs_activate_path_control(imemory, 1);
924
683
    return 0;
925
683
}
926
static int zcurrentpathcontrolstate(i_ctx_t *i_ctx_p)
927
683
{
928
683
    os_ptr op = osp;
929
683
    push(1);
930
683
    if (gs_is_path_control_active(imemory)) {
931
0
        make_true(op);
932
0
    }
933
683
    else {
934
683
        make_false(op);
935
683
    }
936
683
    return 0;
937
683
}
938
939
/* ------ Initialization procedure ------ */
940
941
const op_def zfile_op_defs[] =
942
{
943
    {"1deletefile", zdeletefile},
944
    {"1.execfile", zexecfile},
945
    {"2file", zfile},
946
    {"3filenameforall", zfilenameforall},
947
    {"0.filenamelistseparator", zfilenamelistseparator},
948
    {"1.filenamesplit", zfilenamesplit},
949
    {"1.libfile", zlibfile},
950
    {"2renamefile", zrenamefile},
951
    {"1status", zstatus},
952
    {"2.tempfile", ztempfile},
953
                /* Internal operators */
954
    {"0%file_continue", file_continue},
955
    {"0%execfile_finish", execfile_finish},
956
    {"1.getfilename", zgetfilename},
957
    /* Control path operators */
958
    {"2.addcontrolpath", zaddcontrolpath},
959
    {"0.activatepathcontrol", zactivatepathcontrol},
960
    {"0.currentpathcontrolstate", zcurrentpathcontrolstate},
961
    op_def_end(0)
962
};
963
964
/* ------ File name parsing ------ */
965
966
/* Parse a file name into device and individual name. */
967
/* See gsfname.c for details. */
968
static int
969
parse_file_name(const ref * op, gs_parsed_file_name_t * pfn, bool safemode,
970
                gs_memory_t *memory)
971
127k
{
972
127k
    int code;
973
974
127k
    check_read_type(*op, t_string);
975
127k
    code = gs_parse_file_name(pfn, (const char *)op->value.const_bytes,
976
127k
                              r_size(op), memory);
977
127k
    if (code < 0)
978
0
        return code;
979
    /*
980
     * Check here for the %pipe device which is illegal when
981
     * LockFilePermissions is true. In the future we might want to allow
982
     * the %pipe device to be included on the PermitFile... paths, but
983
     * for now it is simply disallowed.
984
     */
985
127k
    if (pfn->iodev && safemode && strcmp(pfn->iodev->dname, "%pipe%") == 0)
986
0
        return gs_error_invalidfileaccess;
987
127k
    return code;
988
127k
}
989
990
/* Parse a real (non-device) file name and convert to a C string. */
991
/* See gsfname.c for details. */
992
static int
993
parse_real_file_name(const ref *op, gs_parsed_file_name_t *pfn,
994
                     gs_memory_t *mem, client_name_t cname)
995
668
{
996
668
    check_read_type(*op, t_string);
997
668
    return gs_parse_real_file_name(pfn, (const char *)op->value.const_bytes,
998
668
                                   r_size(op), mem, cname);
999
668
}
1000
1001
/* Parse the access string for opening a file. */
1002
/* [4] is for r/w, +, b, \0. */
1003
static int
1004
parse_file_access_string(const ref *op, char file_access[4])
1005
94.4k
{
1006
94.4k
    const byte *astr;
1007
1008
94.4k
    check_read_type(*op, t_string);
1009
94.4k
    astr = op->value.const_bytes;
1010
94.4k
    switch (r_size(op)) {
1011
669
        case 2:
1012
669
            if (astr[1] != '+')
1013
0
                return_error(gs_error_invalidfileaccess);
1014
669
            file_access[1] = '+';
1015
669
            file_access[2] = 0;
1016
669
            break;
1017
93.7k
        case 1:
1018
93.7k
            file_access[1] = 0;
1019
93.7k
            break;
1020
0
        default:
1021
0
            return_error(gs_error_invalidfileaccess);
1022
94.4k
    }
1023
94.4k
    switch (astr[0]) {
1024
16.7k
        case 'r':
1025
94.4k
        case 'w':
1026
94.4k
        case 'a':
1027
94.4k
            break;
1028
0
        default:
1029
0
            return_error(gs_error_invalidfileaccess);
1030
94.4k
    }
1031
94.4k
    file_access[0] = astr[0];
1032
94.4k
    return 0;
1033
94.4k
}
1034
1035
/* ------ Stream opening ------ */
1036
1037
/*
1038
 * Open a file specified by a parsed file name (which may be only a
1039
 * device).
1040
 */
1041
int
1042
zopen_file(i_ctx_t *i_ctx_p, const gs_parsed_file_name_t *pfn,
1043
           const char *file_access, stream **ps, gs_memory_t *mem)
1044
18.5k
{
1045
18.5k
    gx_io_device *const iodev = pfn->iodev;
1046
18.5k
    int code = 0;
1047
1048
18.5k
    if (pfn->fname == NULL) {     /* just a device */
1049
0
        iodev->state = i_ctx_p;
1050
0
        code = iodev->procs.open_device(iodev, file_access, ps, mem);
1051
0
        iodev->state = NULL;
1052
0
        return code;
1053
0
    }
1054
18.5k
    else {                      /* file */
1055
18.5k
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
1056
1057
18.5k
        if (open_file == 0)
1058
7.51k
            open_file = iodev_os_open_file;
1059
        /* Check OS files to make sure we allow the type of access */
1060
18.5k
        if (open_file == iodev_os_open_file) {
1061
7.51k
            code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev,
1062
7.51k
                file_access[0] == 'r' ? "PermitFileReading" : "PermitFileWriting");
1063
1064
7.51k
            if (code < 0 && !file_is_tempfile(i_ctx_p,
1065
0
                                          (const uchar *)pfn->fname, pfn->len))
1066
0
                return code;
1067
7.51k
        }
1068
18.5k
        return open_file(iodev, pfn->fname, pfn->len, file_access, ps, mem);
1069
18.5k
    }
1070
18.5k
}
1071
1072
/*
1073
 * Define the file_open procedure for the %os% IODevice (also used, as the
1074
 * default, for %pipe% and possibly others).
1075
 */
1076
static int
1077
iodev_os_open_file(gx_io_device * iodev, const char *fname, uint len,
1078
                   const char *file_access, stream ** ps, gs_memory_t * mem)
1079
106k
{
1080
106k
    return file_open_stream(fname, len, file_access,
1081
106k
                            file_default_buffer_size, ps,
1082
106k
                            iodev, iodev->procs.gp_fopen, mem);
1083
106k
}
1084
1085
/* Make a t_file reference to a stream. */
1086
void
1087
make_stream_file(ref * pfile, stream * s, const char *access)
1088
94.0k
{
1089
94.0k
    uint attrs =
1090
94.0k
        (access[1] == '+' ? a_write + a_read + a_execute : 0) |
1091
94.0k
        imemory_space((gs_ref_memory_t *) s->memory);
1092
1093
94.0k
    if (access[0] == 'r') {
1094
15.7k
        make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
1095
15.7k
        s->write_id = 0;
1096
78.3k
    } else {
1097
78.3k
        make_file(pfile, attrs | a_write, s->write_id, s);
1098
78.3k
        s->read_id = 0;
1099
78.3k
    }
1100
94.0k
}
1101
1102
/* return zero for success, -ve for error, +1 for continue */
1103
static int
1104
lib_file_open_search_with_no_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1105
                                     const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1106
                                     gx_io_device *iodev, bool starting_arg_file, char *fmode)
1107
0
{
1108
0
    stream *s;
1109
0
    uint blen1 = blen;
1110
0
    struct stat fstat;
1111
0
    int code = 1;
1112
1113
0
    if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success)
1114
0
      goto skip;
1115
1116
0
    if (starting_arg_file || check_file_permissions(i_ctx_p, buffer, blen1, iodev, "PermitFileReading") >= 0) {
1117
0
        if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1118
0
                       (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1119
0
            *pclen = blen1;
1120
0
            make_stream_file(pfile, s, "r");
1121
0
            code = 0;
1122
0
        }
1123
0
    }
1124
0
    else {
1125
        /* If we are not allowed to open the file by check_file_permissions_aux()
1126
         * and if the file exists, throw an error.......
1127
         * Otherwise, keep searching.
1128
         */
1129
0
        if ((*iodev->procs.file_status)(iodev,  buffer, &fstat) >= 0) {
1130
0
            code = gs_note_error(gs_error_invalidfileaccess);
1131
0
        }
1132
0
    }
1133
1134
0
 skip:
1135
0
    return code;
1136
0
}
1137
1138
/* return zero for success, -ve for error, +1 for continue */
1139
static int
1140
lib_file_open_search_with_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1141
                                  const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1142
                                  gx_io_device *iodev, bool starting_arg_file, char *fmode)
1143
12.4k
{
1144
12.4k
    stream *s;
1145
12.4k
    const gs_file_path *pfpath = lib_path;
1146
12.4k
    uint pi;
1147
12.4k
    int code = 1;
1148
1149
133k
    for (pi = 0; pi < r_size(&pfpath->list) && code == 1; ++pi) {
1150
120k
        const ref *prdir = pfpath->list.value.refs + pi;
1151
120k
        const char *pstr = (const char *)prdir->value.const_bytes;
1152
120k
        uint plen = r_size(prdir), blen1 = blen;
1153
120k
        gs_parsed_file_name_t pname;
1154
120k
        gp_file_name_combine_result r;
1155
1156
        /* We need to concatenate and parse the file name here
1157
         * if this path has a %device% prefix.              */
1158
120k
        if (pstr[0] == '%') {
1159
            /* We concatenate directly since gp_file_name_combine_*
1160
             * rules are not correct for other devices such as %rom% */
1161
21.4k
            code = gs_parse_file_name(&pname, pstr, plen, mem);
1162
21.4k
            if (code < 0) {
1163
0
                code = 1;
1164
0
                continue;
1165
0
            }
1166
21.4k
            if (blen < max(pname.len, plen) + flen)
1167
0
              return_error(gs_error_limitcheck);
1168
21.4k
            memcpy(buffer, pname.fname, pname.len);
1169
21.4k
            memcpy(buffer+pname.len, fname, flen);
1170
21.4k
            code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode,
1171
21.4k
                                          &s, (gs_memory_t *)mem);
1172
21.4k
            if (code < 0) {
1173
18.0k
                code = 1;
1174
18.0k
                continue;
1175
18.0k
            }
1176
3.41k
            make_stream_file(pfile, s, "r");
1177
            /* fill in the buffer with the device concatenated */
1178
3.41k
            memcpy(buffer, pstr, plen);
1179
3.41k
            memcpy(buffer+plen, fname, flen);
1180
3.41k
            *pclen = plen + flen;
1181
3.41k
            code = 0;
1182
99.1k
        } else {
1183
99.1k
            r = gp_file_name_combine(pstr, plen,
1184
99.1k
                    fname, flen, false, buffer, &blen1);
1185
99.1k
            if (r != gp_combine_success)
1186
0
                continue;
1187
99.1k
            if (starting_arg_file || check_file_permissions(i_ctx_p, buffer,
1188
99.1k
                                      blen1, iodev, "PermitFileReading") >= 0) {
1189
1190
99.1k
                if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1191
99.1k
                            (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1192
0
                    *pclen = blen1;
1193
0
                    make_stream_file(pfile, s, "r");
1194
0
                    code = 0;
1195
0
                }
1196
99.1k
            }
1197
0
            else {
1198
0
                struct stat fstat;
1199
                /* If we are not allowed to open the file by check_file_permissions_aux()
1200
                 * and if the file exists, throw an error.......
1201
                 * Otherwise, keep searching.
1202
                 */
1203
0
                if ((*iodev->procs.file_status)(iodev,  (const char *)buffer, &fstat) >= 0) {
1204
0
                    code = gs_note_error(gs_error_invalidfileaccess);
1205
0
                }
1206
0
            }
1207
99.1k
        }
1208
120k
    }
1209
12.4k
    return code;
1210
12.4k
}
1211
1212
/* Return a file object of of the file searched for using the search paths. */
1213
/* The fname cannot contain a device part (%...%) but the lib paths might. */
1214
/* The startup code calls this to open the initialization file gs_init.ps. */
1215
/* The startup code also calls this to open @-files. */
1216
int
1217
lib_file_open(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1218
                       const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile)
1219
12.4k
{   /* i_ctx_p is NULL running arg (@) files.
1220
     * lib_path and mem are never NULL
1221
     */
1222
12.4k
    bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file;
1223
12.4k
    bool search_with_no_combine = false;
1224
12.4k
    bool search_with_combine = false;
1225
12.4k
    char fmode[2] = { 'r', 0};
1226
12.4k
    gx_io_device *iodev = iodev_default(mem);
1227
12.4k
    gs_main_instance *minst = get_minst_from_memory(mem);
1228
12.4k
    int code;
1229
1230
12.4k
    if (i_ctx_p && starting_arg_file)
1231
0
        i_ctx_p->starting_arg_file = false;
1232
1233
    /* when starting arg files (@ files) iodev_default is not yet set */
1234
12.4k
    if (iodev == 0)
1235
0
        iodev = (gx_io_device *)gx_io_device_table[0];
1236
1237
12.4k
    if (gp_file_name_is_absolute(fname, flen)) {
1238
0
       search_with_no_combine = true;
1239
0
       search_with_combine = false;
1240
12.4k
    } else {
1241
12.4k
       search_with_no_combine = starting_arg_file;
1242
12.4k
       search_with_combine = true;
1243
12.4k
    }
1244
12.4k
    if (minst->search_here_first) {
1245
0
      if (search_with_no_combine) {
1246
0
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1247
0
                                                    fname, flen, buffer, blen, pclen, pfile,
1248
0
                                                    iodev, starting_arg_file, fmode);
1249
0
        if (code <= 0) /* +ve means continue continue */
1250
0
          return code;
1251
0
      }
1252
0
      if (search_with_combine) {
1253
0
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1254
0
                                                 fname, flen, buffer, blen, pclen, pfile,
1255
0
                                                 iodev, starting_arg_file, fmode);
1256
0
        if (code <= 0) /* +ve means continue searching */
1257
0
          return code;
1258
0
      }
1259
12.4k
    } else {
1260
12.4k
      if (search_with_combine) {
1261
12.4k
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1262
12.4k
                                                 fname, flen, buffer, blen, pclen, pfile,
1263
12.4k
                                                 iodev, starting_arg_file, fmode);
1264
12.4k
        if (code <= 0) /* +ve means continue searching */
1265
3.41k
          return code;
1266
12.4k
      }
1267
9.01k
      if (search_with_no_combine) {
1268
0
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1269
0
                                                    fname, flen, buffer, blen, pclen, pfile,
1270
0
                                                    iodev, starting_arg_file, fmode);
1271
0
        if (code <= 0) /* +ve means continue searching */
1272
0
          return code;
1273
0
      }
1274
9.01k
    }
1275
12.4k
    return_error(gs_error_undefinedfilename);
1276
12.4k
}
1277
1278
/* The startup code calls this to open @-files. */
1279
gp_file *
1280
lib_fopen(const gs_file_path_ptr pfpath, const gs_memory_t *mem, const char *fname)
1281
0
{
1282
    /* We need a buffer to hold the expanded file name. */
1283
0
    char filename_found[DEFAULT_BUFFER_SIZE];
1284
0
    gp_file *file = NULL;
1285
0
    uint fnamelen;
1286
0
    ref obj;
1287
0
    int code;
1288
0
    stream *s;
1289
1290
    /* open the usual 'stream', then if successful, return the file */
1291
0
    code = lib_file_open(pfpath, mem, NULL, fname, strlen(fname),
1292
0
                            filename_found, sizeof(filename_found), &fnamelen, &obj);
1293
1294
0
    if (code < 0)
1295
0
        return NULL;
1296
1297
    /* This all seems a bit grotty. The above code has generated us a stream
1298
     * that wraps a file. We actually want the file. So we reach in, and steal
1299
     * the file pointer. Nasty. */
1300
0
    s = ((stream *)(obj.value.pfile));
1301
0
    file = s->file;
1302
    /* Historically we've then just abandoned the stream, resulting in blocks
1303
     * leaking. Let's free the leaked blocks (in rather hacky style). First,
1304
     * we clear the file reference, and then drop the stream. */
1305
0
    s->file = NULL;
1306
0
    sclose(s);
1307
    /* Then free the stream block itself. */
1308
0
    gs_free_object(s->memory, s, "lib_fopen");
1309
0
    return file;
1310
0
}
1311
1312
/* Open a file stream that reads a string. */
1313
/* (This is currently used only by the ccinit feature.) */
1314
/* The string must be allocated in non-garbage-collectable (foreign) space. */
1315
int
1316
file_read_string(const byte *str, uint len, ref *pfile, gs_ref_memory_t *imem)
1317
0
{
1318
0
    stream *s = file_alloc_stream((gs_memory_t *)imem, "file_read_string");
1319
1320
0
    if (s == 0)
1321
0
        return_error(gs_error_VMerror);
1322
0
    sread_string(s, str, len);
1323
0
    s->foreign = 1;
1324
0
    s->write_id = 0;
1325
0
    make_file(pfile, a_readonly | imemory_space(imem), s->read_id, s);
1326
0
    s->save_close = s->procs.close;
1327
0
    s->procs.close = file_close_disable;
1328
0
    return 0;
1329
0
}
1330
1331
/* Report an error by storing it in the stream's error_string. */
1332
int
1333
filter_report_error(stream_state * st, const char *str)
1334
0
{
1335
0
    if_debug1m('s', st->memory, "[s]stream error: %s\n", str);
1336
0
    strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING);
1337
    /* Ensure null termination. */
1338
0
    st->error_string[STREAM_MAX_ERROR_STRING] = 0;
1339
0
    return 0;
1340
0
}
1341
1342
/* Open a file stream for a filter. */
1343
int
1344
filter_open(const char *file_access, uint buffer_size, ref * pfile,
1345
            const stream_procs * procs, const stream_template * templat,
1346
            const stream_state * st, gs_memory_t *mem)
1347
6.15k
{
1348
6.15k
    stream *s;
1349
6.15k
    uint ssize = gs_struct_type_size(templat->stype);
1350
6.15k
    stream_state *sst = 0;
1351
6.15k
    int code;
1352
1353
6.15k
    if (templat->stype != &st_stream_state) {
1354
6.15k
        sst = s_alloc_state(mem, templat->stype, "filter_open(stream_state)");
1355
6.15k
        if (sst == 0)
1356
0
            return_error(gs_error_VMerror);
1357
6.15k
    }
1358
6.15k
    code = file_open_stream((char *)0, 0, file_access, buffer_size, &s,
1359
6.15k
                                (gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
1360
6.15k
    if (code < 0) {
1361
0
        gs_free_object(mem, sst, "filter_open(stream_state)");
1362
0
        return code;
1363
0
    }
1364
6.15k
    s_std_init(s, s->cbuf, s->bsize, procs,
1365
6.15k
               (*file_access == 'r' ? s_mode_read : s_mode_write));
1366
6.15k
    s->procs.process = templat->process;
1367
6.15k
    s->save_close = s->procs.close;
1368
6.15k
    s->procs.close = file_close_file;
1369
6.15k
    if (sst == 0) {
1370
        /* This stream doesn't have any state of its own. */
1371
        /* Hack: use the stream itself as the state. */
1372
0
        sst = (stream_state *) s;
1373
6.15k
    } else if (st != 0)         /* might not have client parameters */
1374
6.15k
        memcpy(sst, st, ssize);
1375
6.15k
    s->state = sst;
1376
6.15k
    s_init_state(sst, templat, mem);
1377
6.15k
    sst->report_error = filter_report_error;
1378
1379
6.15k
    if (templat->init != 0) {
1380
6.15k
        code = (*templat->init)(sst);
1381
6.15k
        if (code < 0) {
1382
0
            gs_free_object(mem, sst, "filter_open(stream_state)");
1383
0
            gs_free_object(mem, s->cbuf, "filter_open(buffer)");
1384
0
            return code;
1385
0
        }
1386
6.15k
    }
1387
6.15k
    make_stream_file(pfile, s, file_access);
1388
6.15k
    return 0;
1389
6.15k
}
1390
1391
/* Close a file object. */
1392
/* This is exported only for gsmain.c. */
1393
int
1394
file_close(ref * pfile)
1395
0
{
1396
0
    stream *s;
1397
1398
0
    if (file_is_valid(s, pfile)) {      /* closing a closed file is a no-op */
1399
0
        if (sclose(s))
1400
0
            return_error(gs_error_ioerror);
1401
0
    }
1402
0
    return 0;
1403
0
}