stat.pm 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package File::stat;
  2. use 5.006;
  3. use strict;
  4. use warnings;
  5. use warnings::register;
  6. use Carp;
  7. BEGIN { *warnif = \&warnings::warnif }
  8. our(@EXPORT, @EXPORT_OK, %EXPORT_TAGS);
  9. our $VERSION = '1.07';
  10. my @fields;
  11. BEGIN {
  12. use Exporter ();
  13. @EXPORT = qw(stat lstat);
  14. @fields = qw( $st_dev $st_ino $st_mode
  15. $st_nlink $st_uid $st_gid
  16. $st_rdev $st_size
  17. $st_atime $st_mtime $st_ctime
  18. $st_blksize $st_blocks
  19. );
  20. @EXPORT_OK = ( @fields, "stat_cando" );
  21. %EXPORT_TAGS = ( FIELDS => [ @fields, @EXPORT ] );
  22. }
  23. use vars @fields;
  24. use Fcntl qw(S_IRUSR S_IWUSR S_IXUSR);
  25. BEGIN {
  26. # These constants will croak on use if the platform doesn't define
  27. # them. It's important to avoid inflicting that on the user.
  28. no strict 'refs';
  29. for (qw(suid sgid svtx)) {
  30. my $val = eval { &{"Fcntl::S_I\U$_"} };
  31. *{"_$_"} = defined $val ? sub { $_[0] & $val ? 1 : "" } : sub { "" };
  32. }
  33. for (qw(SOCK CHR BLK REG DIR LNK)) {
  34. *{"S_IS$_"} = defined eval { &{"Fcntl::S_IF$_"} }
  35. ? \&{"Fcntl::S_IS$_"} : sub { "" };
  36. }
  37. # FIFO flag and macro don't quite follow the S_IF/S_IS pattern above
  38. # RT #111638
  39. *{"S_ISFIFO"} = defined &Fcntl::S_IFIFO
  40. ? \&Fcntl::S_ISFIFO : sub { "" };
  41. }
  42. # from doio.c
  43. sub _ingroup {
  44. my ($gid, $eff) = @_;
  45. # I am assuming that since VMS doesn't have getgroups(2), $) will
  46. # always only contain a single entry.
  47. $^O eq "VMS" and return $_[0] == $);
  48. my ($egid, @supp) = split " ", $);
  49. my ($rgid) = split " ", $(;
  50. $gid == ($eff ? $egid : $rgid) and return 1;
  51. grep $gid == $_, @supp and return 1;
  52. return "";
  53. }
  54. # VMS uses the Unix version of the routine, even though this is very
  55. # suboptimal. VMS has a permissions structure that doesn't really fit
  56. # into struct stat, and unlike on Win32 the normal -X operators respect
  57. # that, but unfortunately by the time we get here we've already lost the
  58. # information we need. It looks to me as though if we were to preserve
  59. # the st_devnam entry of vmsish.h's fake struct stat (which actually
  60. # holds the filename) it might be possible to do this right, but both
  61. # getting that value out of the struct (perl's stat doesn't return it)
  62. # and interpreting it later would require this module to have an XS
  63. # component (at which point we might as well just call Perl_cando and
  64. # have done with it).
  65. if (grep $^O eq $_, qw/os2 MSWin32 dos/) {
  66. # from doio.c
  67. *cando = sub { ($_[0][2] & $_[1]) ? 1 : "" };
  68. }
  69. else {
  70. # from doio.c
  71. *cando = sub {
  72. my ($s, $mode, $eff) = @_;
  73. my $uid = $eff ? $> : $<;
  74. my ($stmode, $stuid, $stgid) = @$s[2,4,5];
  75. # This code basically assumes that the rwx bits of the mode are
  76. # the 0777 bits, but so does Perl_cando.
  77. if ($uid == 0 && $^O ne "VMS") {
  78. # If we're root on unix
  79. # not testing for executable status => all file tests are true
  80. return 1 if !($mode & 0111);
  81. # testing for executable status =>
  82. # for a file, any x bit will do
  83. # for a directory, always true
  84. return 1 if $stmode & 0111 || S_ISDIR($stmode);
  85. return "";
  86. }
  87. if ($stuid == $uid) {
  88. $stmode & $mode and return 1;
  89. }
  90. elsif (_ingroup($stgid, $eff)) {
  91. $stmode & ($mode >> 3) and return 1;
  92. }
  93. else {
  94. $stmode & ($mode >> 6) and return 1;
  95. }
  96. return "";
  97. };
  98. }
  99. # alias for those who don't like objects
  100. *stat_cando = \&cando;
  101. my %op = (
  102. r => sub { cando($_[0], S_IRUSR, 1) },
  103. w => sub { cando($_[0], S_IWUSR, 1) },
  104. x => sub { cando($_[0], S_IXUSR, 1) },
  105. o => sub { $_[0][4] == $> },
  106. R => sub { cando($_[0], S_IRUSR, 0) },
  107. W => sub { cando($_[0], S_IWUSR, 0) },
  108. X => sub { cando($_[0], S_IXUSR, 0) },
  109. O => sub { $_[0][4] == $< },
  110. e => sub { 1 },
  111. z => sub { $_[0][7] == 0 },
  112. s => sub { $_[0][7] },
  113. f => sub { S_ISREG ($_[0][2]) },
  114. d => sub { S_ISDIR ($_[0][2]) },
  115. l => sub { S_ISLNK ($_[0][2]) },
  116. p => sub { S_ISFIFO($_[0][2]) },
  117. S => sub { S_ISSOCK($_[0][2]) },
  118. b => sub { S_ISBLK ($_[0][2]) },
  119. c => sub { S_ISCHR ($_[0][2]) },
  120. u => sub { _suid($_[0][2]) },
  121. g => sub { _sgid($_[0][2]) },
  122. k => sub { _svtx($_[0][2]) },
  123. M => sub { ($^T - $_[0][9] ) / 86400 },
  124. C => sub { ($^T - $_[0][10]) / 86400 },
  125. A => sub { ($^T - $_[0][8] ) / 86400 },
  126. );
  127. use constant HINT_FILETEST_ACCESS => 0x00400000;
  128. # we need fallback=>1 or stringifying breaks
  129. use overload
  130. fallback => 1,
  131. -X => sub {
  132. my ($s, $op) = @_;
  133. if (index("rwxRWX", $op) >= 0) {
  134. (caller 0)[8] & HINT_FILETEST_ACCESS
  135. and warnif("File::stat ignores use filetest 'access'");
  136. $^O eq "VMS" and warnif("File::stat ignores VMS ACLs");
  137. # It would be nice to have a warning about using -l on a
  138. # non-lstat, but that would require an extra member in the
  139. # object.
  140. }
  141. if ($op{$op}) {
  142. return $op{$op}->($_[0]);
  143. }
  144. else {
  145. croak "-$op is not implemented on a File::stat object";
  146. }
  147. };
  148. # Class::Struct forbids use of @ISA
  149. sub import { goto &Exporter::import }
  150. use Class::Struct qw(struct);
  151. struct 'File::stat' => [
  152. map { $_ => '$' } qw{
  153. dev ino mode nlink uid gid rdev size
  154. atime mtime ctime blksize blocks
  155. }
  156. ];
  157. sub populate (@) {
  158. return unless @_;
  159. my $stob = new();
  160. @$stob = (
  161. $st_dev, $st_ino, $st_mode, $st_nlink, $st_uid, $st_gid, $st_rdev,
  162. $st_size, $st_atime, $st_mtime, $st_ctime, $st_blksize, $st_blocks )
  163. = @_;
  164. return $stob;
  165. }
  166. sub lstat ($) { populate(CORE::lstat(shift)) }
  167. sub stat ($) {
  168. my $arg = shift;
  169. my $st = populate(CORE::stat $arg);
  170. return $st if defined $st;
  171. my $fh;
  172. {
  173. local $!;
  174. no strict 'refs';
  175. require Symbol;
  176. $fh = \*{ Symbol::qualify( $arg, caller() )};
  177. return unless defined fileno $fh;
  178. }
  179. return populate(CORE::stat $fh);
  180. }
  181. 1;
  182. __END__
  183. =head1 NAME
  184. File::stat - by-name interface to Perl's built-in stat() functions
  185. =head1 SYNOPSIS
  186. use File::stat;
  187. $st = stat($file) or die "No $file: $!";
  188. if ( ($st->mode & 0111) && $st->nlink > 1) ) {
  189. print "$file is executable with lotsa links\n";
  190. }
  191. if ( -x $st ) {
  192. print "$file is executable\n";
  193. }
  194. use Fcntl "S_IRUSR";
  195. if ( $st->cando(S_IRUSR, 1) ) {
  196. print "My effective uid can read $file\n";
  197. }
  198. use File::stat qw(:FIELDS);
  199. stat($file) or die "No $file: $!";
  200. if ( ($st_mode & 0111) && ($st_nlink > 1) ) {
  201. print "$file is executable with lotsa links\n";
  202. }
  203. =head1 DESCRIPTION
  204. This module's default exports override the core stat()
  205. and lstat() functions, replacing them with versions that return
  206. "File::stat" objects. This object has methods that
  207. return the similarly named structure field name from the
  208. stat(2) function; namely,
  209. dev,
  210. ino,
  211. mode,
  212. nlink,
  213. uid,
  214. gid,
  215. rdev,
  216. size,
  217. atime,
  218. mtime,
  219. ctime,
  220. blksize,
  221. and
  222. blocks.
  223. As of version 1.02 (provided with perl 5.12) the object provides C<"-X">
  224. overloading, so you can call filetest operators (C<-f>, C<-x>, and so
  225. on) on it. It also provides a C<< ->cando >> method, called like
  226. $st->cando( ACCESS, EFFECTIVE )
  227. where I<ACCESS> is one of C<S_IRUSR>, C<S_IWUSR> or C<S_IXUSR> from the
  228. L<Fcntl|Fcntl> module, and I<EFFECTIVE> indicates whether to use
  229. effective (true) or real (false) ids. The method interprets the C<mode>,
  230. C<uid> and C<gid> fields, and returns whether or not the current process
  231. would be allowed the specified access.
  232. If you don't want to use the objects, you may import the C<< ->cando >>
  233. method into your namespace as a regular function called C<stat_cando>.
  234. This takes an arrayref containing the return values of C<stat> or
  235. C<lstat> as its first argument, and interprets it for you.
  236. You may also import all the structure fields directly into your namespace
  237. as regular variables using the :FIELDS import tag. (Note that this still
  238. overrides your stat() and lstat() functions.) Access these fields as
  239. variables named with a preceding C<st_> in front their method names.
  240. Thus, C<$stat_obj-E<gt>dev()> corresponds to $st_dev if you import
  241. the fields.
  242. To access this functionality without the core overrides,
  243. pass the C<use> an empty import list, and then access
  244. function functions with their full qualified names.
  245. On the other hand, the built-ins are still available
  246. via the C<CORE::> pseudo-package.
  247. =head1 BUGS
  248. As of Perl 5.8.0 after using this module you cannot use the implicit
  249. C<$_> or the special filehandle C<_> with stat() or lstat(), trying
  250. to do so leads into strange errors. The workaround is for C<$_> to
  251. be explicit
  252. my $stat_obj = stat $_;
  253. and for C<_> to explicitly populate the object using the unexported
  254. and undocumented populate() function with CORE::stat():
  255. my $stat_obj = File::stat::populate(CORE::stat(_));
  256. =head1 ERRORS
  257. =over 4
  258. =item -%s is not implemented on a File::stat object
  259. The filetest operators C<-t>, C<-T> and C<-B> are not implemented, as
  260. they require more information than just a stat buffer.
  261. =back
  262. =head1 WARNINGS
  263. These can all be disabled with
  264. no warnings "File::stat";
  265. =over 4
  266. =item File::stat ignores use filetest 'access'
  267. You have tried to use one of the C<-rwxRWX> filetests with C<use
  268. filetest 'access'> in effect. C<File::stat> will ignore the pragma, and
  269. just use the information in the C<mode> member as usual.
  270. =item File::stat ignores VMS ACLs
  271. VMS systems have a permissions structure that cannot be completely
  272. represented in a stat buffer, and unlike on other systems the builtin
  273. filetest operators respect this. The C<File::stat> overloads, however,
  274. do not, since the information required is not available.
  275. =back
  276. =head1 NOTE
  277. While this class is currently implemented using the Class::Struct
  278. module to build a struct-like class, you shouldn't rely upon this.
  279. =head1 AUTHOR
  280. Tom Christiansen