Coverage Report

Created: 2022-04-16 11:23

/src/ghostpdl/base/sfxcommon.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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
/* $Id: sfxcommon.c 8250 2007-09-25 13:31:24Z giles $ */
18
/* Common routines for stdio and fd file stream implementations. */
19
#include "stdio_.h"   /* includes std.h */
20
#include "memory_.h"
21
#include "unistd_.h"
22
#include "gsmemory.h"
23
#include "gp.h"
24
#include "gserrors.h"
25
#include "stream.h"
26
#include "assert_.h"
27
28
#define DEFAULT_BUFFER_SIZE 2048
29
const uint file_default_buffer_size = DEFAULT_BUFFER_SIZE;
30
31
/* Allocate and return a file stream. */
32
/* Return 0 if the allocation failed. */
33
/* The stream is initialized to an invalid state, so the caller need not */
34
/* worry about cleaning up if a later step in opening the stream fails. */
35
stream *
36
file_alloc_stream(gs_memory_t * mem, client_name_t cname)
37
724k
{
38
724k
    stream *s;
39
724k
    s = s_alloc(mem, cname);
40
724k
    if (s == 0)
41
0
        return 0;
42
724k
    s_init_ids(s);
43
724k
    s->is_temp = 0;   /* not a temp stream */
44
724k
    s->foreign = 0;
45
    /*
46
     * Disable the stream now (in case we can't open the file,
47
     * or a filter init procedure fails) so that `restore' won't
48
     * crash when it tries to close open files.
49
     */
50
724k
    s_disable(s);
51
724k
    s->prev = 0;
52
724k
    s->next = 0;
53
724k
    return s;
54
724k
}
55
56
/* Open a file stream, optionally on an OS file. */
57
/* Return 0 if successful, error code if not. */
58
/* On a successful return, the C file name is in the stream buffer. */
59
/* If fname==0, set up the file entry, stream, and buffer, */
60
/* but don't open an OS file or initialize the stream. */
61
int
62
file_open_stream(const char *fname, uint len, const char *file_access,
63
                 uint buffer_size, stream ** ps, gx_io_device *iodev,
64
                 iodev_proc_fopen_t fopen_proc, gs_memory_t *mem)
65
464k
{
66
464k
    int code;
67
464k
    gp_file *file;
68
464k
    char fmode[4];  /* r/w/a, [+], [b], null */
69
70
#ifdef DEBUG
71
    if (strlen(gp_fmode_binary_suffix) > 0) {
72
        if (strchr(file_access, gp_fmode_binary_suffix[0]) != NULL)
73
      dmprintf(mem, "\nWarning: spurious 'b' character in file access mode\n");
74
  assert(strchr(file_access, gp_fmode_binary_suffix[0]) == NULL);
75
    }
76
#endif
77
78
464k
    if (!iodev)
79
97.2k
        iodev = iodev_default(mem);
80
464k
    code = file_prepare_stream(fname, len, file_access, buffer_size, ps, fmode, mem);
81
464k
    if (code < 0)
82
0
        return code;
83
464k
    if (fname == 0)
84
97.2k
        return 0;
85
367k
    if (fname[0] == 0) {        /* fopen_proc gets NUL terminated string, not len */
86
                                /* so this is the same as len == 0, so return NULL */
87
        /* discard the stuff we allocated to keep from accumulating stuff needing GC */
88
0
        gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
89
0
        gs_free_object(mem, *ps, "file_prepare_stream(stream)");
90
0
        *ps = NULL;
91
92
0
        return 0;
93
0
    }
94
367k
    code = (*fopen_proc)(iodev, (char *)(*ps)->cbuf, fmode, &file,
95
367k
                         (char *)(*ps)->cbuf, (*ps)->bsize, mem);
96
367k
    if (code < 0) {
97
        /* discard the stuff we allocated to keep from accumulating stuff needing GC */
98
367k
        gs_free_object(mem, (*ps)->cbuf, "file_close(buffer)");
99
367k
        gs_free_object(mem, *ps, "file_prepare_stream(stream)");
100
367k
        *ps = NULL;
101
367k
        return code;
102
367k
    }
103
0
    if (file_init_stream(*ps, file, fmode, (*ps)->cbuf, (*ps)->bsize) != 0)
104
0
        return_error(gs_error_ioerror);
105
0
    return 0;
106
0
}
107
108
/* Close a file stream.  This replaces the close procedure in the stream */
109
/* for normal (OS) files and for filters. */
110
int
111
file_close_file(stream * s)
112
95.8k
{
113
95.8k
    stream *stemp = s->strm;
114
95.8k
    gs_memory_t *mem;
115
95.8k
    int code = file_close_disable(s);
116
117
95.8k
    if (code)
118
0
        return code;
119
    /*
120
     * Check for temporary streams created for filters.
121
     * There may be more than one in the case of a procedure-based filter,
122
     * or if we created an intermediate stream to ensure
123
     * a large enough buffer.  Note that these streams may have been
124
     * allocated by file_alloc_stream, so we mustn't free them.
125
     */
126
98.6k
    while (stemp != 0 && stemp->is_temp != 0) {
127
2.73k
        stream *snext = stemp->strm;
128
129
2.73k
        mem = stemp->memory;
130
2.73k
        if (stemp->is_temp > 1)
131
2.73k
            gs_free_object(mem, stemp->cbuf,
132
2.73k
                           "file_close(temp stream buffer)");
133
2.73k
        s_disable(stemp);
134
2.73k
        stemp = snext;
135
2.73k
    }
136
95.8k
    mem = s->memory;
137
95.8k
    gs_free_object(mem, s->cbuf, "file_close(buffer)");
138
95.8k
    if (s->close_strm && stemp != 0)
139
0
        return sclose(stemp);
140
95.8k
    return 0;
141
95.8k
}
142
143
/*
144
 * Set up a file stream on an OS file.  The caller has allocated the
145
 * stream and buffer.
146
 */
