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