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