Class File::Stat
In: file.c
Parent: Object

Objects of class File::Stat encapsulate common status information for File objects. The information is recorded at the moment the File::Stat object is created; changes made to the file after that point will not be reflected. File::Stat objects are returned by IO#stat, File::stat, File#lstat, and File::lstat. Many of these methods return platform-specific values, and not all values are meaningful on all systems. See also Kernel#test.

Methods

<=>   atime   blksize   blockdev?   blocks   chardev?   ctime   dev   dev_major   dev_minor   directory?   executable?   executable_real?   file?   ftype   gid   grpowned?   ino   inspect   mode   mtime   new   nlink   owned?   pipe?   rdev   rdev_major   rdev_minor   readable?   readable_real?   setgid?   setuid?   size   size?   socket?   sticky?   symlink?   uid   writable?   writable_real?   zero?  

Included Modules

Comparable

Public Class methods

  File::Stat.new(file_name)  => stat

Create a File::Stat object for the given file name (raising an exception if the file doesn‘t exist).

[Source]

/*
 * call-seq:
 *
 *   File::Stat.new(file_name)  => stat
 *
 * Create a File::Stat object for the given file name (raising an
 * exception if the file doesn't exist).
 */

static VALUE
rb_stat_init(obj, fname)
    VALUE obj, fname;
{
    struct stat st, *nst;

    SafeStringValue(fname);

    if (stat(StringValueCStr(fname), &st) == -1) {
        rb_sys_fail(RSTRING(fname)->ptr);
    }
    if (DATA_PTR(obj)) {
        free(DATA_PTR(obj));
        DATA_PTR(obj) = NULL;
    }
    nst = ALLOC(struct stat);
    *nst = st;
    DATA_PTR(obj) = nst;

    return Qnil;
}

Public Instance methods

Compares File::Stat objects by comparing their respective modification times.

   f1 = File.new("f1", "w")
   sleep 1
   f2 = File.new("f2", "w")
   f1.stat <=> f2.stat   #=> -1

[Source]

/*
 *  call-seq:
 *     stat <=> other_stat    => -1, 0, 1
 *  
 *  Compares <code>File::Stat</code> objects by comparing their
 *  respective modification times.
 *     
 *     f1 = File.new("f1", "w")
 *     sleep 1
 *     f2 = File.new("f2", "w")
 *     f1.stat <=> f2.stat   #=> -1
 */

static VALUE
rb_stat_cmp(self, other)
    VALUE self, other;
{
    if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
        time_t t1 = get_stat(self)->st_mtime;
        time_t t2 = get_stat(other)->st_mtime;
        if (t1 == t2)
            return INT2FIX(0);
        else if (t1 < t2)
            return INT2FIX(-1);
        else
            return INT2FIX(1);
    }
    return Qnil;
}

Returns the last access time for this file as an object of class Time.

   File.stat("testfile").atime   #=> Wed Dec 31 18:00:00 CST 1969

[Source]

/*
 *  call-seq:
 *     stat.atime   => time
 *  
 *  Returns the last access time for this file as an object of class
 *  <code>Time</code>.
 *     
 *     File.stat("testfile").atime   #=> Wed Dec 31 18:00:00 CST 1969
 *     
 */

static VALUE
rb_stat_atime(self)
    VALUE self;
{
    return rb_time_new(get_stat(self)->st_atime, 0);
}

Returns the native file system‘s block size. Will return nil on platforms that don‘t support this information.

   File.stat("testfile").blksize   #=> 4096

[Source]

/*
 *  call-seq:
 *     stat.blksize   => integer or nil
 *  
 *  Returns the native file system's block size. Will return <code>nil</code>
 *  on platforms that don't support this information.
 *     
 *     File.stat("testfile").blksize   #=> 4096
 *     
 */

static VALUE
rb_stat_blksize(self)
    VALUE self;
{
#ifdef HAVE_ST_BLKSIZE
    return ULONG2NUM(get_stat(self)->st_blksize);
#else
    return Qnil;
#endif
}

Returns true if the file is a block device, false if it isn‘t or if the operating system doesn‘t support this feature.

   File.stat("testfile").blockdev?    #=> false
   File.stat("/dev/hda1").blockdev?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.blockdev?   => true or false
 *  
 *  Returns <code>true</code> if the file is a block device,
 *  <code>false</code> if it isn't or if the operating system doesn't
 *  support this feature.
 *     
 *     File.stat("testfile").blockdev?    #=> false
 *     File.stat("/dev/hda1").blockdev?   #=> true
 *     
 */

