Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gsioram.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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
/* %ram% file device implementation */
17
18
/*
19
 *  This file implements a simple ram-based file system.
20
 *
21
 * The fs has no subdirs, only a root directory. Files are stored as a
22
 * resizable array of pointers to blocks.  Timestamps are not implemented
23
 * for performance reasons.
24
 *
25
 * The implementation is in two parts - a ramfs interface that works
26
 * mostly like the unix file system calls, and a layer to hook this up
27
 * to ghostscript.
28
 *
29
 * Macros define an upper limit on the number of blocks a ram device
30
 * can take up, and (in ramfs.c) the size of each block.
31
 *
32
 * Routines for the gs stream interface were graciously stolen from
33
 * sfxstdio.c et al.
34
 */
35
36
#include "string_.h"
37
#include "unistd_.h"
38
#include "gx.h"
39
#include "gserrors.h"
40
#include "gp.h"
41
#include "gscdefs.h"
42
#include "gsparam.h"
43
#include "gsstruct.h"
44
#include "gxiodev.h"
45
#include "gsutil.h"
46
#include "stream.h"
47
#include "ramfs.h"
48
49
/* Function prototypes */
50
static iodev_proc_init(iodev_ram_init);
51
static iodev_proc_finit(iodev_ram_finit);
52
static iodev_proc_open_file(ram_open_file);
53
static iodev_proc_delete_file(ram_delete);
54
static iodev_proc_rename_file(ram_rename);
55
static iodev_proc_file_status(ram_status);
56
static iodev_proc_enumerate_files(ram_enumerate_init);
57
static iodev_proc_enumerate_next(ram_enumerate_next);
58
static iodev_proc_enumerate_close(ram_enumerate_close);
59
static iodev_proc_get_params(ram_get_params);
60
static void ram_finalize(const gs_memory_t *memory, void * vptr);
61
62
const gx_io_device gs_iodev_ram = {
63
    "%ram%", "FileSystem", {
64
        iodev_ram_init, iodev_ram_finit, iodev_no_open_device,
65
        ram_open_file, iodev_no_fopen, iodev_no_fclose,
66
        ram_delete, ram_rename, ram_status,
67
        ram_enumerate_init, ram_enumerate_next, ram_enumerate_close,
68
        ram_get_params, iodev_no_put_params
69
    },
70
    NULL,
71
    NULL
72
};
73
74
typedef struct ramfs_state_s {
75
    gs_memory_t *memory;
76
    ramfs* fs;
77
} ramfs_state;
78
79
178k
#define GETRAMFS(state) (((ramfs_state*)(state))->fs)
80
81
gs_private_st_simple_final(st_ramfs_state, struct ramfs_state_s, "ramfs_state", ram_finalize);
82
83
typedef struct gsram_enum_s {
84
    char *pattern;
85
    ramfs_enum* e;
86
    gs_memory_t *memory;
87
} gsram_enum;
88
89
gs_private_st_ptrs3(st_gsram_enum, struct gsram_enum_s, "gsram_enum",
90
    gsram_enum_enum_ptrs, gsram_enum_reloc_ptrs, pattern, e, memory);
91
92
/* could make this runtime configurable later.  It doesn't allocate
93
   all the blocks in one go so it's not critical */
94
89.2k
#define MAXBLOCKS 2000000
95
96
0
#define DEFAULT_BUFFER_SIZE 2048
97
98
/* stream stuff */
99
100
static int
101
s_ram_available(stream *, gs_offset_t *),
102
 s_ram_read_seek(stream *, gs_offset_t),
103
 s_ram_read_close(stream *),
104
 s_ram_read_process(stream_state *, stream_cursor_read *,
105
     stream_cursor_write *, bool);
106
static int
107
s_ram_write_seek(stream *, gs_offset_t),
108
 s_ram_write_flush(stream *),
109
 s_ram_write_close(stream *),
110
 s_ram_write_process(stream_state *, stream_cursor_read *,
111
     stream_cursor_write *, bool);
