1 /* Copyright (C) 1993, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gsiodev.c,v 1.5.2.1.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* IODevice implementation for Ghostscript */
21 #include "errno_.h"
22 #include "string_.h"
23 #include "unistd_.h"
24 #include "gx.h"
25 #include "gserrors.h"
26 #include "gp.h"
27 #include "gscdefs.h"
28 #include "gsparam.h"
29 #include "gsstruct.h"
30 #include "gxiodev.h"
31 
32 /* Import the IODevice table from gconf.c. */
33 extern_gx_io_device_table();
34 
35 /* Define a table of local copies of the IODevices, */
36 /* allocated at startup.  This just postpones the day of reckoning.... */
37 private gx_io_device **io_device_table;
38 
39 private_st_io_device();
40 gs_private_st_ptr(st_io_device_ptr, gx_io_device *, "gx_io_device *",
41 		  iodev_ptr_enum_ptrs, iodev_ptr_reloc_ptrs);
42 gs_private_st_element(st_io_device_ptr_element, gx_io_device *,
43       "gx_io_device *[]", iodev_ptr_elt_enum_ptrs, iodev_ptr_elt_reloc_ptrs,
44 		      st_io_device_ptr);
45 
46 /* Define the OS (%os%) device. */
47 iodev_proc_fopen(iodev_os_fopen);
48 iodev_proc_fclose(iodev_os_fclose);
49 private iodev_proc_delete_file(os_delete);
50 private iodev_proc_rename_file(os_rename);
51 private iodev_proc_file_status(os_status);
52 private iodev_proc_enumerate_files(os_enumerate);
53 private iodev_proc_get_params(os_get_params);
54 const gx_io_device gs_iodev_os =
55 {
56     "%os%", "FileSystem",
57     {iodev_no_init, iodev_no_open_device,
58      NULL /*iodev_os_open_file */ , iodev_os_fopen, iodev_os_fclose,
59      os_delete, os_rename, os_status,
60      os_enumerate, gp_enumerate_files_next, gp_enumerate_files_close,
61      os_get_params, iodev_no_put_params
62     }
63 };
64 
65 /* ------ Initialization ------ */
66 
67 init_proc(gs_iodev_init);	/* check prototype */
68 int
gs_iodev_init(gs_memory_t * mem)69 gs_iodev_init(gs_memory_t * mem)
70 {				/* Make writable copies of all IODevices. */
71     gx_io_device **table =
72 	gs_alloc_struct_array(mem, gx_io_device_table_count,
73 			      gx_io_device *, &st_io_device_ptr_element,
74 			      "gs_iodev_init(table)");
75     int i, j;
76     int code = 0;
77 
78     if (table == 0)
79 	return_error(gs_error_VMerror);
80     for (i = 0; i < gx_io_device_table_count; ++i) {
81 	gx_io_device *iodev =
82 	    gs_alloc_struct(mem, gx_io_device, &st_io_device,
83 			    "gs_iodev_init(iodev)");
84 
85 	if (iodev == 0)
86 	    goto fail;
87 	table[i] = iodev;
88 	memcpy(table[i], gx_io_device_table[i], sizeof(gx_io_device));
89     }
90     io_device_table = table;
91     code = gs_register_struct_root(mem, NULL, (void **)&io_device_table,
92 				   "io_device_table");
93     if (code < 0)
94 	goto fail;
95     /* Run the one-time initialization of each IODevice. */
96     for (j = 0; j < gx_io_device_table_count; ++j)
97 	if ((code = (table[j]->procs.init)(table[j], mem)) < 0)
98 	    goto f2;
99     return 0;
100  f2:
101     /****** CAN'T FIND THE ROOT ******/
102     /*gs_unregister_root(mem, root, "io_device_table");*/
103  fail:
104     for (; i >= 0; --i)
105 	gs_free_object(mem, table[i - 1], "gs_iodev_init(iodev)");
106     gs_free_object(mem, table, "gs_iodev_init(table)");
107     io_device_table = 0;
108     return (code < 0 ? code : gs_note_error(gs_error_VMerror));
109 }
110 
111 /* ------ Default (unimplemented) IODevice procedures ------ */
112 
113 int
iodev_no_init(gx_io_device * iodev,gs_memory_t * mem)114 iodev_no_init(gx_io_device * iodev, gs_memory_t * mem)
115 {
116     return 0;
117 }
118 
119 int
iodev_no_open_device(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)120 iodev_no_open_device(gx_io_device * iodev, const char *access, stream ** ps,
121 		     gs_memory_t * mem)
122 {
123     return_error(gs_error_invalidfileaccess);
124 }
125 
126 int
iodev_no_open_file(gx_io_device * iodev,const char * fname,uint namelen,const char * access,stream ** ps,gs_memory_t * mem)127 iodev_no_open_file(gx_io_device * iodev, const char *fname, uint namelen,
128 		   const char *access, stream ** ps, gs_memory_t * mem)
129 {
130     return_error(gs_error_invalidfileaccess);
131 }
132 
133 int
iodev_no_fopen(gx_io_device * iodev,const char * fname,const char * access,FILE ** pfile,char * rfname,uint rnamelen)134 iodev_no_fopen(gx_io_device * iodev, const char *fname, const char *access,
135 	       FILE ** pfile, char *rfname, uint rnamelen)
136 {
137     return_error(gs_error_invalidfileaccess);
138 }
139 
140 int
iodev_no_fclose(gx_io_device * iodev,FILE * file)141 iodev_no_fclose(gx_io_device * iodev, FILE * file)
142 {
143     return_error(gs_error_ioerror);
144 }
145 
146 int
iodev_no_delete_file(gx_io_device * iodev,const char * fname)147 iodev_no_delete_file(gx_io_device * iodev, const char *fname)
148 {
149     return_error(gs_error_invalidfileaccess);
150 }
151 
152 int
iodev_no_rename_file(gx_io_device * iodev,const char * from,const char * to)153 iodev_no_rename_file(gx_io_device * iodev, const char *from, const char *to)
154 {
155     return_error(gs_error_invalidfileaccess);
156 }
157 
158 int
iodev_no_file_status(gx_io_device * iodev,const char * fname,struct stat * pstat)159 iodev_no_file_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
160 {
161     return_error(gs_error_undefinedfilename);
162 }
163 
164 file_enum *
iodev_no_enumerate_files(gx_io_device * iodev,const char * pat,uint patlen,gs_memory_t * memory)165 iodev_no_enumerate_files(gx_io_device * iodev, const char *pat, uint patlen,
166 			 gs_memory_t * memory)
167 {
168     return NULL;
169 }
170 
171 int
iodev_no_get_params(gx_io_device * iodev,gs_param_list * plist)172 iodev_no_get_params(gx_io_device * iodev, gs_param_list * plist)
173 {
174     return 0;
175 }
176 
177 int
iodev_no_put_params(gx_io_device * iodev,gs_param_list * plist)178 iodev_no_put_params(gx_io_device * iodev, gs_param_list * plist)
179 {
180     return param_commit(plist);
181 }
182 
183 /* ------ %os% ------ */
184 
185 /* The fopen routine is exported for %null. */
186 int
iodev_os_fopen(gx_io_device * iodev,const char * fname,const char * access,FILE ** pfile,char * rfname,uint rnamelen)187 iodev_os_fopen(gx_io_device * iodev, const char *fname, const char *access,
188 	       FILE ** pfile, char *rfname, uint rnamelen)
189 {
190     errno = 0;
191     *pfile = gp_fopen(fname, access);
192     if (*pfile == NULL)
193 	return_error(gs_fopen_errno_to_code(errno));
194     if (rfname != NULL)
195 	strcpy(rfname, fname);
196     return 0;
197 }
198 
199 /* The fclose routine is exported for %null. */
200 int
iodev_os_fclose(gx_io_device * iodev,FILE * file)201 iodev_os_fclose(gx_io_device * iodev, FILE * file)
202 {
203     fclose(file);
204     return 0;
205 }
206 
207 private int
os_delete(gx_io_device * iodev,const char * fname)208 os_delete(gx_io_device * iodev, const char *fname)
209 {
210     return (unlink(fname) == 0 ? 0 : gs_error_ioerror);
211 }
212 
213 private int
os_rename(gx_io_device * iodev,const char * from,const char * to)214 os_rename(gx_io_device * iodev, const char *from, const char *to)
215 {
216     return (rename(from, to) == 0 ? 0 : gs_error_ioerror);
217 }
218 
219 private int
os_status(gx_io_device * iodev,const char * fname,struct stat * pstat)220 os_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
221 {				/* The RS/6000 prototype for stat doesn't include const, */
222     /* so we have to explicitly remove the const modifier. */
223     return (stat((char *)fname, pstat) < 0 ? gs_error_undefinedfilename : 0);
224 }
225 
226 private file_enum *
os_enumerate(gx_io_device * iodev,const char * pat,uint patlen,gs_memory_t * mem)227 os_enumerate(gx_io_device * iodev, const char *pat, uint patlen,
228 	     gs_memory_t * mem)
229 {
230     return gp_enumerate_files_init(pat, patlen, mem);
231 }
232 
233 private int
os_get_params(gx_io_device * iodev,gs_param_list * plist)234 os_get_params(gx_io_device * iodev, gs_param_list * plist)
235 {
236     int code;
237     int i0 = 0, i2 = 2;
238     bool btrue = true, bfalse = false;
239     int BlockSize;
240     long Free, LogicalSize;
241 
242     /*
243      * Return fake values for BlockSize and Free, since we can't get the
244      * correct values in a platform-independent manner.
245      */
246     BlockSize = 1024;
247     LogicalSize = 2000000000 / BlockSize;	/* about 2 Gb */
248     Free = LogicalSize * 3 / 4;			/* about 1.5 Gb */
249 
250     if (
251 	(code = param_write_bool(plist, "HasNames", &btrue)) < 0 ||
252 	(code = param_write_int(plist, "BlockSize", &BlockSize)) < 0 ||
253 	(code = param_write_long(plist, "Free", &Free)) < 0 ||
254 	(code = param_write_int(plist, "InitializeAction", &i0)) < 0 ||
255 	(code = param_write_bool(plist, "Mounted", &btrue)) < 0 ||
256 	(code = param_write_bool(plist, "Removable", &bfalse)) < 0 ||
257 	(code = param_write_bool(plist, "Searchable", &btrue)) < 0 ||
258 	(code = param_write_int(plist, "SearchOrder", &i2)) < 0 ||
259 	(code = param_write_bool(plist, "Writeable", &btrue)) < 0 ||
260 	(code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0
261 	)
262 	return code;
263     return 0;
264 }
265 
266 /* ------ Utilities ------ */
267 
268 /* Get the N'th IODevice from the known device table. */
269 gx_io_device *
gs_getiodevice(int index)270 gs_getiodevice(int index)
271 {
272     if (index < 0 || index >= gx_io_device_table_count)
273 	return 0;		/* index out of range */
274     return io_device_table[index];
275 }
276 
277 /* Look up an IODevice name. */
278 /* The name may be either %device or %device%. */
279 gx_io_device *
gs_findiodevice(const byte * str,uint len)280 gs_findiodevice(const byte * str, uint len)
281 {
282     int i;
283 
284     if (len > 1 && str[len - 1] == '%')
285 	len--;
286     for (i = 0; i < gx_io_device_table_count; ++i) {
287 	gx_io_device *iodev = io_device_table[i];
288 	const char *dname = iodev->dname;
289 
290 	if (dname && strlen(dname) == len + 1 && !memcmp(str, dname, len))
291 	    return iodev;
292     }
293     return 0;
294 }
295 
296 /* ------ Accessors ------ */
297 
298 /* Get IODevice parameters. */
299 int
gs_getdevparams(gx_io_device * iodev,gs_param_list * plist)300 gs_getdevparams(gx_io_device * iodev, gs_param_list * plist)
301 {				/* All IODevices have the Type parameter. */
302     gs_param_string ts;
303     int code;
304 
305     param_string_from_string(ts, iodev->dtype);
306     code = param_write_name(plist, "Type", &ts);
307     if (code < 0)
308 	return code;
309     return (*iodev->procs.get_params) (iodev, plist);
310 }
311 
312 /* Put IODevice parameters. */
313 int
gs_putdevparams(gx_io_device * iodev,gs_param_list * plist)314 gs_putdevparams(gx_io_device * iodev, gs_param_list * plist)
315 {
316     return (*iodev->procs.put_params) (iodev, plist);
317 }
318 
319 /* Convert an OS error number to a PostScript error */
320 /* if opening a file fails. */
321 int
gs_fopen_errno_to_code(int eno)322 gs_fopen_errno_to_code(int eno)
323 {				/* Different OSs vary widely in their error codes. */
324     /* We try to cover as many variations as we know about. */
325     switch (eno) {
326 #ifdef ENOENT
327 	case ENOENT:
328 	    return_error(gs_error_undefinedfilename);
329 #endif
330 #ifdef ENOFILE
331 #  ifndef ENOENT
332 #    define ENOENT ENOFILE
333 #  endif
334 #  if ENOFILE != ENOENT
335 	case ENOFILE:
336 	    return_error(gs_error_undefinedfilename);
337 #  endif
338 #endif
339 #ifdef ENAMETOOLONG
340 	case ENAMETOOLONG:
341 	    return_error(gs_error_undefinedfilename);
342 #endif
343 #ifdef EACCES
344 	case EACCES:
345 	    return_error(gs_error_invalidfileaccess);
346 #endif
347 #ifdef EMFILE
348 	case EMFILE:
349 	    return_error(gs_error_limitcheck);
350 #endif
351 #ifdef ENFILE
352 	case ENFILE:
353 	    return_error(gs_error_limitcheck);
354 #endif
355 	default:
356 	    return_error(gs_error_ioerror);
357     }
358 }
359