Coverage Report

Created: 2022-10-31 07:00

/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
25.2M
{
127
25.2M
    long i;
128
25.2M
    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
25.2M
    const char *win_sep2 = "\\";
132
25.2M
    bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
133
25.2M
    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
25.2M
    if (iodev && iodev != iodev_default(imemory)) {
139
4.64M
        return 0;
140
4.64M
    }
141
142
    /* Assuming a reduced file name. */
143
20.6M
    if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
144
0
        return 0;       /* if Permissions not found, just allow access */
145
146
20.6M
    for (i=0; i<r_size(permitlist); i++) {
147
20.6M
        ref permitstring;
148
20.6M
        const string_match_params win_filename_params = {
149
                '*', '?', '\\', true, true      /* ignore case & '/' == '\\' */
150
20.6M
        };
151
20.6M
        const byte *permstr;
152
20.6M
        uint permlen;
153
20.6M
        int cwd_len = 0;
154
155
20.6M
        if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
156
20.6M
            r_type(&permitstring) != t_string
157
20.6M
           )
158
0
            break;      /* any problem, just fail */
159
20.6M
        permstr = permitstring.value.bytes;
160
20.6M
        permlen = r_size(&permitstring);
161
        /*
162
         * Check if any file name is permitted with "*".
163
         */
164
20.6M
        if (permlen == 1 && permstr[0] == '*')
165
20.6M
            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
20.6M
}
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
25.2M
{
199
25.2M
    char fname_reduced[gp_file_name_sizeof];
200
25.2M
    uint rlen = sizeof(fname_reduced);
201
202
25.2M
    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
25.2M
    return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, iodev, permitgroup);
205
25.2M
}
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
6.13M
{
212
6.13M
    i_ctx_t *i_ctx_p = get_minst_from_memory(mem)->i_ctx_p;
213
6.13M
    gs_parsed_file_name_t pname;
214
6.13M
    const char *permitgroup = permission[0] == 'r' ? "PermitFileReading" : "PermitFileWriting";
215
6.13M
    int code = gs_parse_file_name(&pname, fname, len, imemory);
216
6.13M
    if (code < 0)
217
0
        return code;
218
219
6.13M
    if (pname.iodev && i_ctx_p->LockFilePermissions
220
6.13M
         && strcmp(pname.iodev->dname, "%pipe%") == 0) {
221
0
        code = gs_note_error(gs_error_invalidfileaccess);
222
0
    }
223
6.13M
    else {
224
6.13M
        code = check_file_permissions(i_ctx_p, pname.fname, pname.len, pname.iodev, permitgroup);
225
6.13M
    }
226
6.13M
    return code;
227
6.13M
}
228
229
/* <name_string> <access_string> file <file> */
230
int                             /* exported for zsysvm.c */
231
zfile(i_ctx_t *i_ctx_p)
232
22.2M
{
233
22.2M
    os_ptr op = osp;
234
22.2M
    char file_access[4];
235
22.2M
    gs_parsed_file_name_t pname;
236
22.2M
    int code = parse_file_access_string(op, file_access);
237
22.2M
    stream *s;
238
239
22.2M
    if (code < 0)
240
37
        return code;
241
22.2M
    code = parse_file_name(op-1, &pname, i_ctx_p->LockFilePermissions, imemory);
242
22.2M
    if (code < 0)
243
2
        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
22.2M
    if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) {
250
20.0M
        bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0);
251
20.0M
        bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0);
252
20.0M
        if (pname.fname)
253
0
            return_error(gs_error_invalidfileaccess);
254
20.0M
        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
20.0M
        pname.iodev->state = i_ctx_p;
275
20.0M
        code = (*pname.iodev->procs.open_device)(pname.iodev,
276
20.0M
                                                 file_access, &s, imemory);
277
20.0M
        pname.iodev->state = NULL;
278
20.0M
    } else {
279
2.19M
        if (pname.iodev == NULL)
280
985k
            pname.iodev = iodev_default(imemory);
281
2.19M
        code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory);
282
2.19M
    }
283
22.2M
    if (code < 0)
284
1.68M
        return code;
285
20.5M
    if (s == NULL)
286
43
        return_error(gs_error_undefinedfilename);
287
20.5M
    code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1));
288
20.5M
    if (code < 0) {
289
0
        sclose(s);
290
0
        return_error(gs_error_VMerror);
291
0
    }
292
20.5M
    make_stream_file(op - 1, s, file_access);
293
20.5M
    pop(1);
294
20.5M
    return code;
295
20.5M
}
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
40.8k
{
321
40.8k
    ref *SAFETY;
322
40.8k
    ref *tempfiles;
323
40.8k
    ref kname, bref;
324
40.8k
    int code = 0;
325
326
40.8k
    if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
327
40.8k
            dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0) {
328
0
        return 0;
329
0
    }
330
40.8k
    if ((code = name_ref(imemory, fname, len, &kname, 1)) < 0) {
331
0
        return code;
332
0
    }
333
40.8k
    make_bool(&bref, true);
334
40.8k
    if (add)
335
40.8k
        return idict_put(tempfiles, &kname, &bref);
336
0
    else
337
0
        return idict_undef(tempfiles, &kname);
338
40.8k
}
339
340
/* ------ Level 2 extensions ------ */
341
342
/* <string> deletefile - */
343
static int
344
zdeletefile(i_ctx_t *i_ctx_p)
345
40.7k
{
346
40.7k
    os_ptr op = osp;
347
40.7k
    gs_parsed_file_name_t pname;
348
40.7k
    int code = parse_real_file_name(op, &pname, imemory, "deletefile");
349
40.7k
    bool is_temp = false;
350
351
40.7k
    if (code < 0)
352
15
        return code;
353
40.7k
    if (pname.iodev == iodev_default(imemory)) {
354
40.7k
        if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
355
40.7k
                pname.iodev, "PermitFileControl")) < 0 &&
