by an expression such as C<state @a = qw(x y z)>. Initialization of a
list of persistent lexical variables is still not possible.
+=head2 Full-size inode numbers
+
+On platforms where inode numbers are of a type larger than perl's native
+integer numerical types, L<stat|perlfunc/stat> will preserve the full
+content of large inode numbers by returning them in the form of strings of
+decimal digits. Exact comparison of inode numbers can thus be achieved by
+comparing with C<eq> rather than C<==>. Comparison with C<==>, and other
+numerical operations (which are usually meaningless on inode numbers),
+work as well as they did before, which is to say they fall back to
+floating point, and ultimately operate on a fairly useless rounded inode
+number if the real inode number is too big for the floating point format.
+
=head1 Security
XXX Any security-related notices go here. In particular, any security
(This works on machines only for which the device number is negative
under NFS.)
+On some platforms inode numbers are of a type larger than perl knows how
+to handle as integer numerical values. If necessary, an inode number will
+be returned as a decimal string in order to preserve the entire value.
+If used in a numeric context, this will be converted to a floating-point
+numerical value, with rounding, a fate that is best avoided. Therefore,
+you should prefer to compare inode numbers using C<eq> rather than C<==>.
+C<eq> will work fine on inode numbers that are represented numerically,
+as well as those represented as strings.
+
Because the mode contains both the file type and its permissions, you
should mask off the file type portion and (s)printf using a C<"%o">
if you want to see the real permissions.
EXTEND(SP, max);
EXTEND_MORTAL(max);
mPUSHi(PL_statcache.st_dev);
-#if ST_INO_SIZE > IVSIZE
- mPUSHn(PL_statcache.st_ino);
-#elif ST_INO_SIGN <= 0
- mPUSHi(PL_statcache.st_ino);
-#else
- mPUSHu(PL_statcache.st_ino);
-#endif
+ {
+ /*
+ * We try to represent st_ino as a native IV or UV where
+ * possible, but fall back to a decimal string where
+ * necessary. The code to generate these decimal strings
+ * is quite obtuse, because (a) we're portable to non-POSIX
+ * platforms where st_ino might be signed; (b) we didn't
+ * necessarily detect at Configure time whether st_ino is
+ * signed; (c) we're portable to non-POSIX platforms where
+ * ino_t isn't defined, so have no name for the type of
+ * st_ino; and (d) sprintf() doesn't necessarily support
+ * integers as large as st_ino.
+ */
+ bool neg;
+ Stat_t s;
+ GCC_DIAG_IGNORE(-Wtype-limits);
+ neg = PL_statcache.st_ino < 0;
+ GCC_DIAG_RESTORE;
+ if (neg) {
+ s.st_ino = (IV)PL_statcache.st_ino;
+ if (LIKELY(s.st_ino == PL_statcache.st_ino)) {
+ mPUSHi(s.st_ino);
+ } else {
+ char buf[sizeof(s.st_ino)*3+1], *p;
+ s.st_ino = PL_statcache.st_ino;
+ for (p = buf + sizeof(buf); p != buf+1; ) {
+ Stat_t t;
+ t.st_ino = s.st_ino / 10;
+ *--p = '0' + (int)(t.st_ino*10 - s.st_ino);
+ s.st_ino = t.st_ino;
+ }
+ while (*p == '0')
+ p++;
+ *--p = '-';
+ mPUSHp(p, buf+sizeof(buf) - p);
+ }
+ } else {
+ s.st_ino = (UV)PL_statcache.st_ino;
+ if (LIKELY(s.st_ino == PL_statcache.st_ino)) {
+ mPUSHu(s.st_ino);
+ } else {
+ char buf[sizeof(s.st_ino)*3], *p;
+ s.st_ino = PL_statcache.st_ino;
+ for (p = buf + sizeof(buf); p != buf; ) {
+ Stat_t t;
+ t.st_ino = s.st_ino / 10;
+ *--p = '0' + (int)(s.st_ino - t.st_ino*10);
+ s.st_ino = t.st_ino;
+ }
+ while (*p == '0')
+ p++;
+ mPUSHp(p, buf+sizeof(buf) - p);
+ }
+ }
+ }
mPUSHu(PL_statcache.st_mode);
mPUSHu(PL_statcache.st_nlink);