Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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