356
40.7k
                 !(is_temp = file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op)))) {
357
0
            return code;
358
0
        }
359
40.7k
    }
360
361
40.7k
    code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
362
363
40.7k
    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
40.7k
    gs_free_file_name(&pname, "deletefile");
367
40.7k
    if (code < 0)
368
6
        return code;
369
40.7k
    pop(1);
370
40.7k
    return 0;
371
40.7k
}
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
1.24M
{
379
1.24M
    os_ptr op = osp;
380
1.24M
    file_enum *pfen;
381
1.24M
    gx_io_device *iodev = NULL;
382
1.24M
    gs_parsed_file_name_t pname;
383
1.24M
    int code = 0;
384
385
1.24M
    check_write_type(*op, t_string);
386
1.24M
    check_proc(op[-1]);
387
1.24M
    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
1.24M
    check_estack(7);
391
    /* Get the iodevice */
392
1.24M
    code = parse_file_name(op-2, &pname, i_ctx_p->LockFilePermissions, imemory);
393
1.24M
    if (code < 0)
394
0
        return code;
395
1.24M
    iodev = (pname.iodev == NULL) ? iodev_default(imemory) : pname.iodev;
396
397
    /* Check for several conditions that just cause us to return success */
398
1.24M
    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
1.24M
    pfen = iodev->procs.enumerate_files(imemory, iodev, (const char *)pname.fname,
403
1.24M
                pname.len);
404
1.24M
    if (pfen == 0)
405
0
        return_error(gs_error_VMerror);
406
1.24M
    push_mark_estack(es_for, file_cleanup);
407
1.24M
    ++esp;
408
1.24M
    make_istruct(esp, 0, iodev);
409
1.24M
    ++esp;
410
1.24M
    make_int(esp, r_size(op-2) - pname.len);
411
1.24M
    *++esp = *op;
412
1.24M
    ++esp;
413
1.24M
    make_istruct(esp, 0, pfen);
414
1.24M
    *++esp = op[-1];
415
1.24M
    ref_stack_pop(&o_stack, 3);
416
1.24M
    code = file_continue(i_ctx_p);
417
1.24M
    return (code == o_pop_estack ? o_push_estack : code);
418
1.24M
}
419
/* Continuation operator for enumerating files */
420
static int
421
file_continue(i_ctx_t *i_ctx_p)
422
1.42M
{
423
1.42M
    os_ptr op = osp;
424
1.42M
    es_ptr pscratch = esp - 2;
425
1.42M
    file_enum *pfen = r_ptr(esp - 1, file_enum);
426
1.42M
    int devlen = esp[-3].value.intval;
427
1.42M
    gx_io_device *iodev = r_ptr(esp - 4, gx_io_device);
428
1.42M
    uint len = r_size(pscratch);
429
1.42M
    uint code;
430
431
1.42M
    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
1.42M
    do {
437
1.42M
        memcpy((char *)pscratch->value.bytes, iodev->dname, devlen);
438
1.42M
        code = iodev->procs.enumerate_next(imemory, pfen, (char *)pscratch->value.bytes + devlen,
439
1.42M
                    len - devlen);
440
1.42M
        if (code == ~(uint) 0) {    /* all done */
441
1.24M
            esp -= 5;               /* pop proc, pfen, devlen, iodev , mark */
442
1.24M
            return o_pop_estack;
443
1.24M
        } else if (code > len) {      /* overran string */
444
0
            return_error(gs_error_rangecheck);
445
0
        }
446
178k
        else if (iodev != iodev_default(imemory)
447
178k
              || (check_file_permissions(i_ctx_p, (char *)pscratch->value.bytes, code + devlen, iodev, "PermitFileReading")) == 0) {
448
178k
            push(1);
449
178k
            ref_assign(op, pscratch);
450
178k
            r_set_size(op, code + devlen);
451
178k
            push_op_estack(file_continue);  /* come again */
452
178k
            *++esp = pscratch[2];   /* proc */
453
178k
            return o_push_estack;
454
178k
        }
455
1.42M
    } while(1);
456
1.42M
}
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
5
{
471
5
    int code;
472
5
    os_ptr op = osp;
473
5
    gs_parsed_file_name_t pname1, pname2;
474
475
5
    code = parse_real_file_name(op, &pname2, imemory, "renamefile(to)");
476
5
    if (code < 0)
477
5
        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
1.46M
{
523
1.46M
    os_ptr op = osp;
524
525
1.46M
    switch (r_type(op)) {
526
138k
        case t_file:
527
138k
            {
528
138k
                stream *s;
529
530
138k
                make_bool(op, (file_is_valid(s, op) ? 1 : 0));
531
138k
            }
532
138k
            return 0;
533
1.32M
        case t_string:
534
1.32M
            {
535
1.32M
                gs_parsed_file_name_t pname;
536
1.32M
                struct stat fstat;
537
1.32M
                int code = parse_file_name(op, &pname,
538
1.32M
                                           i_ctx_p->LockFilePermissions, imemory);
539
1.32M
                if (code < 0) {
540
1
                    if (code == gs_error_undefinedfilename) {
541
1
                        make_bool(op, 0);
542
1
                        code = 0;
543
1
                    }
544
1
                    return code;
545
1
                }
546
1.32M
                code = gs_terminate_file_name(&pname, imemory, "status");
547
1.32M
                if (code < 0)
548
0
                    return code;
549
1.32M
                if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
550
1.32M
                                       pname.iodev, "PermitFileReading")) >= 0) {
551
1.32M
                    code = (*pname.iodev->procs.file_status)(pname.iodev,
552
1.32M
                                                       pname.fname, &fstat);
553
1.32M
                }
554
1.32M
                switch (code) {
555
672k
                    case 0:
556
672k
                        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
672k
                        push(4);
563
672k
                        make_int(op - 4, stat_blocks(&fstat));
564
672k
                        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
672k
                        if ((double)op[-4].value.intval !=
574
672k
                              (double)stat_blocks(&fstat) ||
575
672k
                            (double)op[-3].value.intval !=
576
672k
                              (double)fstat.st_size
577
672k
                            )
578
0
                            return_error(gs_error_limitcheck);
579
672k
                        make_int(op - 2, fstat.st_mtime);
580
672k
                        make_int(op - 1, fstat.st_ctime);
581
672k
                        make_bool(op, 1);
582
672k
                        break;
583
652k
                    case gs_error_undefinedfilename:
584
652k
                        make_bool(op, 0);
585
652k
                        code = 0;
586
1.32M
                }
587
1.32M
                gs_free_file_name(&pname, "status");
588
1.32M
                return code;
589
1.32M
            }
