Implemented buffered writes on file system. Implemented SDARCHIVE/SDRESTORE. Fixed bug in ->Q.

This commit is contained in:
claudiol 2017-08-17 19:12:05 -04:00
parent bf8dfea3e5
commit 99c76f0fa3
10 changed files with 377 additions and 54 deletions

View file

@ -108,6 +108,15 @@
*/
#define FSMODE_NOCREATE 32 // DON'T CREATE IF FILE DOESN'T EXIST
/*!
* \brief Enable write buffers
*
* This flag is for the FSOpen function only. By default writes are not
* buffered (written directly). This flag enables buffered writes.
*/
#define FSMODE_WRITEBUFFERS 64 // USE BUFFERED WRITES
// SIMILAR TO STANDARD SEEK_XXX CONSTANTS
#define FSSEEK_SET 0
#define FSSEEK_CUR 1

View file

@ -26,6 +26,16 @@ if(error!=FS_OK) { return error; }
if(file->Mode&FSMODE_WRITE) {
// TO DO:
// FLUSH WRITE BUFFERS
if(file->WrBuffer.Used) {
file->CurrentOffset=file->WrBuffer.Offset;
FSWriteLL(file->WrBuffer.Data,file->WrBuffer.Used,file,FSystem.Volumes[file->Volume]);
if(!(file->Mode&FSMODE_MODIFY)) {
file->FileSize=file->CurrentOffset; // TRUNCATE FILE
}
file->WrBuffer.Used=0;
}
if(!(file->Mode&FSMODE_MODIFY)) {
error=FSTruncateChain(file,file->FileSize); // TRUNCATE CHAIN UNLESS IN MODIFY MODE

View file

@ -24,7 +24,105 @@ if(!file) return FS_ERROR;
if(!(file->Mode&FSMODE_WRITE)) return FS_ERROR; // WRITE NOT ALLOWED
if(file->Attr&FSATTR_RDONLY) return FS_ERROR;
if(file->Mode&FSMODE_APPEND) file->CurrentOffset=file->FileSize; // ONLY AT THE END OF FILE
if(file->Mode&FSMODE_APPEND) file->CurrentOffset=file->FileSize+file->WrBuffer.Used; // ONLY AT THE END OF FILE
int totalwritten=0;
while( (file->Mode&FSMODE_WRITEBUFFERS)&& !(file->Mode&FSMODE_MODIFY)) {
// BUFFERED WRITES
if(!file->WrBuffer.Data) {
file->WrBuffer.Data=simpmallocb(512);
if(!file->WrBuffer.Data) {
// DISABLE BUFFERED WRITES
file->Mode&=~FSMODE_WRITEBUFFERS;
continue;
}
file->WrBuffer.Used=0;
}
if(file->WrBuffer.Used) {
if( (file->CurrentOffset<file->WrBuffer.Offset)||(file->CurrentOffset>file->WrBuffer.Offset+512) || (file->CurrentOffset>file->WrBuffer.Offset+file->WrBuffer.Used)) {
// BUFFER IS NOT CONTIGUOUS, NEEDS TO BE FLUSHED
unsigned int oldoffset=file->CurrentOffset;
file->CurrentOffset=file->WrBuffer.Offset;
int written=FSWriteLL(file->WrBuffer.Data,file->WrBuffer.Used,file,FSystem.Volumes[file->Volume]);
if(!(file->Mode&FSMODE_MODIFY)) {
file->FileSize=file->CurrentOffset; // TRUNCATE FILE
}
if(written!=file->WrBuffer.Used) return FS_ERROR;
file->CurrentOffset=oldoffset;
file->WrBuffer.Used=0;
}
else {
if(file->CurrentOffset<file->WrBuffer.Offset+file->WrBuffer.Used) {
// OVERWRITE A FEW BYTES IN THE BUFFER, IT'S FINE
file->WrBuffer.Used=file->CurrentOffset-file->WrBuffer.Offset;
}
// APPEND DATA TO THE CURRENT BUFFER
int maxbytes=512-file->WrBuffer.Used;
if(nbytes>maxbytes) {
memmoveb(file->WrBuffer.Data+file->WrBuffer.Used,buffer,maxbytes);
file->WrBuffer.Used=512;
// FLUSH THE BUFFER
file->CurrentOffset=file->WrBuffer.Offset;
int written=FSWriteLL(file->WrBuffer.Data,file->WrBuffer.Used,file,FSystem.Volumes[file->Volume]);
if(!(file->Mode&FSMODE_MODIFY)) {
file->FileSize=file->CurrentOffset; // TRUNCATE FILE
}
totalwritten+=maxbytes;
if(written!=file->WrBuffer.Used) return totalwritten;
file->WrBuffer.Used=0;
nbytes-=maxbytes;
buffer+=maxbytes;
}
else {
// THE NEW DATA FITS WITHIN THE BUFFER
memmoveb(file->WrBuffer.Data+file->WrBuffer.Used,buffer,nbytes);
file->WrBuffer.Used+=nbytes;
file->CurrentOffset+=nbytes;
return nbytes;
}
}
}
// HERE IT IS GUARANTEED THAT ANY OLD BUFFERS WERE FLUSHED
// WRITE LARGE BLOCKS DIRECTLY
int remainder=(file->CurrentOffset+nbytes)&511;
if(nbytes>remainder) {
int written=FSWriteLL(buffer,nbytes-remainder,file,FSystem.Volumes[file->Volume]);
if(!(file->Mode&FSMODE_MODIFY)) {
file->FileSize=file->CurrentOffset; // TRUNCATE FILE
}
totalwritten+=written;
if(written!=nbytes-remainder) return totalwritten;
buffer+=nbytes-remainder;
nbytes=remainder;
}
if(nbytes) {
// AND BUFFER THE REST
memmoveb(file->WrBuffer.Data,buffer,nbytes);
file->WrBuffer.Offset=file->CurrentOffset;
file->WrBuffer.Used=nbytes;
totalwritten+=nbytes;
file->CurrentOffset+=nbytes;
}
return totalwritten;
}
// UNBUFFERED WRITES HERE
// CHANGE THIS WITH BUFFERED VERSION WHEN AVAILABLE
nbytes=FSWriteLL(buffer,nbytes,file,FSystem.Volumes[file->Volume]);

View file

@ -27,9 +27,9 @@ extern volatile int __cpu_idle;
extern "C" void __keyb_update();
// BACKUP/RESTORE
extern "C" int rplBackup(void (*writefunc)(unsigned int));
extern "C" int rplRestoreBackup(unsigned int (*readfunc)());
extern "C" int rplRestoreBackupMessedup(unsigned int (*readfunc)()); // DEBUG ONLY
extern "C" int rplBackup(void (*writefunc)(unsigned int,void *),void *);
extern "C" int rplRestoreBackup(unsigned int (*readfunc)(void *),void *);
extern "C" int rplRestoreBackupMessedup(unsigned int (*readfunc)(void *),void *); // DEBUG ONLY
extern "C" void __SD_irqeventinsert();
@ -336,12 +336,14 @@ unsigned int MainWindow::ReadWord()
}
extern "C" void write_data(unsigned int word)
extern "C" void write_data(unsigned int word,void *opaque)
{
(void)opaque;
MainWindow::WriteWord(word);
}
extern "C" unsigned int read_data()
extern "C" unsigned int read_data(void *opaque)
{
(void)opaque;
return MainWindow::ReadWord();
}
@ -381,7 +383,7 @@ void MainWindow::on_actionSave_triggered()
// PERFORM BACKUP
myMainWindow=this;
fileptr=&file;
rplBackup(&write_data);
rplBackup(&write_data,(void *)fileptr);
file.close();
@ -425,7 +427,7 @@ void MainWindow::on_actionOpen_triggered()
// PERFORM RESTORE PROCEDURE
myMainWindow=this;
fileptr=&file;
int result=rplRestoreBackup(&read_data);
int result=rplRestoreBackup(&read_data,(void *)fileptr);
file.close();
@ -519,7 +521,7 @@ void MainWindow::on_actionSaveAs_triggered()
// PERFORM BACKUP
myMainWindow=this;
fileptr=&file;
rplBackup(&write_data);
rplBackup(&write_data,(void *)fileptr);
file.close();

View file

@ -85,7 +85,7 @@ WORDPTR rplConvertIDToPTR(WORD romptrid)
// BACKUP TEMPOB AND DIRECTORIES (NO STACK) TO EXTERNAL DEVICE
BINT rplBackup(void (*writefunc)(unsigned int))
BINT rplBackup(void (*writefunc)(unsigned int,void *),void *OpaqueArgument)
{
BINT offset;
BINT k;
@ -160,37 +160,37 @@ BINT rplBackup(void (*writefunc)(unsigned int))
BINT writeoff=0;
// FIRST, WRITE SIGNATURE TO THE FILE
writefunc( TEXT2WORD('N','R','P','B'));
writefunc( TEXT2WORD('N','R','P','B'),OpaqueArgument);
writeoff++;
// WRITE ALL 10 SECTIONS START OFFSET
// END OFFSET IS THE START OF THE SECTION IMMEDIATELY AFTER
for(k=0;k<10;++k) {
writefunc(sections[k].offwords);
writefunc(sections[k].offwords,OpaqueArgument);
++writeoff;
}
// TODO: WRITE OTHER SYSTEM VARIABLES HERE
// FILL THE HEADER SECTION
while(writeoff<1024) { writefunc(0); ++writeoff; }
while(writeoff<1024) { writefunc(0,OpaqueArgument); ++writeoff; }
// HERE WE ARE AT OFFSET 4096 (1024 WORDS)
// DUMP TEMPBLOCKS TO THE FILE
for(k=0;k<sections[0].nitems;++k) {
writefunc((BINT)(TempBlocks[k]-TempOb)+sections[1].offwords); // WRITE BLOCKS AS OFFSET RELATIVE TO THE FILE INSTEAD OF POINTER
writefunc((BINT)(TempBlocks[k]-TempOb)+sections[1].offwords,OpaqueArgument); // WRITE BLOCKS AS OFFSET RELATIVE TO THE FILE INSTEAD OF POINTER
++writeoff;
}
// DUMP TEMPOB TO THE FILE
for(k=0;k<sections[1].nitems;++k) {
writefunc(TempOb[k]); // WRITE TEMPOB AS-IS, NO POINTERS THERE
writefunc(TempOb[k],OpaqueArgument); // WRITE TEMPOB AS-IS, NO POINTERS THERE
++writeoff;
}
// DUMP TEMPOB AFTER END TO THE FILE
for(k=0;k<sections[2].nitems;++k) {
writefunc(TempObEnd[k]); // WRITE TEMPOB AS-IS, NO POINTERS THERE
writefunc(TempObEnd[k],OpaqueArgument); // WRITE TEMPOB AS-IS, NO POINTERS THERE
++writeoff;
}
@ -201,7 +201,7 @@ BINT rplBackup(void (*writefunc)(unsigned int))
ptr=Directories[k];
if( (ptr>=TempOb) && (ptr<TempObEnd) ) {
// VALID POINTER INTO TEMPOB, CONVERT INTO FILE OFFSET
writefunc( (BINT)(ptr-TempOb)+ sections[1].offwords);
writefunc( (BINT)(ptr-TempOb)+ sections[1].offwords,OpaqueArgument);
} else {
// IF THE OBJECT IS NOT IN TEMPOB IS IN ROM
@ -214,7 +214,7 @@ BINT rplBackup(void (*writefunc)(unsigned int))
// WE DON'T DO THAT HERE
return 0;
}
writefunc(id);
writefunc(id,OpaqueArgument);
}
++writeoff;
}
@ -224,7 +224,7 @@ BINT rplBackup(void (*writefunc)(unsigned int))
ptr=GC_PTRUpdate[k];
if( (ptr>=TempOb) && (ptr<=TempObSize) ) {
// VALID POINTER INTO TEMPOB, CONVERT INTO FILE OFFSET
writefunc( (BINT)(ptr-TempOb)+ sections[1].offwords);
writefunc( (BINT)(ptr-TempOb)+ sections[1].offwords,OpaqueArgument);
} else {
// IF THE OBJECT IS NOT IN TEMPOB IS IN ROM
@ -237,7 +237,7 @@ BINT rplBackup(void (*writefunc)(unsigned int))
// REPLACE WITH zero_bint FOR GOOD MEASURES
id=rplConvertToRomptrID((WORDPTR)zero_bint);
}
writefunc(id);
writefunc(id,OpaqueArgument);
}
++writeoff;
}
@ -257,7 +257,7 @@ BINT rplBackup(void (*writefunc)(unsigned int))
// 1 = RESTORE COMPLETED WITH NO ERRORS
// 2 = RESTORE COMPLETED WITH SOME ERRORS, RUN MEMFIX LATER
BINT rplRestoreBackup(WORD (*readfunc)())
BINT rplRestoreBackup(WORD (*readfunc)(void *),void *OpaqueArgument)
{
// GENERIC SECTIONS
@ -272,7 +272,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
WORD data;
// CHECK FILE SIGNATURE
data=readfunc();
data=readfunc(OpaqueArgument);
++offset;
if(data!=TEXT2WORD('N','R','P','B')) return 0;
@ -280,7 +280,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
// READ ALL 10 SECTIONS
for(k=0;k<10;++k)
{
sections[k].offwords=readfunc();
sections[k].offwords=readfunc(OpaqueArgument);
++offset;
if(k>0) sections[k-1].nitems=sections[k].offwords-sections[k-1].offwords;
}
@ -301,22 +301,23 @@ BINT rplRestoreBackup(WORD (*readfunc)())
// ERASE ALL RPL MEMORY IN PREPARATION FOR RESTORE
// ALL SECTIONS TO MINIMUM SIZE TO FREE AS MANY PAGES AS POSSIBLE
shrinkTempOb(1024); // GET SOME MEMORY FOR TEMPORARY OBJECT STORAGE
TempObEnd=TempOb;
shrinkTempBlocks(1024); // GET SOME MEMORY FOR TEMPORARY OBJECT BLOCKS
TempBlocksEnd=TempBlocks;
shrinkTempOb(1024); // GET SOME MEMORY FOR TEMPORARY OBJECT STORAGE
shrinkTempBlocks(1024); // GET SOME MEMORY FOR TEMPORARY OBJECT BLOCKS
growRStk(1024); // GET SOME MEMORY FOR RETURN STACK
RSTop=RStk;
growDStk(1024); // GET SOME MEMORY FOR DATA STACK
growRStk(1024); // GET SOME MEMORY FOR RETURN STACK
DSTop=DStkBottom=DStkProtect=DStk;
growDStk(1024); // GET SOME MEMORY FOR DATA STACK
growLAMs(1024); // GET SOME MEMORY FOR LAM ENVIRONMENTS
LAMTopSaved=LAMTop=nLAMBase=LAMs;
growLAMs(1024); // GET SOME MEMORY FOR LAM ENVIRONMENTS
growDirs(1024); // MEMORY FOR ROOT DIRECTORY
CurrentDir=Directories;
DirsTop=Directories;
growDirs(1024); // MEMORY FOR ROOT DIRECTORY
// RESIZE ALL SECTIONS TO THE REQUESTED SIZE
if(sections[0].nitems+TEMPBLOCKSLACK>1024) growTempBlocks(sections[0].nitems+TEMPBLOCKSLACK);
@ -327,11 +328,11 @@ BINT rplRestoreBackup(WORD (*readfunc)())
// SKIP TO THE PROPER FILE OFFSET
while(offset!=1024) { readfunc(); ++offset; }
while(offset!=1024) { readfunc(OpaqueArgument); ++offset; }
// HERE'S THE START OF TEMPBLOCKS
for(k=0;k<sections[0].nitems;++k) {
data=readfunc();
data=readfunc(OpaqueArgument);
TempBlocks[k]=TempOb+(data-sections[1].offwords);
++offset;
}
@ -340,7 +341,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
// HERE'S THE START OF TEMPOB
for(k=0;k<sections[1].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
TempOb[k]=data;
++offset;
}
@ -349,7 +350,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
// AFTER TEMPOB
for(k=0;k<sections[2].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
TempObEnd[k]=data;
++offset;
}
@ -359,7 +360,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
for(k=0;k<sections[3].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
if(ISROMPTRID(data)) Directories[k]=rplConvertIDToPTR(data);
else Directories[k]=TempOb+(data-sections[1].offwords);
if(Directories[k]==0) ++errors; // JUST COUNT THE ERRORS BUT DON'T STOP, RECOVER AS MUCH AS POSSIBLE
@ -372,7 +373,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
for(k=0;k<sections[4].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
if(ISROMPTRID(data)) GC_PTRUpdate[k]=rplConvertIDToPTR(data);
else {
if((k==1)||(k==2)) {
@ -394,7 +395,7 @@ BINT rplRestoreBackup(WORD (*readfunc)())
#define DO_SOME_DAMAGE 0x123
BINT rplRestoreBackupMessedup(WORD (*readfunc)())
BINT rplRestoreBackupMessedup(WORD (*readfunc)(void *),void *OpaqueArgument)
{
// GENERIC SECTIONS
@ -409,7 +410,7 @@ BINT rplRestoreBackupMessedup(WORD (*readfunc)())
WORD data;
// CHECK FILE SIGNATURE
data=readfunc();
data=readfunc(OpaqueArgument);
++offset;
if(data!=TEXT2WORD('N','R','P','B')) return 0;
@ -417,7 +418,7 @@ BINT rplRestoreBackupMessedup(WORD (*readfunc)())
// READ ALL 10 SECTIONS
for(k=0;k<10;++k)
{
sections[k].offwords=readfunc();
sections[k].offwords=readfunc(OpaqueArgument);
++offset;
if(k>0) sections[k-1].nitems=sections[k].offwords-sections[k-1].offwords;
}
@ -463,11 +464,11 @@ BINT rplRestoreBackupMessedup(WORD (*readfunc)())
// SKIP TO THE PROPER FILE OFFSET
while(offset!=1024) { readfunc(); ++offset; }
while(offset!=1024) { readfunc(OpaqueArgument); ++offset; }
// HERE'S THE START OF TEMPBLOCKS
for(k=0;k<sections[0].nitems;++k) {
data=readfunc();
data=readfunc(OpaqueArgument);
TempBlocks[k]=TempOb+(data-sections[1].offwords);
++offset;
}
@ -476,7 +477,7 @@ BINT rplRestoreBackupMessedup(WORD (*readfunc)())
// HERE'S THE START OF TEMPOB
for(k=0;k<sections[1].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
TempOb[k]=data;
++offset;
}
@ -485,7 +486,7 @@ BINT rplRestoreBackupMessedup(WORD (*readfunc)())
// AFTER TEMPOB
for(k=0;k<sections[2].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
TempObEnd[k]=data;
++offset;
}
@ -495,7 +496,7 @@ BINT rplRestoreBackupMessedup(WORD (*readfunc)())
for(k=0;k<sections[3].nitems;++k)
{
data=readfunc();
data=readfunc(OpaqueArgument);
if(ISROMPTRID(data)) Directories[k]=rplConvertIDToPTR(data)+DO_SOME_DAMAGE;
else Directories[k]=TempOb+(data-sections[1].offwords);
if(Directories[k]==0) ++errors; // JUST COUNT THE ERRORS BUT DON'T STOP, RECOVER AS MUCH AS POSSIBLE

View file

@ -1271,7 +1271,7 @@ void LIB_HANDLER()
return;
}
BINT64 Ai1,Ai2,Bi1,Bi2,A,B,k;
BINT64 Ai1,Ai2,Bi1,Bi2,A,B,k,oflowA,oflowB;
REAL num;
BINT isneg;
rplReadNumberAsReal(rplPeekData(1),&num);
@ -1302,14 +1302,17 @@ void LIB_HANDLER()
break;
}
k=getBINT64Real(&RReg[4]);
A=Ai2+k*Ai1;
B=Bi2+k*Bi1;
if((A<0) || (B<0)) {
oflowA=(Ai1>>32)*k+(Ai2>>32)+((((Ai1&0xffffffff)*k+(Ai2&0xffffffff))+0x80000000)>>32);
oflowA>>=31;
oflowB=(Bi1>>32)*k+(Bi2>>32)+((((Bi1&0xffffffff)*k+(Bi2&0xffffffff))+0x80000000)>>32);
oflowB>>=31;
if(oflowA || oflowB) {
// OVERFLOW! USE THE PREVIOUS RESULT
A=Ai1;
B=Bi1;
break;
}
A=Ai2+k*Ai1;
B=Bi2+k*Bi1;
Ai2=Ai1;
Bi2=Bi1;
Ai1=A;

View file

@ -59,7 +59,10 @@
CMD(SDMOVE,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2)), \
CMD(SDCOPY,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2)), \
CMD(SDPATH,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2)), \
CMD(SDFREE,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2))
CMD(SDFREE,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2)), \
CMD(SDARCHIVE,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2)), \
CMD(SDRESTORE,MKTOKENINFO(6,TITYPE_NOTALLOWED,1,2))
@ -80,7 +83,8 @@
ERR(ALREADYEXISTS,11), \
ERR(INVALIDHANDLE,12), \
ERR(IDENTORPATHEXPECTED,13), \
ERR(NOTANRPLFILE,14)
ERR(NOTANRPLFILE,14), \
ERR(INVALIDDATA,15)
@ -193,6 +197,31 @@ BINT rplPathFromList(BYTEPTR path,WORDPTR list)
return off;
}
void rplSDArchiveWriteWord(unsigned int data,void *opaque)
{
FS_FILE *file=(FS_FILE *)opaque;
FSWrite((BYTEPTR)&data,4,file);
return;
}
WORD rplSDArchiveReadWord(void *opaque)
{
WORD data;
FS_FILE *file=(FS_FILE *)opaque;
if(FSRead((BYTEPTR)&data,4,file)!=4) return 0;
return data;
}
void LIB_HANDLER()
{
if(ISPROLOG(CurOpcode)) {
@ -2093,6 +2122,177 @@ case SDPATH:
return;
}
case SDARCHIVE:
{
// STORE A BACKUP OBJECT DIRECTLY INTO A FILE
if(rplDepthData()<1) {
rplError(ERR_BADARGCOUNT);
return;
}
if(!ISIDENT(*rplPeekData(1)) && !ISSTRING(*rplPeekData(1)) && !ISLIST(*rplPeekData(1))) {
rplError(ERR_IDENTORPATHEXPECTED);
return;
}
BYTEPTR path=(BYTEPTR)RReg[0].data;
// USE RReg[0] TO STORE THE FILE PATH
if(ISIDENT(*rplPeekData(1))) {
BINT pathlen=rplGetIdentLength(rplPeekData(1));
memmoveb(path,rplPeekData(1)+1,pathlen);
path[pathlen]=0; // NULL TERMINATED STRING
} else
if(ISLIST(*rplPeekData(1))) {
// MAKE A PATH BY APPENDING ALL STRINGS/IDENTS
if(!rplPathFromList(path,rplPeekData(1))) {
rplError(ERR_BADFILENAME);
return;
}
}
else if(ISSTRING(*rplPeekData(1))) {
// FULL PATH GIVEN
BINT pathlen=rplStrSize(rplPeekData(1));
memmoveb(path,rplPeekData(1)+1,pathlen);
path[pathlen]=0; // NULL TERMINATED STRING
}
else {
// TODO: ACCEPT TAGGED NAMES WHEN TAGS EXIST
rplError(ERR_IDENTORPATHEXPECTED);
return;
}
// TRY TO OPEN THE FILE
FS_FILE *objfile;
int err;
err=FSOpen((char *)(RReg[0].data),FSMODE_WRITE|FSMODE_WRITEBUFFERS,&objfile);
err=FS_OK;
if(err!=FS_OK) {
rplError(rplFSError2Error(err));
return;
}
err = rplBackup(&rplSDArchiveWriteWord,(void *)objfile);
if(err!=FS_OK) {
FSClose(objfile);
rplError(ERR_CANTWRITE);
return;
}
FSClose(objfile);
rplDropData(1);
return;
}
case SDRESTORE:
{
// STORE A BACKUP OBJECT DIRECTLY INTO A FILE
if(rplDepthData()<1) {
rplError(ERR_BADARGCOUNT);
return;
}
if(!ISIDENT(*rplPeekData(1)) && !ISSTRING(*rplPeekData(1)) && !ISLIST(*rplPeekData(1))) {
rplError(ERR_IDENTORPATHEXPECTED);
return;
}
BYTEPTR path=(BYTEPTR)RReg[0].data;
// USE RReg[0] TO STORE THE FILE PATH
if(ISIDENT(*rplPeekData(1))) {
BINT pathlen=rplGetIdentLength(rplPeekData(1));
memmoveb(path,rplPeekData(1)+1,pathlen);
path[pathlen]=0; // NULL TERMINATED STRING
} else
if(ISLIST(*rplPeekData(1))) {
// MAKE A PATH BY APPENDING ALL STRINGS/IDENTS
if(!rplPathFromList(path,rplPeekData(1))) {
rplError(ERR_BADFILENAME);
return;
}
}
else if(ISSTRING(*rplPeekData(1))) {
// FULL PATH GIVEN
BINT pathlen=rplStrSize(rplPeekData(1));
memmoveb(path,rplPeekData(1)+1,pathlen);
path[pathlen]=0; // NULL TERMINATED STRING
}
else {
// TODO: ACCEPT TAGGED NAMES WHEN TAGS EXIST
rplError(ERR_IDENTORPATHEXPECTED);
return;
}
// TRY TO OPEN THE FILE
FS_FILE *objfile;
int err;
err=FSOpen((char *)(RReg[0].data),FSMODE_READ,&objfile);
if(err!=FS_OK) {
rplError(rplFSError2Error(err));
return;
}
GCFlags=GC_IN_PROGRESS; // MARK THAT A GC IS IN PROGRESS TO BLOCK ANY HARDWARE INTERRUPTS
err = rplRestoreBackup(&rplSDArchiveReadWord,(void *)objfile);
FSClose(objfile);
switch(err)
{
case -1:
// FILE WAS CORRUPTED, AND MEMORY WAS DESTROYED
GCFlags=GC_COMPLETED; // MARK THAT GC WAS COMPLETED
FSShutdown();
throw_dbgexception("Memory lost during restore",__EX_WIPEOUT|__EX_RESET|__EX_NOREG);
// THIS WON'T RETURN, ONLY A RESET IS ACCEPTABLE AT THIS POINT
return;
case 0:
// FILE WAS CORRUPTED, BUT MEMORY IS STILL INTACT
rplError(ERR_INVALIDDATA);
GCFlags=0; // NOTHING MOVED IN MEMORY, SO DON'T SIGNAL THAT A GC TOOK PLACE
return;
default:
case 1:
// SUCCESS! STILL NEED TO DO A WARMSTART
// FALL THROUGH
case 2:
// SOME ERRORS, BUT rplWarmInit WILL FIX AUTOMATICALLY
FSShutdown();
rplWarmInit();
FSHardReset();
GCFlags=GC_COMPLETED; // MARK THAT GC WAS COMPLETED SO HARDWARE INTERRUPTS ARE ACCEPTED AGAIN
rplException(EX_EXITRPL);
return;
}
return;
}
// STANDARIZED OPCODES:
// --------------------
// LIBRARIES ARE FORCED TO ALWAYS HANDLE THE STANDARD OPCODES

View file

@ -395,8 +395,8 @@ WORD rplUpdateSuggestion(WORD suggestion,BYTEPTR start,BYTEPTR end);
void rplGCollect();
// BACKUP/RESTORE
BINT rplBackup(void (*writefunc)(unsigned int));
BINT rplRestoreBackup(WORD (*readfunc)());
BINT rplBackup(void (*writefunc)(unsigned int,void *),void *OpaqueArg);
BINT rplRestoreBackup(WORD (*readfunc)(void *),void *Opaque);
// SYSTEM SANITY CHECKS

View file

@ -173,7 +173,7 @@ I I →"
@#name cmd_TEVAL
:: 0 '.TckStart' LSTO TICKS '.TckStart' LSTO HIDELOCALS EVAL TICKS UNHIDELOCALS .TckStart - 1000000 / ;
« :: 0 '.TckStart' LSTO TICKS '.TckStart' LSTO HIDELOCALS EVAL TICKS UNHIDELOCALS .TckStart - 1000000 / ; »