static VALUE
rb_stat_b(obj)
    VALUE obj;
{
#ifdef S_ISBLK
    if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue;

#endif
    return Qfalse;
}

Returns the number of native file system blocks allocated for this file, or nil if the operating system doesn‘t support this feature.

   File.stat("testfile").blocks   #=> 2

[Source]

/*
 *  call-seq:
 *     stat.blocks    => integer or nil
 *  
 *  Returns the number of native file system blocks allocated for this
 *  file, or <code>nil</code> if the operating system doesn't 
 *  support this feature.
 *     
 *     File.stat("testfile").blocks   #=> 2
 */

static VALUE
rb_stat_blocks(self)
    VALUE self;
{
#ifdef HAVE_ST_BLOCKS
    return ULONG2NUM(get_stat(self)->st_blocks);
#else
    return Qnil;
#endif
}

Returns true if the file is a character device, false if it isn‘t or if the operating system doesn‘t support this feature.

   File.stat("/dev/tty").chardev?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.chardev?    => true or false
 *  
 *  Returns <code>true</code> if the file is a character device,
 *  <code>false</code> if it isn't or if the operating system doesn't
 *  support this feature.
 *     
 *     File.stat("/dev/tty").chardev?   #=> true
 *     
 */

static VALUE
rb_stat_c(obj)
    VALUE obj;
{
    if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue;

    return Qfalse;
}

Returns the change time for stat (that is, the time directory information about the file was changed, not the file itself).

   File.stat("testfile").ctime   #=> Wed Apr 09 08:53:14 CDT 2003

[Source]

/*
 *  call-seq:
 *     stat.ctime -> aTime
 *  
 *  Returns the change time for <i>stat</i> (that is, the time
 *  directory information about the file was changed, not the file
 *  itself).
 *     
 *     File.stat("testfile").ctime   #=> Wed Apr 09 08:53:14 CDT 2003
 *     
 */

static VALUE
rb_stat_ctime(self)
    VALUE self;
{
    return rb_time_new(get_stat(self)->st_ctime, 0);
}

Returns an integer representing the device on which stat resides.

   File.stat("testfile").dev   #=> 774

[Source]

/*
 *  call-seq:
 *     stat.dev    => fixnum
 *  
 *  Returns an integer representing the device on which <i>stat</i>
 *  resides.
 *     
 *     File.stat("testfile").dev   #=> 774
 */

static VALUE
rb_stat_dev(self)
    VALUE self;
{
    return INT2NUM(get_stat(self)->st_dev);
}

Returns the major part of File_Stat#dev or nil.

   File.stat("/dev/fd1").dev_major   #=> 2
   File.stat("/dev/tty").dev_major   #=> 5

[Source]

/*
 *  call-seq:
 *     stat.dev_major   => fixnum
 *  
 *  Returns the major part of <code>File_Stat#dev</code> or
 *  <code>nil</code>.
 *     
 *     File.stat("/dev/fd1").dev_major   #=> 2
 *     File.stat("/dev/tty").dev_major   #=> 5
 */

static VALUE
rb_stat_dev_major(self)
    VALUE self;
{
#if defined(major)
    long dev = get_stat(self)->st_dev;
    return ULONG2NUM(major(dev));
#else
    return Qnil;
#endif
}

Returns the minor part of File_Stat#dev or nil.

   File.stat("/dev/fd1").dev_minor   #=> 1
   File.stat("/dev/tty").dev_minor   #=> 0

[Source]

/*
 *  call-seq:
 *     stat.dev_minor   => fixnum
 *  
 *  Returns the minor part of <code>File_Stat#dev</code> or
 *  <code>nil</code>.
 *     
 *     File.stat("/dev/fd1").dev_minor   #=> 1
 *     File.stat("/dev/tty").dev_minor   #=> 0
 */

static VALUE
rb_stat_dev_minor(self)
    VALUE self;
{
#if defined(minor)
    long dev = get_stat(self)->st_dev;
    return ULONG2NUM(minor(dev));
#else
    return Qnil;
#endif
}

Returns true if stat is a directory, false otherwise.

   File.stat("testfile").directory?   #=> false
   File.stat(".").directory?          #=> true

[Source]