590
7
        default:
591
7
            return_op_typecheck(op);
592
1.46M
    }
593
1.46M
}
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
2.52M
{
656
2.52M
    os_ptr op = osp;
657
2.52M
    int code;
658
2.52M
    byte cname[DEFAULT_BUFFER_SIZE];
659
2.52M
    uint clen;
660
2.52M
    gs_parsed_file_name_t pname;
661
2.52M
    stream *s;
662
2.52M
    gx_io_device *iodev_dflt;
663
664
2.52M
    check_ostack(2);
665
2.52M
    code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions, imemory);
666
2.52M
    if (code < 0)
667
701
        return code;
668
2.52M
    iodev_dflt = iodev_default(imemory);
669
2.52M
    if (pname.iodev == NULL)
670
1.88M
        pname.iodev = iodev_dflt;
671
2.52M
    if (pname.iodev != iodev_dflt) { /* Non-OS devices don't have search paths (yet). */
672
641k
        code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
673
641k
        if (s == NULL) code = gs_note_error(gs_error_undefinedfilename);
674
641k
        if (code >= 0) {
675
89.2k
            code = ssetfilename(s, op->value.const_bytes, r_size(op));
676
89.2k
            if (code < 0) {
677
0
                sclose(s);
678
0
                return_error(gs_error_VMerror);
679
0
            }
680
89.2k
        }
681
641k
        if (code < 0) {
682
552k
            push(1);
683
552k
            make_false(op);
684
552k
            return 0;
685
552k
        }
686
89.2k
        make_stream_file(op, s, "r");
687
1.88M
    } else {
688
1.88M
        ref fref;
689
690
1.88M
        code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len,
691
1.88M
                             (char *)cname, sizeof(cname), &clen, &fref);
692
1.88M
        if (code >= 0) {
693
357k
            s = fptr(&fref);
694
357k
            code = ssetfilename(s, cname, clen);
695
357k
            if (code < 0) {
696
0
                sclose(s);
697
0
                return_error(gs_error_VMerror);
698
0
            }
699
357k
        }
700
1.88M
        if (code < 0) {
701
1.52M
            if (code == gs_error_VMerror || code == gs_error_invalidfileaccess)
702
0
                return code;
703
1.52M
            push(1);
704
1.52M
            make_false(op);
705
1.52M
            return 0;
706
1.52M
        }
707
357k
        ref_assign(op, &fref);
708
357k
    }
709
2.52M
    push(1);
710
446k
    make_true(op);
711
446k
    return 0;