112
static int
113
s_ram_switch(stream *, bool);
114
115
static int
116
0
ramfs_errno_to_code(int error_number) {
117
0
    switch (error_number) {
118
0
    case RAMFS_NOTFOUND:
119
0
        return_error(gs_error_undefinedfilename);
120
0
    case RAMFS_NOACCESS:
121
0
        return_error(gs_error_invalidfileaccess);
122
0
    case RAMFS_NOMEM:
123
0
        return_error(gs_error_VMerror);
124
    /* just in case */
125
0
    default:
126
0
        return_error(gs_error_ioerror);
127
0
    }
128
0
}
129
130
static void
131
sread_ram(register stream * s, ramhandle * file, byte * buf, uint len),
132
 swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len),
133
 sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len);
134
135
static int
136
ram_open_file(gx_io_device * iodev, const char *fname, uint len,
137
    const char *file_access, stream ** ps, gs_memory_t * mem)
138
0
{
139
0
    int code = 0;
140
0
    ramhandle * file;
141
0
    char fmode[4];  /* r/w/a, [+], [b], null */
142
0
    int openmode=RAMFS_READ;
143
0
    ramfs * fs;
144
0
    char * namestr = NULL;
145
146
    /* Is there a more efficient way to do this? */
147
0
    namestr = (char *)gs_alloc_bytes(mem, len + 1, "temporary filename string");
148
0
    if(!namestr)
149
0
        return_error(gs_error_VMerror);
150
0
    strncpy(namestr,fname,len);
151
0
    namestr[len] = 0;
152
153
0
    if (!iodev) {/*iodev = iodev_default;*/
154
0
        gs_free_object(mem, namestr, "free temporary filename string");
155
0
        return gs_note_error(gs_error_invalidaccess);
156
0
    }
157
0
    fs = GETRAMFS(iodev->state);
158
0
    code = file_prepare_stream(fname, len, file_access, DEFAULT_BUFFER_SIZE,
159
0
    ps, fmode, mem
160
0
    );
161
0
    if (code < 0) goto error;
162
0
    if (fname == 0) {
163
0
        gs_free_object(mem, namestr, "free temporary filename string");
164
0
        return 0;
165
0
    }
166
167
0
    switch (fmode[0]) {
168
0
        case 'a':
169
0
          openmode = RAMFS_WRITE | RAMFS_APPEND;
170
0
          break;
171
0
        case 'r':
172
0
          openmode = RAMFS_READ;
173
0
          if (fmode[1] == '+')
174
0
            openmode |= RAMFS_WRITE;
175
0
          break;
176
0
        case 'w':
177
0
          openmode |= RAMFS_WRITE | RAMFS_TRUNC | RAMFS_CREATE;
178
0
          if (fmode[1] == '+')
179
0
             openmode |= RAMFS_READ;
180
0
    }
181
182
    /* For now, we cheat here in the same way that sfxstdio.c et al cheat -
183
       append mode is faked by opening in write mode and seeking to EOF just
184
       once. This is different from unix semantics, which seeks atomically
185
       before each write, and is actually useful as a distinct mode. */
186
    /* if (fmode[0] == 'a') openmode |= RAMFS_APPEND; */
187
188
0
    file = ramfs_open(mem, fs,namestr,openmode);
189
0
    if(!file) { code = ramfs_errno_to_code(ramfs_error(fs)); goto error; }
190
191
0
    switch (fmode[0]) {
192
0
    case 'a':
193
0
    sappend_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize);
194
0
    break;
195
0
    case 'r':
196
0
    sread_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize);
197
0
    break;
198
0
    case 'w':
199
0
    swrite_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize);
200
0
    }
201
0
    if (fmode[1] == '+') {
202
0
      (*ps)->modes = (*ps)->file_modes |= s_mode_read | s_mode_write;
203
0
    }
204
0
    (*ps)->save_close = (*ps)->procs.close;
