Removing Storage compile warnings, more tests and a few fixes for memory leaks

This commit is contained in:
Gordon Williams 2023-06-20 16:09:48 +01:00
parent a287150167
commit 8f6bb0fdfc
2 changed files with 108 additions and 53 deletions

View File

@ -29,12 +29,12 @@
#define DBG(...)
#endif
const int STORAGEFILE_CHUNKSIZE =
const int STORAGEFILE_CHUNKSIZE =
#if FLASH_SAVED_CODE_LENGTH < 1000000
// for normal devices
(((FLASH_PAGE_SIZE<4096)?FLASH_PAGE_SIZE:4096) - sizeof(JsfFileHeader)); // use 32 for testing
#else
// where we have large external flash (eg Bangle.js), choose a chunk size much bigger than the
// where we have large external flash (eg Bangle.js), choose a chunk size much bigger than the
// page size. This allows us to have less chunks around, and to store much bigger files.
(FLASH_PAGE_SIZE*10) - sizeof(JsfFileHeader);
#endif
@ -163,7 +163,7 @@ JsVar *jswrap_storage_readJSON(JsVar *name, bool noExceptions) {
jsvUnLock(v);
if (noExceptions) {
jsvUnLock(jspGetException());
execInfo.execute &= ~EXEC_EXCEPTION;
execInfo.execute &= (JsExecFlags)~EXEC_EXCEPTION;
}
return r;
}
@ -373,7 +373,7 @@ instance the bootloader will add all `.boot.js` files together into a single
`.boot0` file, but it needs to know quickly whether anything has changed.
*/
JsVarInt jswrap_storage_hash(JsVar *regex) {
return jsfHashFiles(regex, 0, JSFF_STORAGEFILE);
return (JsVarInt)jsfHashFiles(regex, 0, JSFF_STORAGEFILE);
}
/*JSON{
@ -456,12 +456,12 @@ JsVar *jswrap_storage_getStats() {
JsVar *o = jsvNewObject();
if (!o) return NULL;
JsfStorageStats stats = jsfGetStorageStats(0, true);
jsvObjectSetChildAndUnLock(o, "totalBytes", jsvNewFromInteger(stats.total));
jsvObjectSetChildAndUnLock(o, "freeBytes", jsvNewFromInteger(stats.free));
jsvObjectSetChildAndUnLock(o, "fileBytes", jsvNewFromInteger(stats.fileBytes));
jsvObjectSetChildAndUnLock(o, "fileCount", jsvNewFromInteger(stats.fileCount));
jsvObjectSetChildAndUnLock(o, "trashBytes", jsvNewFromInteger(stats.trashBytes));
jsvObjectSetChildAndUnLock(o, "trashCount", jsvNewFromInteger(stats.trashCount));
jsvObjectSetChildAndUnLock(o, "totalBytes", jsvNewFromInteger((JsVarInt)stats.total));
jsvObjectSetChildAndUnLock(o, "freeBytes", jsvNewFromInteger((JsVarInt)stats.free));
jsvObjectSetChildAndUnLock(o, "fileBytes", jsvNewFromInteger((JsVarInt)stats.fileBytes));
jsvObjectSetChildAndUnLock(o, "fileCount", jsvNewFromInteger((JsVarInt)stats.fileCount));
jsvObjectSetChildAndUnLock(o, "trashBytes", jsvNewFromInteger((JsVarInt)stats.trashBytes));
jsvObjectSetChildAndUnLock(o, "trashCount", jsvNewFromInteger((JsVarInt)stats.trashCount));
return o;
}
@ -522,7 +522,7 @@ JsVar *jswrap_storage_open(JsVar *name, JsVar *modeVar) {
JsfFileName fname = jsfNameFromVar(n);
int fnamei = sizeof(fname)-1;
while (fnamei && fname.c[fnamei-1]==0) fnamei--;
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
jsvObjectSetChildAndUnLock(f,"name",n);
int offset = 0; // offset in file
@ -534,16 +534,16 @@ JsVar *jswrap_storage_open(JsVar *name, JsVar *modeVar) {
addr = 0;
}
}
uint32_t fileLen = addr ? jsfGetFileSize(&header) : 0;
int fileLen = addr ? (int)jsfGetFileSize(&header) : 0;
if (mode=='a') { // append
// Find the last free page (eg it has 0xFF at the end)
unsigned char lastCh = 255;
if (addr) jshFlashRead(&lastCh, addr+jsfGetFileSize(&header)-1, 1);
while (addr && lastCh!=255 && chunk<255) {
chunk++;
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
addr = jsfFindFile(fname, &header);
fileLen = jsfGetFileSize(&header);
fileLen = (int)jsfGetFileSize(&header);
if (addr) jshFlashRead(&lastCh, addr+jsfGetFileSize(&header)-1, 1);
}
if (addr) {
@ -551,13 +551,13 @@ JsVar *jswrap_storage_open(JsVar *name, JsVar *modeVar) {
char buf[64];
bool foundEnd = false;
while (!foundEnd) {
int l = fileLen - offset;
int l = (int)fileLen - offset;
if (l<=0) {
foundEnd = true;
break;
}
if (l>(int)sizeof(buf)) l=(int)sizeof(buf);
jshFlashRead(buf, addr+offset, l);
jshFlashRead(buf, addr+(uint32_t)offset, (uint32_t)l);
for (int i=0;i<l;i++) {
if (buf[i]==(char)255) {
l = i;
@ -577,7 +577,7 @@ JsVar *jswrap_storage_open(JsVar *name, JsVar *modeVar) {
DBG("Open %j Chunk %d Offset %d addr 0x%08x len %d\n",name,chunk,offset,addr,fileLen);
jsvObjectSetChildAndUnLock(f,"chunk",jsvNewFromInteger(chunk));
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger(addr));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger((JsVarInt)addr));
jsvObjectSetChildAndUnLock(f,"len",jsvNewFromInteger(fileLen));
jsvObjectSetChildAndUnLock(f,"mode",jsvNewFromInteger(mode));
@ -651,7 +651,7 @@ JsVar *jswrap_storagefile_read_internal(JsVar *f, int len) {
JsfFileName fname = jsfNameFromVarAndUnLock(jsvObjectGetChildIfExists(f,"name"));
int fnamei = sizeof(fname)-1;
while (fnamei && fname.c[fnamei-1]==0) fnamei--;
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
JsVar *result = 0;
char buf[32];
@ -664,13 +664,13 @@ JsVar *jswrap_storagefile_read_internal(JsVar *f, int len) {
addr=0;
} else {
chunk++;
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
JsfFileHeader header;
addr = jsfFindFile(fname, &header);
fileLen = jsfGetFileSize(&header);
fileLen = (int)jsfGetFileSize(&header);
jsvObjectSetChildAndUnLock(f,"len",jsvNewFromInteger(fileLen));
}
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger(addr));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger((JsVarInt)addr));
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
jsvObjectSetChildAndUnLock(f,"chunk",jsvNewFromInteger(chunk));
remaining = fileLen;
@ -682,7 +682,7 @@ JsVar *jswrap_storagefile_read_internal(JsVar *f, int len) {
int l = len;
if (l>(int)sizeof(buf)) l=(int)sizeof(buf);
if (l>remaining) l=remaining;
jshFlashRead(buf, addr+offset, l);
jshFlashRead(buf, addr+(uint32_t)offset, (uint32_t)l);
for (int i=0;i<l;i++) {
if (buf[i]==(char)255) {
// end of file!
@ -702,7 +702,7 @@ JsVar *jswrap_storagefile_read_internal(JsVar *f, int len) {
if (!result)
result = jsvNewFromEmptyString();
if (result)
jsvAppendStringBuf(result,buf,l);
jsvAppendStringBuf(result,buf,(size_t)l);
len -= l;
offset += l;
@ -770,7 +770,7 @@ int jswrap_storagefile_getLength(JsVar *f) {
int fnamei = sizeof(fname)-1;
while (fnamei && fname.c[fnamei-1]==0) fnamei--;
int chunk = 1;
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
int length = 0; // actual length
int offset = 0; // offset in file
@ -780,9 +780,9 @@ int jswrap_storagefile_getLength(JsVar *f) {
unsigned char lastCh = 255;
if (addr) jshFlashRead(&lastCh, addr+jsfGetFileSize(&header)-1, 1);
while (addr && lastCh!=255 && chunk<255) {
length += jsfGetFileSize(&header);
length += (int)jsfGetFileSize(&header);
chunk++;
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
addr = jsfFindFile(fname, &header);
if (addr) jshFlashRead(&lastCh, addr+jsfGetFileSize(&header)-1, 1);
}
@ -791,13 +791,13 @@ int jswrap_storagefile_getLength(JsVar *f) {
char buf[64];
bool foundEnd = false;
while (!foundEnd) {
int l = jsfGetFileSize(&header) - offset;
int l = (int)jsfGetFileSize(&header) - offset;
if (l<=0) {
foundEnd = true;
break;
}
if (l>(int)sizeof(buf)) l=(int)sizeof(buf);
jshFlashRead(buf, addr+offset, l);
jshFlashRead(buf, addr+(uint32_t)offset, (uint32_t)l);
for (int i=0;i<l;i++) {
if (buf[i]==(char)255) {
l = i;
@ -838,7 +838,10 @@ void jswrap_storagefile_write(JsVar *f, JsVar *_data) {
JsVar *data = jsvAsString(_data);
if (!data) return;
size_t len = jsvGetStringLength(data);
if (len==0) return;
if (len==0) {
jsvUnLock(data);
return;
}
int offset = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(f,"offset"));
int fileLen = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(f,"len"));
int chunk = jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(f,"chunk"));
@ -846,20 +849,21 @@ void jswrap_storagefile_write(JsVar *f, JsVar *_data) {
int fnamei = sizeof(fname)-1;
while (fnamei && fname.c[fnamei-1]==0) fnamei--;
//DBG("Filename[%d]=%d\n",fnamei,chunk);
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
uint32_t addr = (uint32_t)jsvGetIntegerAndUnLock(jsvObjectGetChildIfExists(f,"addr"));
DBG("Write Chunk %d Offset %d addr 0x%08x\n",chunk,offset,addr);
int remaining = fileLen - offset;
if (addr) {
JsfFileHeader header;
// check the header before we write, just to ensure it's all as expected!
jshFlashRead(&header, addr-(uint32_t)sizeof(JsfFileHeader), sizeof(JsfFileHeader));
if (memcmp(&header.name, &fname, fnamei+1)!=0) {
if (memcmp(&header.name, &fname, sizeof(fname))!=0) { // uh-oh, it's different!
addr = jsfFindFile(fname, &header);
if (!addr) {
jsvUnLock(data);
jsExceptionHere(JSET_ERROR, "File deleted while writing!");
return;
} else {
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger(addr));
} else { // file has moved - update addr
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger((JsVarInt)addr));
}
}
} else {
@ -867,29 +871,33 @@ void jswrap_storagefile_write(JsVar *f, JsVar *_data) {
if (jsfWriteFile(fname, data, JSFF_STORAGEFILE, 0, STORAGEFILE_CHUNKSIZE)) {
JsfFileHeader header;
addr = jsfFindFile(fname, &header);
fileLen = jsfGetFileSize(&header);
offset = len;
fileLen = (int)jsfGetFileSize(&header);
offset = (int)len;
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
jsvObjectSetChildAndUnLock(f,"len",jsvNewFromInteger(fileLen));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger(addr));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger((JsVarInt)addr));
} else {
DBG("Write Create Chunk FAILED\n");
// there would already have been an exception
}
jsvUnLock(data);
return;
}
int remaining = fileLen - offset;
if ((int)len<remaining) {
DBG("Write Append Chunk\n");
// Great, it all fits in
jswrap_flash_write(data, addr+offset);
offset += len;
jswrap_flash_write(data, (int)addr+offset);
offset += (int)len;
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
} else {
DBG("Write Append Chunk and create new\n");
DBG("Write Append Chunk and create new file\n");
// Fill up this page, do part of old page
// End of this page
JsVar *part = jsvNewFromStringVar(data,0,remaining);
jswrap_flash_write(part, addr+offset);
JsVar *part = jsvNewFromStringVar(data,0,(size_t)remaining);
jswrap_flash_write(part, (int)addr+offset);
offset += remaining; // update offset now we've written
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
jsvUnLock(part);
// Next page
if (chunk==255) {
@ -898,26 +906,24 @@ void jswrap_storagefile_write(JsVar *f, JsVar *_data) {
return;
} else {
chunk++;
fname.c[fnamei]=chunk;
jsvObjectSetChildAndUnLock(f,"chunk",jsvNewFromInteger(chunk));
fname.c[fnamei]=(char)chunk;
}
// Write Next page
part = jsvNewFromStringVar(data,remaining,JSVAPPENDSTRINGVAR_MAXLENGTH);
part = jsvNewFromStringVar(data,(size_t)remaining,JSVAPPENDSTRINGVAR_MAXLENGTH);
if (jsfWriteFile(fname, part, JSFF_STORAGEFILE, 0, STORAGEFILE_CHUNKSIZE)) {
JsfFileHeader header;
addr = jsfFindFile(fname, &header);
fileLen = jsfGetFileSize(&header);
offset = len;
fileLen = (int)jsfGetFileSize(&header);
offset = (int)jsvGetStringLength(part);
jsvObjectSetChildAndUnLock(f,"chunk",jsvNewFromInteger(chunk));
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
jsvObjectSetChildAndUnLock(f,"len",jsvNewFromInteger(fileLen));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger(addr));
jsvObjectSetChildAndUnLock(f,"addr",jsvNewFromInteger((JsVarInt)addr));
} else {
jsvUnLock(data);
return; // there would already have been an exception
// there would already have been an exception - no need to return
// we can free data up below
}
offset = jsvGetStringLength(part);
jsvUnLock(part);
jsvObjectSetChildAndUnLock(f,"offset",jsvNewFromInteger(offset));
}
jsvUnLock(data);
}
@ -939,7 +945,7 @@ void jswrap_storagefile_erase(JsVar *f) {
int chunk = 1;
bool ok = true;
while (ok) {
fname.c[fnamei]=chunk;
fname.c[fnamei]=(char)chunk;
ok = jsfEraseFile(fname);
chunk++;
}

View File

@ -40,4 +40,53 @@ test(s.list().length, 0);
//print(JSON.stringify(s.read("foobar\1")));
//print(JSON.stringify(s.read("foobar\2")));
// Test write with no space at all
s.eraseAll();
s.write("blob", "\xFF", 0, s.getStats().freeBytes-200);
f = s.open("foobar","w");
try {
tests++;
f.write("Hello World");
} catch (e) { // this should throw an error - no space
console.log("EXPECTED ERROR", e);
testsPass++;
}
// Test write with only enough space for one page (1024 bytes on Linux currently)
s.eraseAll();
s.write("blob", "\xFF", 0, s.getStats().freeBytes-1500);
f = s.open("foobar","w");
var buffer = "This is a long line of text that we want to write to our file over and over and over.\n"; // 86 bytes
console.log("Write ",f);
f.write(buffer.repeat(11)); // 946 bytes
console.log("After write ",f);
f.write(""); // 0 bytes
try {
tests++;
f.write(buffer); // 86 bytes - should fail as not enough space - fills up to end up current page, tries to write more
} catch (e) { // this should throw an error - no space
console.log("EXPECTED ERROR 2", e);
testsPass++;
}
console.log("After failed write ",f);
try {
tests++;
f.write("Hello"); // 5 bytes
} catch (e) { // this should throw an error - no space
console.log("EXPECTED ERROR 3", e);
testsPass++;
}
console.log("After failed write ",f);
print(JSON.stringify(s.list()));
try {
tests++;
f.write("A"); // 1 bytes
} catch (e) { // this should throw an error - no space
console.log("EXPECTED ERROR 4", e);
testsPass++;
}
result = tests==testsPass;