712
446k
}
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
40.8k
{
719
40.8k
    int i;
720
40.8k
    char c;
721
722
163k
    for (i = 0; (c = pstr[i]) != 0; i++) {
723
122k
        if (!(c == '-' || c == '_' || (c >= '0' && c <= '9') ||
724
122k
              (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
725
0
            return false;
726
122k
    }
727
40.8k
    return true;
728
40.8k
}
729
730
/* <prefix|null> <access_string> .tempfile <name_string> <file> */
731
static int
732
ztempfile(i_ctx_t *i_ctx_p)
733
40.8k
{
734
40.8k
    os_ptr op = osp;
735
40.8k
    const char *pstr;
736
40.8k
    char fmode[4];
737
40.8k
    char fmode_temp[4];
738
40.8k
    int code = parse_file_access_string(op, fmode_temp);
739
40.8k
    char *prefix = NULL;
740
40.8k
    char *fname= NULL;
741
40.8k
    uint fnlen;
742
40.8k
    gp_file *sfile;
743
40.8k
    stream *s;
744
40.8k
    byte *buf, *sbody;
745
746
40.8k
    if (code < 0)
747
3
        return code;
748
40.8k
    prefix = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(prefix)");
749
40.8k
    fname = (char *)gs_alloc_bytes(imemory, gp_file_name_sizeof, "ztempfile(fname)");
750
40.8k
    if (!prefix || !fname) {
751
0
        code = gs_note_error(gs_error_VMerror);
752
0
        goto done;
753
0
    }
754
755
40.8k
    snprintf(fmode, sizeof(fmode), "%s%s", fmode_temp, gp_fmode_binary_suffix);
756
40.8k
    if (r_has_type(op - 1, t_null))
757
40.8k
        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
40.8k
    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
0
        int seplen = strlen(sep);
776
777
        /* This should not be possible if gp_file_name_is_absolute is true I think
778
         * But let's avoid the problem.
779
         */
780
0
        if (plen < seplen)
781
0
            return_error(gs_error_Fatal);
782
783
0
        plen -= seplen;
784
        /* strip off the file name prefix, leave just the directory name
785
         * so we can check if we are allowed to write to it
786
         */
787
0
        for ( ; plen >=0; plen--) {
788
0
            if ( gs_file_name_check_separator(&pstr[plen], seplen, &pstr[plen]))
789
0
                break;
790
0
        }
791
0
        if (plen < 0)
792
0
            return_error(gs_error_Fatal);
793
794
0
        memcpy(fname, pstr, plen);
795
0
        fname[plen] = '\0';
796
0
        if (check_file_permissions(i_ctx_p, fname, strlen(fname),
797
0
                                   NULL, "PermitFileWriting") < 0) {
798
0
            code = gs_note_error(gs_error_invalidfileaccess);
799
0
            goto done;
800
0
        }
801
40.8k
    } else if (!prefix_is_simple(pstr)) {
802
0
        code = gs_note_error(gs_error_invalidfileaccess);
803
0
        goto done;
804
0
    }
805
806
40.8k
    s = file_alloc_stream(imemory, "ztempfile(stream)");
807
40.8k
    if (s == 0) {
808
0
        code = gs_note_error(gs_error_VMerror);
809
0
        goto done;
810
0
    }
811
40.8k
    buf = gs_alloc_bytes(imemory, file_default_buffer_size,
812
40.8k
                         "ztempfile(buffer)");
813
40.8k
    if (buf == 0) {
814
0
        code = gs_note_error(gs_error_VMerror);
815
0
        goto done;
816
0
    }
817
40.8k
    sfile = gp_open_scratch_file(imemory, pstr, fname, fmode);
818
40.8k
    if (sfile == 0) {
819
0
        gs_free_object(imemory, buf, "ztempfile(buffer)");
820
0
        code = gs_note_error(gs_error_invalidfileaccess);
821
0
        goto done;
822
0
    }
823
40.8k
    fnlen = strlen(fname);
824
40.8k
    sbody = ialloc_string(fnlen, ".tempfile(fname)");
825
40.8k
    if (sbody == 0) {
826
0
        gs_free_object(imemory, buf, "ztempfile(buffer)");
827
0
        code = gs_note_error(gs_error_VMerror);
828
0
        goto done;
829
0
    }
830
40.8k
    memcpy(sbody, fname, fnlen);
831
40.8k
    file_init_stream(s, sfile, fmode, buf, file_default_buffer_size);
832
40.8k
    code = ssetfilename(s, (const unsigned char*) fname, fnlen);
833
40.8k
    if (code < 0) {
834
0
        gx_io_device *iodev_dflt = iodev_default(imemory);
835
0
        sclose(s);
836
0
        iodev_dflt->procs.delete_file(iodev_dflt, fname);
837
0
        ifree_string(sbody, fnlen, ".tempfile(fname)");
838
0
        code = gs_note_error(gs_error_VMerror);
839
0
        goto done;
840
0
    }
841
40.8k
    make_string(op - 1, a_readonly | icurrent_space, fnlen, sbody);
842
40.8k
    make_stream_file(op, s, fmode);
843
40.8k
    code = record_file_is_tempfile(i_ctx_p, (unsigned char *)fname, fnlen, true);
844
845
40.8k
done:
846
40.8k
    if (prefix)
847
40.8k
        gs_free_object(imemory, prefix, "ztempfile(prefix)");
848
40.8k
    if (fname)
849
40.8k
        gs_free_object(imemory, fname, "ztempfile(fname)");
850
40.8k
    return code;
851
40.8k
}
852
853
/* Return the filename used to open a file object
854
 * this is currently only used by the PDF interpreter to
855
 * get a filename corresponding to the PDF file being
856
 * executed. Since we always execute PDF files from disk
857
 * this will always be OK.
858
 */
859
static int zgetfilename(i_ctx_t *i_ctx_p)
860
0
{
861
0
    os_ptr op = osp;
862
0
    uint fnlen;
863
0
    gs_const_string pfname;
864
0
    stream *s;
865
0
    byte *sbody;
866
0
    int code;
867
868
0
    check_ostack(1);
869
0
    check_read_type(*op, t_file);
870
871
0
    s = (op)->value.pfile;
872
873
0
    code = sfilename(s, &pfname);
874
0
    if (code < 0) {
875
0
        pfname.size = 0;
876
0
    }
877
878
0
    fnlen = pfname.size;
879
0
    sbody = ialloc_string(fnlen, ".getfilename");
880
0
    if (sbody == 0) {
881
0
        code = gs_note_error(gs_error_VMerror);
882
0
        return code;
883
0
    }
884
0
    memcpy(sbody, pfname.data, fnlen);
885
0
    make_string(op, a_readonly | icurrent_space, fnlen, sbody);
886
887
0
    return 0;
888
0
}
889
890
static int zaddcontrolpath(i_ctx_t *i_ctx_p)
891
1.96M
{
892
1.96M
    int code;
893
1.96M
    os_ptr op = osp;
894
1.96M
    ref nsref;
895
1.96M
    unsigned int n = -1;
896
897
1.96M
    check_ostack(2);
898
1.96M
    check_read_type(*op, t_string);
899
1.96M
    check_type(op[-1], t_name);
900
901
1.96M
    name_string_ref(imemory, op-1, &nsref);
902
1.96M
    if (r_size(&nsref) == 17 &&
903
1.96M
        strncmp((const char *)nsref.value.const_bytes,
904
1.96M
                "PermitFileReading", 17) == 0) {
905
1.60M
        n = gs_permit_file_reading;
906
1.60M
    } else if (r_size(&nsref) == 17 &&
907
356k
               strncmp((const char *)nsref.value.const_bytes,
908
356k
                       "PermitFileWriting", 17) == 0) {
909
178k
        n = gs_permit_file_writing;
910
178k
    } else if (r_size(&nsref) == 17 &&
911
178k
               strncmp((const char *)nsref.value.const_bytes,
912
178k
                       "PermitFileControl", 17) == 0) {
913
178k
        n = gs_permit_file_control;
914
178k
    }
915
916
1.96M
    if (n == -1)
917
0
        code = gs_note_error(gs_error_rangecheck);
918
1.96M
    else if (gs_is_path_control_active(imemory))
919
0
        code = gs_note_error(gs_error_Fatal);
920
1.96M
    else
921
1.96M
        code = gs_add_control_path_len(imemory, n,
922
1.96M
                                       (const char *)op[0].value.const_bytes,
923
1.96M
                                       (size_t)r_size(&op[0]));
924
1.96M
    pop(2);
925
1.96M
    return code;
926
1.96M
}
927
928
static int zactivatepathcontrol(i_ctx_t *i_ctx_p)
929
89.2k
{
930
89.2k
    gs_activate_path_control(imemory, 1);
931
89.2k
    return 0;
932
89.2k
}
933
static int zcurrentpathcontrolstate(i_ctx_t *i_ctx_p)
934
89.2k
{
935
89.2k
    os_ptr op = osp;
936
89.2k
    push(1);
937
89.2k
    if (gs_is_path_control_active(imemory)) {
938
2
        make_true(op);
939
2
    }
940
89.2k
    else {
941
89.2k
        make_false(op);
942
89.2k
    }
943
89.2k
    return 0;
944
89.2k
}
945
946
/* ------ Initialization procedure ------ */
947
948
const op_def zfile_op_defs[] =
949
{
950
    {"1deletefile", zdeletefile},
951
    {"1.execfile", zexecfile},
952
    {"2file", zfile},
953
    {"3filenameforall", zfilenameforall},
954
    {"0.filenamelistseparator", zfilenamelistseparator},
955
    {"1.filenamesplit", zfilenamesplit},
956
    {"1.libfile", zlibfile},
957
    {"2renamefile", zrenamefile},
958
    {"1status", zstatus},
959
    {"2.tempfile", ztempfile},
960
                /* Internal operators */
961
    {"0%file_continue", file_continue},
962
    {"0%execfile_finish", execfile_finish},
963
    {"1.getfilename", zgetfilename},
964
    /* Control path operators */
965
    {"2.addcontrolpath", zaddcontrolpath},
966
    {"0.activatepathcontrol", zactivatepathcontrol},
967
    {"0.currentpathcontrolstate", zcurrentpathcontrolstate},
968
    op_def_end(0)
969
};
970
971
/* ------ File name parsing ------ */
972
973
/* Parse a file name into device and individual name. */
974
/* See gsfname.c for details. */
975
static int
976
parse_file_name(const ref * op, gs_parsed_file_name_t * pfn, bool safemode,
977
                gs_memory_t *memory)
978
27.3M
{
979
27.3M
    int code;
980
981
27.3M
    check_read_type(*op, t_string);
982
27.3M
    code = gs_parse_file_name(pfn, (const char *)op->value.const_bytes,
983
27.3M
                              r_size(op), memory);
984
27.3M
    if (code < 0)
985
702
        return code;
986
    /*
987
     * Check here for the %pipe device which is illegal when
988
     * LockFilePermissions is true. In the future we might want to allow
989
     * the %pipe device to be included on the PermitFile... paths, but
990
     * for now it is simply disallowed.
991
     */
992
27.3M
    if (pfn->iodev && safemode && strcmp(pfn->iodev->dname, "%pipe%") == 0)
993
0
        return gs_error_invalidfileaccess;
994
27.3M
    return code;
995
27.3M
}
996
997
/* Parse a real (non-device) file name and convert to a C string. */
998
/* See gsfname.c for details. */
999
static int
1000
parse_real_file_name(const ref *op, gs_parsed_file_name_t *pfn,
1001
                     gs_memory_t *mem, client_name_t cname)
1002
40.7k
{
1003
40.7k
    check_read_type(*op, t_string);
1004
40.7k
    return gs_parse_real_file_name(pfn, (const char *)op->value.const_bytes,
1005
40.7k
                                   r_size(op), mem, cname);
1006
40.7k
}
1007
1008
/* Parse the access string for opening a file. */
1009
/* [4] is for r/w, +, b, \0. */
1010
static int
1011
parse_file_access_string(const ref *op, char file_access[4])
1012
22.3M
{
1013
22.3M
    const byte *astr;
1014
1015
22.3M
    check_read_type(*op, t_string);
1016
22.3M
    astr = op->value.const_bytes;
1017
22.3M
    switch (r_size(op)) {
1018
40.8k
        case 2:
1019
40.8k
            if (astr[1] != '+')
1020
0
                return_error(gs_error_invalidfileaccess);
1021
40.8k
            file_access[1] = '+';
1022
40.8k
            file_access[2] = 0;
1023
40.8k
            break;
1024
22.2M
        case 1:
1025
22.2M
            file_access[1] = 0;
1026
22.2M
            break;
1027
7
        default:
1028
7
            return_error(gs_error_invalidfileaccess);
1029
22.3M
    }
1030
22.3M
    switch (astr[0]) {
1031
2.41M
        case 'r':
1032
22.3M
        case 'w':
1033
22.3M
        case 'a':
1034
22.3M
            break;
1035
1
        default:
1036
1
            return_error(gs_error_invalidfileaccess);
1037
22.3M
    }
1038
22.3M
    file_access[0] = astr[0];
1039
22.3M
    return 0;
1040
22.3M
}
1041
1042
/* ------ Stream opening ------ */
1043
1044
/*
1045
 * Open a file specified by a parsed file name (which may be only a
1046
 * device).
1047
 */
1048
int
1049
zopen_file(i_ctx_t *i_ctx_p, const gs_parsed_file_name_t *pfn,
1050
           const char *file_access, stream **ps, gs_memory_t *mem)
1051
2.83M
{
1052
2.83M
    gx_io_device *const iodev = pfn->iodev;
1053
2.83M
    int code = 0;
1054
1055
2.83M
    if (pfn->fname == NULL) {     /* just a device */
1056
0
        iodev->state = i_ctx_p;
1057
0
        code = iodev->procs.open_device(iodev, file_access, ps, mem);
1058
0
        iodev->state = NULL;
1059
0
        return code;
1060
0
    }
1061
2.83M
    else {                      /* file */
1062
2.83M
        iodev_proc_open_file((*open_file)) = iodev->procs.open_file;
1063
1064
2.83M
        if (open_file == 0)
1065
985k
            open_file = iodev_os_open_file;
1066
        /* Check OS files to make sure we allow the type of access */
1067
2.83M
        if (open_file == iodev_os_open_file) {
1068
985k
            code = check_file_permissions(i_ctx_p, pfn->fname, pfn->len, pfn->iodev,
1069
985k
                file_access[0] == 'r' ? "PermitFileReading" : "PermitFileWriting");
1070
1071
985k
            if (code < 0 && !file_is_tempfile(i_ctx_p,
1072
0
                                          (const uchar *)pfn->fname, pfn->len))
1073
0
                return code;
1074
985k
        }
1075
2.83M
        return open_file(iodev, pfn->fname, pfn->len, file_access, ps, mem);
1076
2.83M
    }
1077
2.83M
}
1078
1079
/*
1080
 * Define the file_open procedure for the %os% IODevice (also used, as the
1081
 * default, for %pipe% and possibly others).
1082
 */
1083
static int
1084
iodev_os_open_file(gx_io_device * iodev, const char *fname, uint len,
1085
                   const char *file_access, stream ** ps, gs_memory_t * mem)
1086
17.7M
{
1087
17.7M
    return file_open_stream(fname, len, file_access,
1088
17.7M
                            file_default_buffer_size, ps,
1089
17.7M
                            iodev, iodev->procs.gp_fopen, mem);
1090
17.7M
}
1091
1092
/* Make a t_file reference to a stream. */
1093
void
1094
make_stream_file(ref * pfile, stream * s, const char *access)
1095
23.4M
{
1096
23.4M
    uint attrs =
1097
23.4M
        (access[1] == '+' ? a_write + a_read + a_execute : 0) |
1098
23.4M
        imemory_space((gs_ref_memory_t *) s->memory);
1099
1100
23.4M
    if (access[0] == 'r') {
1101
1.98M
        make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
1102
1.98M
        s->write_id = 0;
1103
21.4M
    } else {
1104
21.4M
        make_file(pfile, attrs | a_write, s->write_id, s);
1105
21.4M
        s->read_id = 0;
1106
21.4M
    }
1107
23.4M
}
1108
1109
/* return zero for success, -ve for error, +1 for continue */
1110
static int
1111
lib_file_open_search_with_no_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1112
                                     const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1113
                                     gx_io_device *iodev, bool starting_arg_file, char *fmode)
1114
24
{
1115
24
    stream *s;
1116
24
    uint blen1 = blen;
1117
24
    struct stat fstat;
1118
24
    int code = 1;
1119
1120
24
    if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success)
1121
0
      goto skip;
1122
1123
24
    if (starting_arg_file || check_file_permissions(i_ctx_p, buffer, blen1, iodev, "PermitFileReading") >= 0) {
1124
24
        if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1125
24
                       (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1126
0
            *pclen = blen1;
1127
0
            make_stream_file(pfile, s, "r");
1128
0
            code = 0;
1129
0
        }
1130
24
    }
1131
0
    else {
1132
        /* If we are not allowed to open the file by check_file_permissions_aux()
1133
         * and if the file exists, throw an error.......
1134
         * Otherwise, keep searching.
1135
         */
1136
0
        if ((*iodev->procs.file_status)(iodev,  buffer, &fstat) >= 0) {
1137
0
            code = gs_note_error(gs_error_invalidfileaccess);
1138
0
        }
1139
0
    }
1140
1141
24
 skip:
1142
24
    return code;
1143
24
}
1144
1145
/* return zero for success, -ve for error, +1 for continue */
1146
static int
1147
lib_file_open_search_with_combine(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1148
                                  const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile,
1149
                                  gx_io_device *iodev, bool starting_arg_file, char *fmode)