147
int
148
file_init_stream(stream *s, gp_file *file, const char *fmode, byte *buffer,
149
                 uint buffer_size)
150
669
{
151
669
    switch (fmode[0]) {
152
0
    case 'a':
153
0
        if (sappend_file(s, file, buffer, buffer_size) != 0)
154
0
            return ERRC;
155
0
        break;
156
0
    case 'r':
157
        /* Defeat buffering for terminals. */
158
0
        {
159
0
            int char_buffered = gp_file_is_char_buffered(file);
160
0
            if (char_buffered < 0)
161
0
                return char_buffered;
162
0
            sread_file(s, file, buffer, char_buffered ? 1 : buffer_size);
163
0
        }
164
0
        break;
165
669
    case 'w':
166
669
        swrite_file(s, file, buffer, buffer_size);
167
669
    }
168
669
    if (fmode[1] == '+')
169
669
        s->file_modes |= s_mode_read | s_mode_write;
170
669
    s->save_close = s->procs.close;
171
669
    s->procs.close = file_close_file;
172
669
    return 0;
173
669
}
174
175
/* Prepare a stream with a file name. */
176
/* Return 0 if successful, error code if not. */
177
/* On a successful return, the C file name is in the stream buffer. */
178
/* If fname==0, set up stream, and buffer. */
179
int
180
file_prepare_stream(const char *fname, uint len, const char *file_access,
181
                 uint buffer_size, stream ** ps, char fmode[4], gs_memory_t *mem)
182
709k
{
183
709k
    byte *buffer;
184
709k
    register stream *s;
185
186
709k
    if (strlen(file_access) > 2)
187
0
        return_error(gs_error_invalidfileaccess);
188
189
    /* Open the file, always in binary mode. */
190
709k
    strcpy(fmode, file_access);
191
709k
    strcat(fmode, gp_fmode_binary_suffix);
192
709k
    if (buffer_size == 0)
193
0
        buffer_size = file_default_buffer_size;
194
709k
    if (len >= buffer_size)    /* we copy the file name into the buffer */
195
0
        return_error(gs_error_limitcheck);
196
    /* Allocate the stream first, since it persists */
197
    /* even after the file has been closed. */
198
709k
    s = file_alloc_stream(mem, "file_prepare_stream");
199
709k
    if (s == 0)
200
0
        return_error(gs_error_VMerror);
201
    /* Allocate the buffer. */
202
709k
    buffer = gs_alloc_bytes(mem, buffer_size, "file_prepare_stream(buffer)");
203
709k
    if (buffer == 0) {
204
1
        gs_free_object(mem, s, "file_prepare_stream");
205
1
        return_error(gs_error_VMerror);
206
1
    }
207
709k
    if (fname != 0) {
208
612k
        memcpy(buffer, fname, len);
209
612k
        buffer[len] = 0;  /* terminate string */
210
612k
    } else
211
97.2k
        buffer[0] = 0; /* safety */
212
709k
    s->cbuf = buffer;
213
709k
    s->bsize = s->cbsize = buffer_size;
214
709k
    s->save_close = 0;      /* in case this stream gets disabled before init finishes */
215
709k
    *ps = s;
216
709k
    return 0;
217
709k
}