/*
 *  call-seq:
 *     stat.directory?   => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is a directory,
 *  <code>false</code> otherwise.
 *     
 *     File.stat("testfile").directory?   #=> false
 *     File.stat(".").directory?          #=> true
 */

static VALUE
rb_stat_d(obj)
    VALUE obj;
{
    if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue;
    return Qfalse;
}

Returns true if stat is executable or if the operating system doesn‘t distinguish executable files from nonexecutable files. The tests are made using the effective owner of the process.

   File.stat("testfile").executable?   #=> false

[Source]

/*
 *  call-seq:
 *     stat.executable?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is executable or if the
 *  operating system doesn't distinguish executable files from
 *  nonexecutable files. The tests are made using the effective owner of
 *  the process.
 *     
 *     File.stat("testfile").executable?   #=> false
 *     
 */

static VALUE
rb_stat_x(obj)
    VALUE obj;
{
    struct stat *st = get_stat(obj);

#ifdef USE_GETEUID
    if (geteuid() == 0) {
        return st->st_mode & S_IXUGO ? Qtrue : Qfalse;
    }
#endif
#ifdef S_IXUSR
    if (rb_stat_owned(obj))
        return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
#endif
#ifdef S_IXGRP
    if (rb_stat_grpowned(obj))
        return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
#endif
#ifdef S_IXOTH
    if (!(st->st_mode & S_IXOTH)) return Qfalse;
#endif
    return Qtrue;
}

Same as executable?, but tests using the real owner of the process.

[Source]

/*
 *  call-seq:
 *     stat.executable_real?    => true or false
 *  
 *  Same as <code>executable?</code>, but tests using the real owner of
 *  the process.
 */


static VALUE
rb_stat_X(obj)
    VALUE obj;
{
    struct stat *st = get_stat(obj);

#ifdef USE_GETEUID
    if (getuid() == 0) {
        return st->st_mode & S_IXUGO ? Qtrue : Qfalse;
    }
#endif
#ifdef S_IXUSR
    if (rb_stat_rowned(obj))
        return st->st_mode & S_IXUSR ? Qtrue : Qfalse;
#endif
#ifdef S_IXGRP
    if (group_member(get_stat(obj)->st_gid))
        return st->st_mode & S_IXGRP ? Qtrue : Qfalse;
#endif
#ifdef S_IXOTH
    if (!(st->st_mode & S_IXOTH)) return Qfalse;
#endif
    return Qtrue;
}

Returns true if stat is a regular file (not a device file, pipe, socket, etc.).

   File.stat("testfile").file?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.file?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is a regular file (not
 *  a device file, pipe, socket, etc.).
 *     
 *     File.stat("testfile").file?   #=> true
 *     
 */

static VALUE
rb_stat_f(obj)
    VALUE obj;
{
    if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue;
    return Qfalse;
}

Identifies the type of stat. The return string is one of: ``file’’, ``directory’’, ``characterSpecial’’, ``blockSpecial’’, ``fifo’’, ``link’’, ``socket’’, or ``unknown’’.

   File.stat("/dev/tty").ftype   #=> "characterSpecial"

[Source]

/*
 *  call-seq:
 *     stat.ftype   => string
 *  
 *  Identifies the type of <i>stat</i>. The return string is one of:
 *  ``<code>file</code>'', ``<code>directory</code>'',
 *  ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'',
 *  ``<code>fifo</code>'', ``<code>link</code>'',
 *  ``<code>socket</code>'', or ``<code>unknown</code>''.
 *     
 *     File.stat("/dev/tty").ftype   #=> "characterSpecial"
 *     
 */

static VALUE
rb_stat_ftype(obj)
    VALUE obj;
{
    return rb_file_ftype(get_stat(obj));
}

Returns the numeric group id of the owner of stat.

   File.stat("testfile").gid   #=> 500

[Source]

/*
 *  call-seq:
 *     stat.gid   => fixnum
 *  
 *  Returns the numeric group id of the owner of <i>stat</i>.
 *     
 *     File.stat("testfile").gid   #=> 500
 *     
 */

static VALUE
rb_stat_gid(self)
    VALUE self;
{
    return UINT2NUM(get_stat(self)->st_gid);
}

Returns true if the effective group id of the process is the same as the group id of stat. On Windows NT, returns false.

   File.stat("testfile").grpowned?      #=> true
   File.stat("/etc/passwd").grpowned?   #=> false

[Source]

