diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2013-06-14 10:33:19 +0100 |
---|---|---|
committer | Ken Sharp <ken.sharp@artifex.com> | 2013-06-14 11:09:52 +0100 |
commit | 1ebbb14391559b4da0c623e6c02840f7e41aa10b (patch) | |
tree | 25871d3d727017edcaf3dd249338b1f1adbb67cf | |
parent | cb2e0f784882696e930e5077ecb1a2feef76fadf (diff) | |
download | ghostpdl-1ebbb14391559b4da0c623e6c02840f7e41aa10b.tar.gz |
temporary commit of ramfs changes for chris to look at
-rw-r--r-- | gs/Makefile.in | 4 | ||||
-rw-r--r-- | gs/base/gsioram.c | 527 | ||||
-rw-r--r-- | gs/base/lib.mak | 15 | ||||
-rw-r--r-- | gs/base/ramfs.c | 453 | ||||
-rw-r--r-- | gs/base/ramfs.h | 62 | ||||
-rw-r--r-- | gs/psi/msvc.mak | 2 |
6 files changed, 1060 insertions, 3 deletions
diff --git a/gs/Makefile.in b/gs/Makefile.in index 6808a0de2..3111b3f0d 100644 --- a/gs/Makefile.in +++ b/gs/Makefile.in @@ -451,11 +451,11 @@ DYNANIC_LIB_EXT = @DYNANIC_LIB_EXT@ # Choose the language feature(s) to include. See gs.mak for details. -FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)epsf.dev $(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev @JBIG2DEVS@ @JPXDEVS@ @UTF8DEVS@ +FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)epsf.dev $(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev @JBIG2DEVS@ @JPXDEVS@ @UTF8DEVS@ $(GLD)ramfs.dev #FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev #FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)rasterop.dev $(GLD)pipe.dev # The following is strictly for testing. -FEATURE_DEVS_ALL=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)rasterop.dev $(PSD)double.dev $(PSD)trapping.dev $(PSD)stocht.dev $(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev @JBIG2DEVS@ @JPXDEVS@ @UTF8DEVS@ +FEATURE_DEVS_ALL=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)rasterop.dev $(PSD)double.dev $(PSD)trapping.dev $(PSD)stocht.dev $(GLD)pipe.dev $(GLD)gsnogc.dev $(GLD)htxlib.dev @JBIG2DEVS@ @JPXDEVS@ @UTF8DEVS@ $(GLD)ramfs.dev #FEATURE_DEVS=$(FEATURE_DEVS_ALL) # The list of resources to be included in the %rom% file system. diff --git a/gs/base/gsioram.c b/gs/base/gsioram.c new file mode 100644 index 000000000..bd2cee302 --- /dev/null +++ b/gs/base/gsioram.c @@ -0,0 +1,527 @@ +/* $Id$ */ +/* %ram% file device implementation */ + +/* + * This file implements a simple ram-based file system. + * + * The fs has no subdirs, only a root directory. Files are stored as a + * resizable array of pointers to blocks. Timestamps are not implemented + * for performance reasons. + * + * The implementation is in two parts - a ramfs interface that works + * mostly like the unix file system calls, and a layer to hook this up + * to ghostscript. + * + * Macros define an upper limit on the number of blocks a ram device + * can take up, and (in ramfs.c) the size of each block. + * + * Routines for the gs stream interface were graciously stolen from + * sfxstdio.c et al. + */ + +#include "string_.h" +#include "unistd_.h" +#include "gx.h" +#include "gserrors.h" +#include "gp.h" +#include "gscdefs.h" +#include "gsparam.h" +#include "gsstruct.h" +#include "gxiodev.h" +#include "gsutil.h" +#include "stream.h" +#include "ramfs.h" +#include <malloc.h> + +/* Function prototypes */ +static iodev_proc_init(iodev_ram_init); +static iodev_proc_open_file(ram_open_file); +static iodev_proc_delete_file(ram_delete); +static iodev_proc_rename_file(ram_rename); +static iodev_proc_file_status(ram_status); +static iodev_proc_enumerate_files(ram_enumerate_init); +static iodev_proc_enumerate_next(ram_enumerate_next); +static iodev_proc_enumerate_close(ram_enumerate_close); +static iodev_proc_get_params(ram_get_params); +static iodev_proc_put_params(ram_put_params); +static void ram_finalize(const gs_memory_t *memory, void * vptr); + +const gx_io_device gs_iodev_ram = { + "%ram%", "FileSystem", { + iodev_ram_init, iodev_no_open_device, + ram_open_file, iodev_no_fopen, iodev_no_fclose, + ram_delete, ram_rename, ram_status, + ram_enumerate_init, ram_enumerate_next, ram_enumerate_close, + ram_get_params, iodev_no_put_params + } +}; + +typedef struct ramfs_state_s { + char *t; + ramfs* fs; +} ramfs_state; + +#define GETRAMFS(state) (((ramfs_state*)(state))->fs) + +gs_private_st_ptrs2_final(st_ramfs_state, struct ramfs_state_s, + "ramfs_state", ramfs_state_enum_ptrs, ramfs_state_reloc_ptrs, ram_finalize, t, fs); + +typedef struct gsram_enum_s { + char *pattern; + ramfs_enum* e; + gs_memory_t *memory; +} gsram_enum; + +gs_private_st_ptrs3(st_gsram_enum, struct gsram_enum_s, "gsram_enum", + gsram_enum_enum_ptrs, gsram_enum_reloc_ptrs, pattern, e, memory); + +/* could make this runtime configurable later. It doesn't allocate + all the blocks in one go so it's not critical */ +#define MAXBLOCKS 2000000 + +#define DEFAULT_BUFFER_SIZE 2048 + +/* stream stuff */ + +static int +s_ram_available(stream *, gs_offset_t *), + s_ram_read_seek(stream *, gs_offset_t), + s_ram_read_close(stream *), + s_ram_read_process(stream_state *, stream_cursor_read *, + stream_cursor_write *, bool); +static int +s_ram_write_seek(stream *, gs_offset_t), + s_ram_write_flush(stream *), + s_ram_write_close(stream *), + s_ram_write_process(stream_state *, stream_cursor_read *, + stream_cursor_write *, bool); +static int +s_ram_switch(stream *, bool); + +static int +ramfs_errno_to_code(int errno) { + switch (errno) { + case RAMFS_NOTFOUND: + return_error(gs_error_undefinedfilename); + case RAMFS_NOACCESS: + return_error(gs_error_invalidfileaccess); + case RAMFS_NOMEM: + return_error(gs_error_VMerror); + /* just in case */ + default: + return_error(gs_error_ioerror); + } +} + +static void +sread_ram(register stream * s, ramhandle * file, byte * buf, uint len), + swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len), + sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len); + +static int +ram_open_file(gx_io_device * iodev, const char *fname, uint len, + const char *file_access, stream ** ps, gs_memory_t * mem) +{ + int code = 0; + ramhandle * file; + char fmode[4]; /* r/w/a, [+], [b], null */ + int openmode=RAMFS_READ; + ramfs * fs = GETRAMFS(iodev->state); + char * namestr = NULL; + + /* Is there a more efficient way to do this? */ + namestr = malloc(len+1); + if(!namestr) return_error(gs_error_VMerror); + strncpy(namestr,fname,len); + namestr[len] = 0; + + if (!iodev) /*iodev = iodev_default;*/ + return gs_note_error(gs_error_invalidaccess); + code = file_prepare_stream(fname, len, file_access, DEFAULT_BUFFER_SIZE, + ps, fmode, mem + ); + if (code < 0) goto error; + if (fname == 0) return 0; + + if (fmode[0] != 'r' || fmode[1] == '+') openmode |= RAMFS_WRITE; + if (fmode[0] != 'r') openmode |= RAMFS_CREATE; + + /* For now, we cheat here in the same way that sfxstdio.c et al cheat - + append mode is faked by opening in write mode and seeking to EOF just + once. This is different from unix semantics, which seeks atomically + before each write, and is actually useful as a distinct mode. */ + /* if (fmode[0] == 'a') openmode |= RAMFS_APPEND; */ + + file = ramfs_open(mem, fs,namestr,openmode); + if(!file) { code = ramfs_errno_to_code(ramfs_error(fs)); goto error; } + + switch (fmode[0]) { + case 'a': + sappend_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); + break; + case 'r': + sread_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); + break; + case 'w': + swrite_ram(*ps, file, (*ps)->cbuf, (*ps)->bsize); + } + (*ps)->save_close = (*ps)->procs.close; + (*ps)->procs.close = file_close_file; + error: + free(namestr); + /* XXX free stream stuff? */ + return code; +} + +/* Initialize a stream for reading an OS file. */ +static void +sread_ram(register stream * s, ramhandle * file, byte * buf, uint len) +{ + static const stream_procs p = { + s_ram_available, s_ram_read_seek, s_std_read_reset, + s_std_read_flush, s_ram_read_close, s_ram_read_process, + s_ram_switch + }; + + s_std_init(s, buf, len, &p,s_mode_read + s_mode_seek); + s->file = (FILE*)file; + s->file_modes = s->modes; + s->file_offset = 0; + /* XXX get a more sensible number from the fs? */ + s->file_limit = max_long; +} + +/* Procedures for reading from a file */ +static int +s_ram_available(register stream * s, gs_offset_t *pl) +{ + long max_avail = s->file_limit - stell(s); + long buf_avail = sbufavailable(s); + + *pl = min(max_avail, buf_avail); + if(*pl == 0 && ramfile_eof((ramhandle*)s->file)) + *pl = -1; /* EOF */ + return 0; +} + +static int +s_ram_read_seek(register stream * s, gs_offset_t pos) +{ + uint end = s->srlimit - s->cbuf + 1; + long offset = pos - s->position; + + if (offset >= 0 && offset <= end) { /* Staying within the same buffer */ + s->srptr = s->cbuf + offset - 1; + return 0; + } + if (pos < 0 || pos > s->file_limit || + ramfile_seek((ramhandle*)s->file, s->file_offset + pos, RAMFS_SEEK_SET) != 0 + ) + return ERRC; + s->srptr = s->srlimit = s->cbuf - 1; + s->end_status = 0; + s->position = pos; + return 0; +} +static int +s_ram_read_close(stream * s) +{ + ramhandle *file = (ramhandle*)s->file; + + if (file != 0) { + s->file = 0; + ramfile_close(file); + } + return 0; +} + +/* + * Process a buffer for a file reading stream. + * This is the first stream in the pipeline, so pr is irrelevant. + */ +static int +s_ram_read_process(stream_state * st, stream_cursor_read * ignore_pr, + stream_cursor_write * pw, bool last) +{ + stream *s = (stream *)st; /* no separate state */ + ramhandle *file = (ramhandle*)s->file; + uint max_count = pw->limit - pw->ptr; + int status = 1; + int count; + + if (s->file_limit < max_long) { + long limit_count = s->file_offset + s->file_limit - + ramfile_tell(file); + + if (max_count > limit_count) + max_count = limit_count, status = EOFC; + } + count = ramfile_read(file,pw->ptr + 1, max_count); + if (count < 0) return ERRC; + pw->ptr += count; + /* process_interrupts(s->memory); */ + return ramfile_eof(file) ? EOFC : status; +} + +/* ------ File writing ------ */ + +/* Initialize a stream for writing a file. */ +static void +swrite_ram(register stream * s, ramhandle * file, byte * buf, uint len) +{ + static const stream_procs p = { + s_std_noavailable, s_ram_write_seek, s_std_write_reset, + s_ram_write_flush, s_ram_write_close, s_ram_write_process, + s_ram_switch + }; + + s_std_init(s, buf, len, &p, s_mode_write + s_mode_seek); + s->file = (FILE*)file; + s->file_modes = s->modes; + s->file_offset = 0; /* in case we switch to reading later */ + s->file_limit = max_long; /* ibid. */ +} + +/* Initialize for appending to a file. */ +static void +sappend_ram(register stream * s, ramhandle * file, byte * buf, uint len) +{ + swrite_ram(s, file, buf, len); + s->modes = s_mode_write + s_mode_append; /* no seek */ + s->file_modes = s->modes; + ramfile_seek(file,0,RAMFS_SEEK_END); + s->position = ramfile_tell(file); +} + +/* Procedures for writing on a file */ +static int +s_ram_write_seek(stream * s, gs_offset_t pos) +{ + /* We must flush the buffer to reposition. */ + int code = sflush(s); + + if (code < 0) return code; + if (ramfile_seek((ramhandle*)s->file, pos, RAMFS_SEEK_SET) != 0) + return ERRC; + s->position = pos; + return 0; +} + +static int +s_ram_write_flush(register stream * s) +{ + int result = s_process_write_buf(s, false); + return result; +} + +static int +s_ram_write_close(register stream * s) +{ + s_process_write_buf(s, true); + return s_ram_read_close(s); +} + +/* + * Process a buffer for a file writing stream. + * This is the last stream in the pipeline, so pw is irrelevant. + */ +static int +s_ram_write_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * ignore_pw, bool last) +{ + uint count = pr->limit - pr->ptr; + + ramhandle *file = (ramhandle*)((stream *) st)->file; + int written = ramfile_write(file,pr->ptr + 1, count); + + if (written < 0) return ERRC; + pr->ptr += written; + return 0; +} + +static int +s_ram_switch(stream * s, bool writing) +{ + uint modes = s->file_modes; + ramhandle *file = (ramhandle*)s->file; + long pos; + + if (writing) { + if (!(s->file_modes & s_mode_write)) return ERRC; + pos = stell(s); + ramfile_seek(file, pos, RAMFS_SEEK_SET); + if (modes & s_mode_append) { + sappend_ram(s, file, s->cbuf, s->cbsize); /* sets position */ + } else { + swrite_ram(s, file, s->cbuf, s->cbsize); + s->position = pos; + } + s->modes = modes; + } else { + if (!(s->file_modes & s_mode_read)) return ERRC; + pos = stell(s); + if (sflush(s) < 0) return ERRC; + sread_ram(s, file, s->cbuf, s->cbsize); + s->modes |= modes & s_mode_append; /* don't lose append info */ + s->position = pos; + } + s->file_modes = modes; + return 0; +} + + +/* gx_io_device stuff */ + +static int +iodev_ram_init(gx_io_device * iodev, gs_memory_t * mem) +{ + ramfs* fs = ramfs_new(mem, MAXBLOCKS); + ramfs_state* state = gs_alloc_struct(mem, ramfs_state, &st_ramfs_state, + "ramfs_init(state)" + ); + if (fs && state) { + state->fs = fs; + iodev->state = state; + return 0; + } + if(fs) ramfs_destroy(mem, fs); + if(state) gs_free_object(mem,state,"iodev_ram_init(state)"); + return gs_error_VMerror; +} + +static void +ram_finalize(const gs_memory_t *memory, void * vptr) +{ + ramfs* fs = GETRAMFS((ramfs_state*)vptr); + ramfs_destroy((gs_memory_t *)memory, fs); +} + +static int +ram_delete(gx_io_device * iodev, const char *fname) +{ + ramfs* fs = GETRAMFS(iodev->state); + + if(ramfs_unlink(fs,fname)!=0) { + return_error(ramfs_errno_to_code(ramfs_error(fs))); + } + return 0; +} + +static int +ram_rename(gx_io_device * iodev, const char *from, const char *to) +{ + ramfs* fs = GETRAMFS(iodev->state); + + if(ramfs_rename(fs,from,to)!=0) { + return_error(ramfs_errno_to_code(ramfs_error(fs))); + } + return 0; +} + +static int +ram_status(gx_io_device * iodev, const char *fname, struct stat *pstat) +{ + ramhandle * f; + ramfs* fs = GETRAMFS(iodev->state); + int blocksize = ramfs_blocksize(fs); + + f = ramfs_open(fs,fname,RAMFS_READ); + if(!f) return_error(ramfs_errno_to_code(ramfs_error(fs))); + + memset(pstat, 0, sizeof(*pstat)); + pstat->st_size = ramfile_size(f); + /* The Windows definition of struct stat doesn't include a st_blocks member + pstat->st_blocks = (pstat->st_size+blocksize-1)/blocksize;*/ + /* XXX set mtime & ctime */ + ramfile_close(f); + return 0; +} + +static file_enum * +ram_enumerate_init(gx_io_device *iodev, const char *pat, uint patlen, + gs_memory_t *mem) +{ + gsram_enum * penum = gs_alloc_struct( + mem, gsram_enum, &st_gsram_enum, + "ram_enumerate_files_init(file_enum)" + ); + char *pattern = (char *)gs_alloc_bytes( + mem, patlen+1, "ram_enumerate_file_init(pattern)" + ); + ramfs_enum * e = ramfs_enum_new(GETRAMFS(iodev->state)); + if(penum && pattern && e) { + memcpy(pattern, pat, patlen); + pattern[patlen]=0; + + penum->memory = mem; + penum->pattern = pattern; + penum->e = e; + return (file_enum *)penum; + } + if (penum) gs_free_object(mem,penum,"ramfs_enum_init(ramfs_enum)"); + if (pattern) + gs_free_object(mem, penum->pattern, "ramfs_enum_init(pattern)"); + if(e) ramfs_enum_end(e); + return NULL; +} + +static void +ram_enumerate_close(file_enum *pfen) +{ + gsram_enum *penum = (gsram_enum *)pfen; + gs_memory_t *mem = penum->memory; + + ramfs_enum_end(penum->e); + gs_free_object(mem, penum->pattern, "ramfs_enum_init(pattern)"); + gs_free_object(mem, penum, "ramfs_enum_init(ramfs_enum)"); +} + +static uint +ram_enumerate_next(file_enum *pfen, char *ptr, uint maxlen) +{ + gsram_enum *penum = (gsram_enum *)pfen; + + char * filename; + while (filename = ramfs_enum_next(penum->e)) { + if (string_match((byte *)filename, strlen(filename), + (byte *)penum->pattern, + strlen(penum->pattern), 0)) { + if (strlen(filename) < maxlen) + memcpy(ptr, filename, strlen(filename)); + return strlen(filename); /* if > maxlen, caller will detect rangecheck */ + } + } + /* ran off end of list, close the enum */ + ram_enumerate_close(pfen); + return ~(uint)0; +} + +static int +ram_get_params(gx_io_device * iodev, gs_param_list * plist) +{ + int code; + int i0 = 0, so = 1; + bool btrue = true, bfalse = false; + ramfs* fs = GETRAMFS(iodev->state); + int BlockSize; + long Free, LogicalSize; + + BlockSize = ramfs_blocksize(fs); + LogicalSize = MAXBLOCKS; + Free = ramfs_blocksfree(fs); + + if ( + (code = param_write_bool(plist, "HasNames", &btrue)) < 0 || + (code = param_write_int (plist, "BlockSize", &BlockSize)) < 0 || + (code = param_write_long(plist, "Free", &Free)) < 0 || + (code = param_write_int (plist, "InitializeAction",&i0)) < 0 || + (code = param_write_bool(plist, "Mounted", &btrue)) < 0 || + (code = param_write_bool(plist, "Removable", &bfalse)) < 0 || + (code = param_write_bool(plist, "Searchable", &btrue)) < 0 || + (code = param_write_int (plist, "SearchOrder", &so)) < 0 || + (code = param_write_bool(plist, "Writeable", &btrue)) < 0 || + (code = param_write_long(plist, "LogicalSize", &LogicalSize)) < 0 + ) + return code; + return 0; +} diff --git a/gs/base/lib.mak b/gs/base/lib.mak index 653243d7e..703493cc8 100644 --- a/gs/base/lib.mak +++ b/gs/base/lib.mak @@ -3164,6 +3164,21 @@ MKROMFS_ZLIB_OBJS=$(AUX)compress.$(OBJ) $(AUX)deflate.$(OBJ) \ MKROMFS_COMMON_DEPS=$(stdpre_h) $(stdint__h) $(gsiorom_h) $(arch_h)\ $(gsmemret_h) $(gsmalloc_h) $(gsstype_h) $(gp_h) $(time__h) +# ---------------- Support for %ram% IODevice ----------------- # +gsioram_h=$(GLSRC)gsioram.h $(GLSRC)ramfs.h +ramfs_=$(GLOBJ)gsioram.$(OBJ) $(GLOBJ)ramfs.$(OBJ) +$(GLD)ramfs.dev : $(LIB_MAK) $(ECHOGS_XE) $(ramfs_) + $(SETMOD) $(GLD)ramfs $(ramfs_) + $(ADDMOD) $(GLD)ramfs -iodev ram + $(ADDMOD) $(GLD)ramfs -obj $(GLOBJ)ramfs.$(OBJ) + +$(GLOBJ)ramfs.$(OBJ) : $(GLSRC)ramfs.c + $(GLCC) $(GLO_)ramfs.$(OBJ) $(C_) $(GLSRC)ramfs.c + +$(GLOBJ)gsioram.$(OBJ) : $(GLSRC)gsioram.c + $(GLCC) $(GLO_)gsioram.$(OBJ) $(C_) $(GLSRC)gsioram.c + + # ---------------- Support for %disk IODevices ---------------- # # The following module is included only if the diskn.dev FEATURE is included $(GLOBJ)gsiodisk.$(OBJ) : $(GLSRC)gsiodisk.c $(AK) $(gx_h)\ diff --git a/gs/base/ramfs.c b/gs/base/ramfs.c new file mode 100644 index 000000000..644eaf192 --- /dev/null +++ b/gs/base/ramfs.c @@ -0,0 +1,453 @@ +/* + memory-based simulated file system + + files only, no directories (well, one) + (C) 2006 Michael Slade <micksa@knobbits.org> + */ + +#include "unistd_.h" +#include "string_.h" +#include "malloc_.h" +#include "gx.h" +#include "gserrors.h" +#include "gp.h" +#include "gscdefs.h" +#include "gsparam.h" +#include "gsstruct.h" +#include "ramfs.h" + +#define MACROBLOCK_REALLOC_MAX 128 + +typedef struct _ramfs { + struct _ramdirent * files; + struct _ramfs_enum* active_enums; + int blocksfree; + int last_error; +}; + +gs_private_st_ptrs2(st_ramfs, struct _ramfs, "gsram_ramfs", + _ramfs_enum_ptrs, _ramfs_reloc_ptrs, files, active_enums); + +struct _ramdirent { + char* filename; + struct _ramfile* inode; + struct _ramdirent* next; +}; + +gs_private_st_ptrs3(st_ramdirent, struct _ramdirent, "gsram_ramdirent", + _ramdirent_enum_ptrs, _ramdirent_reloc_ptrs, filename, inode, next); + +typedef struct _ramfile { + ramfs* fs; + int refcount; + int size; + int blocks; + int blocklist_size; + char** data; +} ramfile; + +gs_private_st_ptrs2(st_ramfile, struct _ramfile, "gsram_ramfile", + _ramfile_enum_ptrs, _ramfile_reloc_ptrs, fs, data); + +struct _ramhandle { + ramfile * file; + int last_error; + int filepos; + int mode; +}; + +gs_private_st_ptrs1(st_ramhandle, struct _ramhandle, "gsram_ramhandle", + _ramhandle_enum_ptrs, _ramhandle_reloc_ptrs, file); + +struct _ramfs_enum { + ramfs* fs; + ramdirent * current; + struct _ramfs_enum* next; +}; + +gs_private_st_ptrs3(st_ramfs_enum, struct _ramfs_enum, "gsram_ramfs_enum", + _ramfs_enum_enum_ptrs, _ramfs_enum_reloc_ptrs, fs, current, next); + +static void unlink_node(ramfile * inode); +static int ramfile_truncate(ramhandle * handle,int size); + + +ramfs * ramfs_new(gs_memory_t *mem, int size) { + ramfs * fs = gs_alloc_struct(mem, ramfs, &st_ramfs, + "ramfs_new" + ); + + if (fs == NULL) { + fs->last_error = RAMFS_NOMEM; + return NULL; + } + size = size/(RAMFS_BLOCKSIZE/1024); + fs->files = NULL; + fs->active_enums = NULL; + fs->blocksfree = size; + fs->last_error = 0; + return fs; +} + +/* This function makes no attempt to check that there are no open files or + enums. If there are any when this function is called, memory leakage will + result and any attempt to access the open files or enums will probably + cause a segfault. Caveat emptor, or something. +*/ +void ramfs_destroy(gs_memory_t *mem, ramfs * fs) { + ramdirent * ent; + + if(fs == NULL) return; + + ent = fs->files; + while(ent) { + ramdirent* prev; + free(ent->filename); + unlink_node(ent->inode); + prev = ent; + ent = ent->next; + free(prev); + } + gs_free_object(mem, fs, "ramfs_destroy"); +} + +int ramfs_error(const ramfs* fs) { return fs->last_error; } + +static int resize(ramfile * file,int size) { + int newblocks = (size+RAMFS_BLOCKSIZE-1)/RAMFS_BLOCKSIZE; + if(newblocks > file->blocks) { + /* allocate blocks for file as necessary */ + + if(newblocks-file->blocks > file->fs->blocksfree) { + return -RAMFS_NOSPACE; + } + if(file->blocklist_size < newblocks) { + int newsize = file->blocklist_size; + if (newsize > MACROBLOCK_REALLOC_MAX) { + newsize = ((newblocks+MACROBLOCK_REALLOC_MAX-1)/ + MACROBLOCK_REALLOC_MAX) * MACROBLOCK_REALLOC_MAX; + } else { + if(!newsize) newsize = 1; + while(newsize < newblocks) newsize *= 2; + } + file->data = realloc(file->data,newsize * sizeof(char*)); + file->blocklist_size = newsize; + } + while(file->blocks<newblocks) { + char * block = file->data[file->blocks] = malloc(RAMFS_BLOCKSIZE); + if(!block) { + return -RAMFS_NOMEM; + } + file->blocks++; + file->fs->blocksfree--; + } + } else if (newblocks < file->blocks) { + /* don't bother shrinking the block array */ + file->fs->blocksfree += (file->blocks-newblocks); + while(file->blocks > newblocks) { + free(file->data[--file->blocks]); + } + } + file->size = size; + return 0; +} + +static ramdirent * ramfs_findfile(const ramfs* fs,const char *filename) { + ramdirent * this = fs->files; + while(this) { + if(strcmp(this->filename,filename) == 0) break; + this = this->next; + } + return this; +} + +ramhandle * ramfs_open(gs_memory_t *mem, ramfs* fs,const char * filename,int mode) { + ramdirent * this; + ramfile* file; + ramhandle* handle; + + if(mode & (RAMFS_CREATE|RAMFS_APPEND)) mode |= RAMFS_WRITE; + + this = ramfs_findfile(fs,filename); + + if(!this) { + /* create file? */ + char * dirent_filename; + + if(!(mode & RAMFS_CREATE)) { + fs->last_error = RAMFS_NOTFOUND; + return NULL; + } + this = malloc(sizeof(ramdirent)); + file = malloc(sizeof(ramfile)); + dirent_filename = malloc(strlen(filename)+1); + if(!(this && file && dirent_filename)) { + free(this); + free(file); + free(dirent_filename); + fs->last_error = RAMFS_NOMEM; + return NULL; + } + strcpy(dirent_filename,filename); + this->filename = dirent_filename; + file->refcount = 1; + file->size = 0; + file->blocks = 0; + file->blocklist_size = 0; + file->data = NULL; + file->fs = fs; + this->inode = file; + this->next = fs->files; + fs->files = this; + } + file = this->inode; + file->refcount++; + + handle = malloc(sizeof(ramhandle)); + if(!handle) { + fs->last_error = RAMFS_NOMEM; + return NULL; + } + handle->file = file; + handle->filepos = 0; + handle->mode = mode; + + if(mode & RAMFS_TRUNC) { + resize(file,0); + } + return handle; +} + +int ramfs_blocksize(ramfs * fs) { return RAMFS_BLOCKSIZE; } +int ramfs_blocksfree(ramfs * fs) { return fs->blocksfree; } +int ramfile_error(ramhandle * handle) { return handle->last_error; } + +static void unlink_node(ramfile * inode) { + int c; + + --inode->refcount; + if(inode->refcount) return; + + /* remove the file and its data */ + for(c=0;c<inode->blocks;c++) { + free(inode->data[c]); + } + inode->fs->blocksfree += c; + free(inode->data); + free(inode); +} + +int ramfs_unlink(ramfs * fs,const char *filename) { + ramdirent ** last; + ramdirent * this; + ramfs_enum* e; + + last = &fs->files; + while(1) { + if(!(this = *last)) { + fs->last_error = RAMFS_NOTFOUND; + return -1; + } + if(strcmp(this->filename,filename) == 0) break; + last = &(this->next); + } + + unlink_node(this->inode); + free(this->filename); + (*last) = this->next; + + e = fs->active_enums; + /* advance enums that are pointing to the just-deleted file */ + while(e) { + if(e->current == this) e->current = this->next; + e = e->next; + } + free(this); + return 0; +} + +int ramfs_rename(ramfs * fs,const char* oldname,const char* newname) { + ramdirent * this; + char * newnamebuf; + + this = ramfs_findfile(fs,oldname); + + if(!this) { + fs->last_error = RAMFS_NOTFOUND; + return -1; + } + + /* just in case */ + if(strcmp(oldname,newname) == 0) return 0; + + newnamebuf = realloc(this->filename,strlen(newname)+1); + if(!newnamebuf) { + fs->last_error = RAMFS_NOMEM; + return -1; + } + + /* this may return RAMFS_NOTFOUND, which can be ignored. */ + ramfs_unlink(fs,newname); + + strcpy(newnamebuf,newname); + this->filename = newnamebuf; + return 0; +} + +ramfs_enum * ramfs_enum_new(ramfs * fs) { + ramfs_enum * e; + + e = malloc(sizeof(ramfs_enum)); + if(!e) { + fs->last_error = RAMFS_NOMEM; + return NULL; + } + e->current = fs->files; + e->next = fs->active_enums; + e->fs = fs; + fs->active_enums = e; + return e; +} + +char* ramfs_enum_next(ramfs_enum * e) { + char * filename = NULL; + if(e->current) { + filename = e->current->filename; + e->current = e->current->next; + } + return filename; +} + +void ramfs_enum_end(ramfs_enum * e) { + ramfs_enum** last = &e->fs->active_enums; + while(*last) { + if(*last == e) { + *last = e->next; + break; + } + last = &(e->next); + } + free(e); +} + +int ramfile_read(ramhandle * handle,void * buf,int len) { + ramfile * file = handle->file; + int left; + char *t = (char *)buf; + + if(len>file->size - handle->filepos) len = file->size-handle->filepos; + if(len<0) return 0; + + left = len; + while(left) { + char * p = file->data[handle->filepos/RAMFS_BLOCKSIZE]+handle->filepos%RAMFS_BLOCKSIZE; + int x = RAMFS_BLOCKSIZE-handle->filepos%RAMFS_BLOCKSIZE; + if(x>left) x = left; + + memcpy(t,p,x); + handle->filepos += x; + left -= x; + t += x; + } + buf = (void *)t; + return len; +} + +int ramfile_write(ramhandle * handle,const void * buf,int len) { + ramfile * file = handle->file; + int left; + char *t = (char *)buf; + + if(!handle->mode & RAMFS_WRITE) { + handle->last_error = RAMFS_NOACCESS; + return -1; + } + + if(handle->mode & RAMFS_APPEND) { + handle->filepos = file->size; + } + + if(file->size < handle->filepos) { + /* if this fails then pass the error on */ + if(ramfile_truncate(handle,handle->filepos) == -1) return -1; + } + + if(file->size < handle->filepos+len) { + int x = resize(file,handle->filepos+len); + if(x) { + handle->last_error = -x; + return -1; + } + } + + /* This is exactly the same as for reading, cept the copy is in the + other direction. */ + left = len; + while(left) { + char * p = file->data[handle->filepos/RAMFS_BLOCKSIZE] + + handle->filepos%RAMFS_BLOCKSIZE; + int x = RAMFS_BLOCKSIZE-handle->filepos%RAMFS_BLOCKSIZE; + if(x>left) x = left; + + memcpy(p,buf,x); + handle->filepos += x; + left -= x; + t += x; + } + buf = (void *)t; + return len; +} + +int ramfile_seek(ramhandle * handle,int pos,int whence) { + /* Just set the handle's file position. The effects become noticeable + at the next read or write. + */ + if(whence == RAMFS_SEEK_CUR) { + handle->filepos += pos; + } else if(whence == RAMFS_SEEK_END) { + handle->filepos = handle->file->size+pos; + } else { + handle->filepos = pos; + } + return 0; +} + +int ramfile_size(ramhandle * handle) { + return handle->file->size; +} + +static int ramfile_truncate(ramhandle * handle,int size) { + ramfile * file = handle->file; + int oldsize = file->size; + int x = resize(file,size); + + if(x) { + handle->last_error = -x; + return -1; + } + if(oldsize >= size) return 0; + + /* file was expanded. fill the new space with zeros. */ + while(oldsize < file->size) { + char * p = file->data[oldsize/RAMFS_BLOCKSIZE]+oldsize%RAMFS_BLOCKSIZE; + int len = RAMFS_BLOCKSIZE - oldsize%RAMFS_BLOCKSIZE; + if(len>file->size-oldsize) len = file->size-oldsize; + oldsize += len; + memset(p,0,len); + } + return 0; +} + +void ramfile_close(ramhandle * handle) { + ramfile * file = handle->file; + unlink_node(file); + free(handle); +} + +int ramfile_tell(ramhandle* handle) { + return handle->filepos; +} + +int ramfile_eof(ramhandle* handle) { + return (handle->filepos >= handle->file->size); +} diff --git a/gs/base/ramfs.h b/gs/base/ramfs.h new file mode 100644 index 000000000..b2d6f29a8 --- /dev/null +++ b/gs/base/ramfs.h @@ -0,0 +1,62 @@ +#ifndef __RAMFS_H__ +#define __RAMFS_H__ + +#define RAMFS_BLOCKSIZE 1024 + +typedef struct _ ; +typedef struct _ramdirent ramdirent; +typedef struct _ramhandle ramhandle; +typedef struct _ _enum _enum; + +/* + _new: NOMEM + _open: NOTFOUND + _unlink: NOTFOUND + _enum_new: NOMEM + _enum_next: none + _enum_end: none + ramfile_read: none + ramfile_write: NOSPACE, NOMEM, NOACCESS + ramfile_seek: none + ramfile_pos: none + ramfile_close: none +*/ + +/* Error constants */ +#define RAMFS_NOTFOUND 2 +#define RAMFS_NOACCESS 5 +#define RAMFS_NOMEM 6 +#define RAMFS_NOSPACE 7 + +/* Open mode flags */ +#define RAMFS_READ 1 +#define RAMFS_CREATE 2 +#define RAMFS_WRITE 4 +#define RAMFS_TRUNC 8 +#define RAMFS_APPEND 16 + +#define RAMFS_SEEK_SET 0 +#define RAMFS_SEEK_CUR 1 +#define RAMFS_SEEK_END 2 + + * _new(gs_memory_t *mem, int size); /* size is in KiB */ +void _destroy(gs_memory_t *, * fs); +int _error(const * fs); +ramhandle * _open(gs_memory_t *mem, * fs,const char * filename,int mode); +int _blocksize( * fs); +int _blocksfree( * fs); +int _unlink( * fs,const char *filename); +int _rename( * fs,const char *oldname,const char *newname); + _enum * _enum_new( * fs); +char* _enum_next( _enum * e); +void _enum_end( _enum * e); +int ramfile_read(ramhandle * handle,void * buf,int len); +int ramfile_write(ramhandle * handle,const void * buf,int len); +int ramfile_seek(ramhandle * handle,int pos,int whence); +int ramfile_eof(ramhandle * handle); +int ramfile_tell(ramhandle * handle); +int ramfile_size(ramhandle * handle); +void ramfile_close(ramhandle * handle); +int ramfile_error(ramhandle * handle); + +#endif /* __RAMFS_H__ */ diff --git a/gs/psi/msvc.mak b/gs/psi/msvc.mak index 0da900e45..4e9316cf2 100644 --- a/gs/psi/msvc.mak +++ b/gs/psi/msvc.mak @@ -935,7 +935,7 @@ JPX_CFLAGS = $JPX_CFLAGS -DUSE_OPENJPEG_JP2 # Choose the language feature(s) to include. See gs.mak for details. !ifndef FEATURE_DEVS -FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)rasterop.dev $(PSD)epsf.dev $(PSD)mshandle.dev $(PSD)mspoll.dev $(PSD)fapi_ps.dev $(PSD)jbig2.dev $(PSD)jpx.dev $(PSD)winutf8.dev +FEATURE_DEVS=$(PSD)psl3.dev $(PSD)pdf.dev $(PSD)dpsnext.dev $(PSD)ttfont.dev $(PSD)rasterop.dev $(PSD)epsf.dev $(PSD)mshandle.dev $(PSD)mspoll.dev $(PSD)fapi_ps.dev $(PSD)jbig2.dev $(PSD)jpx.dev $(PSD)winutf8.dev $(PSD)ramfs.dev !ifndef METRO FEATURE_DEVS=$(FEATURE_DEVS) $(PSD)msprinter.dev $(GLD)pipe.dev !endif |