Webclient: Avoid strerror for printing error code descriptions and use custom implementation instead

Because the error codes hardcoded in interop_web.js no longer match the error codes in emscripten, strerror would print unexpected descriptions due to assuming the provided value used emscripten error codes values

(E.g. 'ENOENT' returned by interop_web.js would output 'Operation not permitted' from strerror)
This commit is contained in:
UnknownShadow200 2023-07-11 20:18:38 +10:00
parent b5f0076d46
commit 6f754a1187
3 changed files with 116 additions and 99 deletions

View File

@ -22,20 +22,28 @@
#define O_EXCL 0x080 #define O_EXCL 0x080
#define O_TRUNC 0x200 #define O_TRUNC 0x200
/* Unfortunately, errno constants are different in some older emscripten versions */ /* General error codes */
/* (linux errno numbers compared to WASI errno numbers) */ #define E_INVALID_VALUE 1
/* So just use the same errono numbers as interop_web.js */ /* File I/O specific errors */
#define _ENOENT 2 #define E_ENTRY_NOT_FOUND 2
#define _EAGAIN 6 /* same as EWOULDBLOCK */ #define E_ENTRY_EXISTS 3
#define _EEXIST 17 #define E_FD_CLOSED 4
#define _EHOSTUNREACH 23 #define E_TOO_MANY_FDS 5
#define _EINPROGRESS 26 #define E_READONLY_FILE 6
#define E_WRITEONLY_FILE 7
/* Socket specific errors */
#define E_IS_CONN 8
#define E_NOT_CONN 9
#define E_WOULD_BLOCK 10
#define E_INVALID_HOST 11
#define E_CONN_INPROGRESS 12
#define E_CONN_REFUSED 13
const cc_result ReturnCode_FileShareViolation = 1000000000; /* Not used in web filesystem backend */ const cc_result ReturnCode_FileShareViolation = 1000000000; /* Not used in web filesystem backend */
const cc_result ReturnCode_FileNotFound = _ENOENT; const cc_result ReturnCode_FileNotFound = E_ENTRY_NOT_FOUND;
const cc_result ReturnCode_SocketInProgess = _EINPROGRESS; const cc_result ReturnCode_SocketInProgess = E_CONN_INPROGRESS;
const cc_result ReturnCode_SocketWouldBlock = _EAGAIN; const cc_result ReturnCode_SocketWouldBlock = E_WOULD_BLOCK;
const cc_result ReturnCode_DirectoryExists = _EEXIST; const cc_result ReturnCode_DirectoryExists = E_ENTRY_EXISTS;
/*########################################################################################################################* /*########################################################################################################################*
@ -123,7 +131,7 @@ EMSCRIPTEN_KEEPALIVE void Directory_IterCallback(const char* src) {
enum_callback(&path, enum_obj); enum_callback(&path, enum_obj);
} }
extern int interop_DirectoryIter(const char* path); extern int interop_DirectoryIterate(const char* path);
cc_result Directory_Enum(const cc_string* path, void* obj, Directory_EnumCallback callback) { cc_result Directory_Enum(const cc_string* path, void* obj, Directory_EnumCallback callback) {
char str[NATIVE_STR_LEN]; char str[NATIVE_STR_LEN];
String_EncodeUtf8(str, path); String_EncodeUtf8(str, path);
@ -131,7 +139,7 @@ cc_result Directory_Enum(const cc_string* path, void* obj, Directory_EnumCallbac
enum_obj = obj; enum_obj = obj;
enum_callback = callback; enum_callback = callback;
/* returned result is negative for error */ /* returned result is negative for error */
return -interop_DirectoryIter(str); return -interop_DirectoryIterate(str);
} }
extern int interop_FileCreate(const char* path, int mode); extern int interop_FileCreate(const char* path, int mode);
@ -266,7 +274,7 @@ cc_result Socket_Connect(cc_socket* s, const cc_string* address, int port, cc_bo
res = -interop_SocketConnect(*s, addr, port); res = -interop_SocketConnect(*s, addr, port);
/* error returned when invalid address provided */ /* error returned when invalid address provided */
if (res == _EHOSTUNREACH) return ERR_INVALID_ARGUMENT; if (res == E_INVALID_HOST) return ERR_INVALID_ARGUMENT;
return res; return res;
} }
@ -284,8 +292,8 @@ cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* r
*read += res; *read += res;
data += res; count -= res; data += res; count -= res;
} else { } else {
/* EAGAIN when no more data available */ /* E_WOULD_BLOCK when no more data available */
if (res == -_EAGAIN) return *read == 0 ? _EAGAIN : 0; if (res == -E_WOULD_BLOCK) return *read == 0 ? E_WOULD_BLOCK : 0;
return -res; return -res;
} }
@ -301,11 +309,11 @@ cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_ui
if (res >= 0) { if (res >= 0) {
*modified = res; return 0; *modified = res; return 0;
} else { } else {
*modified = 0; return -res; *modified = 0; return -res;
} }
} }
extern int interop_SocketClose(int sock); extern void interop_SocketClose(int sock);
void Socket_Close(cc_socket s) { void Socket_Close(cc_socket s) {
interop_SocketClose(s); interop_SocketClose(s);
} }
@ -343,20 +351,37 @@ cc_result Process_StartOpen(const cc_string* args) {
/*########################################################################################################################* /*########################################################################################################################*
*--------------------------------------------------------Platform---------------------------------------------------------* *--------------------------------------------------------Platform---------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
static const char* const error_descs[] = {
NULL,
"Invalid argument", /* E_INVALID_VALUE */
"No such file or directory", /* E_ENTRY_NOT_FOUND */
"File or directory already exists", /* E_ENTRY_EXISTS */
"File descriptor already closed", /* E_FD_CLOSED */
"Too many open File descriptors", /* E_TOO_MANY_FDS */
"Write to readonly file", /* E_READONLY_FILE */
"Read on writeonly file", /* E_WRITEONLY_FILE */
"Socket already connecting", /* E_IS_CONN */
"Socket not connected", /* E_NOT_CONN */
"Operation would block", /* E_WOULD_BLOCK */
"Invalid host provided", /* E_INVALID_HOST */
"Connection in progress", /* E_CONN_INPROGRESS */
"Connection refused", /* E_CONN_REFUSED */
};
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) { cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
char* str; char* str;
int len; int len;
/* For unrecognised error codes, strerror might return messages */ if (res > 0 && res < Array_Elems(error_descs)) {
/* such as 'No error information', which is not very useful */ str = error_descs[res];
if (res >= 1000) return false; len = String_CalcLen(str, NATIVE_STR_LEN);
str = strerror(res); String_AppendUtf8(dst, str, len);
if (!str) return false; return true;
}
len = String_CalcLen(str, NATIVE_STR_LEN); return false;
String_AppendUtf8(dst, str, len);
return true;
} }
EMSCRIPTEN_KEEPALIVE void Platform_LogError(const char* msg) { EMSCRIPTEN_KEEPALIVE void Platform_LogError(const char* msg) {

View File

@ -585,7 +585,8 @@ cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
fileBuffer[file.length] = '\0'; fileBuffer[file.length] = '\0';
/* Calls Window_OnFileUploaded on success */ /* Calls Window_OnFileUploaded on success */
return interop_DownloadFile(fileBuffer, args->filters, args->titles); /* returned result is negative for error */
return -interop_DownloadFile(fileBuffer, args->filters, args->titles);
} }
void Window_AllocFramebuffer(struct Bitmap* bmp) { } void Window_AllocFramebuffer(struct Bitmap* bmp) { }