/*
 *  call-seq:
 *     stat.grpowned?   => true or false
 *  
 *  Returns true if the effective group id of the process is the same as
 *  the group id of <i>stat</i>. On Windows NT, returns <code>false</code>.
 *     
 *     File.stat("testfile").grpowned?      #=> true
 *     File.stat("/etc/passwd").grpowned?   #=> false
 *     
 */

static VALUE
rb_stat_grpowned(obj)
    VALUE obj;
{
#ifndef _WIN32
    if (group_member(get_stat(obj)->st_gid)) return Qtrue;
#endif
    return Qfalse;
}

Returns the inode number for stat.

   File.stat("testfile").ino   #=> 1083669

[Source]

/*
 *  call-seq:
 *     stat.ino   => fixnum
 *  
 *  Returns the inode number for <i>stat</i>.
 *     
 *     File.stat("testfile").ino   #=> 1083669
 *     
 */

static VALUE
rb_stat_ino(self)
    VALUE self;
{
#ifdef HUGE_ST_INO
    return ULL2NUM(get_stat(self)->st_ino);
#else
    return ULONG2NUM(get_stat(self)->st_ino);
#endif
}

Produce a nicely formatted description of stat.

  File.stat("/etc/passwd").inspect
     #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644,
          nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096,
          blocks=8, atime=Wed Dec 10 10:16:12 CST 2003,
          mtime=Fri Sep 12 15:41:41 CDT 2003,
          ctime=Mon Oct 27 11:20:27 CST 2003>"

[Source]

/*
 * call-seq:
 *   stat.inspect  =>  string
 *
 * Produce a nicely formatted description of <i>stat</i>.
 *
 *   File.stat("/etc/passwd").inspect
 *      #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644, 
 *           nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096, 
 *           blocks=8, atime=Wed Dec 10 10:16:12 CST 2003, 
 *           mtime=Fri Sep 12 15:41:41 CDT 2003, 
 *           ctime=Mon Oct 27 11:20:27 CST 2003>"
 */

static VALUE
rb_stat_inspect(self)
    VALUE self;
{
    VALUE str;
    int 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},
    };

    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 */
            char buf[32];

            sprintf(buf, "0%lo", NUM2ULONG(v));
            rb_str_buf_cat2(str, buf);
        }
        else if (i == 0 || i == 6) { /* dev/rdev */
            char buf[32];

            sprintf(buf, "0x%lx", NUM2ULONG(v));
            rb_str_buf_cat2(str, buf);
        }
        else {
            rb_str_append(str, rb_inspect(v));
        }
    }
    rb_str_buf_cat2(str, ">");
    OBJ_INFECT(str, self);

    return str;
}

Returns an integer representing the permission bits of stat. The meaning of the bits is platform dependent; on Unix systems, see stat(2).

   File.chmod(0644, "testfile")   #=> 1
   s = File.stat("testfile")
   sprintf("%o", s.mode)          #=> "100644"

[Source]

/*
 *  call-seq:
 *     stat.mode   => fixnum
 *  
 *  Returns an integer representing the permission bits of
 *  <i>stat</i>. The meaning of the bits is platform dependent; on
 *  Unix systems, see <code>stat(2)</code>.
 *     
 *     File.chmod(0644, "testfile")   #=> 1
 *     s = File.stat("testfile")
 *     sprintf("%o", s.mode)          #=> "100644"
 */

static VALUE
rb_stat_mode(self)
    VALUE self;
{
#ifdef __BORLANDC__
    return UINT2NUM((unsigned short)(get_stat(self)->st_mode));
#else
    return UINT2NUM(get_stat(self)->st_mode);
#endif
}

Returns the modification time of stat.

   File.stat("testfile").mtime   #=> Wed Apr 09 08:53:14 CDT 2003

[Source]

/*
 *  call-seq:
 *     stat.mtime -> aTime
 *  
 *  Returns the modification time of <i>stat</i>.
 *     
 *     File.stat("testfile").mtime   #=> Wed Apr 09 08:53:14 CDT 2003
 *     
 */

static VALUE
rb_stat_mtime(self)
    VALUE self;
{
    return rb_time_new(get_stat(self)->st_mtime, 0);
}

Returns the number of hard links to stat.

   File.stat("testfile").nlink             #=> 1
   File.link("testfile", "testfile.bak")   #=> 0
   File.stat("testfile").nlink             #=> 2

[Source]