1150
1.97M
{
1151
1.97M
    stream *s;
1152
1.97M
    const gs_file_path *pfpath = lib_path;
1153
1.97M
    uint pi;
1154
1.97M
    int code = 1;
1155
1156
22.2M
    for (pi = 0; pi < r_size(&pfpath->list) && code == 1; ++pi) {
1157
20.2M
        const ref *prdir = pfpath->list.value.refs + pi;
1158
20.2M
        const char *pstr = (const char *)prdir->value.const_bytes;
1159
20.2M
        uint plen = r_size(prdir), blen1 = blen;
1160
20.2M
        gs_parsed_file_name_t pname;
1161
20.2M
        gp_file_name_combine_result r;
1162
1163
        /* We need to concatenate and parse the file name here
1164
         * if this path has a %device% prefix.              */
1165
20.2M
        if (pstr[0] == '%') {
1166
            /* We concatenate directly since gp_file_name_combine_*
1167
             * rules are not correct for other devices such as %rom% */
1168
3.49M
            code = gs_parse_file_name(&pname, pstr, plen, mem);
1169
3.49M
            if (code < 0) {
1170
0
                code = 1;
1171
0
                continue;
1172
0
            }
1173
3.49M
            if (blen < max(pname.len, plen) + flen)
1174
0
              return_error(gs_error_limitcheck);
1175
3.49M
            memcpy(buffer, pname.fname, pname.len);
1176
3.49M
            memcpy(buffer+pname.len, fname, flen);
1177
3.49M
            code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode,
1178
3.49M
                                          &s, (gs_memory_t *)mem);
1179
3.49M
            if (code < 0) {
1180
3.04M
                code = 1;
1181
3.04M
                continue;
1182
3.04M
            }
1183
446k
            make_stream_file(pfile, s, "r");
1184
            /* fill in the buffer with the device concatenated */
1185
446k
            memcpy(buffer, pstr, plen);
1186
446k
            memcpy(buffer+plen, fname, flen);
1187
446k
            *pclen = plen + flen;
1188
446k
            code = 0;
1189
16.7M
        } else {
1190
16.7M
            r = gp_file_name_combine(pstr, plen,
1191
16.7M
                    fname, flen, false, buffer, &blen1);
1192
16.7M
            if (r != gp_combine_success)
1193
0
                continue;
1194
16.7M
            if (starting_arg_file || check_file_permissions(i_ctx_p, buffer,
1195
16.7M
                                      blen1, iodev, "PermitFileReading") >= 0) {
1196
1197
16.7M
                if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
1198
16.7M
                            (const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
1199
0
                    *pclen = blen1;
1200
0
                    make_stream_file(pfile, s, "r");
1201
0
                    code = 0;
1202
0
                }
1203
16.7M
            }
1204
0
            else {
1205
0
                struct stat fstat;
1206
                /* If we are not allowed to open the file by check_file_permissions_aux()
1207
                 * and if the file exists, throw an error.......
1208
                 * Otherwise, keep searching.
1209
                 */
1210
0
                if ((*iodev->procs.file_status)(iodev,  (const char *)buffer, &fstat) >= 0) {
1211
0
                    code = gs_note_error(gs_error_invalidfileaccess);
1212
0
                }
1213
0
            }
1214
16.7M
        }
1215
20.2M
    }
