/src/ghostpdl/base/gsioram.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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_fopen(ram_fopen); |
54 | | static iodev_proc_fclose(ram_fclose); |
55 | | static iodev_proc_delete_file(ram_delete); |
56 | | static iodev_proc_rename_file(ram_rename); |
57 | | static iodev_proc_file_status(ram_status); |
58 | | static iodev_proc_enumerate_files(ram_enumerate_init); |
59 | | static iodev_proc_enumerate_next(ram_enumerate_next); |
60 | | static iodev_proc_enumerate_close(ram_enumerate_close); |
61 | | static iodev_proc_get_params(ram_get_params); |
62 | | static void ram_finalize(const gs_memory_t *memory, void * vptr); |
63 | | |
64 | | const gx_io_device gs_iodev_ram = { |
65 | | "%ram%", "FileSystem", { |
66 | | iodev_ram_init, iodev_ram_finit, iodev_no_open_device, |
67 | | ram_open_file, ram_fopen, ram_fclose, |
68 | | ram_delete, ram_rename, ram_status, |
69 | | ram_enumerate_init, ram_enumerate_next, ram_enumerate_close, |
70 | | ram_get_params, iodev_no_put_params |
71 | | }, |
72 | | NULL, |
73 | | NULL |
74 | | }; |
75 | | |
76 | | typedef struct ramfs_state_s { |
77 | | gs_memory_t *memory; |
78 | | ramfs* fs; |
79 | | } ramfs_state; |
80 | | |
81 | 381k | #define GETRAMFS(state) (((ramfs_state*)(state))->fs) |
82 | | |
83 | | gs_private_st_simple_final(st_ramfs_state, struct ramfs_state_s, "ramfs_state", ram_finalize); |
84 | | |
85 | | typedef struct gsram_enum_s { |
86 | | char *pattern; |
87 | | ramfs_enum* e; |
88 | | gs_memory_t *memory; |
89 | | } gsram_enum; |
90 | | |
91 | | gs_private_st_ptrs2(st_gsram_enum, struct gsram_enum_s, "gsram_enum", |
92 | | gsram_enum_enum_ptrs, gsram_enum_reloc_ptrs, pattern, memory); |
93 | | |
94 | | /* could make this runtime configurable later. It doesn't allocate |
95 | | all the blocks in one go so it's not critical */ |
96 | 190k | #define MAXBLOCKS 2000000 |
97 | | |
98 | 0 | #define DEFAULT_BUFFER_SIZE 2048 |
99 | | |
100 | | /* stream stuff */ |
101 | | |
102 | | static int |
103 | | s_ram_available(stream *, gs_offset_t *), |
104 | | s_ram_read_seek(stream *, gs_offset_t), |
105 | | s_ram_read_close(stream *), |
106 | | s_ram_read_process(stream_state *, stream_cursor_read *, |
107 | | stream_cursor_write *, bool); |
108 | | static int |
109 | | s_ram_write_seek(stream *, gs_offset_t), |
110 | | s_ram_write_flush(stream *), |
111 | | s_ram_write_close(stream *), |
112 | | s_ram_write_process(stream_state *, stream_cursor_read *, |
113 | | stream_cursor_write *, bool); |
114 | | static int |
115 | | s_ram_switch(stream *, bool); |
116 | | |
117 | | static int |
118 | 0 | ramfs_errno_to_code(int error_number) { |
119 | 0 | switch (error_number) { |
120 | 0 | case RAMFS_NOTFOUND: |
121 | 0 | return_error(gs_error_undefinedfilename); |
122 | 0 | case RAMFS_NOACCESS: |
123 | 0 | return_error(gs_error_invalidfileaccess); |
124 | 0 | case RAMFS_NOMEM: |
125 | 0 | return_error(gs_error_VMerror); |
126 | 0 | case RAMFS_BADRANGE: |
127 | 0 | return_error(gs_error_rangecheck); |
128 | 0 | case RAMFS_DELETEOPENFILE: |
129 | 0 | return_error(gs_error_ioerror); |
130 | | /* just in case */ |
131 | 0 | default: |
132 | 0 | return_error(gs_error_ioerror); |
133 | 0 | } |
134 | 0 | } |
135 | | |
136 | | static void |
137 | | sread_ram(register stream * s, ramhandle * file, byte * buf, uint len), |
138 | | swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len), |
139 | | sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len); |
140 | | |
141 | | static int |
142 | | ram_open_file(gx_io_device * iodev, const char *fname, uint len, |
143 | | const char *file_access, stream ** ps, gs_memory_t * mem) |
144 | 0 | { |
145 | 0 | int code = 0; |
146 | 0 | ramhandle * file; |
147 | 0 | char fmode[4]; /* r/w/a, [+], [b], null */ |
148 | 0 | int openmode=RAMFS_READ; |
149 | 0 | ramfs * fs; |
150 | 0 | char * namestr = NULL; |
151 | | |
152 | | /* Is there a more efficient way to do this? */ |
153 | 0 | namestr = (char *)gs_alloc_bytes(mem, len + 1, "temporary filename string"); |
154 | 0 | if(!namestr) |
155 | 0 | return_error(gs_error_VMerror); |
156 | 0 | strncpy(namestr,fname,len); |
157 | 0 | namestr[len] = 0; |
158 | | |
159 | | /* Make sure iodev is valid, and we have initialised the RAM file system (state != NULL) */ |
160 | 0 | if (iodev == NULL || iodev->state == NULL) {/*iodev = iodev_default;*/ |
161 | 0 | gs_free_object(mem, namestr, "free temporary filename string"); |
162 | 0 | return gs_note_error(gs_error_invalidaccess); |
163 | 0 | } |
164 | 0 | fs = GETRAMFS(iodev->state); |
165 | 0 | code = file_prepare_stream(fname, len, file_access, DEFAULT_BUFFER_SIZE, |
166 | 0 | ps, fmode, mem |
167 | 0 | ); |
168 | 0 | if (code < 0) goto error; |
169 | 0 | if (fname == 0) { |
170 | 0 | gs_free_object(mem, namestr, "free temporary filename string"); |
171 | 0 | return 0; |
172 | 0 | } |
173 | | |
174 | 0 | switch (fmode[0]) { |
175 | 0 | case 'a': |
176 | 0 | openmode = RAMFS_WRITE | RAMFS_APPEND; |
177 | 0 | break; |
178 | 0 | case 'r': |
179 | 0 | openmode = RAMFS_READ; |
180 | 0 | if (fmode[1] == '+') |
181 | 0 | openmode |= RAMFS_WRITE; |
182 | 0 | break; |
183 | 0 | case 'w': |
184 | 0 | openmode |= RAMFS_WRITE | RAMFS_TRUNC | RAMFS_CREATE; |
185 | 0 | if (fmode[1] == '+') |
186 | 0 | openmode |= RAMFS_READ; |
187 | 0 | } |
188 | | |
189 | | /* For now, we cheat here in the same way that sfxstdio.c et al cheat - |
190 | | append mode is faked by opening in write mode and seeking to EOF just |
191 | | once. This is different from unix semantics, which seeks atomically |
192 | | before each write, and is actually useful as a distinct mode. */ |
193 | | /* if (fmode[0] == 'a') openmode |= RAMFS_APPEND; */ |
194 | | |
195 | 0 | file = ramfs_open(mem, fs,namestr,openmode); |
196 | 0 | if(!file) { code = ramfs_errno_to_code(ramfs_error(fs)); goto error; } |
197 | | |
198 | 0 | switch (fmode[0]) { |
199 | 0 | case 'a': |
200 | 0 | sappend_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); |
201 | 0 | break; |
202 | 0 | case 'r': |
203 | 0 | sread_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); |
204 | 0 | break; |
205 | 0 | case 'w': |
206 | 0 | swrite_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); |
207 | 0 | } |
208 | 0 | if (fmode[1] == '+') { |
209 | 0 | (*ps)->modes = (*ps)->file_modes |= s_mode_read | s_mode_write; |
210 | 0 | } |
211 | 0 | (*ps)->save_close = (*ps)->procs.close; |
212 | 0 | (*ps)->procs.close = file_close_file; |
213 | 0 | error: |
214 | 0 | gs_free_object(mem, namestr, "free temporary filename string"); |
215 | | /* XXX free stream stuff? */ |
216 | 0 | return code; |
217 | 0 | } |
218 | | |
219 | | static const gp_file_ops_t gp_file_RAM_prototype = |
220 | | { |
221 | | gp_file_ram_close, |
222 | | gp_file_ram_getc, |
223 | | gp_file_ram_putc, |
224 | | gp_file_ram_read, |
225 | | gp_file_ram_write, |
226 | | gp_file_ram_seek, |
227 | | gp_file_ram_tell, |
228 | | gp_file_ram_eof, |
229 | | gp_file_ram_dup, |
230 | | gp_file_ram_seekable, |
231 | | gp_file_ram_pread, |
232 | | gp_file_ram_pwrite, |
233 | | gp_file_ram_is_char_buffered, |
234 | | gp_file_ram_fflush, |
235 | | gp_file_ram_ferror, |
236 | | gp_file_ram_get_file, |
237 | | gp_file_ram_clearerror, |
238 | | gp_file_ram_reopen |
239 | | }; |
240 | | |
241 | | static gp_file_RAM *gp_file_RAM_alloc(const gs_memory_t *mem) |
242 | 0 | { |
243 | 0 | return (gp_file_RAM *)gp_file_alloc(mem->non_gc_memory, |
244 | 0 | &gp_file_RAM_prototype, |
245 | 0 | sizeof(gp_file_RAM), |
246 | 0 | "gp_file_RAM"); |
247 | 0 | } |
248 | | |
249 | | int ram_fopen(gx_io_device *iodev, const char *fname, const char *access, |
250 | | gp_file **pfile, char *rfname, uint rnamelen, gs_memory_t *mem) |
251 | 0 | { |
252 | 0 | ramfs_state* state = (ramfs_state *)iodev->state; |
253 | 0 | gp_file_RAM **file = (gp_file_RAM **)pfile; |
254 | 0 | int i, mode = 0; |
255 | |
|
256 | 0 | *file = gp_file_RAM_alloc(mem); |
257 | 0 | if (*file == NULL) |
258 | 0 | return 0; |
259 | | |
260 | 0 | for (i=0;i<strlen(access);i++) { |
261 | 0 | if (access[i] == 'r') |
262 | 0 | mode |= RAMFS_READ; |
263 | 0 | else { |
264 | 0 | if (access[i] == 'w') { |
265 | 0 | mode |= RAMFS_WRITE; |
266 | 0 | mode |= RAMFS_CREATE; |
267 | 0 | mode |= RAMFS_TRUNC; |
268 | 0 | } |
269 | 0 | else |
270 | 0 | { |
271 | 0 | if (access[i] == 'a') { |
272 | 0 | mode |= RAMFS_APPEND; |
273 | 0 | mode |= RAMFS_CREATE; |
274 | 0 | } |
275 | 0 | else { |
276 | 0 | if (access[i] == '+') { |
277 | 0 | if (mode & RAMFS_WRITE) |
278 | 0 | mode |= RAMFS_READ; |
279 | 0 | else |
280 | 0 | mode |= RAMFS_WRITE; |
281 | 0 | } |
282 | 0 | else |
283 | 0 | if (access[i] == 'b') |
284 | 0 | ; |
285 | 0 | else |
286 | 0 | return 0; |
287 | 0 | } |
288 | 0 | } |
289 | 0 | } |
290 | 0 | } |
291 | 0 | (*file)->handle = ramfs_open(iodev->memory, state->fs, fname, mode); |
292 | 0 | if ((*file)->handle == NULL) |
293 | 0 | return_error(gs_error_undefinedfilename); |
294 | | |
295 | 0 | if (rfname != NULL && rfname != fname) |
296 | 0 | strcpy(rfname, fname); |
297 | |
|
298 | 0 | return 0; |
299 | 0 | } |
300 | | |
301 | | int ram_fclose(gx_io_device *iodev, gp_file *file) |
302 | 0 | { |
303 | 0 | gp_file_RAM *pfile = (gp_file_RAM *)file; |
304 | |
|
305 | 0 | ramfile_close(pfile->handle); |
306 | 0 | return 0; |
307 | 0 | } |
308 | | |
309 | | /* Initialize a stream for reading an OS file. */ |
310 | | static void |
311 | | sread_ram(register stream * s, ramhandle * file, byte * buf, uint len) |
312 | 0 | { |
313 | 0 | static const stream_procs p = { |
314 | 0 | s_ram_available, s_ram_read_seek, s_std_read_reset, |
315 | 0 | s_std_read_flush, s_ram_read_close, s_ram_read_process, |
316 | 0 | s_ram_switch |
317 | 0 | }; |
318 | |
|
319 | 0 | s_std_init(s, buf, len, &p,s_mode_read + s_mode_seek); |
320 | 0 | s->file = (gp_file *)file; |
321 | 0 | s->file_modes = s->modes; |
322 | 0 | s->file_offset = 0; |
323 | 0 | ramfile_seek(file, 0, RAMFS_SEEK_END); |
324 | 0 | s->file_limit = ramfile_tell(file); |
325 | 0 | ramfile_seek(file, 0, RAMFS_SEEK_SET); |
326 | 0 | } |
327 | | |
328 | | /* Procedures for reading from a file */ |
329 | | static int |
330 | | s_ram_available(register stream * s, gs_offset_t *pl) |
331 | 0 | { |
332 | 0 | long max_avail = s->file_limit - stell(s); |
333 | |
|
334 | 0 | *pl = max_avail; |
335 | 0 | if(*pl == 0 && ramfile_eof((ramhandle*)s->file)) |
336 | 0 | *pl = -1; /* EOF */ |
337 | 0 | return 0; |
338 | 0 | } |
339 | | |
340 | | static int |
341 | | s_ram_read_seek(register stream * s, gs_offset_t pos) |
342 | 0 | { |
343 | 0 | uint end = s->cursor.r.limit - s->cbuf + 1; |
344 | 0 | long offset = pos - s->position; |
345 | |
|
346 | 0 | if (offset >= 0 && offset <= end) { /* Staying within the same buffer */ |
347 | 0 | s->cursor.r.ptr = s->cbuf + offset - 1; |
348 | 0 | return 0; |
349 | 0 | } |
350 | | |
351 | 0 | if (pos < 0 || pos > s->file_limit || s->file == NULL || |
352 | 0 | ramfile_seek((ramhandle*)s->file, s->file_offset + pos, RAMFS_SEEK_SET) != 0) |
353 | 0 | return ERRC; |
354 | | |
355 | 0 | s->cursor.r.ptr = s->cursor.r.limit = s->cbuf - 1; |
356 | 0 | s->end_status = 0; |
357 | 0 | s->position = pos; |
358 | 0 | return 0; |
359 | 0 | } |
360 | | static int |
361 | | s_ram_read_close(stream * s) |
362 | 0 | { |
363 | 0 | ramhandle *file = (ramhandle*)s->file; |
364 | |
|
365 | 0 | if (file != 0) { |
366 | 0 | s->file = 0; |
367 | 0 | ramfile_close(file); |
368 | 0 | } |
369 | 0 | return 0; |
370 | 0 | } |
371 | | |
372 | | /* |
373 | | * Process a buffer for a file reading stream. |
374 | | * This is the first stream in the pipeline, so pr is irrelevant. |
375 | | */ |
376 | | static int |
377 | | s_ram_read_process(stream_state * st, stream_cursor_read * ignore_pr, |
378 | | stream_cursor_write * pw, bool last) |
379 | 0 | { |
380 | 0 | stream *s = (stream *)st; /* no separate state */ |
381 | 0 | ramhandle *file = (ramhandle*)s->file; |
382 | 0 | uint max_count = pw->limit - pw->ptr; |
383 | 0 | int status = 1; |
384 | 0 | int count; |
385 | |
|
386 | 0 | if (s->file_limit < S_FILE_LIMIT_MAX) { |
387 | 0 | long limit_count = s->file_offset + s->file_limit - |
388 | 0 | ramfile_tell(file); |
389 | |
|
390 | 0 | if (max_count > limit_count) |
391 | 0 | max_count = limit_count, status = EOFC; |
392 | 0 | } |
393 | 0 | count = ramfile_read(file,pw->ptr + 1, max_count); |
394 | 0 | if (count < 0) return ERRC; |
395 | 0 | pw->ptr += count; |
396 | | /* process_interrupts(s->memory); */ |
397 | 0 | return ramfile_eof(file) ? EOFC : status; |
398 | 0 | } |
399 | | |
400 | | /* ------ File writing ------ */ |
401 | | |
402 | | /* Initialize a stream for writing a file. */ |
403 | | static void |
404 | | swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len) |
405 | 0 | { |
406 | 0 | static const stream_procs p = { |
407 | 0 | s_std_noavailable, s_ram_write_seek, s_std_write_reset, |
408 | 0 | s_ram_write_flush, s_ram_write_close, s_ram_write_process, |
409 | 0 | s_ram_switch |
410 | 0 | }; |
411 | |
|
412 | 0 | s_std_init(s, buf, len, &p, s_mode_write + s_mode_seek); |
413 | 0 | s->file = (gp_file *)file; |
414 | 0 | s->file_modes = s->modes; |
415 | 0 | s->file_offset = 0; /* in case we switch to reading later */ |
416 | 0 | s->file_limit = S_FILE_LIMIT_MAX; |
417 | 0 | } |
418 | | |
419 | | /* Initialize for appending to a file. */ |
420 | | static void |
421 | | sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len) |
422 | 0 | { |
423 | 0 | swrite_ram(s, file, buf, len); |
424 | 0 | s->modes = s_mode_write + s_mode_append; /* no seek */ |
425 | 0 | s->file_modes = s->modes; |
426 | 0 | ramfile_seek(file,0,RAMFS_SEEK_END); |
427 | 0 | s->position = ramfile_tell(file); |
428 | 0 | } |
429 | | |
430 | | /* Procedures for writing on a file */ |
431 | | static int |
432 | | s_ram_write_seek(stream * s, gs_offset_t pos) |
433 | 0 | { |
434 | | /* We must flush the buffer to reposition. */ |
435 | 0 | int code = sflush(s); |
436 | |
|
437 | 0 | if (code < 0) return code; |
438 | 0 | if (pos < 0 || ramfile_seek((ramhandle*)s->file, pos, RAMFS_SEEK_SET) != 0) |
439 | 0 | return ERRC; |
440 | 0 | s->position = pos; |
441 | 0 | return 0; |
442 | 0 | } |
443 | | |
444 | | static int |
445 | | s_ram_write_flush(register stream * s) |
446 | 0 | { |
447 | 0 | int result = s_process_write_buf(s, false); |
448 | 0 | return result; |
449 | 0 | } |
450 | | |
451 | | static int |
452 | | s_ram_write_close(register stream * s) |
453 | 0 | { |
454 | 0 | s_process_write_buf(s, true); |
455 | 0 | return s_ram_read_close(s); |
456 | 0 | } |
457 | | |
458 | | /* |
459 | | * Process a buffer for a file writing stream. |
460 | | * This is the last stream in the pipeline, so pw is irrelevant. |
461 | | */ |
462 | | static int |
463 | | s_ram_write_process(stream_state * st, stream_cursor_read * pr, |
464 | | stream_cursor_write * ignore_pw, bool last) |
465 | 0 | { |
466 | 0 | uint count = pr->limit - pr->ptr; |
467 | |
|
468 | 0 | ramhandle *file = (ramhandle*)((stream *) st)->file; |
469 | 0 | int written = ramfile_write(file,pr->ptr + 1, count); |
470 | |
|
471 | 0 | if (written < 0) return ERRC; |
472 | 0 | pr->ptr += written; |
473 | 0 | return 0; |
474 | 0 | } |
475 | | |
476 | | static int |
477 | | s_ram_switch(stream * s, bool writing) |
478 | 0 | { |
479 | 0 | uint modes = s->file_modes; |
480 | 0 | ramhandle *file = (ramhandle*)s->file; |
481 | 0 | long pos; |
482 | |
|
483 | 0 | if (writing) { |
484 | 0 | if (!(s->file_modes & s_mode_write)) return ERRC; |
485 | 0 | pos = stell(s); |
486 | 0 | ramfile_seek(file, pos, RAMFS_SEEK_SET); |
487 | 0 | if (modes & s_mode_append) { |
488 | 0 | sappend_ram(s, file, s->cbuf, s->cbsize); /* sets position */ |
489 | 0 | } else { |
490 | 0 | swrite_ram(s, file, s->cbuf, s->cbsize); |
491 | 0 | s->position = pos; |
492 | 0 | } |
493 | 0 | s->modes = modes; |
494 | 0 | } else { |
495 | 0 | if (!(s->file_modes & s_mode_read)) return ERRC; |
496 | 0 | pos = stell(s); |
497 | 0 | if (sflush(s) < 0) return ERRC; |
498 | 0 | sread_ram(s, file, s->cbuf, s->cbsize); |
499 | 0 | s->modes |= modes & s_mode_append; /* don't lose append info */ |
500 | 0 | s->position = pos; |
501 | 0 | } |
502 | 0 | s->file_modes = modes; |
503 | 0 | return 0; |
504 | 0 | } |
505 | | |
506 | | |
507 | | /* gx_io_device stuff */ |
508 | | |
509 | | static int |
510 | | iodev_ram_init(gx_io_device * iodev, gs_memory_t * mem) |
511 | 190k | { |
512 | 190k | ramfs* fs = ramfs_new(mem, MAXBLOCKS); |
513 | 190k | ramfs_state* state = gs_alloc_struct(mem, ramfs_state, &st_ramfs_state, |
514 | 190k | "ramfs_init(state)" |
515 | 190k | ); |
516 | 190k | if (fs && state) { |
517 | 190k | state->fs = fs; |
518 | 190k | state->memory = mem; |
519 | 190k | iodev->state = state; |
520 | 190k | return 0; |
521 | 190k | } |
522 | 0 | if(fs) ramfs_destroy(mem, fs); |
523 | 0 | if(state) gs_free_object(mem,state,"iodev_ram_init(state)"); |
524 | 0 | return_error(gs_error_VMerror); |
525 | 190k | } |
526 | | |
527 | | static void |
528 | | iodev_ram_finit(gx_io_device * iodev, gs_memory_t * mem) |
529 | 61.1k | { |
530 | 61.1k | ramfs_state *state = (ramfs_state *)iodev->state; |
531 | 61.1k | if (state != NULL) |
532 | 61.1k | { |
533 | 61.1k | iodev->state = NULL; |
534 | 61.1k | gs_free_object(state->memory, state, "iodev_ram_finit"); |
535 | 61.1k | } |
536 | 61.1k | return; |
537 | 61.1k | } |
538 | | |
539 | | static void |
540 | | ram_finalize(const gs_memory_t *memory, void * vptr) |
541 | 190k | { |
542 | 190k | ramfs* fs = GETRAMFS((ramfs_state*)vptr); |
543 | 190k | ramfs_destroy((gs_memory_t *)memory, fs); |
544 | 190k | GETRAMFS((ramfs_state*)vptr) = NULL; |
545 | 190k | } |
546 | | |
547 | | static int |
548 | | ram_delete(gx_io_device * iodev, const char *fname) |
549 | 0 | { |
550 | 0 | ramfs* fs; |
551 | |
|
552 | 0 | if (iodev->state == NULL) |
553 | 0 | return_error(gs_error_ioerror); |
554 | 0 | else |
555 | 0 | fs = GETRAMFS(iodev->state); |
556 | | |
557 | 0 | if(ramfs_unlink(fs,fname)!=0) { |
558 | 0 | return_error(ramfs_errno_to_code(ramfs_error(fs))); |
559 | 0 | } |
560 | 0 | return 0; |
561 | 0 | } |
562 | | |
563 | | static int |
564 | | ram_rename(gx_io_device * iodev, const char *from, const char *to) |
565 | 0 | { |
566 | 0 | ramfs* fs; |
567 | |
|
568 | 0 | if (iodev->state == NULL) |
569 | 0 | return_error(gs_error_ioerror); |
570 | 0 | else |
571 | 0 | fs = GETRAMFS(iodev->state); |
572 | | |
573 | 0 | if(ramfs_rename(fs,from,to)!=0) { |
574 | 0 | return_error(ramfs_errno_to_code(ramfs_error(fs))); |
575 | 0 | } |
576 | 0 | return 0; |
577 | 0 | } |
578 | | |
579 | | static int |
580 | | ram_status(gx_io_device * iodev, const char *fname, struct stat *pstat) |
581 | 0 | { |
582 | 0 | ramhandle * f; |
583 | 0 | ramfs* fs; |
584 | |
|
585 | 0 | if (iodev->state == NULL) |
586 | 0 | return_error(gs_error_ioerror); |
587 | 0 | else |
588 | 0 | fs = GETRAMFS(iodev->state); |
589 | | |
590 | 0 | f = ramfs_open(((ramfs_state *)iodev->state)->memory, fs,fname,RAMFS_READ); |
591 | 0 | if(!f) return_error(ramfs_errno_to_code(ramfs_error(fs))); |
592 | | |
593 | 0 | memset(pstat, 0, sizeof(*pstat)); |
594 | 0 | pstat->st_size = ramfile_size(f); |
595 | | /* The Windows definition of struct stat doesn't include a st_blocks member |
596 | | pstat->st_blocks = (pstat->st_size+blocksize-1)/blocksize;*/ |
597 | | /* XXX set mtime & ctime */ |
598 | 0 | ramfile_close(f); |
599 | 0 | return 0; |
600 | 0 | } |
601 | | |
602 | | static file_enum * |
603 | | ram_enumerate_init(gs_memory_t * mem, gx_io_device *iodev, const char *pat, |
604 | | uint patlen) |
605 | 0 | { |
606 | 0 | gsram_enum * penum = gs_alloc_struct( |
607 | 0 | mem, gsram_enum, &st_gsram_enum, |
608 | 0 | "ram_enumerate_files_init(file_enum)" |
609 | 0 | ); |
610 | 0 | char *pattern = (char *)gs_alloc_bytes( |
611 | 0 | mem, patlen+1, "ram_enumerate_file_init(pattern)" |
612 | 0 | ); |
613 | |
|
614 | 0 | ramfs_enum * e; |
615 | |
|
616 | 0 | if (iodev->state == NULL) |
617 | 0 | return NULL; |
618 | 0 | else |
619 | 0 | e = ramfs_enum_new(GETRAMFS(iodev->state)); |
620 | | |
621 | 0 | if(penum && pattern && e) { |
622 | 0 | memcpy(pattern, pat, patlen); |
623 | 0 | pattern[patlen]=0; |
624 | |
|
625 | 0 | penum->memory = mem; |
626 | 0 | penum->pattern = pattern; |
627 | 0 | penum->e = e; |
628 | 0 | return (file_enum *)penum; |
629 | 0 | } |
630 | 0 | if (penum) gs_free_object(mem,penum,"ramfs_enum_init(ramfs_enum)"); |
631 | 0 | if (pattern) |
632 | 0 | gs_free_object(mem, pattern, "ramfs_enum_init(pattern)"); |
633 | 0 | if(e) ramfs_enum_end(e); |
634 | 0 | return NULL; |
635 | 0 | } |
636 | | |
637 | | static void |
638 | | ram_enumerate_close(gs_memory_t * mem, file_enum *pfen) |
639 | 0 | { |
640 | 0 | gsram_enum *penum = (gsram_enum *)pfen; |
641 | 0 | gs_memory_t *mem2 = penum->memory; |
642 | 0 | (void)mem; |
643 | |
|
644 | 0 | ramfs_enum_end(penum->e); |
645 | 0 | gs_free_object(mem2, penum->pattern, "ramfs_enum_init(pattern)"); |
646 | 0 | gs_free_object(mem2, penum, "ramfs_enum_init(ramfs_enum)"); |
647 | 0 | } |
648 | | |
649 | | static uint |
650 | | ram_enumerate_next(gs_memory_t * mem, file_enum *pfen, char *ptr, uint maxlen) |
651 | 0 | { |
652 | 0 | gsram_enum *penum = (gsram_enum *)pfen; |
653 | |
|
654 | 0 | char * filename; |
655 | 0 | while ((filename = ramfs_enum_next(penum->e))) { |
656 | 0 | if (string_match((byte *)filename, strlen(filename), |
657 | 0 | (byte *)penum->pattern, |
658 | 0 | strlen(penum->pattern), 0)) { |
659 | 0 | if (strlen(filename) < maxlen) |
660 | 0 | memcpy(ptr, filename, strlen(filename)); |
661 | 0 | return strlen(filename); /* if > maxlen, caller will detect rangecheck */ |
662 | 0 | } |
663 | 0 | } |
664 | | /* ran off end of list, close the enum */ |
665 | 0 | ram_enumerate_close(mem, pfen); |
666 | 0 | return ~(uint)0; |
667 | 0 | } |
668 | | |
669 | | static int |
670 | | ram_get_params(gx_io_device * iodev, gs_param_list * plist) |
671 | 0 | { |
672 | 0 | int code; |
673 | 0 | int i0 = 0, so = 1; |
674 | 0 | bool btrue = true, bfalse = false; |
675 | 0 | ramfs* fs; |
676 | |
|
677 | 0 | int BlockSize; |
678 | 0 | long Free, LogicalSize; |
679 | |
|
680 | 0 | if (iodev->state == NULL) |
681 | 0 | return_error(gs_error_ioerror); |
682 | 0 | else |
683 | 0 | fs = GETRAMFS(iodev->state); |
684 | | |
685 | 0 | BlockSize = ramfs_blocksize(fs); |
686 | 0 | LogicalSize = MAXBLOCKS; |
687 | 0 | Free = ramfs_blocksfree(fs); |
688 | |
|
689 | 0 | if ( |
690 | 0 | (code = param_write_bool(plist, "HasNames", &btrue)) < 0 || |
691 | 0 | (code = param_write_int (plist, "BlockSize", &BlockSize)) < 0 || |
692 | 0 | (code = param_write_long(plist, "Free", &Free)) < 0 || |
693 | 0 | (code = param_write_int (plist, "InitializeAction",&i0)) < 0 || |
694 | 0 | (code = param_write_bool(plist, "Mounted", &btrue)) < 0 || |
695 | 0 | (code = param_write_bool(plist, "Removable", &bfalse)) < 0 || |
696 | 0 | (code = param_write_bool(plist, "Searchable", &btrue)) < 0 || |
697 | 0 | (code = param_write_int (plist, "SearchOrder", &so)) < 0 || |
698 | 0 | (code = param_write_bool(plist, "Writeable", &btrue)) < 0 || |
699 | 0 | (code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0 |
700 | 0 | ) |
701 | 0 | return code; |
702 | 0 | return 0; |
703 | 0 | } |