1 /* Copyright (C) 2008 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: sfxcommon.c 8250 2007-09-25 13:31:24Z giles $ */
15 /* Common routines for stdio and fd file stream implementations. */
16 #include "stdio_.h" /* includes std.h */
17 #include "memory_.h"
18 #include "unistd_.h"
19 #include "gsmemory.h"
20 #include "gp.h"
21 #include "gserror.h"
22 #include "gserrors.h"
23 #include "stream.h"
24
25 #define DEFAULT_BUFFER_SIZE 2048
26 const uint file_default_buffer_size = DEFAULT_BUFFER_SIZE;
27
28 /* Allocate and return a file stream. */
29 /* Return 0 if the allocation failed. */
30 /* The stream is initialized to an invalid state, so the caller need not */
31 /* worry about cleaning up if a later step in opening the stream fails. */
32 stream *
file_alloc_stream(gs_memory_t * mem,client_name_t cname)33 file_alloc_stream(gs_memory_t * mem, client_name_t cname)
34 {
35 stream *s;
36 s = s_alloc(mem, cname);
37 if (s == 0)
38 return 0;
39 s_init_ids(s);
40 s->is_temp = 0; /* not a temp stream */
41 s->foreign = 0;
42 /*
43 * Disable the stream now (in case we can't open the file,
44 * or a filter init procedure fails) so that `restore' won't
45 * crash when it tries to close open files.
46 */
47 s_disable(s);
48 s->prev = 0;
49 s->next = 0;
50 return s;
51 }
52
53 /* Open a file stream, optionally on an OS file. */
54 /* Return 0 if successful, error code if not. */
55 /* On a successful return, the C file name is in the stream buffer. */
56 /* If fname==0, set up the file entry, stream, and buffer, */
57 /* but don't open an OS file or initialize the stream. */
58 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)59 file_open_stream(const char *fname, uint len, const char *file_access,
60 uint buffer_size, stream ** ps, gx_io_device *iodev,
61 iodev_proc_fopen_t fopen_proc, gs_memory_t *mem)
62 {
63 int code;
64 FILE *file;
65 char fmode[4]; /* r/w/a, [+], [b], null */
66
67 if (!iodev)
68 iodev = iodev_default;
69 code = file_prepare_stream(fname, len, file_access, buffer_size, ps, fmode, mem);
70 if (code < 0)
71 return code;
72 if (fname == 0)
73 return 0;
74 if (fname[0] == 0) /* fopen_proc gets NUL terminated string, not len */
75 return 0; /* so this is the same as len == 0, so return NULL */
76 code = (*fopen_proc)(iodev, (char *)(*ps)->cbuf, fmode, &file,
77 (char *)(*ps)->cbuf, (*ps)->bsize);
78 if (code < 0) {
79 /* discard the stuff we allocated to keep from accumulating stuff needing GC */
80 gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
81 gs_free_object(mem, *ps, "file_prepare_stream(stream)");
82 *ps = NULL;
83 return code;
84 }
85 file_init_stream(*ps, file, fmode, (*ps)->cbuf, (*ps)->bsize);
86 return 0;
87 }
88
89 /* Close a file stream. This replaces the close procedure in the stream */
90 /* for normal (OS) files and for filters. */
91 int
file_close_file(stream * s)92 file_close_file(stream * s)
93 {
94 stream *stemp = s->strm;
95 gs_memory_t *mem;
96 int code = file_close_disable(s);
97
98 if (code)
99 return code;
100 /*
101 * Check for temporary streams created for filters.
102 * There may be more than one in the case of a procedure-based filter,
103 * or if we created an intermediate stream to ensure
104 * a large enough buffer. Note that these streams may have been
105 * allocated by file_alloc_stream, so we mustn't free them.
106 */
107 while (stemp != 0 && stemp->is_temp != 0) {
108 stream *snext = stemp->strm;
109
110 mem = stemp->memory;
111 if (stemp->is_temp > 1)
112 gs_free_object(mem, stemp->cbuf,
113 "file_close(temp stream buffer)");
114 s_disable(stemp);
115 stemp = snext;
116 }
117 mem = s->memory;
118 gs_free_object(mem, s->cbuf, "file_close(buffer)");
119 if (s->close_strm && stemp != 0)
120 return sclose(stemp);
121 return 0;
122 }
123
124 /*
125 * Set up a file stream on an OS file. The caller has allocated the
126 * stream and buffer.
127 */
128 void
file_init_stream(stream * s,FILE * file,const char * fmode,byte * buffer,uint buffer_size)129 file_init_stream(stream *s, FILE *file, const char *fmode, byte *buffer,
130 uint buffer_size)
131 {
132 switch (fmode[0]) {
133 case 'a':
134 sappend_file(s, file, buffer, buffer_size);
135 break;
136 case 'r':
137 /* Defeat buffering for terminals. */
138 {
139 struct stat rstat;
140
141 fstat(fileno(file), &rstat);
142 sread_file(s, file, buffer,
143 (S_ISCHR(rstat.st_mode) ? 1 : buffer_size));
144 }
145 break;
146 case 'w':
147 swrite_file(s, file, buffer, buffer_size);
148 }
149 if (fmode[1] == '+')
150 s->file_modes |= s_mode_read | s_mode_write;
151 s->save_close = s->procs.close;
152 s->procs.close = file_close_file;
153 }
154
155 /* Prepare a stream with a file name. */
156 /* Return 0 if successful, error code if not. */
157 /* On a successful return, the C file name is in the stream buffer. */
158 /* If fname==0, set up stream, and buffer. */
159 int
file_prepare_stream(const char * fname,uint len,const char * file_access,uint buffer_size,stream ** ps,char fmode[4],gs_memory_t * mem)160 file_prepare_stream(const char *fname, uint len, const char *file_access,
161 uint buffer_size, stream ** ps, char fmode[4], gs_memory_t *mem)
162 {
163 byte *buffer;
164 register stream *s;
165
166 /* Open the file, always in binary mode. */
167 strcpy(fmode, file_access);
168 strcat(fmode, gp_fmode_binary_suffix);
169 if (buffer_size == 0)
170 buffer_size = file_default_buffer_size;
171 if (len >= buffer_size) /* we copy the file name into the buffer */
172 return_error(gs_error_limitcheck);
173 /* Allocate the stream first, since it persists */
174 /* even after the file has been closed. */
175 s = file_alloc_stream(mem, "file_prepare_stream");
176 if (s == 0)
177 return_error(gs_error_VMerror);
178 /* Allocate the buffer. */
179 buffer = gs_alloc_bytes(mem, buffer_size, "file_prepare_stream(buffer)");
180 if (buffer == 0)
181 return_error(gs_error_VMerror);
182 if (fname != 0) {
183 memcpy(buffer, fname, len);
184 buffer[len] = 0; /* terminate string */
185 } else
186 buffer[0] = 0; /* safety */
187 s->cbuf = buffer;
188 s->bsize = s->cbsize = buffer_size;
189 s->save_close = 0; /* in case this stream gets disabled before init finishes */
190 *ps = s;
191 return 0;
192 }
193