1216
1.97M
    return code;
1217
1.97M
}
1218
1219
/* Return a file object of of the file searched for using the search paths. */
1220
/* The fname cannot contain a device part (%...%) but the lib paths might. */
1221
/* The startup code calls this to open the initialization file gs_init.ps. */
1222
/* The startup code also calls this to open @-files. */
1223
int
1224
lib_file_open(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
1225
                       const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile)
1226
1.97M
{   /* i_ctx_p is NULL running arg (@) files.
1227
     * lib_path and mem are never NULL
1228
     */
1229
1.97M
    bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file;
1230
1.97M
    bool search_with_no_combine = false;
1231
1.97M
    bool search_with_combine = false;
1232
1.97M
    char fmode[2] = { 'r', 0};
1233
1.97M
    gx_io_device *iodev = iodev_default(mem);
1234
1.97M
    gs_main_instance *minst = get_minst_from_memory(mem);
1235
1.97M
    int code;
1236
1237
1.97M
    if (i_ctx_p && starting_arg_file)
1238
0
        i_ctx_p->starting_arg_file = false;
1239
1240
    /* when starting arg files (@ files) iodev_default is not yet set */
1241
1.97M
    if (iodev == 0)
1242
0
        iodev = (gx_io_device *)gx_io_device_table[0];
1243
1244
1.97M
    if (gp_file_name_is_absolute(fname, flen)) {
1245
24
       search_with_no_combine = true;
1246
24
       search_with_combine = false;
1247
1.97M
    } else {
1248
1.97M
       search_with_no_combine = starting_arg_file;
1249
1.97M
       search_with_combine = true;
1250
1.97M
    }
1251
1.97M
    if (minst->search_here_first) {
1252
0
      if (search_with_no_combine) {
1253
0
        code = lib_file_open_search_with_no_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 continue */
1257
0
          return code;
1258
0
      }
1259
0
      if (search_with_combine) {
1260
0
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1261
0
                                                 fname, flen, buffer, blen, pclen, pfile,
1262
0
                                                 iodev, starting_arg_file, fmode);
1263
0
        if (code <= 0) /* +ve means continue searching */
1264
0
          return code;
1265
0
      }
1266
1.97M
    } else {
1267
1.97M
      if (search_with_combine) {
1268
1.97M
        code = lib_file_open_search_with_combine(lib_path, mem, i_ctx_p,
1269
1.97M
                                                 fname, flen, buffer, blen, pclen, pfile,
1270
1.97M
                                                 iodev, starting_arg_file, fmode);
1271
1.97M
        if (code <= 0) /* +ve means continue searching */
1272
446k
          return code;
1273
1.97M
      }
1274
1.52M
      if (search_with_no_combine) {
1275
24
        code = lib_file_open_search_with_no_combine(lib_path, mem, i_ctx_p,
1276
24
                                                    fname, flen, buffer, blen, pclen, pfile,
1277
24
                                                    iodev, starting_arg_file, fmode);
1278
24
        if (code <= 0) /* +ve means continue searching */
1279
0
          return code;
1280
24
      }
1281
1.52M
    }