205
0
    (*ps)->procs.close = file_close_file;
206
0
 error:
207
0
    gs_free_object(mem, namestr, "free temporary filename string");
208
    /* XXX free stream stuff? */
209
0
    return code;
210
0
}
211
212
/* Initialize a stream for reading an OS file. */
213
static void
214
sread_ram(register stream * s, ramhandle * file, byte * buf, uint len)
215
0
{
216
0
    static const stream_procs p = {
217
0
    s_ram_available, s_ram_read_seek, s_std_read_reset,
218
0
    s_std_read_flush, s_ram_read_close, s_ram_read_process,
219
0
    s_ram_switch
220
0
    };
221
222
0
    s_std_init(s, buf, len, &p,s_mode_read + s_mode_seek);
223
0
    s->file = (gp_file *)file;
224
0
    s->file_modes = s->modes;
225
0
    s->file_offset = 0;
226
0
    ramfile_seek(file, 0, RAMFS_SEEK_END);
227
0
    s->file_limit = ramfile_tell(file);
228
0
    ramfile_seek(file, 0, RAMFS_SEEK_SET);
229
0
}
230
231
/* Procedures for reading from a file */
232
static int
233
s_ram_available(register stream * s, gs_offset_t *pl)
234
0
{
235
0
    long max_avail = s->file_limit - stell(s);
236
237
0
    *pl = max_avail;
238
0
    if(*pl == 0 && ramfile_eof((ramhandle*)s->file))
239
0
    *pl = -1;        /* EOF */
240
0
    return 0;
241
0
}
242
243
static int
244
s_ram_read_seek(register stream * s, gs_offset_t pos)
245
0
{
246
0
    uint end = s->cursor.r.limit - s->cbuf + 1;
247
0
    long offset = pos - s->position;
248
249
0
    if (offset >= 0 && offset <= end) {  /* Staying within the same buffer */
250
0
        s->cursor.r.ptr = s->cbuf + offset - 1;
251
0
        return 0;
252
0
    }
253
0
    if (pos < 0 || pos > s->file_limit ||
254
0
        ramfile_seek((ramhandle*)s->file, s->file_offset + pos, RAMFS_SEEK_SET) != 0
255
0
    )
256
0
    return ERRC;
257
0
    s->cursor.r.ptr = s->cursor.r.limit = s->cbuf - 1;
258
0
    s->end_status = 0;
259
0
    s->position = pos;
260
0
    return 0;
261
0
}
262
static int
263
s_ram_read_close(stream * s)
264
0
{
265
0
    ramhandle *file = (ramhandle*)s->file;
266
267
0
    if (file != 0) {
268
0
    s->file = 0;
269
0
    ramfile_close(file);
270
0
    }
271
0
    return 0;
272
0
}
273
274
/*
275
 * Process a buffer for a file reading stream.
276
 * This is the first stream in the pipeline, so pr is irrelevant.
277
 */
278
static int
279
s_ram_read_process(stream_state * st, stream_cursor_read * ignore_pr,
280
    stream_cursor_write * pw, bool last)
