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