class File::Stat
A File::Stat object contains information about an entry in the filesystem.
Each of these methods returns a new File::Stat object. the first three follow symbolic links; the others don’t:
Snapshot
A new File::Stat object takes an immediate “snapshot” of the filesystem entry at the given ‘path’; the snapshot is never updated, regardless of changes in the entry (even its deletion):
filepath = '/tmp/t.tmp' File.stat(filepath) # Raises Errno::ENOENT: No such file or directory. File.write(filepath, 'foo') stat = File.stat(filepath) stat.birthtime # => 2026-10-03 12:19:23.723062465 -0500 File.delete(filepath) stat.birthtime # => 2026-10-03 12:19:23.723062465 -0500
Filesystem Dependencies
Methods in a File::Stat object may return filesystem-dependent values, and not all values are meaningful on all filesystems; for example, File::Stat#blocks returns nil on a Windows filesystem, but returns an integer on others.
See also Kernel#test.
Public Class Methods
(path file_name) → void
Source
static VALUE
rb_stat_init(VALUE obj, VALUE fname)
{
rb_io_stat_data st;
FilePathValue(fname);
fname = rb_str_encode_ospath(fname);
if (STATX(StringValueCStr(fname), &st, STATX_ALL) == -1) {
rb_sys_fail_path(fname);
}
struct rb_stat *rb_st;
TypedData_Get_Struct(obj, struct rb_stat, &stat_data_type, rb_st);
rb_st->stat = st;
rb_st->initialized = true;
return Qnil;
}
Returns a new File::Stat object containing a snapshot of the filesystem entry at the given path:
File::Stat.new('/etc/passwd') File::Stat.new('/tmp') File::Stat.new('nosuch') # Raises Errno::ENOENT: No such file or directory.
Public Instance Methods
(self other) → (-1 | 0 | 1)
(untyped) → (-1 | 0 | 1)?
Source
static VALUE
rb_stat_cmp(VALUE self, VALUE other)
{
if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
stat_timestamp ts1 = statx_mtimespec(get_stat(self));
stat_timestamp ts2 = statx_mtimespec(get_stat(other));
if (ts1.tv_sec == ts2.tv_sec) {
if (ts1.tv_nsec == ts2.tv_nsec) return INT2FIX(0);
if (ts1.tv_nsec < ts2.tv_nsec) return INT2FIX(-1);
return INT2FIX(1);
}
if (ts1.tv_sec < ts2.tv_sec) return INT2FIX(-1);
return INT2FIX(1);
}
return Qnil;
}
Compares the snapshots in self and other, by comparing their modification times self.mtime and other.mtime.
Returns:
-
-1, ifself.mtimeis earlier. -
0, if the two values are equal. -
1, ifself.mtimeis later. -
nil, ifotheris not a File::Stat object.
Examples:
stat0 = File.stat('/etc') stat1 = File.stat('/tmp') stat0.mtime # => 2026-10-02 07:52:03.151556038 -0500 stat1.mtime # => 2026-10-03 12:22:25.719215899 -0500 stat0 <=> stat1 # => -1 stat0 <=> stat0.dup # => 0 stat1 <=> stat0 # => 1 stat0 <=> :foo # => nil
Class File::Stat includes module Comparable, each of whose methods uses File::Stat#<=> for comparison.
() → Time
Source
static VALUE
rb_stat_atime(VALUE self)
{
return stat_time(statx_atimespec(get_stat(self)));
}
Returns a new Time object containing the access time of the snapshot in self. See File System Timestamps.
Access time for a file is established when it is created, and may be updated when the file content is read:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') File.atime(filepath) # => 2026-10-04 14:58:58.805179514 -0500 stat0 = File.stat(filepath) # Take snapshot. stat0.atime # => 2026-10-04 14:58:58.805179514 -0500 File.read(filepath) # Updates file atime. File.atime(filepath) # => 2026-10-04 14:59:47.707059351 -0500 stat0.atime # => 2026-10-04 14:58:58.805179514 -0500 # Not updated. stat1 = File.stat(filepath) # Take new snapshot. stat1.atime # => 2026-10-04 14:59:47.707059351 -0500 # Updated. File.delete(filepath) # Clean up.
Access time for a directory is established when it is created, and may be updated when its entries are read:
“‘ruby dirpath = ’/tmp/dir’ Dir.mkdir(dirpath) File.atime(dirpath) # => 2026-10-04 15:07:26.194548647 -0500 stat0 = File.stat(dirpath) # Take snapshot. stat0.atime # => 2026-10-04 15:07:26.194548647 -0500 Dir.entries(dirpath) # Updates directory atime. File.atime(dirpath) # => 2026-10-04 15:08:14.818746815 -0500 # Updated. stat0.atime # => 2026-10-04 15:07:26.194548647 -0500 # Not updated. stat1 = File.stat(dirpath) # Take new shapshot. stat1.atime # => 2026-10-04 15:08:14.818746815 -0500 # Updated. Dir.rmdir(dirpath) # Clean up.
() → Time
Source
static VALUE
rb_stat_birthtime(VALUE self)
{
return statx_birthtime(get_stat(self));
}
Returns a new Time object containing the creation time of the snapshot in self. See File System Timestamps:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') stat = File.stat(filepath) # Take shapshot. stat.birthtime # => 2026-10-05 13:14:24.844158315 -0500 File.delete(filepath) stat.birthtime # => 2026-10-05 13:14:24.844158315 -0500 # Unchanged.
Source
static VALUE
rb_stat_blksize(VALUE self)
{
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
return ULONG2NUM(get_stat(self)->ST_(blksize));
#else
return Qnil;
#endif
}
Returns the block size of the filesystem of the snapshot in self, or nil on Windows:
File.stat('/etc').blksize # => 4096 File.stat('/etc/passwd').blksize # => 4096 File.stat('nosuch').blksize # Raises Errno::ENOENT: No such file or directory.
() → bool
Source
static VALUE
rb_stat_b(VALUE obj)
{
#ifdef S_ISBLK
if (S_ISBLK(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
}
Returns whether the entry in the snapshot in self is a block device (i.e., a direct-access device):
File.stat('/dev/nvme0n1').blockdev? # => true File.stat('/dev/loop0').blockdev? # => true File.stat('/dev/tty').blockdev? # => false File.stat('/dev/null').blockdev? # => false
The returned value is filesystem-dependent; returns false on Windows or MacOS.
Source
static VALUE
rb_stat_blocks(VALUE self)
{
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
# if SIZEOF_STRUCT_STAT_ST_BLOCKS > SIZEOF_LONG
return ULL2NUM(get_stat(self)->ST_(blocks));
# else
return ULONG2NUM(get_stat(self)->ST_(blocks));
# endif
#else
return Qnil;
#endif
}
Returns the number of filesystem blocks allocated for the entry in the snapshot in self:
File.stat('/etc').blocks # => 24 File.stat('/etc/passwd').blocks # => 8
Returns nil on Windows.
() → bool
Source
static VALUE
rb_stat_c(VALUE obj)
{
if (S_ISCHR(get_stat(obj)->ST_(mode))) return Qtrue;
return Qfalse;
}
Returns whether the entry in the snapshot in self is a character device (i.e., a sequential-access device):
File.stat('/dev/tty').chardev? # => true File.stat('/dev/null').chardev? # => true File.stat('/dev/nvme0n1').chardev? # => false File.stat('/dev/loop0').chardev? # => false
The returned value is filesystem-dependent; on Windows, always false.
() → Time
Source
static VALUE
rb_stat_ctime(VALUE self)
{
return stat_time(statx_ctimespec(get_stat(self)));
}
On Windows, returns the birthtime for the entry in self.
On other systems, returns the time of the most recent metadata change to the snapshot in self:
dirpath = '/tmp/dir' Dir.mkdir(dirpath) # Establishes directory ctime. dirstat0 = File.stat(dirpath) # Take directory snapshot. dirstat0.ctime # => 2026-10-06 11:07:18.073533542 -0500 # Initial directory ctime. filepath = File.join(dirpath, 't.tmp') # => "/tmp/dir/t.tmp" File.write(filepath, 'foo') # Establishes file ctime; upates directory ctime. filestat0 = File.stat(filepath) # Take file snapshot. filestat0.ctime # => 2026-10-06 11:07:52.555027213 -0500 # Initial file ctime. dirstat0.ctime # => 2026-10-06 11:07:18.073533542 -0500 # Directory snapshot unchanged. dirstat1 = File.stat(dirpath) # Take new directory snapshot. dirstat1.ctime # => 2026-10-06 11:07:52.555027213 -0500 # Snapshot has new ctime. File.write(filepath, 'bar') # Updates file ctime. filestat0.ctime # => 2026-10-06 11:07:52.555027213 -0500 # Old file snapshot unchanged. filestat1 = File.stat(filepath) # Take new file snapshot. filestat1.ctime # => 2026-10-06 11:14:11.19290223 -0500 # Snapshot shows change. FileUtils.rmtree(dirpath) # Clean up.
() → Integer
Source
static VALUE
rb_stat_dev(VALUE self)
{
#if RUBY_USE_STATX
unsigned int m = get_stat(self)->stx_dev_major;
unsigned int n = get_stat(self)->stx_dev_minor;
return ULL2NUM(makedev(m, n));
#elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_DEV_T
return DEVT2NUM(get_stat(self)->st_dev);
#elif SIZEOF_STRUCT_STAT_ST_DEV <= SIZEOF_LONG
return ULONG2NUM(get_stat(self)->st_dev);
#else
return ULL2NUM(get_stat(self)->st_dev);
#endif
}
Returns the device number for the snapshot in self:
File.stat('/etc').dev # => 66306 File.stat('/dev').dev # => 5
() → Integer?
Source
static VALUE
rb_stat_dev_major(VALUE self)
{
#if RUBY_USE_STATX
return UINT2NUM(get_stat(self)->stx_dev_major);
#elif defined(major)
return UINT2NUM(major(get_stat(self)->st_dev));
#else
return Qnil;
#endif
}
Returns nil on Windows.
On other systems, returns the major part of the device number for the snapshot in self:
File.stat('/etc').dev_major # => 259 File.stat('/dev').dev_major # => 0
() → Integer?
Source
static VALUE
rb_stat_dev_minor(VALUE self)
{
#if RUBY_USE_STATX
return UINT2NUM(get_stat(self)->stx_dev_minor);
#elif defined(minor)
return UINT2NUM(minor(get_stat(self)->st_dev));
#else
return Qnil;
#endif
}
Returns nil on Windows.
On other systems, returns the minor part of the device number for the snapshot in self:
File.stat('/etc').dev_minor # => 2 File.stat('/dev').dev_minor # => 5
() → bool
Source
static VALUE
rb_stat_d(VALUE obj)
{
if (S_ISDIR(get_stat(obj)->ST_(mode))) return Qtrue;
return Qfalse;
}
Returns whether the entry in the snapshot in self is a directory:
File.stat('/etc').directory? # => true File.stat('/etc/passwd').directory? # => false
() → bool
Source
static VALUE
rb_stat_x(VALUE obj)
{
rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (geteuid() == 0) {
return RBOOL(st->ST_(mode) & S_IXUGO);
}
#endif
#ifdef S_IXUSR
if (rb_stat_owned(obj))
return RBOOL(st->ST_(mode) & S_IXUSR);
#endif
#ifdef S_IXGRP
if (rb_stat_grpowned(obj))
return RBOOL(st->ST_(mode) & S_IXGRP);
#endif
#ifdef S_IXOTH
if (!(st->ST_(mode) & S_IXOTH)) return Qfalse;
#endif
return Qtrue;
}
Returns whether the filesystem entry represented by self is executable by the effective owner/group of the current process:
File.stat('/bin/ruby').executable? # => true File.stat('/etc').executable? # => true File.stat('/etc/passwd').executable? # => false
Raises Errno::ENOENT if the entry does not exist.
Note that some filesystem settings may cause this method to return true even though the entry is not executable by the effective owner/group.
() → bool
Source
static VALUE
rb_stat_X(VALUE obj)
{
rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (getuid() == 0) {
return RBOOL(st->ST_(mode) & S_IXUGO);
}
#endif
#ifdef S_IXUSR
if (rb_stat_rowned(obj))
return RBOOL(st->ST_(mode) & S_IXUSR);
#endif
#ifdef S_IXGRP
if (rb_group_member(get_stat(obj)->ST_(gid)))
return RBOOL(st->ST_(mode) & S_IXGRP);
#endif
#ifdef S_IXOTH
if (!(st->ST_(mode) & S_IXOTH)) return Qfalse;
#endif
return Qtrue;
}
Like Pathname#executable?, but checks against the real owner/group instead of the effective owner/group.
() → bool
Source
static VALUE
rb_stat_f(VALUE obj)
{
if (S_ISREG(get_stat(obj)->ST_(mode))) return Qtrue;
return Qfalse;
}
Returns whether self represents a filesystem entry that exists and is a regular file; see File::Stat.ftype:
File.stat('/etc/passwd').file? # => true File.stat('/etc').file? # => false
() → File::ftype
Source
static VALUE
rb_stat_ftype(VALUE obj)
{
return rb_file_ftype(get_stat(obj)->ST_(mode));
}
Returns the string type of the path in the snapshot in self, one of:
-
'file'. -
'directory'. -
'characterSpecial'. -
'blockSpecial'. -
'fifo'. -
'link'. -
'socket'.
Examples:
File.stat('/etc/passwd').ftype # => "file" File.stat('/etc').ftype # => "directory" File.stat('/dev/null').ftype # => "characterSpecial" File.stat('/dev/loop0').ftype # => "blockSpecial" File.mkfifo('/tmp/pipe', 0o666) File.stat('/tmp/pipe').ftype # => "fifo" File.symlink('/etc/passwd', '/tmp/link') File.lstat('/tmp/link').ftype # => "link" require 'socket' UNIXServer.new('/tmp/socket') File.stat('/tmp/socket').ftype # => "socket" File.delete('/tmp/link', '/tmp/pipe', '/tmp/socket') # Clean up.
Returns 'unknown' if the type cannot be determined.
() → Integer
Source
static VALUE
rb_stat_gid(VALUE self)
{
return GIDT2NUM(get_stat(self)->ST_(gid));
}
On Windows, returns 0.
On other systems, returns the group identifier of the owner of the entry in the snapshot in self:
File.stat('/etc').gid # => 0 filepath = '/tmp/t.tmp' File.write(filepath, 'foo') File.stat(filepath).gid # => 1000 File.delete(filepath) # Clean up.
() → bool
Source
static VALUE
rb_stat_grpowned(VALUE obj)
{
#ifndef _WIN32
if (rb_group_member(get_stat(obj)->ST_(gid))) return Qtrue;
#endif
return Qfalse;
}
Returns false on Windows.
On other systems, returns whether the effective group id of the calling process is the owner of the snapshot in self:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') File.stat(filepath).grpowned? # => true File.stat('/etc').grpowned? # => false File.stat('/etc/passwd').grpowned? # => false File.delete(filepath) # Clean up.
() → Integer
Source
static VALUE
rb_stat_ino(VALUE self)
{
rb_io_stat_data *ptr = get_stat(self);
#ifdef HAVE_STRUCT_STAT_ST_INOHIGH
/* assume INTEGER_PACK_LSWORD_FIRST and st_inohigh is just next of st_ino */
return rb_integer_unpack(&ptr->st_ino, 2,
SIZEOF_STRUCT_STAT_ST_INO, 0,
INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER|
INTEGER_PACK_2COMP);
#else
return UIANY2NUM(ptr->ST_(ino));
#endif
}
Returns the inode value for the entry in the snapshot in self:
File.stat('/etc').ino # => 11141121 File.stat('/etc/passwd').ino # => 11141413
() → String
Source
static VALUE
rb_stat_inspect(VALUE self)
{
VALUE str;
size_t i;
static const struct {
const char *name;
VALUE (*func)(VALUE);
} member[] = {
{"dev", rb_stat_dev},
{"ino", rb_stat_ino},
{"mode", rb_stat_mode},
{"nlink", rb_stat_nlink},
{"uid", rb_stat_uid},
{"gid", rb_stat_gid},
{"rdev", rb_stat_rdev},
{"size", rb_stat_size},
{"blksize", rb_stat_blksize},
{"blocks", rb_stat_blocks},
{"atime", rb_stat_atime},
{"mtime", rb_stat_mtime},
{"ctime", rb_stat_ctime},
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
{"birthtime", rb_stat_birthtime},
#endif
};
struct rb_stat* rb_st;
TypedData_Get_Struct(self, struct rb_stat, &stat_data_type, rb_st);
if (!rb_st->initialized) {
return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
}
str = rb_str_buf_new2("#<");
rb_str_buf_cat2(str, rb_obj_classname(self));
rb_str_buf_cat2(str, " ");
for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
VALUE v;
if (i > 0) {
rb_str_buf_cat2(str, ", ");
}
rb_str_buf_cat2(str, member[i].name);
rb_str_buf_cat2(str, "=");
v = (*member[i].func)(self);
if (i == 2) { /* mode */
rb_str_catf(str, "0%lo", (unsigned long)NUM2ULONG(v));
}
else if (i == 0 || i == 6) { /* dev/rdev */
rb_str_catf(str, "0x%"PRI_DEVT_PREFIX"x", NUM2DEVT(v));
}
else {
rb_str_append(str, rb_inspect(v));
}
}
rb_str_buf_cat2(str, ">");
return str;
}
Returns a string representation of the entry in the snapshot in self; here we split the returned strings for readability:
puts File.stat('/etc/passwd').inspect.split(', ')
Output:
#<File::Stat dev=0x10302 ino=11141413 mode=0100644 nlink=1 uid=0 gid=0 rdev=0x0 size=3092 blksize=4096 blocks=8 atime=2026-10-07 11:25:01.307589569 -0500 mtime=2025-06-10 11:10:47.358999941 -0500 ctime=2025-06-10 11:10:47.38899994 -0500>
puts File.stat('/etc').inspect.split(', ')
Output:
#<File::Stat dev=0x10302 ino=11141121 mode=040755 nlink=143 uid=0 gid=0 rdev=0x0 size=12288 blksize=4096 blocks=24 atime=2026-10-04 14:29:46.907775905 -0500 mtime=2026-10-07 06:13:35.116915307 -0500 ctime=2026-10-07 06:13:35.116915307 -0500>
() → Integer
Source
static VALUE
rb_stat_mode(VALUE self)
{
return UINT2NUM(ST2UINT(get_stat(self)->ST_(mode)));
}
Returns an integer representing the permissions of the entry in the snapshot in self; see Filesystem Modes.
The integer is most usefully formatted as six octal digits:
'%06o' % File.stat('/etc').mode # => "040755" '%06o' % File.stat('/etc/passwd').mode # => "100644"
() → Time
Source
static VALUE
rb_stat_mtime(VALUE self)
{
return stat_time(statx_mtimespec(get_stat(self)));
}
Returns a new Time object containing the modification time of the object in the snapshot in self:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') # Create file. File.mtime(filepath) # => 2026-10-13 10:48:10.477675435 -0500 # File mtime. stat0 = File.stat(filepath) # Take snapshot. stat0.mtime # => 2026-10-13 10:48:10.477675435 -0500 # Snapshot mtime. File.write(filepath, 'bar') # Modify file. File.mtime(filepath) # => 2026-10-13 10:48:37.584264035 -0500 # File mtime updated. stat0.mtime # => 2026-10-13 10:48:10.477675435 -0500 # Snapshot mtime not updated. stat1 = File.stat(filepath) # Take new snapshot. stat1.mtime # => 2026-10-13 10:48:37.584264035 -0500 # New snapshot mtime. File.delete(filepath) # Clean up.
() → Integer
Source
static VALUE
rb_stat_nlink(VALUE self)
{
/* struct stat::st_nlink is nlink_t in POSIX. Not the case for Windows. */
const rb_io_stat_data *ptr = get_stat(self);
return UIANY2NUM(ptr->ST_(nlink));
}
Returns the number of hard links to the entry in the snapshot in self:
filepath = '/tmp/t.txt' File.write(filepath, 'foo') # Creates hard link. stat0 = File.stat(filepath) # Take snapshot. stat0.nlink # => 1 # One hard link. linkpath = '/tmp/t.bak' File.link(filepath, linkpath) # Creates another hard link. stat0.nlink # => 1 # Snapshot not updated. stat1 = File.stat(filepath) # Take new snapshot. stat1.nlink # => 2 # Updated nlink count. File.unlink(linkpath) # Remove one hard link. stat1.nlink # => 2 # Snapshot not updated. stat2 = File.stat(filepath) # Take new shapshot. stat2.nlink # => 1 # Updated nlink count. File.unlink(filepath) # Clean up.
() → bool
Source
static VALUE
rb_stat_owned(VALUE obj)
{
if (get_stat(obj)->ST_(uid) == geteuid()) return Qtrue;
return Qfalse;
}
Returns whether the owner in the snapshot in self is the owner of the current process:
dirpath = '/tmp/dir' Dir.mkdir(dirpath) filepath = File.join(dirpath, 't.tmp') # => "/tmp/dir/t.tmp" File.write(filepath, 'foo') dirstat = File.stat(dirpath) # Snapshot of directory. filestat = File.stat(filepath) # Snapshot of file. dirstat.owned? # => true filestat.owned? # => true FileUtils.rm_rf(dirpath) # Clean up. dirstat.owned? # => true # Snapshot not updated. filestat.owned? # => true # Snapshot not updated.
() → bool
Source
static VALUE
rb_stat_p(VALUE obj)
{
#ifdef S_IFIFO
if (S_ISFIFO(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
}
Returns whether the entry at the path in self is a pipe:
pipepath = '/tmp/pipe' File.mkfifo(pipepath) # Make pipe. stat = File.stat(pipepath) # Take snapshot. stat.pipe? # => true # In snapshot. File.delete(pipepath) # Clean up. stat.pipe? # => true # Snapshot not updated. File.stat('/etc').pipe? # => false File.stat('/etc/passwd').pipe? # => false
() → Integer?
Source
static VALUE
rb_stat_rdev(VALUE self)
{
#if RUBY_USE_STATX
unsigned int m = get_stat(self)->stx_rdev_major;
unsigned int n = get_stat(self)->stx_rdev_minor;
return ULL2NUM(makedev(m, n));
#elif !defined(HAVE_STRUCT_STAT_ST_RDEV)
return Qnil;
#elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_DEV_T
return DEVT2NUM(get_stat(self)->ST_(rdev));
#elif SIZEOF_STRUCT_STAT_ST_RDEV <= SIZEOF_LONG
return ULONG2NUM(get_stat(self)->ST_(rdev));
#else
return ULL2NUM(get_stat(self)->ST_(rdev));
#endif
}
Returns the integer device type of the entry in the snapshot in self.
On a non-Windows system, returns a filesystem-dependent device type; the returned value is non-zero only for character-special and block-special devices.
In these hexadecimal-formatted examples:
-
The two-low order digits contain the device-type minor value, which identifies a specific instance, port, or partition managed by a device driver; see
rdev_minor. -
The higher-order digits contain the device-type major value, which identifies the device driver; see
rdev_major.
# Character-special devices. '%08x' % File.stat('/dev/null').rdev # => "00000103" '%08x' % File.stat('/dev/zero').rdev # => "00000105" '%08x' % File.stat('/dev/random').rdev # => "00000108" '%08x' % File.stat('/dev/tty').rdev # => "00000500" '%08x' % File.stat('/dev/tty0').rdev # => "00000400" '%08x' % File.stat('/dev/tty1').rdev # => "00000401" # Block-special devices. '%08x' % File.stat('/dev/nvme0n1').rdev # => "00010300" '%08x' % File.stat('/dev/nvme0n1p1').rdev # => "00010301" '%08x' % File.stat('/dev/nvme0n1p2').rdev # => "00010302"
On Windows, returns a number corresponding to the given device:
File.stat('C:/').rdev # => 2 File.stat('C:/Users').rdev # => 2 File.stat('D:/').rdev # => 3
() → Integer?
Source
static VALUE
rb_stat_rdev_major(VALUE self)
{
#if RUBY_USE_STATX
return UINT2NUM(get_stat(self)->stx_rdev_major);
#elif defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
return UINT2NUM(major(get_stat(self)->ST_(rdev)));
#else
return Qnil;
#endif
}
Returns the integer major portion of the device type of the entry in the snapshot in self; see also rdev, which returns the entire device type (major and minor).
On a non-Windows system, returns a filesystem-dependent major device type, which identifies the device driver; the returned value is non-zero only for character-special and block-special devices:
# Character-special devices. '%04x' % File.stat('/dev/null').rdev_major # => "0001" '%04x' % File.stat('/dev/zero').rdev_major # => "0001" '%04x' % File.stat('/dev/random').rdev_major # => "0001" '%04x' % File.stat('/dev/tty').rdev_major # => "0005" '%04x' % File.stat('/dev/tty0').rdev_major # => "0004" '%04x' % File.stat('/dev/tty1').rdev_major # => "0004" # Block-special devices. '%04x' % File.stat('/dev/nvme0n1').rdev_major # => "0103" '%04x' % File.stat('/dev/nvme0n1p1').rdev_major # => "0103" '%04x' % File.stat('/dev/nvme0n1p2').rdev_major # => "0103"
On Windows, returns nil.
() → Integer?
Source
static VALUE
rb_stat_rdev_minor(VALUE self)
{
#if RUBY_USE_STATX
return UINT2NUM(get_stat(self)->stx_rdev_minor);
#elif defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
return UINT2NUM(minor(get_stat(self)->ST_(rdev)));
#else
return Qnil;
#endif
}
Returns the integer minor portion of the device type of the entry in the snapshot in self; see also rdev, which returns the entire device type (major and minor).
On a non-Windows system, returns a filesystem-dependent minor device type, which identifies a specific instance, port, or partition on its device; the returned value is non-zero only for character-special and block-special devices:
# Character-special devices. '%02x' % File.stat('/dev/null').rdev_minor # => "03" '%02x' % File.stat('/dev/zero').rdev_minor # => "05" '%02x' % File.stat('/dev/random').rdev_minor # => "08" '%02x' % File.stat('/dev/tty').rdev_minor # => "00" '%02x' % File.stat('/dev/tty0').rdev_minor # => "00" '%02x' % File.stat('/dev/tty1').rdev_minor # => "01" # Block-special devices. '%02x' % File.stat('/dev/nvme0n1').rdev_minor # => "00" '%02x' % File.stat('/dev/nvme0n1p1').rdev_minor # => "01" '%02x' % File.stat('/dev/nvme0n1p2').rdev_minor # => "02"
On Windows, returns nil.
() → bool
Source
static VALUE
rb_stat_r(VALUE obj)
{
rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (geteuid() == 0) return Qtrue;
#endif
#ifdef S_IRUSR
if (rb_stat_owned(obj))
return RBOOL(st->ST_(mode) & S_IRUSR);
#endif
#ifdef S_IRGRP
if (rb_stat_grpowned(obj))
return RBOOL(st->ST_(mode) & S_IRGRP);
#endif
#ifdef S_IROTH
if (!(st->ST_(mode) & S_IROTH)) return Qfalse;
#endif
return Qtrue;
}
Returns whether the entry represented by self exists and is readable by the owner and group of the current process; see Permissions:
path = '/tmp/secret.txt' File.write(path, 'foo') File.stat(path).readable? # => true File.chmod(0o000, path) File.stat(path).readable? # => false File.delete(path) # Clean up.
() → bool
Source
static VALUE
rb_stat_R(VALUE obj)
{
rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (getuid() == 0) return Qtrue;
#endif
#ifdef S_IRUSR
if (rb_stat_rowned(obj))
return RBOOL(st->ST_(mode) & S_IRUSR);
#endif
#ifdef S_IRGRP
if (rb_group_member(get_stat(obj)->ST_(gid)))
return RBOOL(st->ST_(mode) & S_IRGRP);
#endif
#ifdef S_IROTH
if (!(st->ST_(mode) & S_IROTH)) return Qfalse;
#endif
return Qtrue;
}
Like readable?, but checks against the real owner and group ids instead of the effective ids.
() → bool
Source
static VALUE
rb_stat_sgid(VALUE obj)
{
#ifdef S_ISGID
if (get_stat(obj)->ST_(mode) & S_ISGID) return Qtrue;
#endif
return Qfalse;
}
Returns whether the setgid bit is set in the special bits for the entry represented in self:
path = '/tmp/t.tmp' File.write(path, 'foo') stat = File.stat(path) # Take a snapshot. stat.setgid? # => false stat.mode.to_s(8) # => "100664" File.chmod(0o2644, path) # Set the bit; stat snapshot unchanged. stat.setgid? # => false stat.mode.to_s(8) # => "100664" stat = File.stat(path) # Fresh stat; snapshot changed. stat.setgid? # => true stat.mode.to_s(8) # => "102644" File.delete(path) # Clean up.
On Windows, the bit is never set; the method always returns false.
() → bool
Source
static VALUE
rb_stat_suid(VALUE obj)
{
#ifdef S_ISUID
if (get_stat(obj)->ST_(mode) & S_ISUID) return Qtrue;
#endif
return Qfalse;
}
Returns whether the setuid bit is set in the special bits for the entry represented in self:
path = '/tmp/t.tmp' File.write(path, 'foo') stat = File.stat(path) # Take snapshot; bit not set. stat.setuid? # => false stat.mode.to_s(8) # => "100664" File.chmod(0o4644, path) # Set the bit; snapshot not updated. stat.setuid? # => false stat.mode.to_s(8) # => "100664" stat = File.stat(path) # Fresh snapshot. stat.setuid? # => true stat.mode.to_s(8) # => "104644" File.delete(path) # Clean up.
On Windows, the bit is never set; the method always returns false.
() → Integer
Source
static VALUE
rb_stat_size(VALUE self)
{
return OFFT2NUM(get_stat(self)->ST_(size));
}
Returns the size (in bytes) of the entry in the snapshot in self:
File.stat('/etc/passwd').size # => 3092 # Regular file. File.stat('/etc').size # => 12288 # Directory. # When the file size changes. filepath = '/tmp/t.tmp' file = File.new(filepath, 'w+') file.write('foo') file.size # => 3 stat0 = File.stat(filepath) # Take snapshot. stat0.size # => 3 file.write('bar') # Change file size. file.size # => 6 stat0.size # => 3 # Snapshot not updated. stat1 = File.stat(filepath) # Take new snapshot. stat1.size # => 6 # Snapshot has updated size. File.delete(filepath) # Clean up.
Source
static VALUE
rb_stat_s(VALUE obj)
{
rb_off_t size = get_stat(obj)->ST_(size);
if (size == 0) return Qnil;
return OFFT2NUM(size);
}
Returns the size in bytes of the entry in self if the entry exists and has non-zero size, nil otherwise:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') File.size(filepath) # => 3 stat = File.stat(filepath) # Take snapshot. stat.size? # => 3 # Non-zero size. File.write(filepath, '') File.size(filepath) # => 0 stat.size? # => 3 # Snapshot unchanged. stat = File.stat(filepath) # Take new snapshot. stat.size? # => nil # Zero size File.delete(filepath) # Clean up.
() → bool
Source
static VALUE
rb_stat_S(VALUE obj)
{
#ifdef S_ISSOCK
if (S_ISSOCK(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
}
Returns whether entry in the snapshot in self is a socket:
require 'socket' socket_path = '/tmp/socket' server = UNIXServer.new(socket_path) stat = File.stat(socket_path) # Take snapshot. stat.socket? # => true server.close # Clean up. File.delete(socket_path) # Clean up. stat.socket? # => true # Snapshot not updated. File.stat('/tmp').socket? # => false # Not a socket.
() → bool
Source
static VALUE
rb_stat_sticky(VALUE obj)
{
#ifdef S_ISVTX
if (get_stat(obj)->ST_(mode) & S_ISVTX) return Qtrue;
#endif
return Qfalse;
}
Returns whether the sticky bit is set in the special bits for self:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') stat = File.stat(filepath) stat.sticky? # => false stat.mode.to_s(8) # => "100664" File.chmod(01644, filepath) # => 1 # Stat unchanged. stat.sticky? # => false stat.mode.to_s(8) # => "100664" stat = File.stat(filepath) # Fresh stat. stat.sticky? # => true stat.mode.to_s(8) # => "101644" File.delete(filepath) # Clean up.
Returns false on Windows.
() → bool
Source
static VALUE
rb_stat_l(VALUE obj)
{
#ifdef S_ISLNK
if (S_ISLNK(get_stat(obj)->ST_(mode))) return Qtrue;
#endif
return Qfalse;
}
Returns whether the entry in self (see Snapshot) is a symbolic link:
filepath = '/etc/passwd' linkpath = '/tmp/foo' File.symlink(filepath, linkpath) File.stat(filepath).symlink? # => false File.lstat(filepath).symlink? # => false stat = File.stat(linkpath) # Snapshot with stat follows link. stat.symlink? # => false lstat = File.lstat(linkpath) # Snapshot with lstat does not follow link. lstat.symlink? # => true File.delete(linkpath) # Clean up. # Snapshots are unchanged, even when link deleted. stat.symlink? # => false lstat.symlink? # => true
() → Integer
Source
static VALUE
rb_stat_uid(VALUE self)
{
return UIDT2NUM(get_stat(self)->ST_(uid));
}
Returns the integer id of the owner of the entry in the snapshot in self:
Process.uid # => 0 # Superuser; can change owner. filepath = '/tmp/t.tmp' File.write(filepath, 'foo') # Create file. stat0 = File.stat(filepath) # Take snapshot. stat0.uid # => 0 # Snapshot has uid. File.chown(1000, 1000, filepath) # Change owner. stat0.uid # => 0 # Snapshot not updated. stat1 = File.stat(filepath) # Take new snapshot. stat1.uid # => 1000 # Snapshot has new uid. File.delete(filepath) # Clean up.
Source
static VALUE
rb_stat_wr(VALUE obj)
{
#ifdef S_IROTH
rb_io_stat_data *st = get_stat(obj);
if ((st->ST_(mode) & (S_IROTH)) == S_IROTH) {
return UINT2NUM(st->ST_(mode) & (S_IRUGO|S_IWUGO|S_IXUGO));
}
#endif
return Qnil;
}
Returns the integer permissions for the entry in the snapshot in self if those permissions allow reading by others; otherwise, returns nil:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') # Create file. File.chmod(0o000, filepath) # Make file unreadable. stat0 = File.stat(filepath) # Take snapshot. stat0.world_readable? # => nil # Snapshot shows not world-readable. File.chmod(0o644, filepath) # Make file world-readable. stat0.world_readable? # => nil # Snapshot not updated. stat1 = File.stat(filepath) # Take new snapshot. stat1.world_readable?.to_s(8) # => "644" # Snapshot shows world-readable. File.delete(filepath) # Clean up. stat1.world_readable?.to_s(8) # => "644" # Snapshot not updated.
Source
static VALUE
rb_stat_ww(VALUE obj)
{
#ifdef S_IWOTH
rb_io_stat_data *st = get_stat(obj);
if ((st->ST_(mode) & (S_IWOTH)) == S_IWOTH) {
return UINT2NUM(st->ST_(mode) & (S_IRUGO|S_IWUGO|S_IXUGO));
}
#endif
return Qnil;
}
If the entry in self exists and is writable by others, returns the integer permissions for the entry; otherwise, returns nil:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') File.stat(filepath).world_writable? # => nil # Not world-writable. File.chmod(0o777, filepath) # Make world-writable. File.stat(filepath).world_writable?.to_s(8) # => "777" # World-writable. File.delete(filepath) # Clean up. File.stat('/tmp').world_writable?.to_s(8) # => "777" # Directory.
() → bool
Source
static VALUE
rb_stat_w(VALUE obj)
{
rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (geteuid() == 0) return Qtrue;
#endif
#ifdef S_IWUSR
if (rb_stat_owned(obj))
return RBOOL(st->ST_(mode) & S_IWUSR);
#endif
#ifdef S_IWGRP
if (rb_stat_grpowned(obj))
return RBOOL(st->ST_(mode) & S_IWGRP);
#endif
#ifdef S_IWOTH
if (!(st->ST_(mode) & S_IWOTH)) return Qfalse;
#endif
return Qtrue;
}
Returns whether the entry at the path in self exists and is writable by the effective owner and group in the current process:
filepath = '/tmp/secret.txt' File.write(filepath, 'foo') File.stat(filepath).writable? # => true # Writable. File.chmod(0o000, filepath) # Make non-writable. File.stat(filepath).writable? # => false # Not writable. File.delete(filepath) # Clean up. File.stat('/etc').writable? # => false # Directory.
Note that filesystem security features may cause this method to return true even when the file is not writable by the effective owner and group.
() → bool
Source
static VALUE
rb_stat_W(VALUE obj)
{
rb_io_stat_data *st = get_stat(obj);
#ifdef USE_GETEUID
if (getuid() == 0) return Qtrue;
#endif
#ifdef S_IWUSR
if (rb_stat_rowned(obj))
return RBOOL(st->ST_(mode) & S_IWUSR);
#endif
#ifdef S_IWGRP
if (rb_group_member(get_stat(obj)->ST_(gid)))
return RBOOL(st->ST_(mode) & S_IWGRP);
#endif
#ifdef S_IWOTH
if (!(st->ST_(mode) & S_IWOTH)) return Qfalse;
#endif
return Qtrue;
}
Like File::Stat.writable?, but checks against the real owner and group instead of the effective owner and group.
Note that filesystem security features may cause this method to return true even when the entry in self is not writable by the real owner and group.
() → bool
Source
static VALUE
rb_stat_z(VALUE obj)
{
if (get_stat(obj)->ST_(size) == 0) return Qtrue;
return Qfalse;
}
Returns whether the entry at the path in self has size zero.
The entry may be a file:
filepath = '/tmp/t.tmp' File.write(filepath, 'foo') File.stat(filepath).zero? # => false File.truncate(filepath, 0) File.stat(filepath).zero? # => true File.delete(filepath) # Clean up.
The entry may be a directory:
dirpath = '/tmp/foo' Dir.mkdir(dirpath) stat = File.stat(dirpath) # Size is filesystem-dependent; may or may not be zero. stat.size # => 4096 stat.zero? # => false filepath = File.join(dirpath, 't.tmp') # => "/tmp/foo/t.tmp" File.write(filepath, 'foo') stat = File.stat(dirpath) stat.size # => 4096 stat.zero? # => false FileUtils.rm_rf(dirpath) # Clean up.