/src/ghostpdl/base/gsioram.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 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 | | /* %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 | 324k | #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_ptrs2(st_gsram_enum, struct gsram_enum_s, "gsram_enum", |
90 | | gsram_enum_enum_ptrs, gsram_enum_reloc_ptrs, pattern, 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 | 162k | #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 | 0 | case RAMFS_BADRANGE: |
125 | 0 | return_error(gs_error_rangecheck); |
126 | | /* just in case */ |
127 | 0 | default: |
128 | 0 | return_error(gs_error_ioerror); |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | static void |
133 | | sread_ram(register stream * s, ramhandle * file, byte * buf, uint len), |
134 | | swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len), |
135 | | sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len); |
136 | | |
137 | | static int |
138 | | ram_open_file(gx_io_device * iodev, const char *fname, uint len, |
139 | | const char *file_access, stream ** ps, gs_memory_t * mem) |
140 | 0 | { |
141 | 0 | int code = 0; |
142 | 0 | ramhandle * file; |
143 | 0 | char fmode[4]; /* r/w/a, [+], [b], null */ |
144 | 0 | int openmode=RAMFS_READ; |
145 | 0 | ramfs * fs; |
146 | 0 | char * namestr = NULL; |
147 | | |
148 | | /* Is there a more efficient way to do this? */ |
149 | 0 | namestr = (char *)gs_alloc_bytes(mem, len + 1, "temporary filename string"); |
150 | 0 | if(!namestr) |
151 | 0 | return_error(gs_error_VMerror); |
152 | 0 | strncpy(namestr,fname,len); |
153 | 0 | namestr[len] = 0; |
154 | | |
155 | | /* Make sure iodev is valid, and we have initialised the RAM file system (state != NULL) */ |
156 | 0 | if (iodev == NULL || iodev->state == NULL) {/*iodev = iodev_default;*/ |
157 | 0 | gs_free_object(mem, namestr, "free temporary filename string"); |
158 | 0 | return gs_note_error(gs_error_invalidaccess); |
159 | 0 | } |
160 | 0 | fs = GETRAMFS(iodev->state); |
161 | 0 | code = file_prepare_stream(fname, len, file_access, DEFAULT_BUFFER_SIZE, |
162 | 0 | ps, fmode, mem |
163 | 0 | ); |
164 | 0 | if (code < 0) goto error; |
165 | 0 | if (fname == 0) { |
166 | 0 | gs_free_object(mem, namestr, "free temporary filename string"); |
167 | 0 | return 0; |
168 | 0 | } |
169 | | |
170 | 0 | switch (fmode[0]) { |
171 | 0 | case 'a': |
172 | 0 | openmode = RAMFS_WRITE | RAMFS_APPEND; |
173 | 0 | break; |
174 | 0 | case 'r': |
175 | 0 | openmode = RAMFS_READ; |
176 | 0 | if (fmode[1] == '+') |
177 | 0 | openmode |= RAMFS_WRITE; |
178 | 0 | break; |
179 | 0 | case 'w': |
180 | 0 | openmode |= RAMFS_WRITE | RAMFS_TRUNC | RAMFS_CREATE; |
181 | 0 | if (fmode[1] == '+') |
182 | 0 | openmode |= RAMFS_READ; |
183 | 0 | } |
184 | | |
185 | | /* For now, we cheat here in the same way that sfxstdio.c et al cheat - |
186 | | append mode is faked by opening in write mode and seeking to EOF just |
187 | | once. This is different from unix semantics, which seeks atomically |
188 | | before each write, and is actually useful as a distinct mode. */ |
189 | | /* if (fmode[0] == 'a') openmode |= RAMFS_APPEND; */ |
190 | | |
191 | 0 | file = ramfs_open(mem, fs,namestr,openmode); |
192 | 0 | if(!file) { code = ramfs_errno_to_code(ramfs_error(fs)); goto error; } |
193 | | |
194 | 0 | switch (fmode[0]) { |
195 | 0 | case 'a': |
196 | 0 | sappend_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); |
197 | 0 | break; |
198 | 0 | case 'r': |
199 | 0 | sread_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); |
200 | 0 | break; |
201 | 0 | case 'w': |
202 | 0 | swrite_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); |
203 | 0 | } |
204 | 0 | if (fmode[1] == '+') { |
205 | 0 | (*ps)->modes = (*ps)->file_modes |= s_mode_read | s_mode_write; |
206 | 0 | } |
207 | 0 | (*ps)->save_close = (*ps)->procs.close; |
208 | 0 | (*ps)->procs.close = file_close_file; |
209 | 0 | error: |
210 | 0 | gs_free_object(mem, namestr, "free temporary filename string"); |
211 | | /* XXX free stream stuff? */ |
212 | 0 | return code; |
213 | 0 | } |
214 | | |
215 | | /* Initialize a stream for reading an OS file. */ |
216 | | static void |
217 | | sread_ram(register stream * s, ramhandle * file, byte * buf, uint len) |
218 | 0 | { |
219 | 0 | static const stream_procs p = { |
220 | 0 | s_ram_available, s_ram_read_seek, s_std_read_reset, |
221 | 0 | s_std_read_flush, s_ram_read_close, s_ram_read_process, |
222 | 0 | s_ram_switch |
223 | 0 | }; |
224 | |
|
225 | 0 | s_std_init(s, buf, len, &p,s_mode_read + s_mode_seek); |
226 | 0 | s->file = (gp_file *)file; |
227 | 0 | s->file_modes = s->modes; |
228 | 0 | s->file_offset = 0; |
229 | 0 | ramfile_seek(file, 0, RAMFS_SEEK_END); |
230 | 0 | s->file_limit = ramfile_tell(file); |
231 | 0 | ramfile_seek(file, 0, RAMFS_SEEK_SET); |
232 | 0 | } |
233 | | |
234 | | /* Procedures for reading from a file */ |
235 | | static int |
236 | | s_ram_available(register stream * s, gs_offset_t *pl) |
237 | 0 | { |
238 | 0 | long max_avail = s->file_limit - stell(s); |
239 | |
|
240 | 0 | *pl = max_avail; |
241 | 0 | if(*pl == 0 && ramfile_eof((ramhandle*)s->file)) |
242 | 0 | *pl = -1; /* EOF */ |
243 | 0 | return 0; |
244 | 0 | } |
245 | | |
246 | | static int |
247 | | s_ram_read_seek(register stream * s, gs_offset_t pos) |
248 | 0 | { |
249 | 0 | uint end = s->cursor.r.limit - s->cbuf + 1; |
250 | 0 | long offset = pos - s->position; |
251 | |
|
252 | 0 | if (offset >= 0 && offset <= end) { /* Staying within the same buffer */ |
253 | 0 | s->cursor.r.ptr = s->cbuf + offset - 1; |
254 | 0 | return 0; |
255 | 0 | } |
256 | | |
257 | 0 | if (pos < 0 || pos > s->file_limit || s->file == NULL || |
258 | 0 | ramfile_seek((ramhandle*)s->file, s->file_offset + pos, RAMFS_SEEK_SET) != 0) |
259 | 0 | return ERRC; |
260 | | |
261 | 0 | s->cursor.r.ptr = s->cursor.r.limit = s->cbuf - 1; |
262 | 0 | s->end_status = 0; |
263 | 0 | s->position = pos; |
264 | 0 | return 0; |
265 | 0 | } |
266 | | static int |
267 | | s_ram_read_close(stream * s) |
268 | 0 | { |
269 | 0 | ramhandle *file = (ramhandle*)s->file; |
270 | |
|
271 | 0 | if (file != 0) { |
272 | 0 | s->file = 0; |
273 | 0 | ramfile_close(file); |
274 | 0 | } |
275 | 0 | return 0; |
276 | 0 | } |
277 | | |
278 | | /* |
279 | | * Process a buffer for a file reading stream. |
280 | | * This is the first stream in the pipeline, so pr is irrelevant. |
281 | | */ |
282 | | static int |
283 | | s_ram_read_process(stream_state * st, stream_cursor_read * ignore_pr, |
284 | | stream_cursor_write * pw, bool last) |
285 | 0 | { |
286 | 0 | stream *s = (stream *)st; /* no separate state */ |
287 | 0 | ramhandle *file = (ramhandle*)s->file; |
288 | 0 | uint max_count = pw->limit - pw->ptr; |
289 | 0 | int status = 1; |
290 | 0 | int count; |
291 | |
|
292 | 0 | if (s->file_limit < S_FILE_LIMIT_MAX) { |
293 | 0 | long limit_count = s->file_offset + s->file_limit - |
294 | 0 | ramfile_tell(file); |
295 | |
|
296 | 0 | if (max_count > limit_count) |
297 | 0 | max_count = limit_count, status = EOFC; |
298 | 0 | } |
299 | 0 | count = ramfile_read(file,pw->ptr + 1, max_count); |
300 | 0 | if (count < 0) return ERRC; |
301 | 0 | pw->ptr += count; |
302 | | /* process_interrupts(s->memory); */ |
303 | 0 | return ramfile_eof(file) ? EOFC : status; |
304 | 0 | } |
305 | | |
306 | | /* ------ File writing ------ */ |
307 | | |
308 | | /* Initialize a stream for writing a file. */ |
309 | | static void |
310 | | swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len) |
311 | 0 | { |
312 | 0 | static const stream_procs p = { |
313 | 0 | s_std_noavailable, s_ram_write_seek, s_std_write_reset, |
314 | 0 | s_ram_write_flush, s_ram_write_close, s_ram_write_process, |
315 | 0 | s_ram_switch |
316 | 0 | }; |
317 | |
|
318 | 0 | s_std_init(s, buf, len, &p, s_mode_write + s_mode_seek); |
319 | 0 | s->file = (gp_file *)file; |
320 | 0 | s->file_modes = s->modes; |
321 | 0 | s->file_offset = 0; /* in case we switch to reading later */ |
322 | 0 | s->file_limit = S_FILE_LIMIT_MAX; |
323 | 0 | } |
324 | | |
325 | | /* Initialize for appending to a file. */ |
326 | | static void |
327 | | sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len) |
328 | 0 | { |
329 | 0 | swrite_ram(s, file, buf, len); |
330 | 0 | s->modes = s_mode_write + s_mode_append; /* no seek */ |
331 | 0 | s->file_modes = s->modes; |
332 | 0 | ramfile_seek(file,0,RAMFS_SEEK_END); |
333 | 0 | s->position = ramfile_tell(file); |
334 | 0 | } |
335 | | |
336 | | /* Procedures for writing on a file */ |
337 | | static int |
338 | | s_ram_write_seek(stream * s, gs_offset_t pos) |
339 | 0 | { |
340 | | /* We must flush the buffer to reposition. */ |
341 | 0 | int code = sflush(s); |
342 | |
|
343 | 0 | if (code < 0) return code; |
344 | 0 | if (pos < 0 || ramfile_seek((ramhandle*)s->file, pos, RAMFS_SEEK_SET) != 0) |
345 | 0 | return ERRC; |
346 | 0 | s->position = pos; |
347 | 0 | return 0; |
348 | 0 | } |
349 | | |
350 | | static int |
351 | | s_ram_write_flush(register stream * s) |
352 | 0 | { |
353 | 0 | int result = s_process_write_buf(s, false); |
354 | 0 | return result; |
355 | 0 | } |
356 | | |
357 | | static int |
358 | | s_ram_write_close(register stream * s) |
359 | 0 | { |
360 | 0 | s_process_write_buf(s, true); |
361 | 0 | return s_ram_read_close(s); |
362 | 0 | } |
363 | | |
364 | | /* |
365 | | * Process a buffer for a file writing stream. |
366 | | * This is the last stream in the pipeline, so pw is irrelevant. |
367 | | */ |
368 | | static int |
369 | | s_ram_write_process(stream_state * st, stream_cursor_read * pr, |
370 | | stream_cursor_write * ignore_pw, bool last) |
371 | 0 | { |
372 | 0 | uint count = pr->limit - pr->ptr; |
373 | |
|
374 | 0 | ramhandle *file = (ramhandle*)((stream *) st)->file; |
375 | 0 | int written = ramfile_write(file,pr->ptr + 1, count); |
376 | |
|
377 | 0 | if (written < 0) return ERRC; |
378 | 0 | pr->ptr += written; |
379 | 0 | return 0; |
380 | 0 | } |
381 | | |
382 | | static int |
383 | | s_ram_switch(stream * s, bool writing) |
384 | 0 | { |
385 | 0 | uint modes = s->file_modes; |
386 | 0 | ramhandle *file = (ramhandle*)s->file; |
387 | 0 | long pos; |
388 | |
|
389 | 0 | if (writing) { |
390 | 0 | if (!(s->file_modes & s_mode_write)) return ERRC; |
391 | 0 | pos = stell(s); |
392 | 0 | ramfile_seek(file, pos, RAMFS_SEEK_SET); |
393 | 0 | if (modes & s_mode_append) { |
394 | 0 | sappend_ram(s, file, s->cbuf, s->cbsize); /* sets position */ |
395 | 0 | } else { |
396 | 0 | swrite_ram(s, file, s->cbuf, s->cbsize); |
397 | 0 | s->position = pos; |
398 | 0 | } |
399 | 0 | s->modes = modes; |
400 | 0 | } else { |
401 | 0 | if (!(s->file_modes & s_mode_read)) return ERRC; |
402 | 0 | pos = stell(s); |
403 | 0 | if (sflush(s) < 0) return ERRC; |
404 | 0 | sread_ram(s, file, s->cbuf, s->cbsize); |
405 | 0 | s->modes |= modes & s_mode_append; /* don't lose append info */ |
406 | 0 | s->position = pos; |
407 | 0 | } |
408 | 0 | s->file_modes = modes; |
409 | 0 | return 0; |
410 | 0 | } |
411 | | |
412 | | |
413 | | /* gx_io_device stuff */ |
414 | | |
415 | | static int |
416 | | iodev_ram_init(gx_io_device * iodev, gs_memory_t * mem) |
417 | 162k | { |
418 | 162k | ramfs* fs = ramfs_new(mem, MAXBLOCKS); |
419 | 162k | ramfs_state* state = gs_alloc_struct(mem, ramfs_state, &st_ramfs_state, |
420 | 162k | "ramfs_init(state)" |
421 | 162k | ); |
422 | 162k | if (fs && state) { |
423 | 162k | state->fs = fs; |
424 | 162k | state->memory = mem; |
425 | 162k | iodev->state = state; |
426 | 162k | return 0; |
427 | 162k | } |
428 | 0 | if(fs) ramfs_destroy(mem, fs); |
429 | 0 | if(state) gs_free_object(mem,state,"iodev_ram_init(state)"); |
430 | 0 | return_error(gs_error_VMerror); |
431 | 162k | } |
432 | | |
433 | | static void |
434 | | iodev_ram_finit(gx_io_device * iodev, gs_memory_t * mem) |
435 | 47.6k | { |
436 | 47.6k | ramfs_state *state = (ramfs_state *)iodev->state; |
437 | 47.6k | if (state != NULL) |
438 | 47.6k | { |
439 | 47.6k | iodev->state = NULL; |
440 | 47.6k | gs_free_object(state->memory, state, "iodev_ram_finit"); |
441 | 47.6k | } |
442 | 47.6k | return; |
443 | 47.6k | } |
444 | | |
445 | | static void |
446 | | ram_finalize(const gs_memory_t *memory, void * vptr) |
447 | 162k | { |
448 | 162k | ramfs* fs = GETRAMFS((ramfs_state*)vptr); |
449 | 162k | ramfs_destroy((gs_memory_t *)memory, fs); |
450 | 162k | GETRAMFS((ramfs_state*)vptr) = NULL; |
451 | 162k | } |
452 | | |
453 | | static int |
454 | | ram_delete(gx_io_device * iodev, const char *fname) |
455 | 0 | { |
456 | 0 | ramfs* fs; |
457 | |
|
458 | 0 | if (iodev->state == NULL) |
459 | 0 | return_error(gs_error_ioerror); |
460 | 0 | else |
461 | 0 | fs = GETRAMFS(iodev->state); |
462 | | |
463 | 0 | if(ramfs_unlink(fs,fname)!=0) { |
464 | 0 | return_error(ramfs_errno_to_code(ramfs_error(fs))); |
465 | 0 | } |
466 | 0 | return 0; |
467 | 0 | } |
468 | | |
469 | | static int |
470 | | ram_rename(gx_io_device * iodev, const char *from, const char *to) |
471 | 0 | { |
472 | 0 | ramfs* fs; |
473 | |
|
474 | 0 | if (iodev->state == NULL) |
475 | 0 | return_error(gs_error_ioerror); |
476 | 0 | else |
477 | 0 | fs = GETRAMFS(iodev->state); |
478 | | |
479 | 0 | if(ramfs_rename(fs,from,to)!=0) { |
480 | 0 | return_error(ramfs_errno_to_code(ramfs_error(fs))); |
481 | 0 | } |
482 | 0 | return 0; |
483 | 0 | } |
484 | | |
485 | | static int |
486 | | ram_status(gx_io_device * iodev, const char *fname, struct stat *pstat) |
487 | 0 | { |
488 | 0 | ramhandle * f; |
489 | 0 | ramfs* fs; |
490 | |
|
491 | 0 | if (iodev->state == NULL) |
492 | 0 | return_error(gs_error_ioerror); |
493 | 0 | else |
494 | 0 | fs = GETRAMFS(iodev->state); |
495 | | |
496 | 0 | f = ramfs_open(((ramfs_state *)iodev->state)->memory, fs,fname,RAMFS_READ); |
497 | 0 | if(!f) return_error(ramfs_errno_to_code(ramfs_error(fs))); |
498 | | |
499 | 0 | memset(pstat, 0, sizeof(*pstat)); |
500 | 0 | pstat->st_size = ramfile_size(f); |
501 | | /* The Windows definition of struct stat doesn't include a st_blocks member |
502 | | pstat->st_blocks = (pstat->st_size+blocksize-1)/blocksize;*/ |
503 | | /* XXX set mtime & ctime */ |
504 | 0 | ramfile_close(f); |
505 | 0 | return 0; |
506 | 0 | } |
507 | | |
508 | | static file_enum * |
509 | | ram_enumerate_init(gs_memory_t * mem, gx_io_device *iodev, const char *pat, |
510 | | uint patlen) |
511 | 0 | { |
512 | 0 | gsram_enum * penum = gs_alloc_struct( |
513 | 0 | mem, gsram_enum, &st_gsram_enum, |
514 | 0 | "ram_enumerate_files_init(file_enum)" |
515 | 0 | ); |
516 | 0 | char *pattern = (char *)gs_alloc_bytes( |
517 | 0 | mem, patlen+1, "ram_enumerate_file_init(pattern)" |
518 | 0 | ); |
519 | |
|
520 | 0 | ramfs_enum * e; |
521 | |
|
522 | 0 | if (iodev->state == NULL) |
523 | 0 | return NULL; |
524 | 0 | else |
525 | 0 | e = ramfs_enum_new(GETRAMFS(iodev->state)); |
526 | | |
527 | 0 | if(penum && pattern && e) { |
528 | 0 | memcpy(pattern, pat, patlen); |
529 | 0 | pattern[patlen]=0; |
530 | |
|
531 | 0 | penum->memory = mem; |
532 | 0 | penum->pattern = pattern; |
533 | 0 | penum->e = e; |
534 | 0 | return (file_enum *)penum; |
535 | 0 | } |
536 | 0 | if (penum) gs_free_object(mem,penum,"ramfs_enum_init(ramfs_enum)"); |
537 | 0 | if (pattern) |
538 | 0 | gs_free_object(mem, pattern, "ramfs_enum_init(pattern)"); |
539 | 0 | if(e) ramfs_enum_end(e); |
540 | 0 | return NULL; |
541 | 0 | } |
542 | | |
543 | | static void |
544 | | ram_enumerate_close(gs_memory_t * mem, file_enum *pfen) |
545 | 0 | { |
546 | 0 | gsram_enum *penum = (gsram_enum *)pfen; |
547 | 0 | gs_memory_t *mem2 = penum->memory; |
548 | 0 | (void)mem; |
549 | |
|
550 | 0 | ramfs_enum_end(penum->e); |
551 | 0 | gs_free_object(mem2, penum->pattern, "ramfs_enum_init(pattern)"); |
552 | 0 | gs_free_object(mem2, penum, "ramfs_enum_init(ramfs_enum)"); |
553 | 0 | } |
554 | | |
555 | | static uint |
556 | | ram_enumerate_next(gs_memory_t * mem, file_enum *pfen, char *ptr, uint maxlen) |
557 | 0 | { |
558 | 0 | gsram_enum *penum = (gsram_enum *)pfen; |
559 | |
|
560 | 0 | char * filename; |
561 | 0 | while ((filename = ramfs_enum_next(penum->e))) { |
562 | 0 | if (string_match((byte *)filename, strlen(filename), |
563 | 0 | (byte *)penum->pattern, |
564 | 0 | strlen(penum->pattern), 0)) { |
565 | 0 | if (strlen(filename) < maxlen) |
566 | 0 | memcpy(ptr, filename, strlen(filename)); |
567 | 0 | return strlen(filename); /* if > maxlen, caller will detect rangecheck */ |
568 | 0 | } |
569 | 0 | } |
570 | | /* ran off end of list, close the enum */ |
571 | 0 | ram_enumerate_close(mem, pfen); |
572 | 0 | return ~(uint)0; |
573 | 0 | } |
574 | | |
575 | | static int |
576 | | ram_get_params(gx_io_device * iodev, gs_param_list * plist) |
577 | 0 | { |
578 | 0 | int code; |
579 | 0 | int i0 = 0, so = 1; |
580 | 0 | bool btrue = true, bfalse = false; |
581 | 0 | ramfs* fs; |
582 | |
|
583 | 0 | int BlockSize; |
584 | 0 | long Free, LogicalSize; |
585 | |
|
586 | 0 | if (iodev->state == NULL) |
587 | 0 | return_error(gs_error_ioerror); |
588 | 0 | else |
589 | 0 | fs = GETRAMFS(iodev->state); |
590 | | |
591 | 0 | BlockSize = ramfs_blocksize(fs); |
592 | 0 | LogicalSize = MAXBLOCKS; |
593 | 0 | Free = ramfs_blocksfree(fs); |
594 | |
|
595 | 0 | if ( |
596 | 0 | (code = param_write_bool(plist, "HasNames", &btrue)) < 0 || |
597 | 0 | (code = param_write_int (plist, "BlockSize", &BlockSize)) < 0 || |
598 | 0 | (code = param_write_long(plist, "Free", &Free)) < 0 || |
599 | 0 | (code = param_write_int (plist, "InitializeAction",&i0)) < 0 || |
600 | 0 | (code = param_write_bool(plist, "Mounted", &btrue)) < 0 || |
601 | 0 | (code = param_write_bool(plist, "Removable", &bfalse)) < 0 || |
602 | 0 | (code = param_write_bool(plist, "Searchable", &btrue)) < 0 || |
603 | 0 | (code = param_write_int (plist, "SearchOrder", &so)) < 0 || |
604 | 0 | (code = param_write_bool(plist, "Writeable", &btrue)) < 0 || |
605 | 0 | (code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0 |
606 | 0 | ) |
607 | 0 | return code; |
608 | 0 | return 0; |
609 | 0 | } |