/src/ghostpdl/base/gdevpipe.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 | | /* %pipe% IODevice */ |
18 | | #include "errno_.h" |
19 | | #include "pipe_.h" |
20 | | #include "stdio_.h" |
21 | | #include "string_.h" |
22 | | #include "gserrors.h" |
23 | | #include "gstypes.h" |
24 | | #include "gsmemory.h" /* for gxiodev.h */ |
25 | | #include "gxiodev.h" |
26 | | |
27 | | /* The file device procedures */ |
28 | | |
29 | | static int |
30 | | do_pclose(FILE *file) |
31 | 0 | { |
32 | | #ifdef GS_NO_FILESYSTEM |
33 | | return gs_error_ok; |
34 | | #else |
35 | 0 | int status = pclose(file); |
36 | 0 | if (status < 0 || status > 0) |
37 | 0 | return_error(gs_error_ioerror); |
38 | | |
39 | 0 | return gs_error_ok; |
40 | 0 | #endif |
41 | 0 | } |
42 | | |
43 | | static int |
44 | | fs_file_open_pipe(const gs_memory_t *mem, void *secret, const char *fname, char *rfname, const char *mode, gp_file **file) |
45 | 0 | { |
46 | 0 | *file = gp_file_FILE_alloc(mem); |
47 | 0 | if (*file == NULL) |
48 | 0 | return gs_error_VMerror; |
49 | | |
50 | 0 | errno = 0; |
51 | | /* |
52 | | * The OSF/1 1.3 library doesn't include const in the |
53 | | * prototype for popen, so we have to break const here. |
54 | | */ |
55 | 0 | if (gp_file_FILE_set(*file, popen((char *)fname, (char *)mode), do_pclose)) { |
56 | 0 | *file = NULL; |
57 | 0 | return_error(gs_fopen_errno_to_code(errno)); |
58 | 0 | } |
59 | | |
60 | 0 | if (rfname != NULL && rfname != fname) |
61 | 0 | strcpy(rfname, fname); |
62 | |
|
63 | 0 | return 0; |
64 | 0 | } |
65 | | |
66 | | static int |
67 | | pipe_fopen(gx_io_device * iodev, const char *fname, const char *access, |
68 | | gp_file ** pfile, char *rfname, uint rnamelen, gs_memory_t *mem) |
69 | 0 | { |
70 | | #ifdef GS_NO_FILESYSTEM |
71 | | return 0; |
72 | | #else |
73 | 0 | gs_lib_ctx_t *ctx = mem->gs_lib_ctx; |
74 | 0 | gs_fs_list_t *fs = ctx->core->fs; |
75 | | /* The pipe device can be reached in two ways, explicltly with %pipe% |
76 | | or implicitly with "|", so we have to check for both |
77 | | */ |
78 | 0 | char f[gp_file_name_sizeof]; |
79 | 0 | const char *pipestr = "|"; |
80 | 0 | const size_t pipestrlen = strlen(pipestr); |
81 | 0 | const size_t preflen = strlen(iodev->dname); |
82 | 0 | const size_t nlen = strlen(fname); |
83 | 0 | int code1; |
84 | |
|
85 | 0 | if (preflen + nlen >= gp_file_name_sizeof) |
86 | 0 | return_error(gs_error_invalidaccess); |
87 | | |
88 | 0 | memcpy(f, iodev->dname, preflen); |
89 | 0 | memcpy(f + preflen, fname, nlen + 1); |
90 | |
|
91 | 0 | code1 = gp_validate_path(mem, f, access); |
92 | |
|
93 | 0 | memcpy(f, pipestr, pipestrlen); |
94 | 0 | memcpy(f + pipestrlen, fname, nlen + 1); |
95 | |
|
96 | 0 | if (code1 != 0 && gp_validate_path(mem, f, access) != 0 ) |
97 | 0 | return gs_error_invalidfileaccess; |
98 | | |
99 | | /* |
100 | | * Some platforms allow opening a pipe with a '+' in the access |
101 | | * mode, even though pipes are not positionable. Detect this here. |
102 | | */ |
103 | 0 | if (strchr(access, '+')) |
104 | 0 | return_error(gs_error_invalidfileaccess); |
105 | | |
106 | 0 | *pfile = NULL; |
107 | 0 | for (fs = ctx->core->fs; fs != NULL; fs = fs->next) |
108 | 0 | { |
109 | 0 | int code = 0; |
110 | 0 | if (fs->fs.open_pipe) |
111 | 0 | code = fs->fs.open_pipe(mem, fs->secret, fname, rfname, access, pfile); |
112 | 0 | if (code < 0) |
113 | 0 | return code; |
114 | 0 | if (*pfile != NULL) |
115 | 0 | break; |
116 | 0 | } |
117 | | |
118 | 0 | return 0; |
119 | 0 | #endif |
120 | 0 | } |
121 | | |
122 | | static int |
123 | | pipe_fclose(gx_io_device * iodev, gp_file * file) |
124 | 0 | { |
125 | | #ifdef GS_NO_FILESYSTEM |
126 | | return 0; |
127 | | #else |
128 | 0 | return gp_fclose(file); |
129 | 0 | #endif |
130 | 0 | } |
131 | | |
132 | | static int |
133 | | pipe_init(gx_io_device * iodev, gs_memory_t * mem) |
134 | 162k | { |
135 | 162k | gs_fs_list_t *fs = mem->gs_lib_ctx->core->fs; |
136 | | |
137 | 162k | while (fs->next) |
138 | 0 | fs = fs->next; |
139 | | |
140 | | /* Last one is out file device */ |
141 | 162k | fs->fs.open_pipe = fs_file_open_pipe; |
142 | | |
143 | 162k | return 0; |
144 | 162k | } |
145 | | |
146 | | /* The pipe IODevice */ |
147 | | const gx_io_device gs_iodev_pipe = { |
148 | | "%pipe%", "Special", |
149 | | {pipe_init, iodev_no_finit, iodev_no_open_device, |
150 | | NULL /*iodev_os_open_file */ , pipe_fopen, pipe_fclose, |
151 | | iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status, |
152 | | iodev_no_enumerate_files, NULL, NULL, |
153 | | iodev_no_get_params, iodev_no_put_params |
154 | | }, |
155 | | NULL, |
156 | | NULL |
157 | | }; |
158 | | |