/*
 *  call-seq:
 *     stat.nlink   => fixnum
 *  
 *  Returns the number of hard links to <i>stat</i>.
 *     
 *     File.stat("testfile").nlink             #=> 1
 *     File.link("testfile", "testfile.bak")   #=> 0
 *     File.stat("testfile").nlink             #=> 2
 *     
 */

static VALUE
rb_stat_nlink(self)
    VALUE self;
{
    return UINT2NUM(get_stat(self)->st_nlink);
}

Returns true if the effective user id of the process is the same as the owner of stat.

   File.stat("testfile").owned?      #=> true
   File.stat("/etc/passwd").owned?   #=> false

[Source]

/*
 *  call-seq:
 *     stat.owned?    => true or false
 *  
 *  Returns <code>true</code> if the effective user id of the process is
 *  the same as the owner of <i>stat</i>.
 *     
 *     File.stat("testfile").owned?      #=> true
 *     File.stat("/etc/passwd").owned?   #=> false
 *     
 */

static VALUE
rb_stat_owned(obj)
    VALUE obj;
{
    if (get_stat(obj)->st_uid == geteuid()) return Qtrue;
    return Qfalse;
}

Returns true if the operating system supports pipes and stat is a pipe; false otherwise.

[Source]

/*
 *  call-seq:
 *     stat.pipe?    => true or false
 *  
 *  Returns <code>true</code> if the operating system supports pipes and
 *  <i>stat</i> is a pipe; <code>false</code> otherwise.
 */

static VALUE
rb_stat_p(obj)
    VALUE obj;
{
#ifdef S_IFIFO
    if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue;

#endif
    return Qfalse;
}

Returns an integer representing the device type on which stat resides. Returns nil if the operating system doesn‘t support this feature.

   File.stat("/dev/fd1").rdev   #=> 513
   File.stat("/dev/tty").rdev   #=> 1280

[Source]

/*
 *  call-seq:
 *     stat.rdev   =>  fixnum or nil
 *  
 *  Returns an integer representing the device type on which
 *  <i>stat</i> resides. Returns <code>nil</code> if the operating
 *  system doesn't support this feature.
 *     
 *     File.stat("/dev/fd1").rdev   #=> 513
 *     File.stat("/dev/tty").rdev   #=> 1280
 */

static VALUE
rb_stat_rdev(self)
    VALUE self;
{
#ifdef HAVE_ST_RDEV
    return ULONG2NUM(get_stat(self)->st_rdev);
#else
    return Qnil;
#endif
}

Returns the major part of File_Stat#rdev or nil.

   File.stat("/dev/fd1").rdev_major   #=> 2
   File.stat("/dev/tty").rdev_major   #=> 5

[Source]

/*
 *  call-seq:
 *     stat.rdev_major   => fixnum
 *  
 *  Returns the major part of <code>File_Stat#rdev</code> or
 *  <code>nil</code>.
 *     
 *     File.stat("/dev/fd1").rdev_major   #=> 2
 *     File.stat("/dev/tty").rdev_major   #=> 5
 */

static VALUE
rb_stat_rdev_major(self)
    VALUE self;
{
#if defined(HAVE_ST_RDEV) && defined(major)
    long rdev = get_stat(self)->st_rdev;
    return ULONG2NUM(major(rdev));
#else
    return Qnil;
#endif
}

Returns the minor part of File_Stat#rdev or nil.

   File.stat("/dev/fd1").rdev_minor   #=> 1
   File.stat("/dev/tty").rdev_minor   #=> 0

[Source]

/*
 *  call-seq:
 *     stat.rdev_minor   => fixnum
 *  
 *  Returns the minor part of <code>File_Stat#rdev</code> or
 *  <code>nil</code>.
 *     
 *     File.stat("/dev/fd1").rdev_minor   #=> 1
 *     File.stat("/dev/tty").rdev_minor   #=> 0
 */

static VALUE
rb_stat_rdev_minor(self)
    VALUE self;
{
#if defined(HAVE_ST_RDEV) && defined(minor)
    long rdev = get_stat(self)->st_rdev;
    return ULONG2NUM(minor(rdev));
#else
    return Qnil;
#endif
}

Returns true if stat is readable by the effective user id of this process.

   File.stat("testfile").readable?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.readable?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is readable by the
 *  effective user id of this process.
 *     
 *     File.stat("testfile").readable?   #=> true
 *     
 */