281
0
{
282
0
    stream *s = (stream *)st;    /* no separate state */
283
0
    ramhandle *file = (ramhandle*)s->file;
284
0
    uint max_count = pw->limit - pw->ptr;
285
0
    int status = 1;
286
0
    int count;
287
288
0
    if (s->file_limit < S_FILE_LIMIT_MAX) {
289
0
    long limit_count = s->file_offset + s->file_limit -
290
0
    ramfile_tell(file);
291
292
0
    if (max_count > limit_count)
293
0
        max_count = limit_count, status = EOFC;
294
0
    }
295
0
    count = ramfile_read(file,pw->ptr + 1, max_count);
296
0
    if (count < 0) return ERRC;
297
0
    pw->ptr += count;
298
    /*    process_interrupts(s->memory); */
299
0
    return ramfile_eof(file) ? EOFC : status;
300
0
}
301
302
/* ------ File writing ------ */
303
304
/* Initialize a stream for writing a file. */
305
static void
306
swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len)
307
0
{
308
0
    static const stream_procs p = {
309
0
    s_std_noavailable, s_ram_write_seek, s_std_write_reset,
310
0
    s_ram_write_flush, s_ram_write_close, s_ram_write_process,
311
0
    s_ram_switch
312
0
    };
313
314
0
    s_std_init(s, buf, len, &p, s_mode_write + s_mode_seek);
315
0
    s->file = (gp_file *)file;
316
0
    s->file_modes = s->modes;
317
0
    s->file_offset = 0;        /* in case we switch to reading later */
318
0
    s->file_limit = S_FILE_LIMIT_MAX;
319
0
}
320
321
/* Initialize for appending to a file. */
322
static void
323
sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len)
324
0
{
325
0
    swrite_ram(s, file, buf, len);
326
0
    s->modes = s_mode_write + s_mode_append;    /* no seek */
327
0
    s->file_modes = s->modes;
328
0
    ramfile_seek(file,0,RAMFS_SEEK_END);
329
0
    s->position = ramfile_tell(file);
330
0
}
331
332
/* Procedures for writing on a file */
333
static int
334
s_ram_write_seek(stream * s, gs_offset_t pos)
335
0
{
336
    /* We must flush the buffer to reposition. */
337
0
    int code = sflush(s);
338
339
0
    if (code < 0) return code;
340
0
    if (ramfile_seek((ramhandle*)s->file, pos, RAMFS_SEEK_SET) != 0)
341
0
    return ERRC;
342
0
    s->position = pos;
343
0
    return 0;
344
0
}
345
346
static int
347
s_ram_write_flush(register stream * s)
348
0
{
349
0
    int result = s_process_write_buf(s, false);
350
0
    return result;
351
0
}
352
353
static int
354
s_ram_write_close(register stream * s)
355
0
{
356
0
    s_process_write_buf(s, true);
357
0
    return s_ram_read_close(s);
358
0
}
359
360
/*
361
 * Process a buffer for a file writing stream.
362
 * This is the last stream in the pipeline, so pw is irrelevant.
363
 */
364
static int
365
s_ram_write_process(stream_state * st, stream_cursor_read * pr,
366
    stream_cursor_write * ignore_pw, bool last)
