1 /* Copyright (C) 2001-2012 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,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* IODevice implementation for Ghostscript */
18 #include "errno_.h"
19 #include "string_.h"
20 #include "unistd_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gp.h"
24 #include "gscdefs.h"
25 #include "gsfname.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 private_st_io_device();
34 gs_private_st_ptr(st_io_device_ptr, gx_io_device *, "gx_io_device *",
35                   iodev_ptr_enum_ptrs, iodev_ptr_reloc_ptrs);
36 gs_private_st_element_final(st_io_device_ptr_element, gx_io_device *,
37       "gx_io_device *[]", iodev_ptr_elt_enum_ptrs, iodev_ptr_elt_reloc_ptrs,
38                       st_io_device_ptr,gs_iodev_finalize);
39 
40 /* Define the OS (%os%) device. */
41 iodev_proc_fopen(iodev_os_fopen);
42 iodev_proc_fclose(iodev_os_fclose);
43 static iodev_proc_delete_file(os_delete);
44 static iodev_proc_rename_file(os_rename);
45 static iodev_proc_file_status(os_status);
46 static iodev_proc_enumerate_files(os_enumerate);
47 static iodev_proc_get_params(os_get_params);
48 const gx_io_device gs_iodev_os =
49 {
50     "%os%", "FileSystem",
51     {iodev_no_init, iodev_no_open_device,
52      NULL /*iodev_os_open_file */ , iodev_os_fopen, iodev_os_fclose,
53      os_delete, os_rename, os_status,
54      os_enumerate, gp_enumerate_files_next, gp_enumerate_files_close,
55      os_get_params, iodev_no_put_params
56     }
57 };
58 
59 /* ------ Initialization ------ */
60 
61 init_proc(gs_iodev_init);	/* check prototype */
62 int
gs_iodev_init(gs_memory_t * mem)63 gs_iodev_init(gs_memory_t * mem)
64 {				/* Make writable copies of all IODevices. */
65     gx_io_device **table =
66         gs_alloc_struct_array(mem, gx_io_device_table_count,
67                               gx_io_device *, &st_io_device_ptr_element,
68                               "gs_iodev_init(table)");
69     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
70     int i, j;
71     int code = 0;
72 
73     if ((table == NULL) || (libctx == NULL))
74         return_error(gs_error_VMerror);
75 
76     for (i = 0; i < gx_io_device_table_count; ++i) {
77         gx_io_device *iodev =
78             gs_alloc_struct(mem, gx_io_device, &st_io_device,
79                             "gs_iodev_init(iodev)");
80 
81         if (iodev == 0)
82             goto fail;
83         table[i] = iodev;
84         memcpy(table[i], gx_io_device_table[i], sizeof(gx_io_device));
85     }
86     libctx->io_device_table = table;
87     code = gs_register_struct_root(mem, NULL,
88                                    (void **)&libctx->io_device_table,
89                                    "io_device_table");
90     if (code < 0)
91         goto fail;
92     /* Run the one-time initialization of each IODevice. */
93     for (j = 0; j < gx_io_device_table_count; ++j)
94         if ((code = (table[j]->procs.init)(table[j], mem)) < 0)
95             goto f2;
96     return 0;
97  f2:
98     /****** CAN'T FIND THE ROOT ******/
99     /*gs_unregister_root(mem, root, "io_device_table");*/
100  fail:
101     for (; i > 0; --i)
102         gs_free_object(mem, table[i - 1], "gs_iodev_init(iodev)");
103     gs_free_object(mem, table, "gs_iodev_init(table)");
104     libctx->io_device_table = NULL;
105     return (code < 0 ? code : gs_note_error(gs_error_VMerror));
106 }
107 
108 static void
gs_iodev_finalize(const gs_memory_t * cmem,void * vptr)109 gs_iodev_finalize(const gs_memory_t *cmem, void *vptr)
110 {
111     if (cmem->gs_lib_ctx->io_device_table == vptr) {
112         cmem->gs_lib_ctx->io_device_table = NULL;
113     }
114 }
115 
116 
117 /* ------ Default (unimplemented) IODevice procedures ------ */
118 
119 int
iodev_no_init(gx_io_device * iodev,gs_memory_t * mem)120 iodev_no_init(gx_io_device * iodev, gs_memory_t * mem)
121 {
122     return 0;
123 }
124 
125 int
iodev_no_open_device(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)126 iodev_no_open_device(gx_io_device * iodev, const char *access, stream ** ps,
127                      gs_memory_t * mem)
128 {
129     return_error(gs_error_invalidfileaccess);
130 }
131 
132 int
iodev_no_open_file(gx_io_device * iodev,const char * fname,uint namelen,const char * access,stream ** ps,gs_memory_t * mem)133 iodev_no_open_file(gx_io_device * iodev, const char *fname, uint namelen,
134                    const char *access, stream ** ps, gs_memory_t * mem)
135 {
136     return_error(gs_error_invalidfileaccess);
137 }
138 
139 int
iodev_no_fopen(gx_io_device * iodev,const char * fname,const char * access,FILE ** pfile,char * rfname,uint rnamelen)140 iodev_no_fopen(gx_io_device * iodev, const char *fname, const char *access,
141                FILE ** pfile, char *rfname, uint rnamelen)
142 {
143     return_error(gs_error_invalidfileaccess);
144 }
145 
146 int
iodev_no_fclose(gx_io_device * iodev,FILE * file)147 iodev_no_fclose(gx_io_device * iodev, FILE * file)
148 {
149     return_error(gs_error_ioerror);
150 }
151 
152 int
iodev_no_delete_file(gx_io_device * iodev,const char * fname)153 iodev_no_delete_file(gx_io_device * iodev, const char *fname)
154 {
155     return_error(gs_error_invalidfileaccess);
156 }
157 
158 int
iodev_no_rename_file(gx_io_device * iodev,const char * from,const char * to)159 iodev_no_rename_file(gx_io_device * iodev, const char *from, const char *to)
160 {
161     return_error(gs_error_invalidfileaccess);
162 }
163 
164 int
iodev_no_file_status(gx_io_device * iodev,const char * fname,struct stat * pstat)165 iodev_no_file_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
166 {
167     return_error(gs_error_undefinedfilename);
168 }
169 
170 file_enum *
iodev_no_enumerate_files(gx_io_device * iodev,const char * pat,uint patlen,gs_memory_t * memory)171 iodev_no_enumerate_files(gx_io_device * iodev, const char *pat, uint patlen,
172                          gs_memory_t * memory)
173 {
174     return NULL;
175 }
176 
177 int
iodev_no_get_params(gx_io_device * iodev,gs_param_list * plist)178 iodev_no_get_params(gx_io_device * iodev, gs_param_list * plist)
179 {
180     return 0;
181 }
182 
183 int
iodev_no_put_params(gx_io_device * iodev,gs_param_list * plist)184 iodev_no_put_params(gx_io_device * iodev, gs_param_list * plist)
185 {
186     return param_commit(plist);
187 }
188 
189 /* ------ %os% ------ */
190 
191 /* The fopen routine is exported for %null. */
192 int
iodev_os_fopen(gx_io_device * iodev,const char * fname,const char * access,FILE ** pfile,char * rfname,uint rnamelen)193 iodev_os_fopen(gx_io_device * iodev, const char *fname, const char *access,
194                FILE ** pfile, char *rfname, uint rnamelen)
195 {
196     errno = 0;
197     *pfile = gp_fopen(fname, access);
198     if (*pfile == NULL)
199         return_error(gs_fopen_errno_to_code(errno));
200     if (rfname != NULL && rfname != fname)
201         strcpy(rfname, fname);
202     return 0;
203 }
204 
205 /* The fclose routine is exported for %null. */
206 int
iodev_os_fclose(gx_io_device * iodev,FILE * file)207 iodev_os_fclose(gx_io_device * iodev, FILE * file)
208 {
209     fclose(file);
210     return 0;
211 }
212 
213 static int
os_delete(gx_io_device * iodev,const char * fname)214 os_delete(gx_io_device * iodev, const char *fname)
215 {
216     return (unlink(fname) == 0 ? 0 : gs_error_ioerror);
217 }
218 
219 static int
os_rename(gx_io_device * iodev,const char * from,const char * to)220 os_rename(gx_io_device * iodev, const char *from, const char *to)
221 {
222     return (rename(from, to) == 0 ? 0 : gs_error_ioerror);
223 }
224 
225 static int
os_status(gx_io_device * iodev,const char * fname,struct stat * pstat)226 os_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
227 {				/* The RS/6000 prototype for stat doesn't include const, */
228     /* so we have to explicitly remove the const modifier. */
229     return (stat((char *)fname, pstat) < 0 ? gs_error_undefinedfilename : 0);
230 }
231 
232 static file_enum *
os_enumerate(gx_io_device * iodev,const char * pat,uint patlen,gs_memory_t * mem)233 os_enumerate(gx_io_device * iodev, const char *pat, uint patlen,
234              gs_memory_t * mem)
235 {
236     return gp_enumerate_files_init(pat, patlen, mem);
237 }
238 
239 static int
os_get_params(gx_io_device * iodev,gs_param_list * plist)240 os_get_params(gx_io_device * iodev, gs_param_list * plist)
241 {
242     int code;
243     int i0 = 0, i2 = 2;
244     bool btrue = true, bfalse = false;
245     int BlockSize;
246     long Free, LogicalSize;
247 
248     /*
249      * Return fake values for BlockSize and Free, since we can't get the
250      * correct values in a platform-independent manner.
251      */
252     BlockSize = 1024;
253     LogicalSize = 2000000000 / BlockSize;	/* about 2 Gb */
254     Free = LogicalSize * 3 / 4;			/* about 1.5 Gb */
255 
256     if (
257         (code = param_write_bool(plist, "HasNames", &btrue)) < 0 ||
258         (code = param_write_int(plist, "BlockSize", &BlockSize)) < 0 ||
259         (code = param_write_long(plist, "Free", &Free)) < 0 ||
260         (code = param_write_int(plist, "InitializeAction", &i0)) < 0 ||
261         (code = param_write_bool(plist, "Mounted", &btrue)) < 0 ||
262         (code = param_write_bool(plist, "Removable", &bfalse)) < 0 ||
263         (code = param_write_bool(plist, "Searchable", &btrue)) < 0 ||
264         (code = param_write_int(plist, "SearchOrder", &i2)) < 0 ||
265         (code = param_write_bool(plist, "Writeable", &btrue)) < 0 ||
266         (code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0
267         )
268         return code;
269     return 0;
270 }
271 
272 /* ------ Utilities ------ */
273 
274 /* Get the N'th IODevice from the known device table. */
275 gx_io_device *
gs_getiodevice(const gs_memory_t * mem,int index)276 gs_getiodevice(const gs_memory_t *mem, int index)
277 {
278     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
279 
280     if (libctx == NULL || libctx->io_device_table == NULL ||
281         index < 0      || index >= gx_io_device_table_count)
282         return 0;		/* index out of range */
283     return libctx->io_device_table[index];
284 }
285 
286 /* Look up an IODevice name. */
287 /* The name may be either %device or %device%. */
288 gx_io_device *
gs_findiodevice(const gs_memory_t * mem,const byte * str,uint len)289 gs_findiodevice(const gs_memory_t *mem, const byte * str, uint len)
290 {
291     int i;
292     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
293 
294     if (len > 1 && str[len - 1] == '%')
295         len--;
296     for (i = 0; i < gx_io_device_table_count; ++i) {
297         gx_io_device *iodev = libctx->io_device_table[i];
298         const char *dname = iodev->dname;
299 
300         if (dname && strlen(dname) == len + 1 && !memcmp(str, dname, len))
301             return iodev;
302     }
303     return 0;
304 }
305 
306 /* ------ Accessors ------ */
307 
308 /* Get IODevice parameters. */
309 int
gs_getdevparams(gx_io_device * iodev,gs_param_list * plist)310 gs_getdevparams(gx_io_device * iodev, gs_param_list * plist)
311 {				/* All IODevices have the Type parameter. */
312     gs_param_string ts;
313     int code;
314 
315     param_string_from_string(ts, iodev->dtype);
316     code = param_write_name(plist, "Type", &ts);
317     if (code < 0)
318         return code;
319     return (*iodev->procs.get_params) (iodev, plist);
320 }
321 
322 /* Put IODevice parameters. */
323 int
gs_putdevparams(gx_io_device * iodev,gs_param_list * plist)324 gs_putdevparams(gx_io_device * iodev, gs_param_list * plist)
325 {
326     return (*iodev->procs.put_params) (iodev, plist);
327 }
328 
329 /* Convert an OS error number to a PostScript error */
330 /* if opening a file fails. */
331 int
gs_fopen_errno_to_code(int eno)332 gs_fopen_errno_to_code(int eno)
333 {				/* Different OSs vary widely in their error codes. */
334     /* We try to cover as many variations as we know about. */
335     switch (eno) {
336 #ifdef ENOENT
337         case ENOENT:
338             return_error(gs_error_undefinedfilename);
339 #endif
340 #ifdef ENOFILE
341 #  ifndef ENOENT
342 #    define ENOENT ENOFILE
343 #  endif
344 #  if ENOFILE != ENOENT
345         case ENOFILE:
346             return_error(gs_error_undefinedfilename);
347 #  endif
348 #endif
349 #ifdef ENAMETOOLONG
350         case ENAMETOOLONG:
351             return_error(gs_error_undefinedfilename);
352 #endif
353 #ifdef EACCES
354         case EACCES:
355             return_error(gs_error_invalidfileaccess);
356 #endif
357 #ifdef EMFILE
358         case EMFILE:
359             return_error(gs_error_limitcheck);
360 #endif
361 #ifdef ENFILE
362         case ENFILE:
363             return_error(gs_error_limitcheck);
364 #endif
365         default:
366             return_error(gs_error_ioerror);
367     }
368 }
369 
370 /* Generic interface for filesystem enumeration given a path that may	*/
371 /* include a %iodev% prefix */
372 
373 typedef struct gs_file_enum_s gs_file_enum;
374 struct gs_file_enum_s {
375     gs_memory_t *memory;
376     gx_io_device *piodev;	/* iodev's are static, so don't need GC tracing */
377     file_enum *pfile_enum;
378     int prepend_iodev_name;
379 };
380 
381 gs_private_st_ptrs1(st_gs_file_enum, gs_file_enum, "gs_file_enum",
382                     gs_file_enum_enum_ptrs, gs_file_enum_reloc_ptrs, pfile_enum);
383 
384 file_enum *
gs_enumerate_files_init(const char * pat,uint patlen,gs_memory_t * mem)385 gs_enumerate_files_init(const char *pat, uint patlen, gs_memory_t * mem)
386 {
387     file_enum *pfen;
388     gs_file_enum *pgs_file_enum;
389     gx_io_device *iodev = NULL;
390     gs_parsed_file_name_t pfn;
391     int code = 0;
392 
393     /* Get the iodevice */
394     code = gs_parse_file_name(&pfn, pat, patlen, mem);
395     if (code < 0)
396         return NULL;
397     iodev = (pfn.iodev == NULL) ? iodev_default(mem) : pfn.iodev;
398 
399     /* Check for several conditions that just cause us to return success */
400     if (pfn.len == 0 || iodev->procs.enumerate_files == iodev_no_enumerate_files) {
401         return NULL;	/* no pattern, or device not found -- just return */
402     }
403     pfen = iodev->procs.enumerate_files(iodev, (const char *)pfn.fname,
404                 pfn.len, mem);
405     if (pfen == 0)
406         return NULL;
407     pgs_file_enum = gs_alloc_struct(mem, gs_file_enum, &st_gs_file_enum,
408                            "gs_enumerate_files_init");
409     if (pgs_file_enum == 0)
410         return NULL;
411     pgs_file_enum->memory = mem;
412     pgs_file_enum->piodev = iodev;
413     pgs_file_enum->pfile_enum = pfen;
414     pgs_file_enum->prepend_iodev_name = (pfn.iodev != NULL);
415     return (file_enum *)pgs_file_enum;
416 }
417 
418 uint
gs_enumerate_files_next(file_enum * pfen,char * ptr,uint maxlen)419 gs_enumerate_files_next(file_enum * pfen, char *ptr, uint maxlen)
420 {
421     gs_file_enum *pgs_file_enum = (gs_file_enum *)pfen;
422     int iodev_name_len = pgs_file_enum->prepend_iodev_name ?
423                         strlen(pgs_file_enum->piodev->dname) : 0;
424     uint return_len;
425 
426     if (iodev_name_len > maxlen)
427         return maxlen + 1;	/* signal overflow error */
428     if (iodev_name_len > 0)
429         memcpy(ptr, pgs_file_enum->piodev->dname, iodev_name_len);
430     return_len = pgs_file_enum->piodev->procs.enumerate_next(pgs_file_enum->pfile_enum,
431                                 ptr + iodev_name_len, maxlen - iodev_name_len);
432     if (return_len == ~0) {
433         gs_memory_t *mem = pgs_file_enum->memory;
434 
435         gs_free_object(mem, pgs_file_enum, "gs_enumerate_files_close");
436         return ~0;
437     }
438     return return_len+iodev_name_len;
439 }
440 
441 void
gs_enumerate_files_close(file_enum * pfen)442 gs_enumerate_files_close(file_enum * pfen)
443 {
444     gs_file_enum *pgs_file_enum = (gs_file_enum *)pfen;
445     gs_memory_t *mem = pgs_file_enum->memory;
446 
447     pgs_file_enum->piodev->procs.enumerate_close(pgs_file_enum->pfile_enum);
448     gs_free_object(mem, pgs_file_enum, "gs_enumerate_files_close");
449 }
450