diff options
-rw-r--r-- | psi/int.mak | 4 | ||||
-rw-r--r-- | psi/isave.h | 6 | ||||
-rw-r--r-- | psi/zdevice2.c | 33 | ||||
-rw-r--r-- | psi/zvmem.c | 56 |
4 files changed, 84 insertions, 15 deletions
diff --git a/psi/int.mak b/psi/int.mak index 19688202a..16db0cff0 100644 --- a/psi/int.mak +++ b/psi/int.mak @@ -1086,8 +1086,8 @@ $(PSD)pagedev.dev : $(ECHOGS_XE) $(pagedev_)\ $(PSOBJ)zdevice2.$(OBJ) : $(PSSRC)zdevice2.c $(OP) $(math__h) $(memory__h)\ $(dstack_h) $(estack_h)\ - $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(iutil_h) $(store_h)\ - $(gxdevice_h) $(gsstate_h) $(INT_MAK) $(MAKEDIRS) + $(idict_h) $(idparam_h) $(igstate_h) $(iname_h) $(isave) $(iutil_h) \ + $(store_h) $(gxdevice_h) $(gsstate_h) $(INT_MAK) $(MAKEDIRS) $(PSCC) $(PSO_)zdevice2.$(OBJ) $(C_) $(PSSRC)zdevice2.c $(PSOBJ)zmedia2.$(OBJ) : $(PSSRC)zmedia2.c $(OP) $(math__h) $(memory__h)\ diff --git a/psi/isave.h b/psi/isave.h index 30216398f..7eaaced46 100644 --- a/psi/isave.h +++ b/psi/isave.h @@ -128,4 +128,10 @@ int font_restore(const alloc_save_t * save); express purpose of getting the library context. */ gs_memory_t *gs_save_any_memory(const alloc_save_t *save); +int +restore_check_save(i_ctx_t *i_ctx_p, alloc_save_t **asave); + +int +dorestore(i_ctx_t *i_ctx_p, alloc_save_t *asave); + #endif /* isave_INCLUDED */ diff --git a/psi/zdevice2.c b/psi/zdevice2.c index 9fbb4e339..0c7080d57 100644 --- a/psi/zdevice2.c +++ b/psi/zdevice2.c @@ -26,6 +26,7 @@ #include "igstate.h" #include "iname.h" #include "iutil.h" +#include "isave.h" #include "store.h" #include "gxdevice.h" #include "gsstate.h" @@ -307,13 +308,24 @@ z2grestoreall(i_ctx_t *i_ctx_p) } return 0; } - +/* This is the Level 2+ variant of restore - which adds restoring + of the page device to the Level 1 variant in zvmem.c. + Previous this restored the device state before calling zrestore.c + which validated operands etc, meaning a restore could error out + partially complete. + The operand checking, and actual VM restore are now in two functions + so they can called separately thus, here, we can do as much + checking as possible, before embarking on actual changes + */ /* <save> restore - */ static int z2restore(i_ctx_t *i_ctx_p) { - os_ptr op = osp; - check_type(*op, t_save); + alloc_save_t *asave; + bool saveLockSafety = gs_currentdevice_inline(igs)->LockSafetyParams; + int code = restore_check_save(i_ctx_p, &asave); + + if (code < 0) return code; while (gs_gstate_saved(gs_gstate_saved(igs))) { if (restore_page_device(igs, gs_gstate_saved(igs))) @@ -322,7 +334,20 @@ z2restore(i_ctx_t *i_ctx_p) } if (restore_page_device(igs, gs_gstate_saved(igs))) return push_callout(i_ctx_p, "%restorepagedevice"); - return zrestore(i_ctx_p); + + code = dorestore(i_ctx_p, asave); + + if (code < 0) { + /* An error here is basically fatal, but.... + restore_page_device() has to set LockSafetyParams false so it can + configure the restored device correctly - in normal operation, that + gets reset by that configuration. If we hit an error, though, that + may not happen - at least ensure we keep the setting through the + error. + */ + gs_currentdevice_inline(igs)->LockSafetyParams = saveLockSafety; + } + return code; } /* <gstate> setgstate - */ diff --git a/psi/zvmem.c b/psi/zvmem.c index 44cd7a8e0..87a0a4ff1 100644 --- a/psi/zvmem.c +++ b/psi/zvmem.c @@ -99,19 +99,18 @@ zsave(i_ctx_t *i_ctx_p) static int restore_check_operand(os_ptr, alloc_save_t **, gs_dual_memory_t *); static int restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t *, const alloc_save_t *, bool); static void restore_fix_stack(i_ctx_t *i_ctx_p, ref_stack_t *, const alloc_save_t *, bool); + +/* Do as many up front checks of the save object as we reasonably can */ int -zrestore(i_ctx_t *i_ctx_p) +restore_check_save(i_ctx_t *i_ctx_p, alloc_save_t **asave) { os_ptr op = osp; - alloc_save_t *asave; - bool last; - vm_save_t *vmsave; - int code = restore_check_operand(op, &asave, idmemory); + int code = restore_check_operand(op, asave, idmemory); if (code < 0) return code; if_debug2m('u', imemory, "[u]vmrestore 0x%lx, id = %lu\n", - (ulong) alloc_save_client_data(asave), + (ulong) alloc_save_client_data(*asave), (ulong) op->value.saveid); if (I_VALIDATE_BEFORE_RESTORE) ivalidate_clean_spaces(i_ctx_p); @@ -120,14 +119,37 @@ zrestore(i_ctx_t *i_ctx_p) { int code; - if ((code = restore_check_stack(i_ctx_p, &o_stack, asave, false)) < 0 || - (code = restore_check_stack(i_ctx_p, &e_stack, asave, true)) < 0 || - (code = restore_check_stack(i_ctx_p, &d_stack, asave, false)) < 0 + if ((code = restore_check_stack(i_ctx_p, &o_stack, *asave, false)) < 0 || + (code = restore_check_stack(i_ctx_p, &e_stack, *asave, true)) < 0 || + (code = restore_check_stack(i_ctx_p, &d_stack, *asave, false)) < 0 ) { osp++; return code; } } + osp++; + return 0; +} + +/* the semantics of restore differ slightly between Level 1 and + Level 2 and later - the latter includes restoring the device + state (whilst Level 1 didn't have "page devices" as such). + Hence we have two restore operators - one here (Level 1) + and one in zdevice2.c (Level 2+). For that reason, the + operand checking and guts of the restore operation are + separated so both implementations can use them to best + effect. + */ +int +dorestore(i_ctx_t *i_ctx_p, alloc_save_t *asave) +{ + os_ptr op = osp; + bool last; + vm_save_t *vmsave; + int code; + + osp--; + /* Reset l_new in all stack entries if the new save level is zero. */ /* Also do some special fixing on the e-stack. */ restore_fix_stack(i_ctx_p, &o_stack, asave, false); @@ -170,9 +192,24 @@ zrestore(i_ctx_t *i_ctx_p) /* cause an 'invalidaccess' in setuserparams. Temporarily set */ /* LockFilePermissions false until the gs_lev2.ps can do a */ /* setuserparams from the restored userparam dictionary. */ + /* NOTE: This is safe to do here, since the restore has */ + /* successfully completed - this should never come before any */ + /* operation that can trigger an error */ i_ctx_p->LockFilePermissions = false; return 0; } + +int +zrestore(i_ctx_t *i_ctx_p) +{ + alloc_save_t *asave; + int code = restore_check_save(i_ctx_p, &asave); + if (code < 0) + return code; + + return dorestore(i_ctx_p, asave); +} + /* Check the operand of a restore. */ static int restore_check_operand(os_ptr op, alloc_save_t ** pasave, @@ -193,6 +230,7 @@ restore_check_operand(os_ptr op, alloc_save_t ** pasave, *pasave = asave; return 0; } + /* Check a stack to make sure all its elements are older than a save. */ static int restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t * pstack, |