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