1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: zfile.c 10120 2009-10-04 12:42:07Z alexcher $ */
15 /* Non-I/O file operators */
16 #include "memory_.h"
17 #include "string_.h"
18 #include "unistd_.h"
19 #include "stat_.h" /* get system header early to avoid name clash on Cygwin */
20 #include "ghost.h"
21 #include "gscdefs.h"		/* for gx_io_device_table */
22 #include "gsutil.h"		/* for bytes_compare */
23 #include "gp.h"
24 #include "gpmisc.h"
25 #include "gsfname.h"
26 #include "gsstruct.h"		/* for registering root */
27 #include "gxalloc.h"		/* for streams */
28 #include "oper.h"
29 #include "dstack.h"		/* for systemdict */
30 #include "estack.h"		/* for filenameforall, .execfile */
31 #include "ialloc.h"
32 #include "ilevel.h"		/* %names only work in Level 2 */
33 #include "iname.h"
34 #include "isave.h"		/* for restore */
35 #include "idict.h"
36 #include "iutil.h"
37 #include "stream.h"
38 #include "strimpl.h"
39 #include "sfilter.h"
40 #include "gxiodev.h"		/* must come after stream.h */
41 				/* and before files.h */
42 #include "files.h"
43 #include "main.h"		/* for gs_lib_paths */
44 #include "store.h"
45 #include "zfile.h"
46 
47 /* Import the IODevice table. */
48 extern_gx_io_device_table();
49 
50 /* Import the dtype of the stdio IODevices. */
51 extern const char iodev_dtype_stdio[];
52 
53 /* Forward references: file name parsing. */
54 static int parse_file_name(const ref * op, gs_parsed_file_name_t * pfn, bool safemode);
55 static int parse_real_file_name(const ref * op,
56 				 gs_parsed_file_name_t * pfn,
57 				 gs_memory_t *mem, client_name_t cname);
58 static int parse_file_access_string(const ref *op, char file_access[4]);
59 
60 /* Forward references: other. */
61 static int execfile_finish(i_ctx_t *);
62 static int execfile_cleanup(i_ctx_t *);
63 static iodev_proc_open_file(iodev_os_open_file);
64 stream_proc_report_error(filter_report_error);
65 
66 /*
67  * Since there can be many file objects referring to the same file/stream,
68  * we can't simply free a stream when we close it.  On the other hand,
69  * we don't want freed streams to clutter up memory needlessly.
70  * Our solution is to retain the freed streams, and reuse them.
71  * To prevent an old file object from being able to access a reused stream,
72  * we keep a serial number in each stream, and check it against a serial
73  * number stored in the file object (as the "size"); when we close a file,
74  * we increment its serial number.  If the serial number ever overflows,
75  * we leave it at zero, and do not reuse the stream.
76  * (This will never happen.)
77  *
78  * Storage management for this scheme is a little tricky.  We maintain an
79  * invariant that says that a stream opened at a given save level always
80  * uses a stream structure allocated at that level.  By doing this, we don't
81  * need to keep track separately of streams open at a level vs. streams
82  * allocated at a level.  To make this interact properly with save and
83  * restore, we maintain a list of all streams allocated at this level, both
84  * open and closed.  We store this list in the allocator: this is a hack,
85  * but it simplifies bookkeeping (in particular, it guarantees the list is
86  * restored properly by a restore).
87  *
88  * We want to close streams freed by restore and by garbage collection.  We
89  * use the finalization procedure for this.  For restore, we don't have to
90  * do anything special to make this happen.  For garbage collection, we do
91  * something more drastic: we simply clear the list of known streams (at all
92  * save levels).  Any streams open at the time of garbage collection will no
93  * longer participate in the list of known streams, but this does no harm;
94  * it simply means that they won't get reused, and can only be reclaimed by
95  * a future garbage collection or restore.
96  */
97 
98 /*
99  * Define the default stream buffer sizes.  For file streams,
100  * this is arbitrary, since the C library or operating system
101  * does its own buffering in addition.
102  * However, a buffer size of at least 2K bytes is necessary to prevent
103  * JPEG decompression from running very slow. When less than 2K, an
104  * intermediate filter is installed that transfers 1 byte at a time
105  * causing many aborted roundtrips through the JPEG filter code.
106  */
107 #define DEFAULT_BUFFER_SIZE 2048
108 extern const uint file_default_buffer_size;
109 
110 /* An invalid file object */
111 static stream invalid_file_stream;
112 stream *const invalid_file_entry = &invalid_file_stream;
113 
114 /* Initialize the file table */
115 static int
zfile_init(i_ctx_t * i_ctx_p)116 zfile_init(i_ctx_t *i_ctx_p)
117 {
118     /* Create and initialize an invalid (closed) stream. */
119     /* Initialize the stream for the sake of the GC, */
120     /* and so it can act as an empty input stream. */
121 
122     stream *const s = &invalid_file_stream;
123 
124     s_init(s, NULL);
125     sread_string(s, NULL, 0);
126     s->next = s->prev = 0;
127     s_init_no_id(s);
128     return 0;
129 }
130 
131 /* Make an invalid file object. */
132 void
make_invalid_file(ref * fp)133 make_invalid_file(ref * fp)
134 {
135     make_file(fp, avm_invalid_file_entry, ~0, invalid_file_entry);
136 }
137 
138 /* Check a file name for permission by stringmatch on one of the */
139 /* strings of the permitgroup array. */
140 static int
check_file_permissions_reduced(i_ctx_t * i_ctx_p,const char * fname,int len,const char * permitgroup)141 check_file_permissions_reduced(i_ctx_t *i_ctx_p, const char *fname, int len,
142 			const char *permitgroup)
143 {
144     long i;
145     ref *permitlist = NULL;
146     /* an empty string (first character == 0) if '\' character is */
147     /* recognized as a file name separator as on DOS & Windows	  */
148     const char *win_sep2 = "\\";
149     bool use_windows_pathsep = (gs_file_name_check_separator(win_sep2, 1, win_sep2) == 1);
150     uint plen = gp_file_name_parents(fname, len);
151 
152     /* Assuming a reduced file name. */
153 
154     if (dict_find_string(&(i_ctx_p->userparams), permitgroup, &permitlist) <= 0)
155         return 0;	/* if Permissions not found, just allow access */
156 
157     for (i=0; i<r_size(permitlist); i++) {
158         ref permitstring;
159 	const string_match_params win_filename_params = {
160 		'*', '?', '\\', true, true	/* ignore case & '/' == '\\' */
161 	};
162 	const byte *permstr;
163 	uint permlen;
164 	int cwd_len = 0;
165 
166 	if (array_get(imemory, permitlist, i, &permitstring) < 0 ||
167 	    r_type(&permitstring) != t_string
168 	   )
169 	    break;	/* any problem, just fail */
170 	permstr = permitstring.value.bytes;
171 	permlen = r_size(&permitstring);
172 	/*
173 	 * Check if any file name is permitted with "*".
174 	 */
175 	if (permlen == 1 && permstr[0] == '*')
176 	    return 0;		/* success */
177 	/*
178 	 * If the filename starts with parent references,
179 	 * the permission element must start with same number of parent references.
180 	 */
181 	if (plen != 0 && plen != gp_file_name_parents((const char *)permstr, permlen))
182 	    continue;
183 	cwd_len = gp_file_name_cwds((const char *)permstr, permlen);
184 	/*
185 	 * If the permission starts with "./", absolute paths
186 	 * are not permitted.
187 	 */
188 	if (cwd_len > 0 && gp_file_name_is_absolute(fname, len))
189 	    continue;
190 	/*
191 	 * If the permission starts with "./", relative paths
192 	 * with no "./" are allowed as well as with "./".
193 	 * 'fname' has no "./" because it is reduced.
194 	 */
195         if (string_match( (const unsigned char*) fname, len,
196 			  permstr + cwd_len, permlen - cwd_len,
197 		use_windows_pathsep ? &win_filename_params : NULL))
198 	    return 0;		/* success */
199     }
200     /* not found */
201     return e_invalidfileaccess;
202 }
203 
204 /* Check a file name for permission by stringmatch on one of the */
205 /* strings of the permitgroup array */
206 static int
check_file_permissions(i_ctx_t * i_ctx_p,const char * fname,int len,const char * permitgroup)207 check_file_permissions(i_ctx_t *i_ctx_p, const char *fname, int len,
208 			const char *permitgroup)
209 {
210     char fname_reduced[gp_file_name_sizeof];
211     uint rlen = sizeof(fname_reduced);
212 
213     if (gp_file_name_reduce(fname, len, fname_reduced, &rlen) != gp_combine_success)
214 	return e_invalidaccess;		/* fail if we couldn't reduce */
215     return check_file_permissions_reduced(i_ctx_p, fname_reduced, rlen, permitgroup);
216 }
217 
218 /* <name_string> <access_string> file <file> */
219 int				/* exported for zsysvm.c */
zfile(i_ctx_t * i_ctx_p)220 zfile(i_ctx_t *i_ctx_p)
221 {
222     os_ptr op = osp;
223     char file_access[4];
224     gs_parsed_file_name_t pname;
225     int code = parse_file_access_string(op, file_access);
226     stream *s;
227 
228     if (code < 0)
229 	return code;
230     code = parse_file_name(op - 1, &pname, i_ctx_p->LockFilePermissions);
231     if (code < 0)
232 	return code;
233 	/*
234 	 * HACK: temporarily patch the current context pointer into the
235 	 * state pointer for stdio-related devices.  See ziodev.c for
236 	 * more information.
237 	 */
238     if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) {
239 	bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0);
240 	bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0);
241 	if (pname.fname)
242 	    return_error(e_invalidfileaccess);
243 	if (statement || lineedit) {
244 	    /* These need special code to support callouts */
245 	    gx_io_device *indev = gs_findiodevice((const byte *)"%stdin", 6);
246 	    stream *ins;
247 	    if (strcmp(file_access, "r"))
248 		return_error(e_invalidfileaccess);
249 	    indev->state = i_ctx_p;
250 	    code = (indev->procs.open_device)(indev, file_access, &ins, imemory);
251 	    indev->state = 0;
252 	    if (code < 0)
253 		return code;
254 	    check_ostack(2);
255 	    push(2);
256 	    make_stream_file(op - 3, ins, file_access);
257 	    make_bool(op-2, statement);
258 	    make_int(op-1, 0);
259 	    make_string(op, icurrent_space, 0, NULL);
260 	    return zfilelineedit(i_ctx_p);
261 	}
262 	pname.iodev->state = i_ctx_p;
263 	code = (*pname.iodev->procs.open_device)(pname.iodev,
264 						 file_access, &s, imemory);
265 	pname.iodev->state = NULL;
266     } else {
267 	if (pname.iodev == NULL)
268 	    pname.iodev = iodev_default;
269 	code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory);
270     }
271     if (code < 0)
272 	return code;
273     code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1));
274     if (code < 0) {
275 	sclose(s);
276 	return_error(e_VMerror);
277     }
278     make_stream_file(op - 1, s, file_access);
279     pop(1);
280     return code;
281 }
282 
283 /*
284  * Files created with .tempfile permit some operations even if the
285  * temp directory is not explicitly named on the PermitFile... path
286  * The names 'SAFETY' and 'tempfiles' are defined by gs_init.ps
287 */
288 static bool
file_is_tempfile(i_ctx_t * i_ctx_p,const uchar * fname,int len)289 file_is_tempfile(i_ctx_t *i_ctx_p, const uchar *fname, int len)
290 {
291     ref *SAFETY;
292     ref *tempfiles;
293     ref kname;
294 
295     if (dict_find_string(systemdict, "SAFETY", &SAFETY) <= 0 ||
296 	    dict_find_string(SAFETY, "tempfiles", &tempfiles) <= 0)
297 	return false;
298     if (name_ref(imemory, fname, len, &kname, -1) < 0 ||
299 	    dict_find(tempfiles, &kname, &SAFETY) <= 0)
300 	return false;
301     return true;
302 }
303 
304 /* ------ Level 2 extensions ------ */
305 
306 /* <string> deletefile - */
307 static int
zdeletefile(i_ctx_t * i_ctx_p)308 zdeletefile(i_ctx_t *i_ctx_p)
309 {
310     os_ptr op = osp;
311     gs_parsed_file_name_t pname;
312     int code = parse_real_file_name(op, &pname, imemory, "deletefile");
313 
314     if (code < 0)
315 	return code;
316     if (pname.iodev == iodev_default) {
317 	if ((code = check_file_permissions(i_ctx_p, pname.fname, pname.len,
318 		"PermitFileControl")) < 0 &&
319 		 !file_is_tempfile(i_ctx_p, op->value.bytes, r_size(op))) {
320 	    return code;
321 	}
322     }
323     code = (*pname.iodev->procs.delete_file)(pname.iodev, pname.fname);
324     gs_free_file_name(&pname, "deletefile");
325     if (code < 0)
326 	return code;
327     pop(1);
328     return 0;
329 }
330 
331 /* <template> <proc> <scratch> filenameforall - */
332 static int file_continue(i_ctx_t *);
333 static int file_cleanup(i_ctx_t *);
334 static int
zfilenameforall(i_ctx_t * i_ctx_p)335 zfilenameforall(i_ctx_t *i_ctx_p)
336 {
337     os_ptr op = osp;
338     file_enum *pfen;
339     gx_io_device *iodev = NULL;
340     gs_parsed_file_name_t pname;
341     int code = 0;
342 
343     check_write_type(*op, t_string);
344     check_proc(op[-1]);
345     check_read_type(op[-2], t_string);
346     /* Push a mark, the iodev, devicenamelen, the scratch string, the enumerator, */
347     /* and the procedure, and invoke the continuation. */
348     check_estack(7);
349     /* Get the iodevice */
350     code = parse_file_name(op - 2, &pname, i_ctx_p->LockFilePermissions);
351     if (code < 0)
352 	return code;
353     iodev = (pname.iodev == NULL) ? iodev_default : pname.iodev;
354 
355     /* Check for several conditions that just cause us to return success */
356     if (pname.len == 0 || iodev->procs.enumerate_files == iodev_no_enumerate_files) {
357         pop(3);
358         return 0;	/* no pattern, or device not found -- just return */
359     }
360     pfen = iodev->procs.enumerate_files(iodev, (const char *)pname.fname,
361     		pname.len, imemory);
362     if (pfen == 0)
363 	return_error(e_VMerror);
364     push_mark_estack(es_for, file_cleanup);
365     ++esp;
366     make_istruct(esp, 0, iodev);
367     ++esp;
368     make_int(esp, r_size(op-2) - pname.len);
369     *++esp = *op;
370     ++esp;
371     make_istruct(esp, 0, pfen);
372     *++esp = op[-1];
373     pop(3);
374     code = file_continue(i_ctx_p);
375     return (code == o_pop_estack ? o_push_estack : code);
376 }
377 /* Continuation operator for enumerating files */
378 static int
file_continue(i_ctx_t * i_ctx_p)379 file_continue(i_ctx_t *i_ctx_p)
380 {
381     os_ptr op = osp;
382     es_ptr pscratch = esp - 2;
383     file_enum *pfen = r_ptr(esp - 1, file_enum);
384     int devlen = esp[-3].value.intval;
385     gx_io_device *iodev = r_ptr(esp - 4, gx_io_device);
386     uint len = r_size(pscratch);
387     uint code;
388 
389     if (len < devlen)
390 	return_error(e_rangecheck);	/* not even room for device len */
391     memcpy((char *)pscratch->value.bytes, iodev->dname, devlen);
392     code = iodev->procs.enumerate_next(pfen, (char *)pscratch->value.bytes + devlen,
393     		len - devlen);
394     if (code == ~(uint) 0) {	/* all done */
395 	esp -= 5;		/* pop proc, pfen, devlen, iodev , mark */
396 	return o_pop_estack;
397     } else if (code > len)	/* overran string */
398 	return_error(e_rangecheck);
399     else {
400 	push(1);
401 	ref_assign(op, pscratch);
402 	r_set_size(op, code + devlen);
403 	push_op_estack(file_continue);	/* come again */
404 	*++esp = pscratch[2];	/* proc */
405 	return o_push_estack;
406     }
407 }
408 /* Cleanup procedure for enumerating files */
409 static int
file_cleanup(i_ctx_t * i_ctx_p)410 file_cleanup(i_ctx_t *i_ctx_p)
411 {
412     gx_io_device *iodev = r_ptr(esp + 2, gx_io_device);
413 
414     iodev->procs.enumerate_close(r_ptr(esp + 5, file_enum));
415     return 0;
416 }
417 
418 /* <string1> <string2> renamefile - */
419 static int
zrenamefile(i_ctx_t * i_ctx_p)420 zrenamefile(i_ctx_t *i_ctx_p)
421 {
422     int code;
423     os_ptr op = osp;
424     gs_parsed_file_name_t pname1, pname2;
425 
426     code = parse_real_file_name(op, &pname2, imemory, "renamefile(to)");
427     if (code < 0)
428 	return code;
429 
430     pname1.fname = 0;
431     code = parse_real_file_name(op - 1, &pname1, imemory, "renamefile(from)");
432     if (code >= 0) {
433 	if (pname1.iodev != pname2.iodev ) {
434 	    if (pname1.iodev == iodev_default)
435 		pname1.iodev = pname2.iodev;
436 	    if (pname2.iodev == iodev_default)
437 		pname2.iodev = pname1.iodev;
438 	}
439 	if (pname1.iodev != pname2.iodev ||
440 	    (pname1.iodev == iodev_default &&
441 		/*
442 		 * We require FileControl permissions on the source path
443 		 * unless it is a temporary file. Also, we require FileControl
444 		 * and FileWriting permissions to the destination file/path.
445 		 */
446 	      ((check_file_permissions(i_ctx_p, pname1.fname, pname1.len,
447 	      				"PermitFileControl") < 0 &&
448 	          !file_is_tempfile(i_ctx_p, op[-1].value.bytes, r_size(op - 1))) ||
449 	      (check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
450 	      				"PermitFileControl") < 0 ||
451 	      check_file_permissions(i_ctx_p, pname2.fname, pname2.len,
452 	      				"PermitFileWriting") < 0 )))) {
453 	    code = gs_note_error(e_invalidfileaccess);
454 	} else {
455 	    code = (*pname1.iodev->procs.rename_file)(pname1.iodev,
456 			    pname1.fname, pname2.fname);
457 	}
458     }
459     gs_free_file_name(&pname2, "renamefile(to)");
460     gs_free_file_name(&pname1, "renamefile(from)");
461     if (code < 0)
462 	return code;
463     pop(2);
464     return 0;
465 }
466 
467 /* <file> status <open_bool> */
468 /* <string> status <pages> <bytes> <ref_time> <creation_time> true */
469 /* <string> status false */
470 static int
zstatus(i_ctx_t * i_ctx_p)471 zstatus(i_ctx_t *i_ctx_p)
472 {
473     os_ptr op = osp;
474 
475     switch (r_type(op)) {
476 	case t_file:
477 	    {
478 		stream *s;
479 
480 		make_bool(op, (file_is_valid(s, op) ? 1 : 0));
481 	    }
482 	    return 0;
483 	case t_string:
484 	    {
485 		gs_parsed_file_name_t pname;
486 		struct stat fstat;
487 		int code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions);
488 
489 		if (code < 0)
490 		    return code;
491 		code = gs_terminate_file_name(&pname, imemory, "status");
492 		if (code < 0)
493 		    return code;
494 		code = (*pname.iodev->procs.file_status)(pname.iodev,
495 						       pname.fname, &fstat);
496 		switch (code) {
497 		    case 0:
498 			check_ostack(4);
499 			/*
500 			 * Check to make sure that the file size fits into
501 			 * a PostScript integer.  (On some systems, long is
502 			 * 32 bits, but file sizes are 64 bits.)
503 			 */
504 			push(4);
505 			make_int(op - 4, stat_blocks(&fstat));
506 			make_int(op - 3, fstat.st_size);
507 			/*
508 			 * We can't check the value simply by using ==,
509 			 * because signed/unsigned == does the wrong thing.
510 			 * Instead, since integer assignment only keeps the
511 			 * bottom bits, we convert the values to double
512 			 * and then test for equality.  This handles all
513 			 * cases of signed/unsigned or width mismatch.
514 			 */
515 			if ((double)op[-4].value.intval !=
516 			      (double)stat_blocks(&fstat) ||
517 			    (double)op[-3].value.intval !=
518 			      (double)fstat.st_size
519 			    )
520 			    return_error(e_limitcheck);
521 			make_int(op - 2, fstat.st_mtime);
522 			make_int(op - 1, fstat.st_ctime);
523 			make_bool(op, 1);
524 			break;
525 		    case e_undefinedfilename:
526 			make_bool(op, 0);
527 			code = 0;
528 		}
529 		gs_free_file_name(&pname, "status");
530 		return code;
531 	    }
532 	default:
533 	    return_op_typecheck(op);
534     }
535 }
536 
537 /* ------ Non-standard extensions ------ */
538 
539 /* <executable_file> .execfile - */
540 static int
zexecfile(i_ctx_t * i_ctx_p)541 zexecfile(i_ctx_t *i_ctx_p)
542 {
543     os_ptr op = osp;
544 
545     check_type_access(*op, t_file, a_executable | a_read | a_execute);
546     check_estack(4);		/* cleanup, file, finish, file */
547     push_mark_estack(es_other, execfile_cleanup);
548     *++esp = *op;
549     push_op_estack(execfile_finish);
550     return zexec(i_ctx_p);
551 }
552 /* Finish normally. */
553 static int
execfile_finish(i_ctx_t * i_ctx_p)554 execfile_finish(i_ctx_t *i_ctx_p)
555 {
556     check_ostack(1);
557     esp -= 2;
558     execfile_cleanup(i_ctx_p);
559     return o_pop_estack;
560 }
561 /* Clean up by closing the file. */
562 static int
execfile_cleanup(i_ctx_t * i_ctx_p)563 execfile_cleanup(i_ctx_t *i_ctx_p)
564 {
565     check_ostack(1);
566     *++osp = esp[2];
567     return zclosefile(i_ctx_p);
568 }
569 
570 /* - .filenamelistseparator <string> */
571 static int
zfilenamelistseparator(i_ctx_t * i_ctx_p)572 zfilenamelistseparator(i_ctx_t *i_ctx_p)
573 {
574     os_ptr op = osp;
575 
576     push(1);
577     make_const_string(op, avm_foreign | a_readonly, 1,
578 		      (const byte *)&gp_file_name_list_separator);
579     return 0;
580 }
581 
582 /* <name> .filenamesplit <dir> <base> <extension> */
583 static int
zfilenamesplit(i_ctx_t * i_ctx_p)584 zfilenamesplit(i_ctx_t *i_ctx_p)
585 {
586     os_ptr op = osp;
587 
588     check_read_type(*op, t_string);
589 /****** NOT IMPLEMENTED YET ******/
590     return_error(e_undefined);
591 }
592 
593 /* <string> .libfile <file> true */
594 /* <string> .libfile <string> false */
595 int				/* exported for zsysvm.c */
zlibfile(i_ctx_t * i_ctx_p)596 zlibfile(i_ctx_t *i_ctx_p)
597 {
598     os_ptr op = osp;
599     int code;
600     byte cname[DEFAULT_BUFFER_SIZE];
601     uint clen;
602     gs_parsed_file_name_t pname;
603     stream *s;
604 
605     check_ostack(2);
606     code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions);
607     if (code < 0)
608 	return code;
609     if (pname.iodev == NULL)
610 	pname.iodev = iodev_default;
611     if (pname.iodev != iodev_default) {		/* Non-OS devices don't have search paths (yet). */
612 	code = zopen_file(i_ctx_p, &pname, "r", &s, imemory);
613 	if (code >= 0) {
614 	    code = ssetfilename(s, op->value.const_bytes, r_size(op));
615 	    if (code < 0) {
616 		sclose(s);
617 		return_error(e_VMerror);
618 	    }
619 	}
620 	if (code < 0) {
621 	    push(1);
622 	    make_false(op);
623 	    return 0;
624 	}
625 	make_stream_file(op, s, "r");
626     } else {
627 	ref fref;
628 
629 	code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len,
630 			     (char *)cname, sizeof(cname), &clen, &fref);
631 	if (code >= 0) {
632 	    s = fptr(&fref);
633 	    code = ssetfilename(s, cname, clen);
634 	    if (code < 0) {
635 		sclose(s);
636 		return_error(e_VMerror);
637 	    }
638 	}
639 	if (code < 0) {
640 	    if (code == e_VMerror || code == e_invalidfileaccess)
641 		return code;
642 	    push(1);
643 	    make_false(op);
644 	    return 0;
645 	}
646 	ref_assign(op, &fref);
647     }
648     push(1);
649     make_true(op);
650     return 0;
651 }
652 
653 /* A "simple" prefix is defined as a (possibly empty) string of
654    alphanumeric, underscore, and hyphen characters. */
655 static bool
prefix_is_simple(const char * pstr)656 prefix_is_simple(const char *pstr)
657 {
658     int i;
659     char c;
660 
661     for (i = 0; (c = pstr[i]) != 0; i++) {
662 	if (!(c == '-' || c == '_' || (c >= '0' && c <= '9') ||
663 	      (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
664 	    return false;
665     }
666     return true;
667 }
668 
669 /* <prefix|null> <access_string> .tempfile <name_string> <file> */
670 static int
ztempfile(i_ctx_t * i_ctx_p)671 ztempfile(i_ctx_t *i_ctx_p)
672 {
673     os_ptr op = osp;
674     const char *pstr;
675     char fmode[4];
676     int code = parse_file_access_string(op, fmode);
677     char prefix[gp_file_name_sizeof];
678     char fname[gp_file_name_sizeof];
679     uint fnlen;
680     FILE *sfile;
681     stream *s;
682     byte *buf, *sbody;
683 
684     if (code < 0)
685 	return code;
686     strcat(fmode, gp_fmode_binary_suffix);
687     if (r_has_type(op - 1, t_null))
688 	pstr = gp_scratch_file_name_prefix;
689     else {
690 	uint psize;
691 
692 	check_read_type(op[-1], t_string);
693 	psize = r_size(op - 1);
694 	if (psize >= gp_file_name_sizeof)
695 	    return_error(e_rangecheck);
696 	memcpy(prefix, op[-1].value.const_bytes, psize);
697 	prefix[psize] = 0;
698 	pstr = prefix;
699     }
700 
701     if (gp_file_name_is_absolute(pstr, strlen(pstr))) {
702 	if (check_file_permissions(i_ctx_p, pstr, strlen(pstr),
703 				   "PermitFileWriting") < 0) {
704 	    return_error(e_invalidfileaccess);
705 	}
706     } else if (!prefix_is_simple(pstr)) {
707 	return_error(e_invalidfileaccess);
708     }
709 
710     s = file_alloc_stream(imemory, "ztempfile(stream)");
711     if (s == 0)
712 	return_error(e_VMerror);
713     buf = gs_alloc_bytes(imemory, file_default_buffer_size,
714 			 "ztempfile(buffer)");
715     if (buf == 0)
716 	return_error(e_VMerror);
717     sfile = gp_open_scratch_file(pstr, fname, fmode);
718     if (sfile == 0) {
719 	gs_free_object(imemory, buf, "ztempfile(buffer)");
720 	return_error(e_invalidfileaccess);
721     }
722     fnlen = strlen(fname);
723     sbody = ialloc_string(fnlen, ".tempfile(fname)");
724     if (sbody == 0) {
725 	gs_free_object(imemory, buf, "ztempfile(buffer)");
726 	return_error(e_VMerror);
727     }
728     memcpy(sbody, fname, fnlen);
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 	ifree_string(sbody, fnlen, ".tempfile(fname)");
735 	return_error(e_VMerror);
736     }
737     make_string(op - 1, a_readonly | icurrent_space, fnlen, sbody);
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 static 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 static 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 static 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 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 && !file_is_tempfile(i_ctx_p,
857                                           (const uchar *)pfn->fname, pfn->len))
858 		return code;
859 	}
860 	return open_file(iodev, pfn->fname, pfn->len, file_access, ps, mem);
861     }
862 }
863 
864 /*
865  * Define the file_open procedure for the %os% IODevice (also used, as the
866  * default, for %pipe% and possibly others).
867  */
868 static int
iodev_os_open_file(gx_io_device * iodev,const char * fname,uint len,const char * file_access,stream ** ps,gs_memory_t * mem)869 iodev_os_open_file(gx_io_device * iodev, const char *fname, uint len,
870 		   const char *file_access, stream ** ps, gs_memory_t * mem)
871 {
872     return file_open_stream(fname, len, file_access,
873 			    file_default_buffer_size, ps,
874 			    iodev, iodev->procs.fopen, mem);
875 }
876 
877 /* Make a t_file reference to a stream. */
878 void
make_stream_file(ref * pfile,stream * s,const char * access)879 make_stream_file(ref * pfile, stream * s, const char *access)
880 {
881     uint attrs =
882 	(access[1] == '+' ? a_write + a_read + a_execute : 0) |
883 	imemory_space((gs_ref_memory_t *) s->memory);
884 
885     if (access[0] == 'r') {
886 	make_file(pfile, attrs | (a_read | a_execute), s->read_id, s);
887 	s->write_id = 0;
888     } else {
889 	make_file(pfile, attrs | a_write, s->write_id, s);
890 	s->read_id = 0;
891     }
892 }
893 
894 static int
check_file_permissions_aux(i_ctx_t * i_ctx_p,char * fname,uint flen)895 check_file_permissions_aux(i_ctx_t *i_ctx_p, char *fname, uint flen)
896 {   /* i_ctx_p is NULL running init files. */
897     /* fname must be reduced. */
898     if (i_ctx_p == NULL)
899 	return 0;
900     if (check_file_permissions_reduced(i_ctx_p, fname, flen, "PermitFileReading") < 0)
901 	return_error(e_invalidfileaccess);
902     return 0;
903 }
904 
905 
906 /* Return a file object of of the file searched for using the search paths. */
907 /* The fname cannot contain a device part (%...%) but the lib paths might. */
908 /* The startup code calls this to open the initialization file gs_init.ps. */
909 /* The startup code also calls this to open @-files. */
910 int
lib_file_open(gs_file_path_ptr lib_path,const gs_memory_t * mem,i_ctx_t * i_ctx_p,const char * fname,uint flen,char * buffer,int blen,uint * pclen,ref * pfile)911 lib_file_open(gs_file_path_ptr  lib_path, const gs_memory_t *mem, i_ctx_t *i_ctx_p,
912 		       const char *fname, uint flen, char *buffer, int blen, uint *pclen, ref *pfile)
913 {   /* i_ctx_p is NULL running arg (@) files.
914      * lib_path and mem are never NULL
915      */
916     bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file;
917     bool search_with_no_combine = false;
918     bool search_with_combine = false;
919     char fmode[4] = { 'r', 0, 0, 0 };		/* room for binary suffix */
920     stream *s;
921     gx_io_device *iodev = iodev_default;
922 
923     /* when starting arg files (@ files) iodev_default is not yet set */
924     if (iodev == 0)
925         iodev = (gx_io_device *)gx_io_device_table[0];
926 
927     strcat(fmode, gp_fmode_binary_suffix);
928     if (gp_file_name_is_absolute(fname, flen)) {
929        search_with_no_combine = true;
930        search_with_combine = false;
931     } else {
932        search_with_no_combine = starting_arg_file;
933        search_with_combine = true;
934     }
935     if (search_with_no_combine) {
936 	uint blen1 = blen;
937 
938 	if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success)
939 	    goto skip;
940 	if (iodev_os_open_file(iodev, (const char *)buffer, blen1,
941 				(const char *)fmode, &s, (gs_memory_t *)mem) == 0) {
942 	    if (starting_arg_file ||
943 			check_file_permissions_aux(i_ctx_p, buffer, blen1) >= 0) {
944 		*pclen = blen1;
945 		make_stream_file(pfile, s, "r");
946 		return 0;
947 	    }
948 	    sclose(s);
949 	    return_error(e_invalidfileaccess);
950 	}
951 	skip:;
952     }
953     if (search_with_combine) {
954 	const gs_file_path *pfpath = lib_path;
955 	uint pi;
956 
957 	for (pi = 0; pi < r_size(&pfpath->list); ++pi) {
958 	    const ref *prdir = pfpath->list.value.refs + pi;
959 	    const char *pstr = (const char *)prdir->value.const_bytes;
960 	    uint plen = r_size(prdir), blen1 = blen;
961     	    gs_parsed_file_name_t pname;
962 	    gp_file_name_combine_result r;
963 
964 	    /* We need to concatenate and parse the file name here
965 	     * if this path has a %device% prefix.		*/
966 	    if (pstr[0] == '%') {
967 		int code;
968 
969 		/* We concatenate directly since gp_file_name_combine_*
970 		 * rules are not correct for other devices such as %rom% */
971 		code = gs_parse_file_name(&pname, pstr, plen);
972 		if (code < 0)
973 		    continue;
974 		memcpy(buffer, pname.fname, pname.len);
975 		memcpy(buffer+pname.len, fname, flen);
976 		code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode,
977 					      &s, (gs_memory_t *)mem);
978 		if (code < 0)
979 		    continue;
980 		make_stream_file(pfile, s, "r");
981 		/* fill in the buffer with the device concatenated */
982 		memcpy(buffer, pstr, plen);
983 		memcpy(buffer+plen, fname, flen);
984 		*pclen = plen + flen;
985 		return 0;
986 	    } else {
987 		r = gp_file_name_combine(pstr, plen,
988 			fname, flen, false, buffer, &blen1);
989 		if (r != gp_combine_success)
990 		    continue;
991 		if (iodev_os_open_file(iodev, (const char *)buffer, blen1, (const char *)fmode,
992 					&s, (gs_memory_t *)mem) == 0) {
993 		    if (starting_arg_file ||
994 			check_file_permissions_aux(i_ctx_p, buffer, blen1) >= 0) {
995 			*pclen = blen1;
996 			make_stream_file(pfile, s, "r");
997 			return 0;
998 		    }
999 		    sclose(s);
1000 		    return_error(e_invalidfileaccess);
1001 		}
1002 	    }
1003 	}
1004     }
1005     return_error(e_undefinedfilename);
1006 }
1007 
1008 /* The startup code calls this to open @-files. */
1009 FILE *
lib_fopen(const gs_file_path_ptr pfpath,const gs_memory_t * mem,const char * fname)1010 lib_fopen(const gs_file_path_ptr pfpath, const gs_memory_t *mem, const char *fname)
1011 {
1012     /* We need a buffer to hold the expanded file name. */
1013     char filename_found[DEFAULT_BUFFER_SIZE];
1014     FILE *file = NULL;
1015     uint fnamelen;
1016     ref obj;
1017     int code;
1018 
1019     /* open the usual 'stream', then if successful, return the file */
1020     code = lib_file_open(pfpath, mem, NULL, fname, strlen(fname),
1021 			    filename_found, sizeof(filename_found), &fnamelen, &obj);
1022 
1023     if (code < 0)
1024 	return NULL;
1025     file = ((stream *)(obj.value.pfile))->file;
1026     return file;
1027 }
1028 
1029 /* Open a file stream that reads a string. */
1030 /* (This is currently used only by the ccinit feature.) */
1031 /* The string must be allocated in non-garbage-collectable (foreign) space. */
1032 int
file_read_string(const byte * str,uint len,ref * pfile,gs_ref_memory_t * imem)1033 file_read_string(const byte *str, uint len, ref *pfile, gs_ref_memory_t *imem)
1034 {
1035     stream *s = file_alloc_stream((gs_memory_t *)imem, "file_read_string");
1036 
1037     if (s == 0)
1038 	return_error(e_VMerror);
1039     sread_string(s, str, len);
1040     s->foreign = 1;
1041     s->write_id = 0;
1042     make_file(pfile, a_readonly | imemory_space(imem), s->read_id, s);
1043     s->save_close = s->procs.close;
1044     s->procs.close = file_close_disable;
1045     return 0;
1046 }
1047 
1048 /* Report an error by storing it in the stream's error_string. */
1049 int
filter_report_error(stream_state * st,const char * str)1050 filter_report_error(stream_state * st, const char *str)
1051 {
1052     if_debug1('s', "[s]stream error: %s\n", str);
1053     strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING);
1054     /* Ensure null termination. */
1055     st->error_string[STREAM_MAX_ERROR_STRING] = 0;
1056     return 0;
1057 }
1058 
1059 /* Open a file stream for a filter. */
1060 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)1061 filter_open(const char *file_access, uint buffer_size, ref * pfile,
1062 	    const stream_procs * procs, const stream_template * template,
1063 	    const stream_state * st, gs_memory_t *mem)
1064 {
1065     stream *s;
1066     uint ssize = gs_struct_type_size(template->stype);
1067     stream_state *sst = 0;
1068     int code;
1069 
1070     if (template->stype != &st_stream_state) {
1071 	sst = s_alloc_state(mem, template->stype, "filter_open(stream_state)");
1072 	if (sst == 0)
1073 	    return_error(e_VMerror);
1074     }
1075     code = file_open_stream((char *)0, 0, file_access, buffer_size, &s,
1076     				(gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
1077     if (code < 0) {
1078 	gs_free_object(mem, sst, "filter_open(stream_state)");
1079 	return code;
1080     }
1081     s_std_init(s, s->cbuf, s->bsize, procs,
1082 	       (*file_access == 'r' ? s_mode_read : s_mode_write));
1083     s->procs.process = template->process;
1084     s->save_close = s->procs.close;
1085     s->procs.close = file_close_file;
1086     if (sst == 0) {
1087 	/* This stream doesn't have any state of its own. */
1088 	/* Hack: use the stream itself as the state. */
1089 	sst = (stream_state *) s;
1090     } else if (st != 0)		/* might not have client parameters */
1091 	memcpy(sst, st, ssize);
1092     s->state = sst;
1093     s_init_state(sst, template, mem);
1094     sst->report_error = filter_report_error;
1095 
1096     if (template->init != 0) {
1097 	code = (*template->init)(sst);
1098 	if (code < 0) {
1099 	    gs_free_object(mem, sst, "filter_open(stream_state)");
1100 	    gs_free_object(mem, s->cbuf, "filter_open(buffer)");
1101 	    return code;
1102 	}
1103     }
1104     make_stream_file(pfile, s, file_access);
1105     return 0;
1106 }
1107 
1108 /* Close a file object. */
1109 /* This is exported only for gsmain.c. */
1110 int
file_close(ref * pfile)1111 file_close(ref * pfile)
1112 {
1113     stream *s;
1114 
1115     if (file_is_valid(s, pfile)) {	/* closing a closed file is a no-op */
1116 	if (sclose(s))
1117 	    return_error(e_ioerror);
1118     }
1119     return 0;
1120 }
1121