View File

@ -235,24 +235,20 @@ mergeInto(LibraryManager.library, {
var path = UTF8ToString(raw); var path = UTF8ToString(raw);
CCFS.chdir(path); CCFS.chdir(path);
}, },
interop_DirectoryIter: function(raw) { interop_DirectoryIterate: function(raw) {
var path = UTF8ToString(raw); var root = UTF8ToString(raw);
try { var entries = CCFS.getDirEntries(root);
var entries = CCFS.readdir(path);
for (var i = 0; i < entries.length; i++) for (var i = 0; i < entries.length; i++)
{ {
var path = entries[i]; var path = entries[i];
// absolute path to root relative path // absolute path to root relative path
if (path.indexOf(CCFS.currentPath) === 0) { if (path.indexOf(CCFS.currentPath) === 0) {
path = path.substring(CCFS.currentPath.length + 1); path = path.substring(CCFS.currentPath.length + 1);
}
ccall('Directory_IterCallback', 'void', ['string'], [path]);
} }
return 0; ccall('Directory_IterCallback', 'void', ['string'], [path]);
} catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno;
} }
return 0;
}, },
interop_FileExists: function (raw) { interop_FileExists: function (raw) {
var path = UTF8ToString(raw); var path = UTF8ToString(raw);
@ -267,7 +263,7 @@ mergeInto(LibraryManager.library, {
return stream.fd|0; return stream.fd|0;
} catch (e) { } catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e); if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno; return e.errno;
} }
}, },
interop_FileRead: function(fd, dst, count) { interop_FileRead: function(fd, dst, count) {
@ -276,7 +272,7 @@ mergeInto(LibraryManager.library, {
return CCFS.read(stream, HEAP8, dst, count)|0; return CCFS.read(stream, HEAP8, dst, count)|0;
} catch (e) { } catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e); if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno; return e.errno;
} }
}, },
interop_FileWrite: function(fd, src, count) { interop_FileWrite: function(fd, src, count) {
@ -285,7 +281,7 @@ mergeInto(LibraryManager.library, {
return CCFS.write(stream, HEAP8, src, count)|0; return CCFS.write(stream, HEAP8, src, count)|0;
} catch (e) { } catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e); if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno; return e.errno;
} }
}, },
interop_FileSeek: function(fd, offset, whence) { interop_FileSeek: function(fd, offset, whence) {
@ -294,17 +290,12 @@ mergeInto(LibraryManager.library, {
return CCFS.llseek(stream, offset, whence)|0; return CCFS.llseek(stream, offset, whence)|0;
} catch (e) { } catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e); if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno; return e.errno;
} }
}, },
interop_FileLength: function(fd) { interop_FileLength: function(fd) {
try { var stream = CCFS.getStream(fd);
var stream = CCFS.getStream(fd); return stream.node.usedBytes|0;
return stream.node.usedBytes|0;
} catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno;
}
}, },
interop_FileClose: function(fd) { interop_FileClose: function(fd) {
try { try {
@ -315,7 +306,7 @@ mergeInto(LibraryManager.library, {
return 0; return 0;
} catch (e) { } catch (e) {
if (!(e instanceof CCFS.ErrnoError)) abort(e); if (!(e instanceof CCFS.ErrnoError)) abort(e);
return -e.errno; return e.errno;
} }
}, },
interop_FileClose__deps: ['interop_SaveNode'], interop_FileClose__deps: ['interop_SaveNode'],
@ -346,7 +337,7 @@ mergeInto(LibraryManager.library, {
ccall('Platform_LogError', 'void', ['string'], [' &c' + err]); ccall('Platform_LogError', 'void', ['string'], [' &c' + err]);
}; };
var stat, node, entry; var node, entry;
try { try {
var lookup = CCFS.lookupPath(path); var lookup = CCFS.lookupPath(path);
node = lookup.node; node = lookup.node;
@ -429,7 +420,7 @@ mergeInto(LibraryManager.library, {
db.onclose = function(ev) { db.onclose = function(ev) {
console.log('IndexedDB connection closed unexpectedly!'); console.log('IndexedDB connection closed unexpectedly!');
window.IDBFS_db = null; window.IDBFS_db = null;
} };
callback(null, db); callback(null, db);
}; };
req.onerror = function(e) { req.onerror = function(e) {
@ -547,7 +538,8 @@ mergeInto(LibraryManager.library, {
//######################################################################################################################## //########################################################################################################################
interop_InitSockets: function() { interop_InitSockets: function() {
window.SOCKETS = { window.SOCKETS = {
EBADF:-8,EISCONN:-30,ENOTCONN:-53,EAGAIN:-6,EHOSTUNREACH:-23,EINPROGRESS:-26,EALREADY:-7,ECONNRESET:-15,EINVAL:-28,ECONNREFUSED:-14, E_INVALID_VALUE:-1,E_IS_CONN:-8,E_NOT_CONN:-9,E_WOULD_BLOCK:-10,
E_INVALID_HOST:-11,E_CONN_INPROGRESS:-12,E_CONN_REFUSED:-13,
sockets: [], sockets: [],
}; };
}, },
@ -564,14 +556,10 @@ mergeInto(LibraryManager.library, {
interop_SocketConnect: function(sockFD, raw, port) { interop_SocketConnect: function(sockFD, raw, port) {
var addr = UTF8ToString(raw); var addr = UTF8ToString(raw);
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF;
// already connecting or connected // already connecting or connected
var ws = sock.socket; var ws = sock.socket;
if (ws) { if (ws) return SOCKETS.E_IS_CONN;
if (ws.readyState === ws.CONNECTING) return SOCKETS.EALREADY;
return SOCKETS.EISCONN;
}
// create the actual websocket object and connect // create the actual websocket object and connect
try { try {
@ -582,7 +570,7 @@ mergeInto(LibraryManager.library, {
ws = new WebSocket(url, 'ClassiCube'); ws = new WebSocket(url, 'ClassiCube');
ws.binaryType = 'arraybuffer'; ws.binaryType = 'arraybuffer';
} catch (e) { } catch (e) {
return SOCKETS.EHOSTUNREACH; return SOCKETS.E_INVALID_HOST;
} }
sock.socket = ws; sock.socket = ws;
@ -609,31 +597,30 @@ mergeInto(LibraryManager.library, {
ws.onerror = function(error) { ws.onerror = function(error) {
// The WebSocket spec only allows a 'simple event' to be thrown on error, // The WebSocket spec only allows a 'simple event' to be thrown on error,
// so we only really know as much as ECONNREFUSED. // so we only really know as much as ECONNREFUSED.
sock.error = SOCKETS.ECONNREFUSED; // Used by interop_SocketWritable sock.error = SOCKETS.E_CONN_REFUSED; // Used by interop_SocketWritable
}; };
// always "fail" in non-blocking mode // always "fail" in non-blocking mode
return SOCKETS.EINPROGRESS; return SOCKETS.E_CONN_INPROGRESS;
}, },
interop_SocketClose: function(sockFD) { interop_SocketClose: function(sockFD) {
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF; if (!sock) return;
try { try {
sock.socket.close(); sock.socket.close();
} catch (e) { } catch (e) {
} }
delete sock.socket; delete sock.socket;
return 0; return;
}, },
interop_SocketSend: function(sockFD, src, length) { interop_SocketSend: function(sockFD, src, length) {
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF; var ws = sock.socket;
var ws = sock.socket;
if (!ws || ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) { if (!ws || ws.readyState === ws.CLOSING || ws.readyState === ws.CLOSED) {
return SOCKETS.ENOTCONN; return SOCKETS.E_NOT_CONN;
} else if (ws.readyState === ws.CONNECTING) { } else if (ws.readyState === ws.CONNECTING) {
return SOCKETS.EAGAIN; return SOCKETS.E_CONN_INPROGRESS;
} }
// var data = HEAP8.slice(src, src + length); unsupported in IE11 // var data = HEAP8.slice(src, src + length); unsupported in IE11
@ -646,22 +633,21 @@ mergeInto(LibraryManager.library, {
ws.send(data); ws.send(data);
return length; return length;
} catch (e) { } catch (e) {
return SOCKETS.EINVAL; return SOCKETS.E_INVALID_VALUE;
} }
}, },
interop_SocketRecv: function(sockFD, dst, length) { interop_SocketRecv: function(sockFD, dst, length) {
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF;
var packet = sock.recv_queue.shift(); var packet = sock.recv_queue.shift();
if (!packet) { if (!packet) {
var ws = sock.socket; var ws = sock.socket;
if (!ws || ws.readyState == ws.CLOSING || ws.readyState == ws.CLOSED) { if (!ws || ws.readyState == ws.CLOSING || ws.readyState == ws.CLOSED) {
return SOCKETS.ENOTCONN; return SOCKETS.E_NOT_CONN;
} else { } else {
// socket is in a valid state but truly has nothing available // socket is in a valid state but truly has nothing available
return SOCKETS.EAGAIN; return SOCKETS.E_WOULD_BLOCK;
} }
} }
@ -686,10 +672,9 @@ mergeInto(LibraryManager.library, {
interop_SocketWritable: function(sockFD, writable) { interop_SocketWritable: function(sockFD, writable) {
HEAPU8[writable|0] = 0; HEAPU8[writable|0] = 0;
var sock = SOCKETS.sockets[sockFD]; var sock = SOCKETS.sockets[sockFD];
if (!sock) return SOCKETS.EBADF;
var ws = sock.socket; var ws = sock.socket;
if (!ws) return SOCKETS.ENOTCONN; if (!ws) return SOCKETS.E_NOT_CONN;
if (ws.readyState === ws.OPEN) HEAPU8[writable|0] = 1; if (ws.readyState === ws.OPEN) HEAPU8[writable|0] = 1;
return sock.error || 0; return sock.error || 0;
}, },
@ -1210,7 +1195,13 @@ mergeInto(LibraryManager.library, {
window.CCFS={ window.CCFS={
streams:[],entries:{},currentPath:"/",ErrnoError:null, streams:[],
entries:{},
currentPath:"/",
ErrnoError:null,
E_INVALID_VALUE:-1,E_ENTRY_NOT_FOUND:-2,E_ENTRY_EXISTS:-3,
E_FD_CLOSED:-4,E_TOO_MANY_FDS:-5,E_READONLY_FILE:-6,E_WRITEONLY_FILE:-7,
resolvePath:function(path) { resolvePath:function(path) {
if (path.charAt(0) !== '/') { if (path.charAt(0) !== '/') {
path = CCFS.currentPath + '/' + path; path = CCFS.currentPath + '/' + path;
@ -1221,7 +1212,7 @@ mergeInto(LibraryManager.library, {
path = CCFS.resolvePath(path); path = CCFS.resolvePath(path);
var node = CCFS.entries[path]; var node = CCFS.entries[path];
if (!node) throw new CCFS.ErrnoError(2); if (!node) throw new CCFS.ErrnoError(CCFS.E_ENTRY_NOT_FOUND);
return { path: path, node: node }; return { path: path, node: node };
}, },
createNode:function(path) { createNode:function(path) {
@ -1239,7 +1230,7 @@ mergeInto(LibraryManager.library, {
{ {
if (!CCFS.streams[fd]) return fd; if (!CCFS.streams[fd]) return fd;
} }
throw new CCFS.ErrnoError(24); throw new CCFS.ErrnoError(CCFS.E_TOO_MANY_FDS);
}, },
getStream:function(fd) { getStream:function(fd) {
return CCFS.streams[fd]; return CCFS.streams[fd];
@ -1250,7 +1241,7 @@ mergeInto(LibraryManager.library, {
CCFS.streams[fd] = stream; CCFS.streams[fd] = stream;
return stream; return stream;
}, },
readdir:function(path) { getDirEntries:function(path) {
path = CCFS.resolvePath(path) + '/'; path = CCFS.resolvePath(path) + '/';
// all entries starting with given directory // all entries starting with given directory
@ -1282,7 +1273,7 @@ mergeInto(LibraryManager.library, {
if (node) { if (node) {
// if O_CREAT and O_EXCL are set, error out if the node already exists // if O_CREAT and O_EXCL are set, error out if the node already exists
if ((flags & 128)) { if ((flags & 128)) {
throw new CCFS.ErrnoError(17); throw new CCFS.ErrnoError(CCFS.E_ENTRY_EXISTS);
} }
} else { } else {
// node doesn't exist, try to create it // node doesn't exist, try to create it
@ -1291,7 +1282,7 @@ mergeInto(LibraryManager.library, {
} }
} }
if (!node) { if (!node) {
throw new CCFS.ErrnoError(2); throw new CCFS.ErrnoError(CCFS.E_ENTRY_NOT_FOUND);
} }
// do truncation if necessary // do truncation if necessary
@ -1314,7 +1305,7 @@ mergeInto(LibraryManager.library, {
}, },
close:function(stream) { close:function(stream) {
if (CCFS.isClosed(stream)) { if (CCFS.isClosed(stream)) {
throw new CCFS.ErrnoError(9); throw new CCFS.ErrnoError(CCFS.E_FD_CLOSED);
} }
CCFS.streams[stream.fd] = null; CCFS.streams[stream.fd] = null;
@ -1325,7 +1316,7 @@ mergeInto(LibraryManager.library, {
}, },
llseek:function(stream, offset, whence) { llseek:function(stream, offset, whence) {
if (CCFS.isClosed(stream)) { if (CCFS.isClosed(stream)) {
throw new CCFS.ErrnoError(9); throw new CCFS.ErrnoError(CCFS.E_FD_CLOSED);
} }
var position = offset; var position = offset;
@ -1338,20 +1329,20 @@ mergeInto(LibraryManager.library, {
} }
if (position < 0) { if (position < 0) {
throw new CCFS.ErrnoError(22); throw new CCFS.ErrnoError(CCFS.E_INVALID_VALUE);
} }
stream.position = position; stream.position = position;
return stream.position; return stream.position;
}, },
read:function(stream, buffer, offset, length) { read:function(stream, buffer, offset, length) {
if (length < 0) { if (length < 0) {
throw new CCFS.ErrnoError(22); throw new CCFS.ErrnoError(CCFS.E_INVALID_VALUE);
} }
if (CCFS.isClosed(stream)) { if (CCFS.isClosed(stream)) {
throw new CCFS.ErrnoError(9); throw new CCFS.ErrnoError(CCFS.E_FD_CLOSED);
} }
if ((stream.flags & 2097155) === 1) { if ((stream.flags & 2097155) === 1) { // O_WRONLY
throw new CCFS.ErrnoError(9); throw new CCFS.ErrnoError(CCFS.E_WRITEONLY_FILE);
} }
var position = stream.position; var position = stream.position;
@ -1361,13 +1352,13 @@ mergeInto(LibraryManager.library, {
}, },
write:function(stream, buffer, offset, length, canOwn) { write:function(stream, buffer, offset, length, canOwn) {
if (length < 0) { if (length < 0) {
throw new CCFS.ErrnoError(22); throw new CCFS.ErrnoError(CCFS.E_INVALID_VALUE);
} }
if (CCFS.isClosed(stream)) { if (CCFS.isClosed(stream)) {
throw new CCFS.ErrnoError(9); throw new CCFS.ErrnoError(CCFS.E_FD_CLOSED);
} }
if ((stream.flags & 2097155) === 0) { if ((stream.flags & 2097155) === 0) { // O_RDONLY
throw new CCFS.ErrnoError(9); throw new CCFS.ErrnoError(CCFS.E_READONLY_FILE);
} }
if (stream.flags & 1024) { if (stream.flags & 1024) {
// seek to the end before writing in append mode // seek to the end before writing in append mode