I want to reproduce the output of ls --full-time
from a Perl script to avoid the overhead of calling ls
several thousand times. I was hoping to use the stat function and grab all the information from there. However, the timestamp in the ls output uses the high-resolution clock so it includes the number of nanoseconds as well (according to the GNU docs, this is because --full-time
is equivalent to --format=long --time-style=full-iso
, and the full-iso time style includes the nanoseconds).
I came across the Time::HiRes module, which overrides the standard stat function with one that returns atime/mtime/ctime as floating point numbers, but there's no override for lstat. This is a problem, because calling stat on a symlink returns info for the linked file, not for the link itself.
So my question is this - where can I find a version of lstat that returns atime/mtime/ctime in the same way as Time::HiRes::stat? Failing that, is there another way to get the modtime for a symlink in high resolution (other than calling ls).
If you are willing to use Inline::C, this will work with recent linux
#!/usr/bin/perl
use strict;
use warnings;
use Inline C => <<'EOC';
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
long mtime_nsec(char* fname)
{
struct stat st;
if (-1 == lstat(fname, &st))
return -1;
return (long)st.st_mtim.tv_nsec;
}
EOC
print mtime_nsec($ARGV[0]);
Your best bet would be to ask for lstat
to be added to Time::HiRes. In fact, you could probably do it yourself. I'd bet that all you need to do is copy the function that starts
void
stat(...)
in HiRes.xs
, change stat(...)
to lstat(...)
& OP_STAT
to OP_LSTAT
, add lstat
to @EXPORT_OK
in HiRes.pm
, and recompile. Then submit a patch so others can benefit.
For the record, lstat
has been added to Time-HiRes version 1.9726 in August 2013.
See https://rt.cpan.org/Public/Bug/Display.html?id=83356 for details.
However, it's still 1.9725
that's included in the latest stable version of perl
as of 2014-01-31 (5.18.2). It was bumped to 1.9726 in the development version in 5.19.3 though.
Note that (as of perl
5.19.8), regardless of whether Time::HiRes
's lstat
is used or not, perl's -M
/-A
/-C
still don't do sub-second granularity (files with time in the same second will be shown as having the same age), so you still can't do things like sort {-M $a <=> -M $b} @files
to sort files by modification time.
The following changes work. This essentially contains changes to both the HiRes.pm module as well as the xs file.
In HiRes.pm
sub lstat {
my @lstatvalues = CORE::lstat(shift);
my @nanosecvalues = Time::HiRes::lstatimplementation( $lstatvalues[8], $lstatvalues[9], $lstatvalues[10]);
( $lstatvalues[8], $lstatvalues[9], $lstatvalues[10] ) = ( $nanosecvalues[0], $nanosecvalues[1], $nanosecvalues[2]);
return @lstatvalues;
}
Also added lstat to @EXPORT_OK list.
In HiRes.xs
void
lstatimplementation(...)
PPCODE:
UV atime = SvUV( ST( 0 ) );
UV mtime = SvUV( ST( 1 ) );
UV ctime = SvUV( ST( 2 ) );
UV atime_nsec;
UV mtime_nsec;
UV ctime_nsec;
hrstatns(atime, mtime, ctime,
&atime_nsec, &mtime_nsec, &ctime_nsec);
if (atime_nsec)
XPUSHs( sv_2mortal(newSVnv(atime + 1e-9 * (NV) atime_nsec)));
if (mtime_nsec)
XPUSHs( sv_2mortal(newSVnv(mtime + 1e-9 * (NV) mtime_nsec)));
if (ctime_nsec)
XPUSHs( sv_2mortal(newSVnv(ctime + 1e-9 * (NV) ctime_nsec)));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With