static VALUE
rb_stat_r(obj)
    VALUE obj;
{
    struct stat *st = get_stat(obj);

#ifdef USE_GETEUID
    if (geteuid() == 0) return Qtrue;
#endif
#ifdef S_IRUSR
    if (rb_stat_owned(obj))
        return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
#endif
#ifdef S_IRGRP
    if (rb_stat_grpowned(obj))
        return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
#endif
#ifdef S_IROTH
    if (!(st->st_mode & S_IROTH)) return Qfalse;
#endif
    return Qtrue;
}

Returns true if stat is readable by the real user id of this process.

   File.stat("testfile").readable_real?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.readable_real? -> true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is readable by the real
 *  user id of this process.
 *     
 *     File.stat("testfile").readable_real?   #=> true
 *     
 */

static VALUE
rb_stat_R(obj)
    VALUE obj;
{
    struct stat *st = get_stat(obj);

#ifdef USE_GETEUID
    if (getuid() == 0) return Qtrue;
#endif
#ifdef S_IRUSR
    if (rb_stat_rowned(obj))
        return st->st_mode & S_IRUSR ? Qtrue : Qfalse;
#endif
#ifdef S_IRGRP
    if (group_member(get_stat(obj)->st_gid))
        return st->st_mode & S_IRGRP ? Qtrue : Qfalse;
#endif
#ifdef S_IROTH
    if (!(st->st_mode & S_IROTH)) return Qfalse;
#endif
    return Qtrue;
}

Returns true if stat has the set-group-id permission bit set, false if it doesn‘t or if the operating system doesn‘t support this feature.

   File.stat("/usr/sbin/lpc").setgid?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.setgid?   => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> has the set-group-id
 *  permission bit set, <code>false</code> if it doesn't or if the
 *  operating system doesn't support this feature.
 *     
 *     File.stat("/usr/sbin/lpc").setgid?   #=> true
 *     
 */

static VALUE
rb_stat_sgid(obj)
    VALUE obj;
{
#ifdef S_ISGID
    if (get_stat(obj)->st_mode & S_ISGID) return Qtrue;
#endif
    return Qfalse;
}

Returns true if stat has the set-user-id permission bit set, false if it doesn‘t or if the operating system doesn‘t support this feature.

   File.stat("/bin/su").setuid?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.setuid?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> has the set-user-id
 *  permission bit set, <code>false</code> if it doesn't or if the
 *  operating system doesn't support this feature.
 *     
 *     File.stat("/bin/su").setuid?   #=> true
 */

static VALUE
rb_stat_suid(obj)
    VALUE obj;
{
#ifdef S_ISUID
    if (get_stat(obj)->st_mode & S_ISUID) return Qtrue;
#endif
    return Qfalse;
}

Returns the size of stat in bytes.

   File.stat("testfile").size   #=> 66

[Source]

/*
 *  call-seq:
 *     stat.size    => fixnum
 *  
 *  Returns the size of <i>stat</i> in bytes.
 *     
 *     File.stat("testfile").size   #=> 66
 */

static VALUE
rb_stat_size(self)
    VALUE self;
{
    return OFFT2NUM(get_stat(self)->st_size);
}

Returns the size of stat in bytes.

   File.stat("testfile").size   #=> 66

[Source]

/*
 *  call-seq:
 *     state.size    => integer
 *  
 *  Returns the size of <i>stat</i> in bytes.
 *     
 *     File.stat("testfile").size   #=> 66
 *     
 */

static VALUE
rb_stat_s(obj)
    VALUE obj;
{
    off_t size = get_stat(obj)->st_size;

    if (size == 0) return Qnil;
    return OFFT2NUM(size);
}

Returns true if stat is a socket, false if it isn‘t or if the operating system doesn‘t support this feature.

   File.stat("testfile").socket?   #=> false

[Source]

/*
 *  call-seq:
 *     stat.socket?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is a socket,
 *  <code>false</code> if it isn't or if the operating system doesn't
 *  support this feature.
 *     
 *     File.stat("testfile").socket?   #=> false
 *     
 */

static VALUE
rb_stat_S(obj)
    VALUE obj;
{
#ifdef S_ISSOCK
    if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue;

#endif
    return Qfalse;
}

Returns true if stat has its sticky bit set, false if it doesn‘t or if the operating system doesn‘t support this feature.

   File.stat("testfile").sticky?   #=> false

[Source]

