/* return zero for success, -ve for error, +1 for continue */ static int lib_file_open_search_with_combine(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, gx_io_device *iodev, bool starting_arg_file, char *fmode) { stream *s; const gs_file_path *pfpath = lib_path; uint pi; for (pi = 0; pi < r_size(&pfpath->list); ++pi) { const ref *prdir = pfpath->list.value.refs + pi; const char *pstr = (const char *)prdir->value.const_bytes; uint plen = r_size(prdir), blen1 = blen; gs_parsed_file_name_t pname; gp_file_name_combine_result r; /* We need to concatenate and parse the file name here * if this path has a %device% prefix. */ if (pstr[0] == '%') { int code; /* We concatenate directly since gp_file_name_combine_* * rules are not correct for other devices such as %rom% */ code = gs_parse_file_name(&pname, pstr, plen, mem); if (code < 0) continue; memcpy(buffer, pname.fname, pname.len); memcpy(buffer+pname.len, fname, flen); code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode, &s, (gs_memory_t *)mem); if (code < 0) continue; make_stream_file(pfile, s, "r"); /* fill in the buffer with the device concatenated */ memcpy(buffer, pstr, plen); memcpy(buffer+plen, fname, flen); *pclen = plen + flen; return 0; } else { r = gp_file_name_combine(pstr, plen, fname, flen, false, buffer, &blen1); if (r != gp_combine_success) continue; if (iodev_os_open_file(iodev, (const char *)buffer, blen1, (const char *)fmode, &s, (gs_memory_t *)mem) == 0) { if (starting_arg_file || check_file_permissions_aux(i_ctx_p, buffer, blen1) >= 0) { *pclen = blen1; make_stream_file(pfile, s, "r"); return 0; } sclose(s); return_error(e_invalidfileaccess); } } } return 1; }
/* Make a reusable file stream. */ static int make_rfs(i_ctx_t *i_ctx_p, os_ptr op, stream *fs, long offset, long length) { uint save_space = icurrent_space; uint stream_space = imemory_space((const gs_ref_memory_t *)fs->memory); gs_const_string fname; gs_parsed_file_name_t pname; stream *s; int code; if (sfilename(fs, &fname) < 0) return_error(e_ioerror); code = gs_parse_file_name(&pname, (const char *)fname.data, fname.size, imemory); if (code < 0) return code; if (pname.len == 0) /* %stdin% etc. won't have a filename */ return_error(e_invalidfileaccess); /* can't reopen */ if (pname.iodev == NULL) pname.iodev = iodev_default(imemory); /* Open the file again, to be independent of the source. */ ialloc_set_space(idmemory, stream_space); code = zopen_file(i_ctx_p, &pname, "r", &s, imemory); ialloc_set_space(idmemory, save_space); if (code < 0) return code; if (sread_subfile(s, offset, length) < 0) { sclose(s); return_error(e_ioerror); } s->close_at_eod = false; make_stream_file(op, s, "r"); return 0; }
/* <string> print - */ static int zprint(i_ctx_t *i_ctx_p) { os_ptr op = osp; stream *s; int status; ref rstdout; int code; check_read_type(*op, t_string); code = zget_stdout(i_ctx_p, &s); if (code < 0) return code; status = write_string(op, s); if (status >= 0) { pop(1); return 0; } /* Convert print to writestring on the fly. */ make_stream_file(&rstdout, s, "w"); code = handle_write_status(i_ctx_p, status, &rstdout, NULL, zwritestring); if (code != o_push_estack) return code; push(1); *op = op[-1]; op[-1] = rstdout; return code; }
/* <string> .libfile <string> false */ int /* exported for zsysvm.c */ zlibfile(i_ctx_t *i_ctx_p) { os_ptr op = osp; int code; byte cname[DEFAULT_BUFFER_SIZE]; uint clen; gs_parsed_file_name_t pname; stream *s; gx_io_device *iodev_dflt; check_ostack(2); code = parse_file_name(op, &pname, i_ctx_p->LockFilePermissions, imemory); if (code < 0) return code; iodev_dflt = iodev_default(imemory); if (pname.iodev == NULL) pname.iodev = iodev_dflt; if (pname.iodev != iodev_dflt) { /* Non-OS devices don't have search paths (yet). */ code = zopen_file(i_ctx_p, &pname, "r", &s, imemory); if (code >= 0) { code = ssetfilename(s, op->value.const_bytes, r_size(op)); if (code < 0) { sclose(s); return_error(e_VMerror); } } if (code < 0) { push(1); make_false(op); return 0; } make_stream_file(op, s, "r"); } else { ref fref; code = lib_file_open(i_ctx_p->lib_path, imemory, i_ctx_p, pname.fname, pname.len, (char *)cname, sizeof(cname), &clen, &fref); if (code >= 0) { s = fptr(&fref); code = ssetfilename(s, cname, clen); if (code < 0) { sclose(s); return_error(e_VMerror); } } if (code < 0) { if (code == e_VMerror || code == e_invalidfileaccess) return code; push(1); make_false(op); return 0; } ref_assign(op, &fref); } push(1); make_true(op); return 0; }
/* Make a reusable string stream. */ int make_rss(i_ctx_t *i_ctx_p, os_ptr op, const byte * data, uint size, uint string_space, long offset, long length, bool is_bytestring) { uint save_space = icurrent_space; stream *s; long left = min(length, size - offset); ialloc_set_space(idmemory, string_space); s = file_alloc_stream(imemory, "make_rss"); ialloc_set_space(idmemory, save_space); if (s == 0) return_error(e_VMerror); sread_string_reusable(s, data + offset, max(left, 0)); if (is_bytestring) s->cbuf_string.data = 0; /* byte array, not string */ make_stream_file(op, s, "r"); return 0; }
/* - flush - */ int zflush(i_ctx_t *i_ctx_p) { stream *s; int status; ref rstdout; int code = zget_stdout(i_ctx_p, &s); if (code < 0) return code; make_stream_file(&rstdout, s, "w"); status = sflush(s); if (status == 0 || status == EOFC) { return 0; } return (s_is_writing(s) ? handle_write_status(i_ctx_p, status, &rstdout, NULL, zflush) : handle_read_status(i_ctx_p, status, &rstdout, NULL, zflush)); }
/* return zero for success, -ve for error, +1 for continue */ static int lib_file_open_search_with_no_combine(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, gx_io_device *iodev, bool starting_arg_file, char *fmode) { stream *s; uint blen1 = blen; if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success) goto skip; if (iodev_os_open_file(iodev, (const char *)buffer, blen1, (const char *)fmode, &s, (gs_memory_t *)mem) == 0) { if (starting_arg_file || check_file_permissions_aux(i_ctx_p, buffer, blen1) >= 0) { *pclen = blen1; make_stream_file(pfile, s, "r"); return 0; } sclose(s); return_error(e_invalidfileaccess); } skip:; return 1; }
/* The startup code also calls this to open @-files. */ 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) { /* i_ctx_p is NULL running arg (@) files. * lib_path and mem are never NULL */ bool starting_arg_file = (i_ctx_p == NULL) ? true : i_ctx_p->starting_arg_file; bool search_with_no_combine = false; bool search_with_combine = false; char fmode[4] = { 'r', 0, 0, 0 }; /* room for binary suffix */ stream *s; gx_io_device *iodev = iodev_default; /* when starting arg files (@ files) iodev_default is not yet set */ if (iodev == 0) iodev = (gx_io_device *)gx_io_device_table[0]; strcat(fmode, gp_fmode_binary_suffix); if (gp_file_name_is_absolute(fname, flen)) { search_with_no_combine = true; search_with_combine = false; } else { search_with_no_combine = starting_arg_file; search_with_combine = true; } if (search_with_no_combine) { uint blen1 = blen; if (gp_file_name_reduce(fname, flen, buffer, &blen1) != gp_combine_success) goto skip; if (iodev_os_open_file(iodev, (const char *)buffer, blen1, (const char *)fmode, &s, (gs_memory_t *)mem) == 0) { if (starting_arg_file || check_file_permissions_aux(i_ctx_p, buffer, blen1) >= 0) { *pclen = blen1; make_stream_file(pfile, s, "r"); return 0; } sclose(s); return_error(e_invalidfileaccess); } skip:; } if (search_with_combine) { const gs_file_path *pfpath = lib_path; uint pi; for (pi = 0; pi < r_size(&pfpath->list); ++pi) { const ref *prdir = pfpath->list.value.refs + pi; const char *pstr = (const char *)prdir->value.const_bytes; uint plen = r_size(prdir), blen1 = blen; gs_parsed_file_name_t pname; gp_file_name_combine_result r; /* We need to concatenate and parse the file name here * if this path has a %device% prefix. */ if (pstr[0] == '%') { int code; /* We concatenate directly since gp_file_name_combine_* * rules are not correct for other devices such as %rom% */ gs_parse_file_name(&pname, pstr, plen); memcpy(buffer, pname.fname, pname.len); memcpy(buffer+pname.len, fname, flen); code = pname.iodev->procs.open_file(pname.iodev, buffer, pname.len + flen, fmode, &s, (gs_memory_t *)mem); if (code < 0) continue; make_stream_file(pfile, s, "r"); /* fill in the buffer with the device concatenated */ memcpy(buffer, pstr, plen); memcpy(buffer+plen, fname, flen); *pclen = plen + flen; return 0; } else { r = gp_file_name_combine(pstr, plen, fname, flen, false, buffer, &blen1); if (r != gp_combine_success) continue; if (iodev_os_open_file(iodev, (const char *)buffer, blen1, (const char *)fmode, &s, (gs_memory_t *)mem) == 0) { if (starting_arg_file || check_file_permissions_aux(i_ctx_p, buffer, blen1) >= 0) { *pclen = blen1; make_stream_file(pfile, s, "r"); return 0; } sclose(s); return_error(e_invalidfileaccess); } } } } return_error(e_undefinedfilename); }
/* <prefix|null> <access_string> .tempfile <name_string> <file> */ static int ztempfile(i_ctx_t *i_ctx_p) { os_ptr op = osp; const char *pstr; char fmode[4]; int code = parse_file_access_string(op, fmode); char prefix[gp_file_name_sizeof]; char fname[gp_file_name_sizeof]; uint fnlen; FILE *sfile; stream *s; byte *buf; if (code < 0) return code; strcat(fmode, gp_fmode_binary_suffix); if (r_has_type(op - 1, t_null)) pstr = gp_scratch_file_name_prefix; else { uint psize; check_read_type(op[-1], t_string); psize = r_size(op - 1); if (psize >= gp_file_name_sizeof) return_error(e_rangecheck); memcpy(prefix, op[-1].value.const_bytes, psize); prefix[psize] = 0; pstr = prefix; } if (gp_file_name_is_absolute(pstr, strlen(pstr))) { if (check_file_permissions(i_ctx_p, pstr, strlen(pstr), "PermitFileWriting") < 0) { return_error(e_invalidfileaccess); } } else if (!prefix_is_simple(pstr)) { return_error(e_invalidfileaccess); } s = file_alloc_stream(imemory, "ztempfile(stream)"); if (s == 0) return_error(e_VMerror); buf = gs_alloc_bytes(imemory, file_default_buffer_size, "ztempfile(buffer)"); if (buf == 0) return_error(e_VMerror); sfile = gp_open_scratch_file(pstr, fname, fmode); if (sfile == 0) { gs_free_object(imemory, buf, "ztempfile(buffer)"); return_error(e_invalidfileaccess); } fnlen = strlen(fname); file_init_stream(s, sfile, fmode, buf, file_default_buffer_size); code = ssetfilename(s, (const unsigned char*) fname, fnlen); if (code < 0) { sclose(s); iodev_default->procs.delete_file(iodev_default, fname); return_error(e_VMerror); } make_const_string(op - 1, a_readonly | icurrent_space, fnlen, s->file_name.data); make_stream_file(op, s, fmode); return code; }
/* <name_string> <access_string> file <file> */ int /* exported for zsysvm.c */ zfile(i_ctx_t *i_ctx_p) { os_ptr op = osp; char file_access[4]; gs_parsed_file_name_t pname; int code = parse_file_access_string(op, file_access); stream *s; if (code < 0) return code; code = parse_file_name(op - 1, &pname, i_ctx_p->LockFilePermissions); if (code < 0) return code; /* * HACK: temporarily patch the current context pointer into the * state pointer for stdio-related devices. See ziodev.c for * more information. */ if (pname.iodev && pname.iodev->dtype == iodev_dtype_stdio) { bool statement = (strcmp(pname.iodev->dname, "%statementedit%") == 0); bool lineedit = (strcmp(pname.iodev->dname, "%lineedit%") == 0); if (pname.fname) return_error(e_invalidfileaccess); if (statement || lineedit) { /* These need special code to support callouts */ gx_io_device *indev = gs_findiodevice((const byte *)"%stdin", 6); stream *ins; if (strcmp(file_access, "r")) return_error(e_invalidfileaccess); indev->state = i_ctx_p; code = (indev->procs.open_device)(indev, file_access, &ins, imemory); indev->state = 0; if (code < 0) return code; check_ostack(2); push(2); make_stream_file(op - 3, ins, file_access); make_bool(op-2, statement); make_int(op-1, 0); make_string(op, icurrent_space, 0, NULL); return zfilelineedit(i_ctx_p); } pname.iodev->state = i_ctx_p; code = (*pname.iodev->procs.open_device)(pname.iodev, file_access, &s, imemory); pname.iodev->state = NULL; } else { if (pname.iodev == NULL) pname.iodev = iodev_default; code = zopen_file(i_ctx_p, &pname, file_access, &s, imemory); } if (code < 0) return code; code = ssetfilename(s, op[-1].value.const_bytes, r_size(op - 1)); if (code < 0) { sclose(s); return_error(e_VMerror); } make_stream_file(op - 1, s, file_access); pop(1); return code; }
/* This opens %statementedit% or %lineedit% and is also the * continuation proc for callouts. * Input: * string is the statement/line buffer, * int is the write index into string * bool is true if %statementedit% * file is stdin * Output: * file is a string based stream * We store the line being read in a PostScript string. * This limits the size to max_string_size (64k). * This could be increased by storing the input line in something * other than a PostScript string. */ int zfilelineedit(i_ctx_t *i_ctx_p) { uint count = 0; bool in_eol = false; int code; os_ptr op = osp; bool statement; stream *s; stream *ins; gs_string str; uint initial_buf_size; const char *filename; /* * buf exists only for stylistic parallelism: all occurrences of * buf-> could just as well be str. . */ gs_string *const buf = &str; check_type(*op, t_string); /* line assembled so far */ buf->data = op->value.bytes; buf->size = op->tas.rsize; check_type(*(op-1), t_integer); /* index */ count = (op-1)->value.intval; check_type(*(op-2), t_boolean); /* statementedit/lineedit */ statement = (op-2)->value.boolval; check_read_file(ins, op - 3); /* %stdin */ /* extend string */ initial_buf_size = statement ? STATEMENTEDIT_BUF_SIZE : LINEEDIT_BUF_SIZE; if (initial_buf_size > max_string_size) return_error(e_limitcheck); if (!buf->data || (buf->size < initial_buf_size)) { count = 0; buf->data = gs_alloc_string(imemory_system, initial_buf_size, "zfilelineedit(buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size = initial_buf_size; } rd: code = zreadline_from(ins, buf, imemory_system, &count, &in_eol); if (buf->size > max_string_size) { /* zreadline_from reallocated the buffer larger than * is valid for a PostScript string. * Return an error, but first realloc the buffer * back to a legal size. */ byte *nbuf = gs_resize_string(imemory_system, buf->data, buf->size, max_string_size, "zfilelineedit(shrink buffer)"); if (nbuf == 0) return_error(e_VMerror); op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = max_string_size; return_error(e_limitcheck); } op->value.bytes = buf->data; /* zreadline_from sometimes resizes the buffer. */ op->tas.rsize = buf->size; switch (code) { case EOFC: code = gs_note_error(e_undefinedfilename); /* falls through */ case 0: break; default: code = gs_note_error(e_ioerror); break; case CALLC: { ref rfile; (op-1)->value.intval = count; /* callout is for stdin */ make_file(&rfile, a_readonly | avm_system, ins->read_id, ins); code = s_handle_read_exception(i_ctx_p, code, &rfile, NULL, 0, zfilelineedit); } break; case 1: /* filled buffer */ { uint nsize = buf->size; byte *nbuf; if (nsize >= max_string_size) { code = gs_note_error(e_limitcheck); break; } else if (nsize >= max_string_size / 2) nsize= max_string_size; else nsize = buf->size * 2; nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); break; } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; goto rd; } } if (code != 0) return code; if (statement) { /* If we don't have a complete token, keep going. */ stream st; stream *ts = &st; scanner_state state; ref ignore_value; uint depth = ref_stack_count(&o_stack); int code; /* Add a terminating EOL. */ if (count + 1 > buf->size) { uint nsize; byte *nbuf; nsize = buf->size + 1; if (nsize > max_string_size) { return_error(gs_note_error(e_limitcheck)); } else { nbuf = gs_resize_string(imemory_system, buf->data, buf->size, nsize, "zfilelineedit(grow buffer)"); if (nbuf == 0) { code = gs_note_error(e_VMerror); return_error(code); } op->value.bytes = buf->data = nbuf; op->tas.rsize = buf->size = nsize; } } buf->data[count++] = char_EOL; s_init(ts, NULL); sread_string(ts, buf->data, count); sc: scanner_init_stream_options(&state, ts, SCAN_CHECK_ONLY); code = scan_token(i_ctx_p, &ignore_value, &state); ref_stack_pop_to(&o_stack, depth); if (code < 0) code = scan_EOF; /* stop on scanner error */ switch (code) { case 0: /* read a token */ case scan_BOS: goto sc; /* keep going until we run out of data */ case scan_Refill: goto rd; case scan_EOF: break; default: /* error */ return code; } } buf->data = gs_resize_string(imemory_system, buf->data, buf->size, count, "zfilelineedit(resize buffer)"); if (buf->data == 0) return_error(e_VMerror); op->value.bytes = buf->data; op->tas.rsize = buf->size; s = file_alloc_stream(imemory_system, "zfilelineedit(stream)"); if (s == 0) return_error(e_VMerror); sread_string(s, buf->data, count); s->save_close = s->procs.close; s->procs.close = file_close_disable; filename = statement ? gs_iodev_statementedit.dname : gs_iodev_lineedit.dname; code = ssetfilename(s, (const byte *)filename, strlen(filename)+1); if (code < 0) { sclose(s); return_error(e_VMerror); } pop(3); make_stream_file(osp, s, "r"); return code; }