xref: /plan9/sys/src/cmd/gs/src/zfile.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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
zfile_init(i_ctx_t * i_ctx_p)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
make_invalid_file(ref * fp)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
check_file_permissions_reduced(i_ctx_t * i_ctx_p,const char * fname,int len,const char * permitgroup)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
check_file_permissions(i_ctx_t * i_ctx_p,const char * fname,int len,const char * permitgroup)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
zfile(i_ctx_t * i_ctx_p)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
file_is_tempfile(i_ctx_t * i_ctx_p,const ref * op)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
zdeletefile(i_ctx_t * i_ctx_p)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
zfilenameforall(i_ctx_t * i_ctx_p)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
file_continue(i_ctx_t * i_ctx_p)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
file_cleanup(i_ctx_t * i_ctx_p)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
zrenamefile(i_ctx_t * i_ctx_p)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
zstatus(i_ctx_t * i_ctx_p)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
zexecfile(i_ctx_t * i_ctx_p)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
execfile_finish(i_ctx_t * i_ctx_p)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
execfile_cleanup(i_ctx_t * i_ctx_p)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
zfilenamelistseparator(i_ctx_t * i_ctx_p)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
zfilenamesplit(i_ctx_t * i_ctx_p)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
zlibfile(i_ctx_t * i_ctx_p)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
prefix_is_simple(const char * pstr)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
ztempfile(i_ctx_t * i_ctx_p)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
parse_file_name(const ref * op,gs_parsed_file_name_t * pfn,bool safemode)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
parse_real_file_name(const ref * op,gs_parsed_file_name_t * pfn,gs_memory_t * mem,client_name_t cname)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
parse_file_access_string(const ref * op,char file_access[4])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
zopen_file(i_ctx_t * i_ctx_p,const gs_parsed_file_name_t * pfn,const char * file_access,stream ** ps,gs_memory_t * mem)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
iodev_os_open_file(gx_io_device * iodev,const char * fname,uint len,const char * file_access,stream ** ps,gs_memory_t * mem)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
make_stream_file(ref * pfile,stream * s,const char * access)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
gp_file_name_combine_patch(const char * prefix,uint plen,const char * fname,uint flen,bool no_sibling,char * buffer,uint * blen)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
file_prepare_stream(const char * fname,uint len,const char * file_access,uint buffer_size,stream ** ps,char fmode[4],gx_io_device * iodev,gs_memory_t * mem)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
check_file_permissions_aux(i_ctx_t * i_ctx_p,char * fname,uint flen)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
lib_fopen_with_libpath(gs_file_path_ptr lib_path,const gs_memory_t * mem,i_ctx_t * i_ctx_p,gx_io_device * iodev,const char * fname,uint flen,char fmode[4],char * buffer,int blen,FILE ** file)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 *
lib_fopen(const gs_file_path_ptr pfpath,const gs_memory_t * mem,const char * fname)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
lib_file_open(const gs_file_path_ptr pfpath,i_ctx_t * i_ctx_p,const char * fname,uint len,byte * cname,uint max_clen,uint * pclen,ref * pfile,gs_memory_t * mem)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
file_read_string(const byte * str,uint len,ref * pfile,gs_ref_memory_t * imem)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
file_init_stream(stream * s,FILE * file,const char * fmode,byte * buffer,uint buffer_size)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
file_open_stream(const char * fname,uint len,const char * file_access,uint buffer_size,stream ** ps,gx_io_device * iodev,iodev_proc_fopen_t fopen_proc,gs_memory_t * mem)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
filter_report_error(stream_state * st,const char * str)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
filter_open(const char * file_access,uint buffer_size,ref * pfile,const stream_procs * procs,const stream_template * template,const stream_state * st,gs_memory_t * mem)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 *
file_alloc_stream(gs_memory_t * mem,client_name_t cname)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
file_close_finish(stream * s)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
file_close_disable(stream * s)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
file_close_file(stream * s)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
file_close(ref * pfile)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 }
1362