From bd75d0b3c95ebbcc91137500c2566b21db023a9d Mon Sep 17 00:00:00 2001 From: Lisa Milne Date: Mon, 4 Dec 2023 21:18:35 +1000 Subject: [PATCH] update open() to work as it should with flags --- clite/commands.js | 20 +++-- clite/core.js | 184 ++++++++++++++++++++++++++++++++++++++-------- clite/libstdio.js | 5 +- clite/shell.js | 14 ++-- clite/vi.js | 15 +--- readme-libs.txt | 24 +++--- 6 files changed, 195 insertions(+), 67 deletions(-) diff --git a/clite/commands.js b/clite/commands.js index fb847af..5564351 100644 --- a/clite/commands.js +++ b/clite/commands.js @@ -96,7 +96,7 @@ Options: dirs.forEach(function(dir,index) { if (dirs.length > 1) stdio.printf(dir+':'); - var fd = stdio.open(dir,false); + var fd = stdio.open(dir,stdio.flags.O_RDONLY|stdio.flags.O_SYNC); if (!fd) { stdio.write(io.stderr,'cannot open directory: '+dir); return; @@ -116,7 +116,7 @@ Options: while ((e = stdio.read(fd)) != null) { if (e[0] == '.' && !all) continue; - var efd = stdio.open(dir+'/'+e,false,true); + var efd = stdio.open(dir+'/'+e,stdio.flags.O_RDONLY|stdio.flags.O_NOFOLLOW|stdio.flags.O_SYNC); if (!efd) { stdio.write(io.stderr,'cannot read contents: '+dir); break; @@ -211,7 +211,7 @@ Options: var d = stdio.readAll(fd); if (d != null) { if (download) { - var ld = stdio.open('/dev/local',false); + var ld = stdio.open('/dev/local',stdio.flags.O_WRONLY); if (ld) { stdio.write(ld,{name:st.name,data:d}); stdio.close(ld); @@ -248,7 +248,7 @@ Options: pending--; return; } - var fd = stdio.open(file,fcb); + var fd = stdio.open(file,stdio.flags.O_RDONLY,fcb); if (!fd) { stdio.write(io.stderr,'cannot open file: '+file); pending--; @@ -311,7 +311,7 @@ Options: } if (!stdio.creat(file)) { - var fd = stdio.open(file,loadRemote); + var fd = stdio.open(file,stdio.flags.O_RDONLY,loadRemote); return null; } @@ -411,7 +411,7 @@ Options: } fd = io.stdin; }else{ - fd = stdio.open(file,prepFile); + fd = stdio.open(file,stdio.flags.O_RDONLY,prepFile); if (!fd) { stdio.write(io.stderr,'could not open file: '+file); return 1; @@ -544,7 +544,7 @@ Options: return 1; } - var fd = stdio.open(path,false,true); + var fd = stdio.open(path,stdio.flags.O_RDONLY|stdio.flags.O_NOFOLLOW|stdio.flags.O_SYNC); if (!fd) { stdio.fprintf(io.stderr,'permission denied: %s',path); return 1; @@ -1089,7 +1089,7 @@ Options: } } - var fd = stdio.open('/dev/initctl',false); + var fd = stdio.open('/dev/initctl',stdio.flags.O_WRONLY|stdio.flags.O_SYNC); if (!fd) return 1; stdio.write(fd,'6'); // switch to runlevel 6, reboot @@ -1196,6 +1196,10 @@ clite.commands.load('test',function(args,env,io) { io.exit(0); } + var fd = clite.io.openp(io.pid,'/var/logs',stdio.flags.O_RDONLY,function(fd) { + alert(fd.node.data.content); + }); + stdio.read(io.stdin,rcb); return null; diff --git a/clite/core.js b/clite/core.js index a62d908..74f1367 100644 --- a/clite/core.js +++ b/clite/core.js @@ -410,7 +410,7 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`; n.data.content = data; n.perms = 'cr--r--r--'; n.data.isdev = true; - var fd = clite.io.open(0,'/dev/wfs'); + var fd = clite.io.open(0,'/dev/wfs',clite.io.flags.O_RDONLY|clite.io.flags.O_SYNC); var l; while ((l = clite.io.readLine(0,fd)) != null) { if (l.length <1 || l[0] == '#') @@ -466,7 +466,7 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`; return; } - var fd = clite.io.open(0,'/dev/initctl',false); + var fd = clite.io.open(0,'/dev/initctl',clite.io.flags.O_WRONLY); if (fd) { clite.io.write(0,fd,'3'); clite.io.close(0,fd); @@ -484,9 +484,9 @@ readme.txt:/usr/clite/readme:0:0:-rw-r--r--`; var env = clite.user.getEnv(1); var io = { pid:0, - stdin:clite.io.open(1,'/dev/tty',false), - stdout:clite.io.open(1,'/dev/tty',false), - stderr:clite.io.open(1,'/dev/tty',false), + stdin:clite.io.open(1,'/dev/tty',clite.io.flags.O_RDONLY), + stdout:clite.io.open(1,'/dev/tty',clite.io.flags.O_WRONLY), + stderr:clite.io.open(1,'/dev/tty',clite.io.flags.O_WRONLY), exit:null, // filled in by fork() include:null, // filled in by fork() }; @@ -630,7 +630,7 @@ clite.proc = { // special case, reboot if pid 1 exits if (pid == 1) { clite.core.execSafeAsync(function() { - var fd = clite.io.open(0,'/dev/initctl',false); + var fd = clite.io.open(0,'/dev/initctl',clite.io.flags.O_WRONLY); if (!fd) { clite.core.reboot(); return; @@ -906,7 +906,7 @@ clite.io = { } }; - function getFileDes(pid,path,link,cb) { + function getFileDesPre(pid,path,link) { var uid = clite.proc.getUID(pid); var n = vfsapi.getNode(uid,path); if (!n) @@ -922,28 +922,39 @@ clite.io = { canexec:false, remote:{ ispending:p, - callback:cb + callback:null } }); fd.canread = perms.checkReadable(fd.node.perms,fd.node.uid,fd.node.gid,pid); fd.canwrite = perms.checkWritable(fd.node.perms,fd.node.uid,fd.node.gid,pid); fd.canexec = perms.checkExecutable(fd.node.perms,fd.node.uid,fd.node.gid,pid); - if (cb == false) { - fd.remote.callback = null; - }else if (p) { - clite.core.load.file(n.data.remote,function(d) { - n.data.content = d; - fd.remote.ispending = false; - try{ - fd.remote.callback(fd); - } catch(err) {} - }); - } - if (!p && fd.remote.callback != null) { - clite.core.execSafeAsync(function() {fd.remote.callback(fd);}); + return fd; + } + + function getFileDesPost(fd,cb) { + if (typeof cb === 'function') { + fd.remote.callback = cb; + if (fd.remote.ispending) { + clite.core.load.file(n.data.remote,function(d) { + n.data.content = d; + fd.remote.ispending = false; + try{ + fd.remote.callback(fd); + } catch(err) {} + }); + }else{ + clite.core.execSafeAsync(function() {fd.remote.callback(fd);}); + } } return fd; } + + function getFileDes(pid,path,link,cb) { + var fd = getFileDesPre(pid,path,link); + if (!fd) + return null; + return getFileDesPost(fd,cb); + } clite.io.creat = function(pid,path,type) { var uid = clite.proc.getUID(pid); switch (type) { @@ -957,12 +968,108 @@ clite.io = { return vfsapi.mkFile(uid,path); } } - clite.io.open = function(pid,path,cb,open_link) { - if (typeof cb === 'undefined') + // TODO: get rid of this + //clite.io.open = function(pid,path,cb,open_link) { + //if (typeof cb === 'undefined') + //cb = false; + //if (typeof open_link === 'undefined') + //open_link = false; + //return getFileDes(pid,path,open_link,cb); + //} + clite.io.open = function(pid,path,flags,cb) { + var read = false; + var write = false; + var exec = false; + var search = false; + + var append = false; + var create = false; + var directory = false; + var excl = false; + var nofollow = false; + var nonblock = false; + var trunc = false; + + if ((flags&clite.io.flags.O_RDONLY) == clite.io.flags.O_RDONLY) + read = true; + if ((flags&clite.io.flags.O_WRONLY) == clite.io.flags.O_WRONLY) + write = true; + if ((flags&clite.io.flags.O_EXEC) == clite.io.flags.O_EXEC) + exec = true; + if ((flags&clite.io.flags.O_SEARCH) == clite.io.flags.O_SEARCH) + search = true; + + // must have one of these set at least + if (!read && !write && !exec && !search) + return null; + + if ((flags&clite.io.flags.O_APPEND) == clite.io.flags.O_APPEND) { + if (!read) + return null; + append = true; + } + if ((flags&clite.io.flags.O_CREAT) == clite.io.flags.O_CREAT) + create = true; + if ((flags&clite.io.flags.O_DIRECTORY) == clite.io.flags.O_DIRECTORY) + directory = true; + if ((flags&clite.io.flags.O_EXCL) == clite.io.flags.O_EXCL) + excl = true; + if ((flags&clite.io.flags.O_NOFOLLOW) == clite.io.flags.O_NOFOLLOW) + nofollow = true; + if ((flags&clite.io.flags.O_SYNC) == clite.io.flags.O_SYNC) cb = false; - if (typeof open_link === 'undefined') - open_link = false; - return getFileDes(pid,path,open_link,cb); + if ((flags&clite.io.flags.O_TRUNC) == clite.io.flags.O_TRUNC) + trunc = true; + + var fd = getFileDesPre(pid,path,nofollow); + if (!fd) { + if (create) { + if (directory) { + if (!clite.io.mkdir(pid,path)) + return null; + }else{ + if (!clite.io.creat(pid,path,'-')) + return null; + } + fd = getFileDesPre(pid,path,nofollow); + } + if (!fd) + return null; + }else if (create && excl) { + return null; + } + + + var type = clite.lib.getFileType(fd); + + if (directory) { + if (type != clite.io.types.FT_DIR) + return null; + + if (read || search) { + if (!fd.canread || !fd.canexec) + return null + }else{ + fd.canread = false; + } + if (write) + return null; + + return getFileDesPost(fd,cb); + } + // check again (search is only for directories, and is basically read) + if (!read && !write && !exec) + return null; + + if (trunc && write) { + if (type == clite.io.types.FT_SCRIPT || type == clite.io.types.FT_TEXT) { + fd.node.data.content = ''; + }else if (type == clite.io.types.FT_REMOTE) { + return null; // cannot truncate unloaded remote data + } + } + + return getFileDesPost(fd,cb); } clite.io.close = function(pid,fd) { try{ @@ -1553,7 +1660,6 @@ clite.io = { }) str = str.replace(/%/g,'%'); - // TODO: actually support formatting return clite.io.write(pid,fd,str); } }, @@ -1579,6 +1685,26 @@ clite.io = { FT_IMAGE:8, FT_LIBRARY:9 }, + flags:{ + // at least one of these + O_EXEC: parseInt('0x010000',16), // open for executing only, no op on directories + O_RDONLY: parseInt('0x020000',16), // open for reading only + O_RDWR: parseInt('0x060000',16), // open for reading and writing + O_SEARCH: parseInt('0x080000',16), // open for directory search only, no op on non-directories + O_WRONLY: parseInt('0x040000',16), // open for writing only + // any of these + O_APPEND: parseInt('0x000001',16), // append to the file, sets pos to content.length, requires O_RDONLY or O_RDWR + O_CLOEXEC: parseInt('0x000002',16), // close on exec + O_CREAT: parseInt('0x000004',16), // create if file does not exist + O_DIRECTORY: parseInt('0x000008',16), // only open if directory + O_EXCL: parseInt('0x000010',16), // if O_CREAT is set, fail if file exists + O_NOCTTY: parseInt('0x0',16), // no op + O_NOFOLLOW: parseInt('0x000020',16), // if file is a symlink, don't follow it + O_NONBLOCK: parseInt('0x000040',16), // no callbacks, return immediately + O_SYNC: parseInt('0x000080',16), // write immediately (may fail on remote data) + O_TRUNC: parseInt('0x000100',16), // set file size to 0 before writing, requires O_RDWR or O_WRONLY + O_TTY_INIT: parseInt('0x0',16) // no op + }, creat:null, open:null, close:null, @@ -2228,7 +2354,7 @@ clite.lib = { if (file == '') return null; - var fd = clite.io.open(0,'/lib/'+file+'.so',false); + var fd = clite.io.open(0,'/lib/'+file+'.so',clite.io.flags.O_RDONLY); if (!fd) return null; @@ -2247,7 +2373,7 @@ clite.lib = { return pid; }, exec:function(path,args,env,io) { - var fd = clite.io.open(io.pid,path,false); + var fd = clite.io.open(io.pid,path,clite.io.flags.O_RDONLY|clite.io.flags.O_EXEC|clite.io.flags.O_SYNC); if (!fd) return -1; diff --git a/clite/libstdio.js b/clite/libstdio.js index e543d60..35e68a1 100644 --- a/clite/libstdio.js +++ b/clite/libstdio.js @@ -5,13 +5,14 @@ clite.libs.load('libio','stdio',function(io,env) { return Object.create({ types:clite.io.types, + flags:clite.io.flags, creat:function(path,type) { return clite.io.creat(io.pid,path,type); }, - open:function(path,cb,open_link) { - return clite.io.open(io.pid,path,cb,open_link); + open:function(path,flags,cb) { + return clite.io.open(io.pid,path,flags,cb); }, close:function(fd) { diff --git a/clite/shell.js b/clite/shell.js index 5a8021c..8017243 100644 --- a/clite/shell.js +++ b/clite/shell.js @@ -17,11 +17,12 @@ clite.commands.load('sh',function(args,env,io) { if (args.length > 1) { dir = clite.resolvePath(args[1]); } - var fd = stdio.open(dir,false); + var fd = stdio.open(dir,stdio.flags.O_SEARCH|stdio.flags.O_DIRECTORY); if (!fd) { stdio.write(io.stderr,'invalid directory: '+dir); return; } + // shouldn't need this now if (!fd.node.data.isdir) { stdio.write(io.stderr,'invalid directory: '+dir); return; @@ -140,9 +141,8 @@ clite.commands.load('sh',function(args,env,io) { if (path) return; var rp = clite.resolvePath(txt,p); - var fd = stdio.open(rp,false); - if (fd) { - stdio.close(fd); + var st = stdio.stat(rp);//open(rp,stdio.flags.O_RDONLY|stdio.flags.O_SYNC); + if (st) { path = rp; } }); @@ -223,7 +223,7 @@ clite.commands.load('sh',function(args,env,io) { pparts.forEach(function(pp) { if (add != '') return; - var fd = stdio.open('/bin',false); + var fd = stdio.open('/bin',stdio.flags.O_SEARCH|stdio.flags.O_DIRECTORY); var f; while (add == '' && (f = stdio.read(fd)) != null) { if (f.substring(0,a.length) == a) { @@ -382,12 +382,12 @@ clite.commands.load('sh',function(args,env,io) { // otherwise we have an interactive shell // so run /etc/shrc and ~/.shrc }else{ - var fd = stdio.open('/etc/shrc',false); + var fd = stdio.open('/etc/shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC); if (fd) { parseScript(fd); stdio.close(fd); } - fd = stdio.open(env.HOME+'/.shrc',false); + fd = stdio.open(env.HOME+'/.shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC); if (fd) { parseScript(fd); stdio.close(fd); diff --git a/clite/vi.js b/clite/vi.js index 09629f2..33e3c8e 100644 --- a/clite/vi.js +++ b/clite/vi.js @@ -150,7 +150,7 @@ Options: } function writeFile(force) { - var fd = stdio.open(file,false); + var fd = stdio.open(file,stdio.flags.O_WRONLY|stdio.flags.O_TRUNC,stdio.flags.O_SYNC); if (!fd) return; var data = ''; @@ -249,17 +249,10 @@ Options: return 1; } - var fd = stdio.open(file,prepFile); + var fd = stdio.open(file,stdio.flags.O_RDONLY|stdio.flags.O_CREAT,prepFile); if (!fd) { - if (!stdio.creat(file,'-')) { - stdio.write(io.stderr,'could not open file: '+file); - return 1; - } - fd = stdio.open(file,prepFile); - if (!fd) { - stdio.write(io.stderr,'could not open file: '+file); - return 1; - } + stdio.write(io.stderr,'could not open file: '+file); + return 1; } curses.initscr(); diff --git a/readme-libs.txt b/readme-libs.txt index 460f71a..b15db95 100644 --- a/readme-libs.txt +++ b/readme-libs.txt @@ -8,7 +8,7 @@ var stdio = io.include('stdio'); This returns a reference to the library which can be stored in a variable as seen above. Calls to library functions can then be made using that reference: -stdio.open('/path/to/file'); +var fd = stdio.open('/path/to/file',stdio.flags.O_RDONLY); There is no need to name the variable the same as the library name, however this is considered good practice. @@ -130,25 +130,29 @@ stdio (libio.so): io.include('stdio') FT_SCRIPT: 7 Plain text file beginning with #! FT_IMAGE: 8 Image file, specifically a javascript Image object + stdio.flags: + object containing flags for use in io functions + creat('path','-') creates a new file at path returns true on success - open('path',callback,open_link) + open('path',flags,callback) Open the file at path, returns a file descriptor. On error returns null, and calls callback(null) if set. If callback is set, will call the function at callback with the file descriptor, this allows remote data to be loaded for the file before beginning read or write operations. - If callback is false, open will return directly, without loading - remote data. - If open_link is set and true, and 'path' is a symbolic link, the - returned file descriptor is for the link, not the file pointed to. + If callback is false or not set, open will return directly, without loading + remote data. this is equivalent to setting stdio.flags.O_SYNC in flags. + flags is a bitwise or group of flags from stdio.flags.O_*. Consisting + of at least one mode (O_RDONLY/O_RDWR/O_WRONLY/O_SEARCH/O_EXEC), + and any other flag or flags. - var fd = stdio.open('path',false); // opens the file without loading data - var fd = stdio.open('path',callback); // calls callback(fd) when data is loaded - var fd = stdio.open('path',callback,true); // as above, but will not follow a link - var fd = stdio.open('path'); // as a general rule, don't do this + var fd = stdio.open('path',stdio.flags.O_RDONLY|stdio.flags.O_SYNC); // opens the file without loading data + var fd = stdio.open('path',stdio.flags.O_RDONLY,callback); // calls callback(fd) when data is loaded + var fd = stdio.open('path',stdio.flags.O_RDONLY|stdio.flags.O_NOFOLLOW,callback); // as above, but will not follow a link + var fd = stdio.open('path'); // fails without a valid mode (O_RDONLY/O_RDWR/O_WRONLY/O_SEARCH/O_EXEC) close(fd) Closes a file opened with open()