Class: File::Stat (Ruby 2.3.4)

    In Files

    • file.c

    Class/Module Index [+]

    Quicksearch

    File::Stat

    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.

    Public Class Methods

    File::Stat.new(file_name) → stat click to toggle source

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

     
                   static VALUE
    rb_stat_init(VALUE obj, VALUE fname)
    {
        struct stat st, *nst;
    
        FilePathValue(fname);
        fname = rb_str_encode_ospath(fname);
        if (STAT(StringValueCStr(fname), &st) == -1) {
            rb_sys_fail_path(fname);
        }
        if (DATA_PTR(obj)) {
            xfree(DATA_PTR(obj));
            DATA_PTR(obj) = NULL;
        }
        nst = ALLOC(struct stat);
        *nst = st;
        DATA_PTR(obj) = nst;
    
        return Qnil;
    }
                

    Public Instance Methods

    stat <=> other_stat → -1, 0, 1, nil click to toggle source

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

    nil is returned if other_stat is not a File::Stat object

    f1 = File.new("f1", "w")
    sleep 1
    f2 = File.new("f2", "w")
    f1.stat <=> f2.stat   #=> -1
    
     
                   static VALUE
    rb_stat_cmp(VALUE self, VALUE other)
    {
        if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
            struct timespec ts1 = stat_mtimespec(get_stat(self));
            struct timespec ts2 = stat_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;
    }
                
    atime → time click to toggle source

    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
    
     
                   static VALUE
    rb_stat_atime(VALUE self)
    {
        return stat_atime(get_stat(self));
    }
                
    birthtime → aTime click to toggle source

    Returns the birth time for stat.

    If the platform doesn’t have birthtime, raises NotImplementedError.

    File.write("testfile", "foo")
    sleep 10
    File.write("testfile", "bar")
    sleep 10
    File.chmod(0644, "testfile")
    sleep 10
    File.read("testfile")
    File.stat("testfile").birthtime   #=> 2014-02-24 11:19:17 +0900
    File.stat("testfile").mtime       #=> 2014-02-24 11:19:27 +0900
    File.stat("testfile").ctime       #=> 2014-02-24 11:19:37 +0900
    File.stat("testfile").atime       #=> 2014-02-24 11:19:47 +0900
    
     
                   static VALUE
    rb_stat_birthtime(VALUE self)
    {
        return stat_birthtime(get_stat(self));
    }
                
    blksize → integer or nil click to toggle source

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

    File.stat("testfile").blksize   #=> 4096
    
     
                   static VALUE
    rb_stat_blksize(VALUE self)
    {
    #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
        return ULONG2NUM(get_stat(self)->st_blksize);
    #else
        return Qnil;
    #endif
    }
                
    blockdev? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_b(VALUE obj)
    {
    #ifdef S_ISBLK
        if (S_ISBLK(get_stat(obj)->st_mode)) return Qtrue;
    
    #endif
        return Qfalse;
    }
                
    blocks → integer or nil click to toggle source

    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
    
     
                   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
    }
                
    chardev? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_c(VALUE obj)
    {
        if (S_ISCHR(get_stat(obj)->st_mode)) return Qtrue;
    
        return Qfalse;
    }
                
    ctime → aTime click to toggle source

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

    Note that on Windows (NTFS), returns creation time (birth time).

    File.stat("testfile").ctime   #=> Wed Apr 09 08:53:14 CDT 2003
    
     
                   static VALUE
    rb_stat_ctime(VALUE self)
    {
        return stat_ctime(get_stat(self));
    }
                
    dev → fixnum click to toggle source

    Returns an integer representing the device on which stat resides.

    File.stat("testfile").dev   #=> 774
    
     
                   static VALUE
    rb_stat_dev(VALUE self)
    {
        return DEVT2NUM(get_stat(self)->st_dev);
    }
                
    dev_major → fixnum click to toggle source

    Returns the major part of File_Stat#dev or nil.

    File.stat("/dev/fd1").dev_major   #=> 2
    File.stat("/dev/tty").dev_major   #=> 5
    
     
                   static VALUE
    rb_stat_dev_major(VALUE self)
    {
    #if defined(major)
        return INT2NUM(major(get_stat(self)->st_dev));
    #else
        return Qnil;
    #endif
    }
                
    dev_minor → fixnum click to toggle source

    Returns the minor part of File_Stat#dev or nil.

    File.stat("/dev/fd1").dev_minor   #=> 1
    File.stat("/dev/tty").dev_minor   #=> 0
    
     
                   static VALUE
    rb_stat_dev_minor(VALUE self)
    {
    #if defined(minor)
        return INT2NUM(minor(get_stat(self)->st_dev));
    #else
        return Qnil;
    #endif
    }
                
    directory?(file_name) → true or false click to toggle source

    Returns true if the named file is a directory, or a symlink that points at a directory, and false otherwise.

    file_name can be an IO object.

    File.directory?(".")
    
     
                   static VALUE
    rb_stat_d(VALUE obj)
    {
        if (S_ISDIR(get_stat(obj)->st_mode)) return Qtrue;
        return Qfalse;
    }
                
    executable? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_x(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;
    }
                
    executable_real? → true or false click to toggle source

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

     
                   static VALUE
    rb_stat_X(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 (rb_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;
    }
                
    file? → true or false click to toggle source

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

    File.stat("testfile").file?   #=> true
    
     
                   static VALUE
    rb_stat_f(VALUE obj)
    {
        if (S_ISREG(get_stat(obj)->st_mode)) return Qtrue;
        return Qfalse;
    }
                
    ftype → string click to toggle source

    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"
    
     
                   static VALUE
    rb_stat_ftype(VALUE obj)
    {
        return rb_file_ftype(get_stat(obj));
    }
                
    gid → fixnum click to toggle source

    Returns the numeric group id of the owner of stat.

    File.stat("testfile").gid   #=> 500
    
     
                   static VALUE
    rb_stat_gid(VALUE self)
    {
        return GIDT2NUM(get_stat(self)->st_gid);
    }
                
    grpowned? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_grpowned(VALUE obj)
    {
    #ifndef _WIN32
        if (rb_group_member(get_stat(obj)->st_gid)) return Qtrue;
    #endif
        return Qfalse;
    }
                
    ino → fixnum click to toggle source

    Returns the inode number for stat.

    File.stat("testfile").ino   #=> 1083669
    
     
                   static VALUE
    rb_stat_ino(VALUE self)
    {
    #ifdef _WIN32
        struct stat *st = get_stat(self);
        unsigned short *p2 = (unsigned short *)st;
        unsigned int *p4 = (unsigned int *)st;
        uint64_t r;
        r = p2[2];
        r <<= 16;
        r |= p2[7];
        r <<= 32;
        r |= p4[5];
        return ULL2NUM(r);
    #elif SIZEOF_STRUCT_STAT_ST_INO > SIZEOF_LONG
        return ULL2NUM(get_stat(self)->st_ino);
    #else
        return ULONG2NUM(get_stat(self)->st_ino);
    #endif
    }
                
    inspect → string click to toggle source

    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,
       #    birthtime=Mon Aug 04 08:13:49 CDT 2003>"
    
     
                   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 stat* st;
        TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
        if (!st) {
            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, ">");
        OBJ_INFECT(str, self);
    
        return str;
    }
                
    mode → fixnum click to toggle source

    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"
    
     
                   static VALUE
    rb_stat_mode(VALUE self)
    {
        return UINT2NUM(ST2UINT(get_stat(self)->st_mode));
    }
                
    mtime → aTime click to toggle source

    Returns the modification time of stat.

    File.stat("testfile").mtime   #=> Wed Apr 09 08:53:14 CDT 2003
    
     
                   static VALUE
    rb_stat_mtime(VALUE self)
    {
        return stat_mtime(get_stat(self));
    }
                
    owned? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_owned(VALUE obj)
    {
        if (get_stat(obj)->st_uid == geteuid()) return Qtrue;
        return Qfalse;
    }
                
    pipe? → true or false click to toggle source

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

     
                   static VALUE
    rb_stat_p(VALUE obj)
    {
    #ifdef S_IFIFO
        if (S_ISFIFO(get_stat(obj)->st_mode)) return Qtrue;
    
    #endif
        return Qfalse;
    }
                
    rdev → fixnum or nil click to toggle source

    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
    
     
                   static VALUE
    rb_stat_rdev(VALUE self)
    {
    #ifdef HAVE_STRUCT_STAT_ST_RDEV
        return DEVT2NUM(get_stat(self)->st_rdev);
    #else
        return Qnil;
    #endif
    }
                
    rdev_major → fixnum click to toggle source

    Returns the major part of File_Stat#rdev or nil.

    File.stat("/dev/fd1").rdev_major   #=> 2
    File.stat("/dev/tty").rdev_major   #=> 5
    
     
                   static VALUE
    rb_stat_rdev_major(VALUE self)
    {
    #if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(major)
        return DEVT2NUM(major(get_stat(self)->st_rdev));
    #else
        return Qnil;
    #endif
    }
                
    rdev_minor → fixnum click to toggle source

    Returns the minor part of File_Stat#rdev or nil.

    File.stat("/dev/fd1").rdev_minor   #=> 1
    File.stat("/dev/tty").rdev_minor   #=> 0
    
     
                   static VALUE
    rb_stat_rdev_minor(VALUE self)
    {
    #if defined(HAVE_STRUCT_STAT_ST_RDEV) && defined(minor)
        return DEVT2NUM(minor(get_stat(self)->st_rdev));
    #else
        return Qnil;
    #endif
    }
                
    readable? → true or false click to toggle source

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

    File.stat("testfile").readable?   #=> true
    
     
                   static VALUE
    rb_stat_r(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;
    }
                
    readable_real? → true or false click to toggle source

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

    File.stat("testfile").readable_real?   #=> true
    
     
                   static VALUE
    rb_stat_R(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 (rb_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;
    }
                
    setgid? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_sgid(VALUE obj)
    {
    #ifdef S_ISGID
        if (get_stat(obj)->st_mode & S_ISGID) return Qtrue;
    #endif
        return Qfalse;
    }
                
    setuid? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_suid(VALUE obj)
    {
    #ifdef S_ISUID
        if (get_stat(obj)->st_mode & S_ISUID) return Qtrue;
    #endif
        return Qfalse;
    }
                
    size → fixnum click to toggle source

    Returns the size of stat in bytes.

    File.stat("testfile").size   #=> 66
    
     
                   static VALUE
    rb_stat_size(VALUE self)
    {
        return OFFT2NUM(get_stat(self)->st_size);
    }
                
    size → integer click to toggle source

    Returns the size of stat in bytes.

    File.stat("testfile").size   #=> 66
    
     
                   static VALUE
    rb_stat_s(VALUE obj)
    {
        off_t size = get_stat(obj)->st_size;
    
        if (size == 0) return Qnil;
        return OFFT2NUM(size);
    }
                
    socket? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_S(VALUE obj)
    {
    #ifdef S_ISSOCK
        if (S_ISSOCK(get_stat(obj)->st_mode)) return Qtrue;
    
    #endif
        return Qfalse;
    }
                
    sticky? → true or false click to toggle source

    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
    
     
                   static VALUE
    rb_stat_sticky(VALUE obj)
    {
    #ifdef S_ISVTX
        if (get_stat(obj)->st_mode & S_ISVTX) return Qtrue;
    #endif
        return Qfalse;
    }
                
    uid → fixnum click to toggle source

    Returns the numeric user id of the owner of stat.

    File.stat("testfile").uid   #=> 501
    
     
                   static VALUE
    rb_stat_uid(VALUE self)
    {
        return UIDT2NUM(get_stat(self)->st_uid);
    }
                
    world_readable? → fixnum or nil click to toggle source

    If stat is readable by others, returns an integer representing the file permission bits of stat. Returns nil otherwise. The meaning of the bits is platform dependent; on Unix systems, see stat(2).

    m = File.stat("/etc/passwd").world_readable?  #=> 420
    sprintf("%o", m)                              #=> "644"
    
     
                   static VALUE
    rb_stat_wr(VALUE obj)
    {
    #ifdef S_IROTH
        struct stat *st = get_stat(obj);
        if ((st->st_mode & (S_IROTH)) == S_IROTH) {
            return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
        }
        else {
            return Qnil;
        }
    #endif
    }
                
    world_writable? → fixnum or nil click to toggle source

    If stat is writable by others, returns an integer representing the file permission bits of stat. Returns nil otherwise. The meaning of the bits is platform dependent; on Unix systems, see stat(2).

    m = File.stat("/tmp").world_writable?         #=> 511
    sprintf("%o", m)                              #=> "777"
    
     
                   static VALUE
    rb_stat_ww(VALUE obj)
    {
    #ifdef S_IROTH
        struct stat *st = get_stat(obj);
        if ((st->st_mode & (S_IWOTH)) == S_IWOTH) {
            return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
        }
        else {
            return Qnil;
        }
    #endif
    }
                
    writable? → true or false click to toggle source

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

    File.stat("testfile").writable?   #=> true
    
     
                   static VALUE
    rb_stat_w(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;
    }
                
    writable_real? → true or false click to toggle source

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

    File.stat("testfile").writable_real?   #=> true
    
     
                   static VALUE
    rb_stat_W(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 (rb_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;
    }
                
    zero? → true or false click to toggle source

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

    File.stat("testfile").zero?   #=> false
    
     
                   static VALUE
    rb_stat_z(VALUE obj)
    {
        if (get_stat(obj)->st_size == 0) return Qtrue;
        return Qfalse;
    }