/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 | 10.8k | { /* Make writable copies of all IODevices. */ |
66 | 10.8k | gx_io_device **table = |
67 | 10.8k | gs_alloc_struct_array_immovable(mem, gx_io_device_table_count + NUM_RUNTIME_IODEVS, |
68 | 10.8k | gx_io_device *, &st_io_device_ptr_element, |
69 | 10.8k | "gs_iodev_init(table)"); |
70 | 10.8k | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
71 | 10.8k | int i, j; |
72 | 10.8k | int code = 0; |
73 | | |
74 | 10.8k | if ((table == NULL) || (libctx == NULL)) |
75 | 0 | return_error(gs_error_VMerror); |
76 | | |
77 | 10.8k | libctx->io_device_table_size = gx_io_device_table_count + NUM_RUNTIME_IODEVS; |
78 | 10.8k | libctx->io_device_table_count = 0; |
79 | 10.8k | libctx->io_device_table = table; |
80 | | |
81 | 86.6k | for (i = 0; i < gx_io_device_table_count; ++i) { |
82 | 75.7k | gx_io_device *iodev = |
83 | 75.7k | gs_alloc_struct_immovable(mem, gx_io_device, &st_io_device, |
84 | 75.7k | "gs_iodev_init(iodev)"); |
85 | | |
86 | 75.7k | if (iodev == 0) |
87 | 0 | goto fail; |
88 | 75.7k | table[i] = iodev; |
89 | 75.7k | memcpy(table[i], gx_io_device_table[i], sizeof(gx_io_device)); |
90 | 75.7k | iodev->memory = mem; |
91 | 75.7k | libctx->io_device_table_count++; |
92 | 75.7k | } |
93 | 184k | for (;i < gx_io_device_table_count + NUM_RUNTIME_IODEVS; i++) { |
94 | 173k | table[i] = NULL; |
95 | 173k | } |
96 | | |
97 | 10.8k | code = gs_register_struct_root(mem, &mem->gs_lib_ctx->io_device_table_root, |
98 | 10.8k | (void **)&libctx->io_device_table, |
99 | 10.8k | "io_device_table"); |
100 | 10.8k | if (code < 0) |
101 | 0 | goto fail; |
102 | | /* Run the one-time initialization of each IODevice. */ |
103 | 86.6k | for (j = 0; j < gx_io_device_table_count; ++j) |
104 | 75.7k | if ((code = (table[j]->procs.init)(table[j], mem)) < 0) |
105 | 0 | goto f2; |
106 | 10.8k | 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 | 10.8k | { |
117 | 10.8k | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
118 | 10.8k | 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 | 10.8k | return; |
123 | 10.8k | } |
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 | 75.7k | { |
131 | 75.7k | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
132 | 75.7k | gx_io_device **table = libctx->io_device_table; |
133 | 75.7k | int code = 0; |
134 | 75.7k | gx_io_device *iodev; |
135 | 75.7k | int i; |
136 | | |
137 | 75.7k | 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 | 75.7k | iodev = gs_alloc_struct(mem, gx_io_device, &st_io_device, |
143 | 75.7k | "gs_iodev_register_dev(iodev)"); |
144 | | |
145 | 75.7k | if (iodev == 0) { |
146 | 0 | code = gs_note_error(gs_error_VMerror); |
147 | 0 | goto fail; |
148 | 0 | } |
149 | 75.7k | table[libctx->io_device_table_count] = iodev; |
150 | 75.7k | memcpy(table[libctx->io_device_table_count], newiodev, sizeof(gx_io_device)); |
151 | | |
152 | 75.7k | if ((code = (table[libctx->io_device_table_count]->procs.init)(table[libctx->io_device_table_count], mem)) < 0) |
153 | 0 | goto fail2; |
154 | 75.7k | libctx->io_device_table_count++; |
155 | | |
156 | 75.7k | 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 | 10.8k | { |
170 | | /* discard const for gs_free_object */ |
171 | 10.8k | gs_memory_t *mem = (gs_memory_t *)cmem; |
172 | 10.8k | if (mem->gs_lib_ctx->io_device_table == vptr) { |
173 | 10.8k | gx_io_device **table = mem->gs_lib_ctx->io_device_table; |
174 | 162k | while (mem->gs_lib_ctx->io_device_table_count-- > 0) { |
175 | 151k | gs_free_object(mem, |
176 | 151k | table[mem->gs_lib_ctx->io_device_table_count], |
177 | 151k | "gs_iodev_finalize"); |
178 | 151k | table[mem->gs_lib_ctx->io_device_table_count] = NULL; |
179 | 151k | } |
180 | 10.8k | mem->gs_lib_ctx->io_device_table = NULL; |
181 | 10.8k | mem->gs_lib_ctx->io_device_table_size = |
182 | 10.8k | mem->gs_lib_ctx->io_device_table_count = 0; |
183 | 10.8k | } |
184 | 10.8k | } |
185 | | |
186 | | void |
187 | | io_device_finalize(const gs_memory_t *cmem, void *vptr) |
188 | 151k | { |
189 | | /* discard const for gs_free_object */ |
190 | 151k | gs_memory_t *mem = (gs_memory_t *)cmem; |
191 | 151k | if (mem->gs_lib_ctx->io_device_table_count > 0) { |
192 | 57.7k | int i; |
193 | 498k | for (i = 0; i < mem->gs_lib_ctx->io_device_table_count |
194 | 498k | && mem->gs_lib_ctx->io_device_table[i] != vptr; i++) |
195 | 440k | ; |
196 | | |
197 | 57.7k | (mem->gs_lib_ctx->io_device_table[i]->procs.finit)(mem->gs_lib_ctx->io_device_table[i], mem); |
198 | 57.7k | mem->gs_lib_ctx->io_device_table[i] = NULL; |
199 | 57.7k | } |
200 | 151k | return; |
201 | 151k | } |
202 | | |
203 | | /* ------ Default (unimplemented) IODevice procedures ------ */ |
204 | | |
205 | | int |
206 | | iodev_no_init(gx_io_device * iodev, gs_memory_t * mem) |
207 | 97.4k | { |
208 | 97.4k | return 0; |
209 | 97.4k | } |
210 | | |
211 | | void |
212 | | iodev_no_finit(gx_io_device * iodev, gs_memory_t * mem) |
213 | 42.2k | { |
214 | 42.2k | return; |
215 | 42.2k | } |
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 | 4.47M | { |
288 | 4.47M | errno = 0; |
289 | 4.47M | *pfile = gp_fopen(mem, fname, access); |
290 | 4.47M | if (*pfile == NULL) |
291 | 4.47M | return_error(gs_fopen_errno_to_code(errno)); |
292 | 0 | if (rfname != NULL && rfname != fname) |
293 | 0 | strcpy(rfname, fname); |
294 | 0 | return 0; |
295 | 4.47M | } |
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 | 5.51k | { |
308 | 5.51k | return (gp_unlink(iodev->memory, fname) == 0 ? 0 : gs_error_ioerror); |
309 | 5.51k | } |
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 | 119k | { |
328 | 119k | return gp_enumerate_files_init(mem, pat, patlen); |
329 | 119k | } |
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 | 7.15M | { |
370 | 7.15M | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
371 | | |
372 | 7.15M | if (libctx == NULL || libctx->io_device_table == NULL || |
373 | 7.15M | index < 0 || index >= libctx->io_device_table_count) |
374 | 10.8k | return 0; /* index out of range */ |
375 | 7.14M | return libctx->io_device_table[index]; |
376 | 7.15M | } |
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 | 9.55M | { |
383 | 9.55M | int i; |
384 | 9.55M | gs_lib_ctx_t *libctx = gs_lib_ctx_get_interp_instance(mem); |
385 | | |
386 | 9.55M | if (libctx->io_device_table == 0) |
387 | 0 | return 0; |
388 | 9.55M | if (len > 1 && str[len - 1] == '%') |
389 | 0 | len--; |
390 | 55.3M | for (i = 0; i < libctx->io_device_table_count; ++i) { |
391 | 55.3M | gx_io_device *iodev = libctx->io_device_table[i]; |
392 | 55.3M | const char *dname = iodev->dname; |
393 | | |
394 | 55.3M | if (dname && strlen(dname) == len + 1 && !memcmp(str, dname, len)) |
395 | 9.55M | return iodev; |
396 | 55.3M | } |
397 | 0 | return 0; |
398 | 9.55M | } |
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 | 4.47M | { /* Different OSs vary widely in their error codes. */ |
428 | | /* We try to cover as many variations as we know about. */ |
429 | 4.47M | switch (eno) { |
430 | 0 | #ifdef ENOENT |
431 | 4.47M | case ENOENT: |
432 | 4.47M | 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 | 1.32k | case EACCES: |
449 | 1.32k | 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 | 4.47M | } |
462 | 4.47M | } |
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 | } |