get file access/modify/change times in place, update stat, add times to ls -l

This commit is contained in:
Lisa Milne 2023-12-10 20:46:41 +10:00
parent cc5de8f5e5
commit b1f3476fc2
3 changed files with 217 additions and 153 deletions

View file

@ -37,8 +37,10 @@ clite.commands.load('ls',function(args,env,io) {
var dirs = [];
var long = false;
var all = false;
var access = false;
var stdlib = io.include('stdlib');
var stdio = io.include('stdio');
var time = io.include('time');
var clite = io.include('clite');
function help() {
stdio.printf(`
@ -48,27 +50,42 @@ Usage: ls [OPTION] [FILE]
Options:
-? Print this help information
-l Display data in long format
-u Display access time in long format
-a Do not ignore entries starting with .
`);
}
function writeNodeData(st,fd) {
if (long) {
var pw = stdlib.getpwuid(st.uid);
var gr = stdlib.getgrgid(st.gid);
var uname = st.uid.toString();
var gname = st.gid.toString();
var pw = stdlib.getpwuid(st.st_uid);
var gr = stdlib.getgrgid(st.st_gid);
var uname = st.st_uid.toString();
var gname = st.st_gid.toString();
if (pw)
uname = pw.pw_name;
if (gr)
gname = gr.gr_name;
if (st.type == stdio.types.FT_LINK) {
var d = stdio.readAll(fd);
if (!d)
d = '?';
stdio.printf('%s%16s%16s%16s -> %s\n',st.perms,uname,gname,st.name,d);
var tm;
var t = time.time();
var tmn = time.localtime(t);
if (access) {
tm = time.localtime(st.st_atim.tv_sec);
}else{
stdio.printf('%s%16s%16s%16s\n',st.perms,uname,gname,st.name);
tm = time.localtime(st.st_mtim.tv_sec);
}
var d = '';
if (tm.tm_year != tmn.tm_year) {
d = time.strftime('%b %d %Y',tm);
}else{
d = time.strftime('%b %d %H:%M',tm);
}
if (st.type == stdio.types.FT_LINK) {
var lp = stdio.readAll(fd);
if (!lp)
lp = '?';
stdio.printf('%s%16s%16s%14s%16s -> %s\n',st.perms,uname,gname,d,st.name,lp);
}else{
stdio.printf('%s%16s%16s%14s%16s\n',st.perms,uname,gname,d,st.name);
}
}else{
stdio.printf(st.name);
@ -86,6 +103,9 @@ Options:
case 'l':
long = true;
break;
case 'u':
access = true;
break;
case 'a':
all = true;
break;
@ -1216,140 +1236,6 @@ Options:
//tm_wday:0, // day of week (0-6, sunday = 0)
//tm_yday:0, // day of year (0-365)
//tm_isdst:0 // 1 if daylight savings
function getDT(fmt,tm) {
var parts = fmt.split('%');
var out = '';
var skip = false;
var data = {
d_s:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
m_s:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
d_l:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
m_l:['January','February','March','April','May','June','July','August','September','October','November','December'],
}
parts.forEach(function(part,i) {
if (part == '') {
if (i != 0) {
out += '%';
skip = true;
}
return;
}
if (skip || i == 0) {
out += part;
skip = false;
return;
}
var o = part.substring(0,1);
var e = part.substring(1);
switch (o) {
case 'a': //Locale's abbreviated weekday name.
out += data.d_s[tm.tm_wday];
break;
case 'A': //Locale's full weekday name.
out += data.d_l[tm.tm_wday];
break;
case 'h':
case 'b': //Locale's abbreviated month name.
out += data.m_s[tm.tm_mon];
break;
case 'B': //Locale's full month name.
out += data.m_l[tm.tm_mon];
break;
case 'c': //Locale's appropriate date and time representation.
out += getDT('%a %d %b %Y %H:%M:%S',tm);
break;
case 'C': //Century (a year divided by 100 and truncated to an integer) as a decimal number [00,99].
var y = tm.tm_year+1900;
out += (y/100).toFixed(0);
break;
case 'd': //Day of the month as a decimal number [01,31].
out += (tm.tm_mday+1).toFixed(0).padStart(2,'0');
break;
case 'D': //Date in the format mm/dd/yy.
out += getDT('%M/%D/%y',tm);
break;
case 'e': //Day of the month as a decimal number [1,31] in a two-digit field with leading <space> character fill.
out += (tm.tm_mday+1).toFixed(0).padStart(2,' ');
break;
case 'H': //Hour (24-hour clock) as a decimal number [00,23].
out += (tm.tm_hour).toFixed(0).padStart(2,'0');
break;
case 'I': //Hour (12-hour clock) as a decimal number [01,12].
out += (tm.tm_hour%12).toFixed(0).padStart(2,'0');
break;
case 'j': //Day of the year as a decimal number [001,366].
out += (tm.tm_yday).toFixed(0).padStart(3,'0');
break;
case 'm': //Month as a decimal number [01,12].
out += (tm.tm_mon+1).toFixed(0).padStart(2,'0');
break;
case 'M': //Minute as a decimal number [00,59].
out += (tm.tm_min).toFixed(0).padStart(2,'0');
break;
case 'n': //A <newline>.
out += '\n';
break;
case 'p': //Locale's equivalent of either AM or PM.
if (tm.tm_hour >11) {
out += 'PM';
}else{
out += 'AM';
}
break;
case 'r': //12-hour clock time [01,12] using the AM/PM notation; in the POSIX locale, this shall be equivalent to %I : %M : %S %p.
out += getDT('%I:%M:%S%p',tm);
break;
case 's':
out += time.mktime(tm).toFixed(0);
break;
case 'S': //Seconds as a decimal number [00,60].
out += tm.tm_sec.toFixed(0).padStart(2,'0');
break;
case 't': //A <tab>.
out += '\t';
break;
case 'T': //24-hour clock time [00,23] in the format HH:MM:SS.
out += getDT('%H:%M:%S',tm);
break;
case 'u': //Weekday as a decimal number [1,7] (1=Monday).
if (tm.tm_wday < 1) {
out += '7';
}else{
out += tm.tm_wday.toFixed(0);
}
break;
case 'U': //Week of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday shall be considered to be in week 0.
// TODO: this
break;
case 'V': //Week of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing January 1 has four or more days in the new year, then it shall be considered week 1; otherwise, it shall be the last week of the previous year, and the next week shall be week 1.
// TODO: this
break;
case 'w': //Weekday as a decimal number [0,6] (0=Sunday).
out += tm.tm_wday.toFixed(0);
break;
case 'W': //Week of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday shall be considered to be in week 0.
// TODO: this
break;
case 'x': //Locale's appropriate date representation.
out += getDT('%d/%m/%Y',tm);
break;
case 'X': //Locale's appropriate time representation.
out += getDT('%H:%M:%S',tm);
break;
case 'y': //Year within century [00,99].
out += (tm.tm_year+1900).toFixed(0).substring(2);
break;
case 'Y': //Year with century as a decimal number.
out += (tm.tm_year+1900).toFixed(0);
break;
case 'Z': //Timezone name, or no characters if no timezone is determinable.
break;
default:;
}
out += e;
});
return out;
}
function main(args) {
var utc = false;
@ -1388,7 +1274,7 @@ Options:
if (!t)
return 1;
var out = getDT(format,tm);
var out = time.strftime(format,tm);
if (!out)
return 1;
@ -1410,6 +1296,7 @@ clite.commands.load('test',function(args,env,io) {
stdio.printf('time is: %d\n',t);
var tm = time.gmtime(t);
stdio.printf('gmtime gives: %d %d %d %d %d %d %d %d %d\n',tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm.tm_wday,tm.tm_yday,tm.tm_isdst);
stdio.printf('%s\n',time.ctime(t));
stdio.printf('Hello world\n');
stdio.printf('uid:%d\n',stdlib.getuid());
stdio.printf('%#15x:%15o:%15.5f:%0$15.5f:%%:\n',10,12,8.123456789);

View file

@ -10,6 +10,17 @@ var clite = {
// a list of library files to load
libs:['libclite.js','libcurses.js','libstd.js','libstdio.js','libterm.js','libtime.js']
},
time:{
sec:function() {
return parseInt(Date.now()/1000.0,10);
},
msec:function() {
return Date.now();
},
nsec:function() {
return parseInt(Date.now()*1000,10);
}
},
core:{
execSafe:function(f) {
try{
@ -275,7 +286,7 @@ var clite = {
}
n.data.content = {
read:function() {
return Date.now().toString();
return clite.time.msec().toString();
},
write:null
};
@ -1295,6 +1306,7 @@ clite.io = {
return false;
if (fd.node.data.isdev) {
if (typeof fd.node.data.content != 'string') {
fd.node.time.modify = clite.time.sec();
try{
return fd.node.data.content.write(data);
} catch(err) {
@ -1315,6 +1327,7 @@ clite.io = {
fd.node.data.content = b+data+e;
fd.pos += data.length;
}
fd.node.time.modify = clite.time.sec();
return true;
}
clite.io.ftruncate = function(pid,fd,len) {
@ -1325,6 +1338,7 @@ clite.io = {
fd.data.content = fd.data.content.substring(0,len);
if (fd.pos > len)
fd.pos = len;
fd.node.time.modify = clite.time.sec();
return true;
}
clite.io.truncate = function(pid,path,len) {
@ -1379,14 +1393,30 @@ clite.io = {
var stat = Object.create({
name:fd.node.name,
type:clite.lib.getFileType(fd),
uid:fd.node.uid,
gid:fd.node.gid,
size:0,
st_dev:0,
st_ino:0,
st_mode:0,
st_nlink:0,
st_uid:fd.node.uid,
st_gid:fd.node.gid,
st_size:0,
st_atim:{
tv_sec:fd.node.time.access,
tv_nsec:0
},
st_mtim:{
tv_sec:fd.node.time.modify,
tv_nsec:0
},
st_ctim:{
tv_sec:fd.node.time.change,
tv_nsec:0
},
perms:fd.node.perms
});
if (stat.type == 1 || stat.type == 7)
stat.size = fd.node.data.content.length;
if (stat.type == clite.io.types.FT_TEXT || stat.type == clite.io.types.FT_SCRIPT)
stat.st_size = fd.node.data.content.length;
return stat;
},
@ -1411,6 +1441,7 @@ clite.io = {
}else{
fd.node.perms = '-'+mode.substring(0);
}
fd.node.time.change = clite.time.sec();
return true;
}
clite.io.chmod = function(pid,path,mode) {
@ -1899,6 +1930,11 @@ clite.vfs = {
uid: 0,
gid: 0,
perms:'-rw-r--r--',
time:{
access:clite.time.sec(),
modify:clite.time.sec(),
change:clite.time.sec()
},
data:{
remote:null,
isdir:false,
@ -1945,6 +1981,7 @@ clite.vfs = {
}
if (!checkCanOpen(uid,n))
return null;
n.time.access = clite.time.sec();
return n;
}
vfsdata.api.getFile = function(uid,path) {
@ -1977,6 +2014,7 @@ clite.vfs = {
n.uid = uid;
n.gid = clite.user.getGID(uid);
parent.data.content.push(n);
parent.time.modify = clite.time.sec();
return true;
}
vfsdata.api.mkFile = function(uid,path) {
@ -2000,6 +2038,7 @@ clite.vfs = {
n.uid = uid;
n.gid = clite.user.getGID(uid);
parent.data.content.push(n);
parent.time.modify = clite.time.sec();
return true;
}
vfsdata.api.mkLink = function(uid,path,target) {
@ -2024,6 +2063,7 @@ clite.vfs = {
n.uid = uid;
n.gid = clite.user.getGID(uid);
parent.data.content.push(n);
parent.time.modify = clite.time.sec();
return true;
}
vfsdata.api.mkPath = function(uid,path) {

View file

@ -4,6 +4,8 @@ clite.libs.load('libtime','time',function(io,env) {
var data = {
days:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
months:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
days_l:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
months_l:['January','February','March','April','May','June','July','August','September','October','November','December'],
mdays:[31,28,31,30,31,30,31,31,30,31,30,31]
}
function getyDay(mon,mday,year) {
@ -58,13 +60,145 @@ clite.libs.load('libtime','time',function(io,env) {
return tm;
}
function getDTStr(fmt,tm) {
var parts = fmt.split('%');
var out = '';
var skip = false;
parts.forEach(function(part,i) {
if (part == '') {
if (i != 0) {
out += '%';
skip = true;
}
return;
}
if (skip || i == 0) {
out += part;
skip = false;
return;
}
var o = part.substring(0,1);
var e = part.substring(1);
switch (o) {
case 'a': //Locale's abbreviated weekday name.
out += data.days[tm.tm_wday];
break;
case 'A': //Locale's full weekday name.
out += data.days_l[tm.tm_wday];
break;
case 'h':
case 'b': //Locale's abbreviated month name.
out += data.months[tm.tm_mon];
break;
case 'B': //Locale's full month name.
out += data.months_l[tm.tm_mon];
break;
case 'c': //Locale's appropriate date and time representation.
out += getDTStr('%a %d %b %Y %H:%M:%S',tm);
break;
case 'C': //Century (a year divided by 100 and truncated to an integer) as a decimal number [00,99].
var y = tm.tm_year+1900;
out += (y/100).toFixed(0);
break;
case 'd': //Day of the month as a decimal number [01,31].
out += (tm.tm_mday+1).toFixed(0).padStart(2,'0');
break;
case 'D': //Date in the format mm/dd/yy.
out += getDTStr('%M/%D/%y',tm);
break;
case 'e': //Day of the month as a decimal number [1,31] in a two-digit field with leading <space> character fill.
out += (tm.tm_mday+1).toFixed(0).padStart(2,' ');
break;
case 'H': //Hour (24-hour clock) as a decimal number [00,23].
out += (tm.tm_hour).toFixed(0).padStart(2,'0');
break;
case 'I': //Hour (12-hour clock) as a decimal number [01,12].
out += (tm.tm_hour%12).toFixed(0).padStart(2,'0');
break;
case 'j': //Day of the year as a decimal number [001,366].
out += (tm.tm_yday).toFixed(0).padStart(3,'0');
break;
case 'm': //Month as a decimal number [01,12].
out += (tm.tm_mon+1).toFixed(0).padStart(2,'0');
break;
case 'M': //Minute as a decimal number [00,59].
out += (tm.tm_min).toFixed(0).padStart(2,'0');
break;
case 'n': //A <newline>.
out += '\n';
break;
case 'p': //Locale's equivalent of either AM or PM.
if (tm.tm_hour >11) {
out += 'PM';
}else{
out += 'AM';
}
break;
case 'r': //12-hour clock time [01,12] using the AM/PM notation; in the POSIX locale, this shall be equivalent to %I : %M : %S %p.
out += getDTStr('%I:%M:%S%p',tm);
break;
case 's':
out += time.mktime(tm).toFixed(0);
break;
case 'S': //Seconds as a decimal number [00,60].
out += tm.tm_sec.toFixed(0).padStart(2,'0');
break;
case 't': //A <tab>.
out += '\t';
break;
case 'T': //24-hour clock time [00,23] in the format HH:MM:SS.
out += getDTStr('%H:%M:%S',tm);
break;
case 'u': //Weekday as a decimal number [1,7] (1=Monday).
if (tm.tm_wday < 1) {
out += '7';
}else{
out += tm.tm_wday.toFixed(0);
}
break;
case 'U': //Week of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday shall be considered to be in week 0.
// TODO: this
break;
case 'V': //Week of the year (Monday as the first day of the week) as a decimal number [01,53]. If the week containing January 1 has four or more days in the new year, then it shall be considered week 1; otherwise, it shall be the last week of the previous year, and the next week shall be week 1.
// TODO: this
break;
case 'w': //Weekday as a decimal number [0,6] (0=Sunday).
out += tm.tm_wday.toFixed(0);
break;
case 'W': //Week of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday shall be considered to be in week 0.
// TODO: this
break;
case 'x': //Locale's appropriate date representation.
out += getDTStr('%d/%m/%Y',tm);
break;
case 'X': //Locale's appropriate time representation.
out += getDTStr('%H:%M:%S',tm);
break;
case 'y': //Year within century [00,99].
out += (tm.tm_year+1900).toFixed(0).substring(2);
break;
case 'Y': //Year with century as a decimal number.
out += (tm.tm_year+1900).toFixed(0);
break;
case 'Z': //Timezone name, or no characters if no timezone is determinable.
break;
default:;
}
out += e;
});
return out;
}
//
return Object.create({
asctime:function(timeptr) {
return data.days[timeptr.tm_wday]+' '+data.months[timeptr.tm_mon]+' '+timeptr.tm_mday+' '+timeptr.tm_hour+':'+timeptr.tm_min+':'+timeptr.tm_sec+' '+(1900+timeptr.tm_year)+'\n';
return getDTStr('%a %d %b %T %Y',timeptr);
},
ctime:function(time) {
var tm = this.localtime(time);
return this.asctime(tm);
},
gmtime:function(time) {
return genTime(time,0);
@ -75,9 +209,12 @@ return Object.create({
return genTime(time,tz);
},
mktime:function(timeptr) {
var t = data.days[timeptr.tm_wday]+' '+data.months[timeptr.tm_mon]+' '+timeptr.tm_mday+' '+timeptr.tm_hour+':'+timeptr.tm_min+':'+timeptr.tm_sec+' '+(1900+timeptr.tm_year+' UTC');
var t = getDTStr('%a %d %b %T %Y %Z',timeptr);
return parseInt(Math.floor((new Date(t)).getTime()/1000.0).toFixed(0));
},
strftime:function(fmt,timeptr) {
return getDTStr(fmt,timeptr);
},
time:function() {
var t = readTime();
return parseInt(Math.floor(t/1000.0).toFixed(0)); // convert from milliseconds to seconds