1282
1.97M
    return_error(gs_error_undefinedfilename);
1283
1.97M
}
1284
1285
/* The startup code calls this to open @-files. */
1286
gp_file *
1287
lib_fopen(const gs_file_path_ptr pfpath, const gs_memory_t *mem, const char *fname)
1288
0
{
1289
    /* We need a buffer to hold the expanded file name. */
1290
0
    char filename_found[DEFAULT_BUFFER_SIZE];
1291
0
    gp_file *file = NULL;
1292
0
    uint fnamelen;
1293
0
    ref obj;
1294
0
    int code;
1295
0
    stream *s;
1296
1297
    /* open the usual 'stream', then if successful, return the file */
1298
0
    code = lib_file_open(pfpath, mem, NULL, fname, strlen(fname),
1299
0
                            filename_found, sizeof(filename_found), &fnamelen, &obj);
1300
1301
0
    if (code < 0)
1302
0
        return NULL;
1303
1304
    /* This all seems a bit grotty. The above code has generated us a stream
1305
     * that wraps a file. We actually want the file. So we reach in, and steal
1306
     * the file pointer. Nasty. */
1307
0
    s = ((stream *)(obj.value.pfile));
1308
0
    file = s->file;
1309
    /* Historically we've then just abandoned the stream, resulting in blocks
1310
     * leaking. Let's free the leaked blocks (in rather hacky style). First,
1311
     * we clear the file reference, and then drop the stream. */
1312
0
    s->file = NULL;
1313
0
    sclose(s);
1314
    /* Then free the stream block itself. */
1315
0
    gs_free_object(s->memory, s, "lib_fopen");
1316
0
    return file;
1317
0
}
1318
1319
/* Open a file stream that reads a string. */
1320
/* (This is currently used only by the ccinit feature.) */
1321
/* The string must be allocated in non-garbage-collectable (foreign) space. */
1322
int
1323
file_read_string(const byte *str, uint len, ref *pfile, gs_ref_memory_t *imem)
1324
0
{
1325
0
    stream *s = file_alloc_stream((gs_memory_t *)imem, "file_read_string");
1326
1327
0
    if (s == 0)
1328
0
        return_error(gs_error_VMerror);
1329
0
    sread_string(s, str, len);
1330
0
    s->foreign = 1;
1331
0
    s->write_id = 0;
1332
0
    make_file(pfile, a_readonly | imemory_space(imem), s->read_id, s);
1333
0
    s->save_close = s->procs.close;
1334
0
    s->procs.close = file_close_disable;
1335
0
    return 0;
1336
0
}
1337
1338
/* Report an error by storing it in the stream's error_string. */
1339
int
1340
filter_report_error(stream_state * st, const char *str)
1341
0
{
1342
0
    if_debug1m('s', st->memory, "[s]stream error: %s\n", str);
1343
0
    strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING);
