Coverage Report

Created: 2025-06-10 07:15

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