367
0
{
368
0
    uint count = pr->limit - pr->ptr;
369
370
0
    ramhandle *file = (ramhandle*)((stream *) st)->file;
371
0
    int written = ramfile_write(file,pr->ptr + 1, count);
372
373
0
    if (written < 0) return ERRC;
374
0
    pr->ptr += written;
375
0
    return 0;
376
0
}
377
378
static int
379
s_ram_switch(stream * s, bool writing)
380
0
{
381
0
    uint modes = s->file_modes;
382
0
    ramhandle *file = (ramhandle*)s->file;
383
0
    long pos;
384
385
0
    if (writing) {
386
0
    if (!(s->file_modes & s_mode_write)) return ERRC;
387
0
    pos = stell(s);
388
0
    ramfile_seek(file, pos, RAMFS_SEEK_SET);
389
0
    if (modes & s_mode_append) {
390
0
        sappend_ram(s, file, s->cbuf, s->cbsize);    /* sets position */
391
0
    } else {
392
0
        swrite_ram(s, file, s->cbuf, s->cbsize);
393
0
        s->position = pos;
394
0
    }
395
0
    s->modes = modes;
396
0
    } else {
397
0
    if (!(s->file_modes & s_mode_read)) return ERRC;
398
0
    pos = stell(s);
399
0
    if (sflush(s) < 0) return ERRC;
400
0
    sread_ram(s, file, s->cbuf, s->cbsize);
401
0
    s->modes |= modes & s_mode_append;    /* don't lose append info */
402
0
    s->position = pos;
403
0
    }
404
0
    s->file_modes = modes;
405
0
    return 0;
406
0
}
407
408
409
/* gx_io_device stuff */
410
411
static int
412
iodev_ram_init(gx_io_device * iodev, gs_memory_t * mem)
413
89.2k
{
414
89.2k
    ramfs* fs = ramfs_new(mem, MAXBLOCKS);
415
89.2k
    ramfs_state* state = gs_alloc_struct(mem, ramfs_state, &st_ramfs_state,
416
89.2k
    "ramfs_init(state)"
417
89.2k
    );
418
89.2k
    if (fs && state) {
419
89.2k
    state->fs = fs;
420
89.2k
    state->memory = mem;
421
89.2k
    iodev->state = state;
422
89.2k
    return 0;
423
89.2k
    }
424
0
    if(fs) ramfs_destroy(mem, fs);
425
0
    if(state) gs_free_object(mem,state,"iodev_ram_init(state)");
426
0
    return_error(gs_error_VMerror);
427
89.2k
}
428
429
static void
430
iodev_ram_finit(gx_io_device * iodev, gs_memory_t * mem)
431
19.6k
{
432
19.6k
    ramfs_state *state = (ramfs_state *)iodev->state;
433
19.6k
    if (state != NULL)
434
19.6k
    {
435
19.6k
        iodev->state = NULL;
436
19.6k
        gs_free_object(state->memory, state, "iodev_ram_finit");
437
19.6k
    }
438
19.6k
    return;
439
19.6k
}
440
441
static void
442
ram_finalize(const gs_memory_t *memory, void * vptr)
443
89.2k
{
444
89.2k
    ramfs* fs = GETRAMFS((ramfs_state*)vptr);
445
89.2k
    ramfs_destroy((gs_memory_t *)memory, fs);
446
89.2k
    GETRAMFS((ramfs_state*)vptr) = NULL;
447
89.2k
}
448
449
static int
450
ram_delete(gx_io_device * iodev, const char *fname)
451
0
{
452
0
    ramfs* fs = GETRAMFS(iodev->state);
453
454
0
    if(ramfs_unlink(fs,fname)!=0) {
455
0
    return_error(ramfs_errno_to_code(ramfs_error(fs)));
456
0
    }
457
0
    return 0;
458
0
}
459
460
static int
461
ram_rename(gx_io_device * iodev, const char *from, const char *to)
462
0
{
463
0
    ramfs* fs = GETRAMFS(iodev->state);
464
465
0
    if(ramfs_rename(fs,from,to)!=0) {
466
0
    return_error(ramfs_errno_to_code(ramfs_error(fs)));
467
0
    }
468
0
    return 0;
469
0
}
470
471
static int
472
ram_status(gx_io_device * iodev, const char *fname, struct stat *pstat)
473
0
{
474
0
    ramhandle * f;
475
0
    ramfs* fs = GETRAMFS(iodev->state);
476
477
0
    f = ramfs_open(((ramfs_state *)iodev->state)->memory, fs,fname,RAMFS_READ);
478
0
    if(!f) return_error(ramfs_errno_to_code(ramfs_error(fs)));
479
480
0
    memset(pstat, 0, sizeof(*pstat));
481
0
    pstat->st_size = ramfile_size(f);
482
    /* The Windows definition of struct stat doesn't include a st_blocks member
483
    pstat->st_blocks = (pstat->st_size+blocksize-1)/blocksize;*/
484
    /* XXX set mtime & ctime */
485
0
    ramfile_close(f);
486
0
    return 0;
487
0
}
488
489
static file_enum *
490
ram_enumerate_init(gs_memory_t * mem, gx_io_device *iodev, const char *pat,
491
                   uint patlen)