1344
    /* Ensure null termination. */
1345
0
    st->error_string[STREAM_MAX_ERROR_STRING] = 0;
1346
0
    return 0;
1347
0
}
1348
1349
/* Open a file stream for a filter. */
1350
int
1351
filter_open(const char *file_access, uint buffer_size, ref * pfile,
1352
            const stream_procs * procs, const stream_template * templat,
1353
            const stream_state * st, gs_memory_t *mem)
1354
791k
{
1355
791k
    stream *s;
1356
791k
    uint ssize = gs_struct_type_size(templat->stype);
1357
791k
    stream_state *sst = 0;
1358
791k
    int code;
1359
1360
791k
    if (templat->stype != &st_stream_state) {
1361
721k
        sst = s_alloc_state(mem, templat->stype, "filter_open(stream_state)");
1362
721k
        if (sst == 0)
1363
0
            return_error(gs_error_VMerror);
1364
721k
    }
1365
791k
    code = file_open_stream((char *)0, 0, file_access, buffer_size, &s,
1366
791k
                                (gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
1367
791k
    if (code < 0) {
1368
0
        gs_free_object(mem, sst, "filter_open(stream_state)");
1369
0
        return code;
1370
0
    }
1371
791k
    s_std_init(s, s->cbuf, s->bsize, procs,
1372
791k
               (*file_access == 'r' ? s_mode_read : s_mode_write));
1373
791k
    s->procs.process = templat->process;
1374
791k
    s->save_close = s->procs.close;
1375
791k
    s->procs.close = file_close_file;
1376
791k
    if (sst == 0) {
1377
        /* This stream doesn't have any state of its own. */
1378
        /* Hack: use the stream itself as the state. */
1379
69.4k
        sst = (stream_state *) s;
1380
721k
    } else if (st != 0)         /* might not have client parameters */
1381
721k
        memcpy(sst, st, ssize);
1382
791k
    s->state = sst;
1383
791k
    s_init_state(sst, templat, mem);
1384
791k
    sst->report_error = filter_report_error;
1385
1386
791k
    if (templat->init != 0) {
1387
721k
        code = (*templat->init)(sst);
1388
721k
        if (code < 0) {
1389
0
            gs_free_object(mem, sst, "filter_open(stream_state)");
1390
0
            gs_free_object(mem, s->cbuf, "filter_open(buffer)");
1391
0
            return code;
1392
0
        }
1393
721k
    }
1394
791k
    make_stream_file(pfile, s, file_access);
1395
791k
    return 0;
1396
791k
}
1397
1398
/* Close a file object. */
1399
/* This is exported only for gsmain.c. */
1400
int
1401
file_close(ref * pfile)
1402
0
{
1403
0
    stream *s;
1404
1405
0
    if (file_is_valid(s, pfile)) {      /* closing a closed file is a no-op */
1406
0
        if (sclose(s))
1407
0
            return_error(gs_error_ioerror);
1408
0
    }
1409
0
    return 0;
1410
0
}