/*
 *  call-seq:
 *     stat.sticky?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> has its sticky bit set,
 *  <code>false</code> if it doesn't or if the operating system doesn't
 *  support this feature.
 *     
 *     File.stat("testfile").sticky?   #=> false
 *     
 */

static VALUE
rb_stat_sticky(obj)
    VALUE obj;
{
#ifdef S_ISVTX
    if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue;
#endif
    return Qfalse;
}

Returns true if stat is a symbolic link, false if it isn‘t or if the operating system doesn‘t support this feature. As File::stat automatically follows symbolic links, symlink? will always be false for an object returned by File::stat.

   File.symlink("testfile", "alink")   #=> 0
   File.stat("alink").symlink?         #=> false
   File.lstat("alink").symlink?        #=> true

[Source]

/*
 *  call-seq:
 *     stat.symlink?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is a symbolic link,
 *  <code>false</code> if it isn't or if the operating system doesn't
 *  support this feature. As <code>File::stat</code> automatically
 *  follows symbolic links, <code>symlink?</code> will always be
 *  <code>false</code> for an object returned by
 *  <code>File::stat</code>.
 *     
 *     File.symlink("testfile", "alink")   #=> 0
 *     File.stat("alink").symlink?         #=> false
 *     File.lstat("alink").symlink?        #=> true
 *     
 */

static VALUE
rb_stat_l(obj)
    VALUE obj;
{
#ifdef S_ISLNK
    if (S_ISLNK(get_stat(obj)->st_mode)) return Qtrue;
#endif
    return Qfalse;
}

Returns the numeric user id of the owner of stat.

   File.stat("testfile").uid   #=> 501

[Source]

/*
 *  call-seq:
 *     stat.uid    => fixnum
 *  
 *  Returns the numeric user id of the owner of <i>stat</i>.
 *     
 *     File.stat("testfile").uid   #=> 501
 *     
 */

static VALUE
rb_stat_uid(self)
    VALUE self;
{
    return UINT2NUM(get_stat(self)->st_uid);
}

Returns true if stat is writable by the effective user id of this process.

   File.stat("testfile").writable?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.writable? -> true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is writable by the
 *  effective user id of this process.
 *     
 *     File.stat("testfile").writable?   #=> true
 *     
 */

static VALUE
rb_stat_w(obj)
    VALUE obj;
{
    struct stat *st = get_stat(obj);

#ifdef USE_GETEUID
    if (geteuid() == 0) return Qtrue;
#endif
#ifdef S_IWUSR
    if (rb_stat_owned(obj))
        return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
#endif
#ifdef S_IWGRP
    if (rb_stat_grpowned(obj))
        return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
#endif
#ifdef S_IWOTH
    if (!(st->st_mode & S_IWOTH)) return Qfalse;
#endif
    return Qtrue;
}

Returns true if stat is writable by the real user id of this process.

   File.stat("testfile").writable_real?   #=> true

[Source]

/*
 *  call-seq:
 *     stat.writable_real? -> true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is writable by the real
 *  user id of this process.
 *     
 *     File.stat("testfile").writable_real?   #=> true
 *     
 */

static VALUE
rb_stat_W(obj)
    VALUE obj;
{
    struct stat *st = get_stat(obj);

#ifdef USE_GETEUID
    if (getuid() == 0) return Qtrue;
#endif
#ifdef S_IWUSR
    if (rb_stat_rowned(obj))
        return st->st_mode & S_IWUSR ? Qtrue : Qfalse;
#endif
#ifdef S_IWGRP
    if (group_member(get_stat(obj)->st_gid))
        return st->st_mode & S_IWGRP ? Qtrue : Qfalse;
#endif
#ifdef S_IWOTH
    if (!(st->st_mode & S_IWOTH)) return Qfalse;
#endif
    return Qtrue;
}

Returns true if stat is a zero-length file; false otherwise.

   File.stat("testfile").zero?   #=> false

[Source]

/*
 *  call-seq:
 *     stat.zero?    => true or false
 *  
 *  Returns <code>true</code> if <i>stat</i> is a zero-length file;
 *  <code>false</code> otherwise.
 *     
 *     File.stat("testfile").zero?   #=> false
 *     
 */

static VALUE
rb_stat_z(obj)
    VALUE obj;
{
    if (get_stat(obj)->st_size == 0) return Qtrue;
    return Qfalse;
}

[Validate]