492
0
{
493
0
    gsram_enum * penum = gs_alloc_struct(
494
0
    mem, gsram_enum, &st_gsram_enum,
495
0
    "ram_enumerate_files_init(file_enum)"
496
0
    );
497
0
    char *pattern = (char *)gs_alloc_bytes(
498
0
    mem, patlen+1, "ram_enumerate_file_init(pattern)"
499
0
    );
500
501
0
    ramfs_enum * e = ramfs_enum_new(GETRAMFS(iodev->state));
502
0
    if(penum && pattern && e) {
503
0
    memcpy(pattern, pat, patlen);
504
0
    pattern[patlen]=0;
505
506
0
    penum->memory = mem;
507
0
    penum->pattern = pattern;
508
0
    penum->e = e;
509
0
    return (file_enum *)penum;
510
0
    }
511
0
    if (penum) gs_free_object(mem,penum,"ramfs_enum_init(ramfs_enum)");
512
0
    if (pattern)
513
0
    gs_free_object(mem, pattern, "ramfs_enum_init(pattern)");
514
0
    if(e) ramfs_enum_end(e);
515
0
    return NULL;
516
0
}
517
518
static void
519
ram_enumerate_close(gs_memory_t * mem, file_enum *pfen)
520
0
{
521
0
    gsram_enum *penum = (gsram_enum *)pfen;
522
0
    gs_memory_t *mem2 = penum->memory;
523
0
    (void)mem;
524
525
0
    ramfs_enum_end(penum->e);
526
0
    gs_free_object(mem2, penum->pattern, "ramfs_enum_init(pattern)");
527
0
    gs_free_object(mem2, penum, "ramfs_enum_init(ramfs_enum)");
528
0
}
529
530
static uint
531
ram_enumerate_next(gs_memory_t * mem, file_enum *pfen, char *ptr, uint maxlen)
532
0
{
533
0
    gsram_enum *penum = (gsram_enum *)pfen;
534
535
0
    char * filename;
536
0
    while ((filename = ramfs_enum_next(penum->e))) {
537
0
    if (string_match((byte *)filename, strlen(filename),
538
0
        (byte *)penum->pattern,
539
0
        strlen(penum->pattern), 0)) {
540
0
        if (strlen(filename) < maxlen)
541
0
        memcpy(ptr, filename, strlen(filename));
542
0
        return strlen(filename);    /* if > maxlen, caller will detect rangecheck */
543
0
    }
544
0
    }
545
    /* ran off end of list, close the enum */
546
0
    ram_enumerate_close(mem, pfen);
547
0
    return ~(uint)0;
548
0
}
549
550
static int
551
ram_get_params(gx_io_device * iodev, gs_param_list * plist)
552
0
{
553
0
    int code;
554
0
    int i0 = 0, so = 1;
555
0
    bool btrue = true, bfalse = false;
556
0
    ramfs* fs = GETRAMFS(iodev->state);
557
0
    int BlockSize;
558
0
    long Free, LogicalSize;
559
560
0
    BlockSize = ramfs_blocksize(fs);
561
0
    LogicalSize = MAXBLOCKS;
562
0
    Free = ramfs_blocksfree(fs);
563
564
0
    if (
565
0
    (code = param_write_bool(plist, "HasNames",        &btrue)) < 0 ||
566
0
    (code = param_write_int (plist, "BlockSize",       &BlockSize)) < 0 ||
567
0
    (code = param_write_long(plist, "Free",            &Free)) < 0 ||
568
0
    (code = param_write_int (plist, "InitializeAction",&i0)) < 0 ||
569
0
    (code = param_write_bool(plist, "Mounted",         &btrue)) < 0 ||
570
0
    (code = param_write_bool(plist, "Removable",       &bfalse)) < 0 ||
571
0
    (code = param_write_bool(plist, "Searchable",      &btrue)) < 0 ||
572
0
    (code = param_write_int (plist, "SearchOrder",     &so)) < 0 ||
573
0
    (code = param_write_bool(plist, "Writeable",       &btrue)) < 0 ||
574
0
    (code = param_write_long(plist, "LogicalSize",     &LogicalSize)) < 0
575
0
    )
576
0
    return code;
577
0
    return 0;
578
0
}