1 /* Copyright (C) 2001-2019 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.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, 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_finit, iodev_no_open_device,
52      NULL /*iodev_os_open_file */ , iodev_os_gp_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     NULL,
58     NULL
59 };
60 
61 /* ------ Initialization ------ */
62 
63 int
gs_iodev_init(gs_memory_t * mem)64 gs_iodev_init(gs_memory_t * mem)
65 {				/* Make writable copies of all IODevices. */
66     gx_io_device **table =
67         gs_alloc_struct_array_immovable(mem, gx_io_device_table_count + NUM_RUNTIME_IODEVS,
68                               gx_io_device *, &st_io_device_ptr_element,
69                               "gs_iodev_init(table)");
70     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
71     int i, j;
72     int code = 0;
73 
74     if ((table == NULL) || (libctx == NULL))
75         return_error(gs_error_VMerror);
76 
77     libctx->io_device_table_size = gx_io_device_table_count + NUM_RUNTIME_IODEVS;
78     libctx->io_device_table_count = 0;
79     libctx->io_device_table = table;
80 
81     for (i = 0; i < gx_io_device_table_count; ++i) {
82         gx_io_device *iodev =
83             gs_alloc_struct_immovable(mem, gx_io_device, &st_io_device,
84                             "gs_iodev_init(iodev)");
85 
86         if (iodev == 0)
87             goto fail;
88         table[i] = iodev;
89         memcpy(table[i], gx_io_device_table[i], sizeof(gx_io_device));
90         iodev->memory = mem;
91         libctx->io_device_table_count++;
92     }
93     for (;i < gx_io_device_table_count + NUM_RUNTIME_IODEVS; i++) {
94         table[i] = NULL;
95     }
96 
97     code = gs_register_struct_root(mem, &mem->gs_lib_ctx->io_device_table_root,
98                                    (void **)&libctx->io_device_table,
99                                    "io_device_table");
100     if (code < 0)
101         goto fail;
102     /* Run the one-time initialization of each IODevice. */
103     for (j = 0; j < gx_io_device_table_count; ++j)
104         if ((code = (table[j]->procs.init)(table[j], mem)) < 0)
105             goto f2;
106     return 0;
107  f2:
108     /****** CAN'T FIND THE ROOT ******/
109     /*gs_unregister_root(mem, root, "io_device_table");*/
110  fail:
111     return (code < 0 ? code : gs_note_error(gs_error_VMerror));
112 }
113 
114 void
gs_iodev_finit(gs_memory_t * mem)115 gs_iodev_finit(gs_memory_t * mem)
116 {
117     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
118     if (libctx && libctx->io_device_table) {
119         gs_free_object(mem, libctx->io_device_table, "gs_iodev_finit");
120         libctx->io_device_table = NULL;
121     }
122     return;
123 }
124 
125 /*
126  * Register io devices *after* lib initialisation
127 */
128 int
gs_iodev_register_dev(gs_memory_t * mem,const gx_io_device * newiodev)129 gs_iodev_register_dev(gs_memory_t * mem, const gx_io_device *newiodev)
130 {
131     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
132     gx_io_device **table = libctx->io_device_table;
133     int code = 0;
134     gx_io_device *iodev;
135     int i;
136 
137     if (libctx->io_device_table_count >= libctx->io_device_table_size) {
138         /* FIXME: table size should be dynamic - deregistering the root node is a problem */
139         return_error(gs_error_limitcheck);
140     }
141 
142     iodev = gs_alloc_struct(mem, gx_io_device, &st_io_device,
143                             "gs_iodev_register_dev(iodev)");
144 
145     if (iodev == 0) {
146         code = gs_note_error(gs_error_VMerror);
147         goto fail;
148     }
149     table[libctx->io_device_table_count] = iodev;
150     memcpy(table[libctx->io_device_table_count], newiodev, sizeof(gx_io_device));
151 
152     if ((code = (table[libctx->io_device_table_count]->procs.init)(table[libctx->io_device_table_count], mem)) < 0)
153         goto fail2;
154     libctx->io_device_table_count++;
155 
156     return(code);
157   fail2:
158     for (i = libctx->io_device_table_count; i > 0; --i)
159         gs_free_object(mem, table[i - 1], "gs_iodev_init(iodev)");
160     gs_free_object(mem, table, "gs_iodev_init(table)");
161     libctx->io_device_table = NULL;
162 
163   fail:
164     return(code);
165 }
166 
167 static void
gs_iodev_finalize(const gs_memory_t * cmem,void * vptr)168 gs_iodev_finalize(const gs_memory_t *cmem, void *vptr)
169 {
170     /* discard const for gs_free_object */
171     gs_memory_t *mem = (gs_memory_t *)cmem;
172     if (mem->gs_lib_ctx->io_device_table == vptr) {
173         gx_io_device **table = mem->gs_lib_ctx->io_device_table;
174         while (mem->gs_lib_ctx->io_device_table_count-- > 0) {
175             gs_free_object(mem,
176               table[mem->gs_lib_ctx->io_device_table_count],
177               "gs_iodev_finalize");
178             table[mem->gs_lib_ctx->io_device_table_count] = NULL;
179         }
180         mem->gs_lib_ctx->io_device_table = NULL;
181         mem->gs_lib_ctx->io_device_table_size =
182             mem->gs_lib_ctx->io_device_table_count = 0;
183     }
184 }
185 
186 void
io_device_finalize(const gs_memory_t * cmem,void * vptr)187 io_device_finalize(const gs_memory_t *cmem, void *vptr)
188 {
189     /* discard const for gs_free_object */
190     gs_memory_t *mem = (gs_memory_t *)cmem;
191     if (mem->gs_lib_ctx->io_device_table_count > 0) {
192         int i;
193         for (i = 0; i < mem->gs_lib_ctx->io_device_table_count
194            && mem->gs_lib_ctx->io_device_table[i] != vptr; i++)
195         ;
196 
197         (mem->gs_lib_ctx->io_device_table[i]->procs.finit)(mem->gs_lib_ctx->io_device_table[i], mem);
198         mem->gs_lib_ctx->io_device_table[i] = NULL;
199     }
200     return;
201 }
202 
203 /* ------ Default (unimplemented) IODevice procedures ------ */
204 
205 int
iodev_no_init(gx_io_device * iodev,gs_memory_t * mem)206 iodev_no_init(gx_io_device * iodev, gs_memory_t * mem)
207 {
208     return 0;
209 }
210 
211 void
iodev_no_finit(gx_io_device * iodev,gs_memory_t * mem)212 iodev_no_finit(gx_io_device * iodev, gs_memory_t * mem)
213 {
214     return;
215 }
216 
217 int
iodev_no_open_device(gx_io_device * iodev,const char * access,stream ** ps,gs_memory_t * mem)218 iodev_no_open_device(gx_io_device * iodev, const char *access, stream ** ps,
219                      gs_memory_t * mem)
220 {
221     return_error(gs_error_invalidfileaccess);
222 }
223 
224 int
iodev_no_open_file(gx_io_device * iodev,const char * fname,uint namelen,const char * access,stream ** ps,gs_memory_t * mem)225 iodev_no_open_file(gx_io_device * iodev, const char *fname, uint namelen,
226                    const char *access, stream ** ps, gs_memory_t * mem)
227 {
228     return_error(gs_error_invalidfileaccess);
229 }
230 
231 int
iodev_no_fopen(gx_io_device * iodev,const char * fname,const char * access,gp_file ** pfile,char * rfname,uint rnamelen,gs_memory_t * mem)232 iodev_no_fopen(gx_io_device * iodev, const char *fname, const char *access,
233                gp_file ** pfile, char *rfname, uint rnamelen, gs_memory_t *mem)
234 {
235     return_error(gs_error_invalidfileaccess);
236 }
237 
238 int
iodev_no_fclose(gx_io_device * iodev,gp_file * file)239 iodev_no_fclose(gx_io_device * iodev, gp_file * file)
240 {
241     return_error(gs_error_ioerror);
242 }
243 
244 int
iodev_no_delete_file(gx_io_device * iodev,const char * fname)245 iodev_no_delete_file(gx_io_device * iodev, const char *fname)
246 {
247     return_error(gs_error_invalidfileaccess);
248 }
249 
250 int
iodev_no_rename_file(gx_io_device * iodev,const char * from,const char * to)251 iodev_no_rename_file(gx_io_device * iodev, const char *from, const char *to)
252 {
253     return_error(gs_error_invalidfileaccess);
254 }
255 
256 int
iodev_no_file_status(gx_io_device * iodev,const char * fname,struct stat * pstat)257 iodev_no_file_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
258 {
259     return_error(gs_error_undefinedfilename);
260 }
261 
262 file_enum *
iodev_no_enumerate_files(gs_memory_t * mem,gx_io_device * iodev,const char * pat,uint patlen)263 iodev_no_enumerate_files(gs_memory_t *mem, gx_io_device * iodev, const char *pat,
264                          uint patlen)
265 {
266     return NULL;
267 }
268 
269 int
iodev_no_get_params(gx_io_device * iodev,gs_param_list * plist)270 iodev_no_get_params(gx_io_device * iodev, gs_param_list * plist)
271 {
272     return 0;
273 }
274 
275 int
iodev_no_put_params(gx_io_device * iodev,gs_param_list * plist)276 iodev_no_put_params(gx_io_device * iodev, gs_param_list * plist)
277 {
278     return param_commit(plist);
279 }
280 
281 /* ------ %os% ------ */
282 
283 /* The fopen routine is exported for %null. */
284 int
iodev_os_gp_fopen(gx_io_device * iodev,const char * fname,const char * access,gp_file ** pfile,char * rfname,uint rnamelen,gs_memory_t * mem)285 iodev_os_gp_fopen(gx_io_device * iodev, const char *fname, const char *access,
286                   gp_file ** pfile, char *rfname, uint rnamelen, gs_memory_t *mem)
287 {
288     errno = 0;
289     *pfile = gp_fopen(mem, fname, access);
290     if (*pfile == NULL)
291         return_error(gs_fopen_errno_to_code(errno));
292     if (rfname != NULL && rfname != fname)
293         strcpy(rfname, fname);
294     return 0;
295 }
296 
297 /* The fclose routine is exported for %null. */
298 int
iodev_os_fclose(gx_io_device * iodev,gp_file * file)299 iodev_os_fclose(gx_io_device * iodev, gp_file * file)
300 {
301     gp_fclose(file);
302     return 0;
303 }
304 
305 static int
os_delete(gx_io_device * iodev,const char * fname)306 os_delete(gx_io_device * iodev, const char *fname)
307 {
308     return (unlink(fname) == 0 ? 0 : gs_error_ioerror);
309 }
310 
311 static int
os_rename(gx_io_device * iodev,const char * from,const char * to)312 os_rename(gx_io_device * iodev, const char *from, const char *to)
313 {
314     return (rename(from, to) == 0 ? 0 : gs_error_ioerror);
315 }
316 
317 static int
os_status(gx_io_device * iodev,const char * fname,struct stat * pstat)318 os_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
319 {				/* The RS/6000 prototype for stat doesn't include const, */
320     /* so we have to explicitly remove the const modifier. */
321     return (gp_stat(iodev->memory, (char *)fname, pstat) < 0 ? gs_error_undefinedfilename : 0);
322 }
323 
324 static file_enum *
os_enumerate(gs_memory_t * mem,gx_io_device * iodev,const char * pat,uint patlen)325 os_enumerate(gs_memory_t * mem, gx_io_device * iodev, const char *pat,
326              uint patlen)
327 {
328     return gp_enumerate_files_init(mem, pat, patlen);
329 }
330 
331 static int
os_get_params(gx_io_device * iodev,gs_param_list * plist)332 os_get_params(gx_io_device * iodev, gs_param_list * plist)
333 {
334     int code;
335     int i0 = 0, i2 = 2;
336     bool btrue = true, bfalse = false;
337     int BlockSize;
338     long Free, LogicalSize;
339 
340     /*
341      * Return fake values for BlockSize and Free, since we can't get the
342      * correct values in a platform-independent manner.
343      */
344     BlockSize = 1024;
345     LogicalSize = 2000000000 / BlockSize;	/* about 2 Gb */
346     Free = LogicalSize * 3 / 4;			/* about 1.5 Gb */
347 
348     if (
349         (code = param_write_bool(plist, "HasNames", &btrue)) < 0 ||
350         (code = param_write_int(plist, "BlockSize", &BlockSize)) < 0 ||
351         (code = param_write_long(plist, "Free", &Free)) < 0 ||
352         (code = param_write_int(plist, "InitializeAction", &i0)) < 0 ||
353         (code = param_write_bool(plist, "Mounted", &btrue)) < 0 ||
354         (code = param_write_bool(plist, "Removable", &bfalse)) < 0 ||
355         (code = param_write_bool(plist, "Searchable", &btrue)) < 0 ||
356         (code = param_write_int(plist, "SearchOrder", &i2)) < 0 ||
357         (code = param_write_bool(plist, "Writeable", &btrue)) < 0 ||
358         (code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0
359         )
360         return code;
361     return 0;
362 }
363 
364 /* ------ Utilities ------ */
365 
366 /* Get the N'th IODevice from the known device table. */
367 gx_io_device *
gs_getiodevice(const gs_memory_t * mem,int index)368 gs_getiodevice(const gs_memory_t *mem, int index)
369 {
370     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
371 
372     if (libctx == NULL || libctx->io_device_table == NULL ||
373         index < 0      || index >= libctx->io_device_table_count)
374         return 0;		/* index out of range */
375     return libctx->io_device_table[index];
376 }
377 
378 /* Look up an IODevice name. */
379 /* The name may be either %device or %device%. */
380 gx_io_device *
gs_findiodevice(const gs_memory_t * mem,const byte * str,uint len)381 gs_findiodevice(const gs_memory_t *mem, const byte * str, uint len)
382 {
383     int i;
384     gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem);
385 
386     if (libctx->io_device_table == 0)
387     	return 0;
388     if (len > 1 && str[len - 1] == '%')
389         len--;
390     for (i = 0; i < libctx->io_device_table_count; ++i) {
391         gx_io_device *iodev = libctx->io_device_table[i];
392         const char *dname = iodev->dname;
393 
394         if (dname && strlen(dname) == len + 1 && !memcmp(str, dname, len))
395             return iodev;
396     }
397     return 0;
398 }
399 
400 /* ------ Accessors ------ */
401 
402 /* Get IODevice parameters. */
403 int
gs_getdevparams(gx_io_device * iodev,gs_param_list * plist)404 gs_getdevparams(gx_io_device * iodev, gs_param_list * plist)
405 {				/* All IODevices have the Type parameter. */
406     gs_param_string ts;
407     int code;
408 
409     param_string_from_string(ts, iodev->dtype);
410     code = param_write_name(plist, "Type", &ts);
411     if (code < 0)
412         return code;
413     return (*iodev->procs.get_params) (iodev, plist);
414 }
415 
416 /* Put IODevice parameters. */
417 int
gs_putdevparams(gx_io_device * iodev,gs_param_list * plist)418 gs_putdevparams(gx_io_device * iodev, gs_param_list * plist)
419 {
420     return (*iodev->procs.put_params) (iodev, plist);
421 }
422 
423 /* Convert an OS error number to a PostScript error */
424 /* if opening a file fails. */
425 int
gs_fopen_errno_to_code(int eno)426 gs_fopen_errno_to_code(int eno)
427 {				/* Different OSs vary widely in their error codes. */
428     /* We try to cover as many variations as we know about. */
429     switch (eno) {
430 #ifdef ENOENT
431         case ENOENT:
432             return_error(gs_error_undefinedfilename);
433 #endif
434 #ifdef ENOFILE
435 #  ifndef ENOENT
436 #    define ENOENT ENOFILE
437 #  endif
438 #  if ENOFILE != ENOENT
439         case ENOFILE:
440             return_error(gs_error_undefinedfilename);
441 #  endif
442 #endif
443 #ifdef ENAMETOOLONG
444         case ENAMETOOLONG:
445             return_error(gs_error_undefinedfilename);
446 #endif
447 #ifdef EACCES
448         case EACCES:
449             return_error(gs_error_invalidfileaccess);
450 #endif
451 #ifdef EMFILE
452         case EMFILE:
453             return_error(gs_error_limitcheck);
454 #endif
455 #ifdef ENFILE
456         case ENFILE:
457             return_error(gs_error_limitcheck);
458 #endif
459         default:
460             return_error(gs_error_ioerror);
461     }
462 }
463 
464 /* Generic interface for filesystem enumeration given a path that may	*/
465 /* include a %iodev% prefix */
466 
467 typedef struct gs_file_enum_s gs_file_enum;
468 struct gs_file_enum_s {
469     gs_memory_t *memory;
470     gx_io_device *piodev;	/* iodev's are static, so don't need GC tracing */
471     file_enum *pfile_enum;
472     int prepend_iodev_name;
473 };
474 
475 gs_private_st_ptrs1(st_gs_file_enum, gs_file_enum, "gs_file_enum",
476                     gs_file_enum_enum_ptrs, gs_file_enum_reloc_ptrs, pfile_enum);
477 
478 file_enum *
gs_enumerate_files_init(gs_memory_t * mem,const char * pat,uint patlen)479 gs_enumerate_files_init(gs_memory_t * mem, const char *pat, uint patlen)
480 {
481     file_enum *pfen;
482     gs_file_enum *pgs_file_enum;
483     gx_io_device *iodev = NULL;
484     gs_parsed_file_name_t pfn;
485     int code = 0;
486 
487     /* Get the iodevice */
488     code = gs_parse_file_name(&pfn, pat, patlen, mem);
489     if (code < 0)
490         return NULL;
491     iodev = (pfn.iodev == NULL) ? iodev_default(mem) : pfn.iodev;
492 
493     /* Check for several conditions that just cause us to return success */
494     if (pfn.len == 0 || iodev->procs.enumerate_files == iodev_no_enumerate_files) {
495         return NULL;	/* no pattern, or device not found -- just return */
496     }
497     pfen = iodev->procs.enumerate_files(mem, iodev, (const char *)pfn.fname,
498                 pfn.len);
499     if (pfen == 0)
500         return NULL;
501     pgs_file_enum = gs_alloc_struct(mem, gs_file_enum, &st_gs_file_enum,
502                            "gs_enumerate_files_init");
503     if (pgs_file_enum == 0)
504     {
505         iodev->procs.enumerate_close(mem, pfen);
506         return NULL;
507     }
508     pgs_file_enum->memory = mem;
509     pgs_file_enum->piodev = iodev;
510     pgs_file_enum->pfile_enum = pfen;
511     pgs_file_enum->prepend_iodev_name = (pfn.iodev != NULL);
512     return (file_enum *)pgs_file_enum;
513 }
514 
515 uint
gs_enumerate_files_next(gs_memory_t * mem,file_enum * pfen,char * ptr,uint maxlen)516 gs_enumerate_files_next(gs_memory_t * mem, file_enum * pfen, char *ptr,
517                         uint maxlen)
518 {
519     gs_file_enum *pgs_file_enum = (gs_file_enum *)pfen;
520     int iodev_name_len;
521     uint return_len;
522 
523     if (pgs_file_enum == NULL)
524         return ~0;
525 
526     iodev_name_len = pgs_file_enum->prepend_iodev_name ?
527                         strlen(pgs_file_enum->piodev->dname) : 0;
528 
529     if (iodev_name_len > maxlen)
530         return maxlen + 1;	/* signal overflow error */
531     if (iodev_name_len > 0)
532         memcpy(ptr, pgs_file_enum->piodev->dname, iodev_name_len);
533     return_len = pgs_file_enum->piodev->procs.enumerate_next(mem, pgs_file_enum->pfile_enum,
534                                 ptr + iodev_name_len, maxlen - iodev_name_len);
535     if (return_len == ~0) {
536         gs_memory_t *mem2 = pgs_file_enum->memory;
537 
538         gs_free_object(mem2, pgs_file_enum, "gs_enumerate_files_close");
539         return ~0;
540     }
541     return return_len+iodev_name_len;
542 }
543 
544 void
gs_enumerate_files_close(gs_memory_t * mem,file_enum * pfen)545 gs_enumerate_files_close(gs_memory_t * mem, file_enum * pfen)
546 {
547     gs_file_enum *pgs_file_enum = (gs_file_enum *)pfen;
548     gs_memory_t *mem2 = pgs_file_enum->memory;
549 
550     pgs_file_enum->piodev->procs.enumerate_close(mem, pgs_file_enum->pfile_enum);
551     gs_free_object(mem2, pgs_file_enum, "gs_enumerate_files_close");
552 }
553