Forum: Ruby Trying to get stat, Win32API to work

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
F3b7b8756d0c7f71cc7460cc33aefaee?d=identicon&s=25 Berger, Daniel (Guest)
on 2006-03-31 22:49
(Received via mailing list)
Hi all,

Ruby 1.8.4
Windows XP

I'm trying to make a pure Ruby version of File::Stat.  Something seems
to go wrong around the time I get rdev.  I think I just need another set
of eyes to see what I'm doing wrong here.

Thanks,

Dan

# stat.rb

require 'Win32API'

# Based on what I see in sys/types.h:
#
# ino_t  - unsigned short
# dev_t  - unsigned int
# off_t  - long
# time_t - long

=begin
   struct _stat {
      _dev_t st_dev;          # 'I', 4
      _ino_t st_ino;          # 'S', 2
      unsigned short st_mode; # 'S', 2
      short st_nlink;         # 's', 2
      short st_uid;           # 's', 2
      short st_gid;           # 's', 2
      _dev_t st_rdev;         # 'I', 4
      _off_t st_size;         # 'l', 4
      time_t st_atime;        # 'l', 4
      time_t st_mtime;        # 'l', 4
      time_t st_ctime;        # 'l', 4
   };
=end

class File::Stat
   @@stat  = Win32API.new('msvcrt', '_stat', 'PP', 'I')

   def initialize(file)
      stat_buf = [0,0,0,0,0,0,0,0,0,0,0].pack('ISSsssIllll')

      @@stat.call(file, stat_buf)

      @dev   = stat_buf[0..3].unpack('I').first
      @ino   = stat_buf[4..5].unpack('S').first
      @mode  = stat_buf[6..7].unpack('S').first
      @nlink = stat_buf[8..9].unpack('s').first
      @uid   = stat_buf[10..11].unpack('s').first
      @gid   = stat_buf[12..13].unpack('s').first
      @rdev  = stat_buf[14..17].unpack('I').first
      @size  = stat_buf[18..21].unpack('l').first
      @atime = stat_buf[22..25].unpack('l').first
      @mtime = stat_buf[26..29].unpack('l').first
      @ctime = stat_buf[30..33].unpack('l').first

      puts "Dev: [#{@dev}]"
      puts "Ino: [#{@ino}]"
      puts "Mode: [#{@mode}]"
      puts "Nlink: [#{@nlink}]"
      puts "Uid: [#{@uid}]"
      puts "Gid: [#{@gid}]"
      puts "RDev: [#{@rdev}]" # Things start to look wrong here...
      puts "Size: [#{@size}]"
      puts "Atime: [" + Time.at(@atime) + "]"
      puts "Mtime: [" + Time.at(@mtime) + "]"
      puts "Ctime: [" + Time.at(@ctime) + "]"
   end
end

if $0 == __FILE__
   File::Stat.new('somefile.txt')
end
E51d56251ec4affafe85ee9367228965?d=identicon&s=25 Park Heesob (Guest)
on 2006-04-01 01:18
(Received via mailing list)
Hi,

>
>I'm trying to make a pure Ruby version of File::Stat.  Something seems
>to go wrong around the time I get rdev.  I think I just need another set
>of eyes to see what I'm doing wrong here.
>
>Thanks,
>
>Dan
>
># stat.rb
>
...
>
It is due to the structure alignment.
Applications should generally align structure members at addresses that
are
¡°natural¡± for the data type and the processor involved. For example, a
4-byte data member should have an address that is a multiple of four.

Refer to
http://msdn.microsoft.com/library/default.asp?url=...

Your code should be like this:
# stat.rb

require 'Win32API'

# Based on what I see in sys/types.h:
#
# ino_t  - unsigned short
# dev_t  - unsigned int
# off_t  - long
# time_t - long

=begin
   struct _stat {
      _dev_t st_dev;          # 'I', 4
      _ino_t st_ino;          # 'S', 2
      unsigned short st_mode; # 'S', 2
      short st_nlink;         # 's', 2
      short st_uid;           # 's', 2
      short st_gid;           # 's', 2
      short padding;         # 's', 2  ---> invisible padding 2 bytes
for
structure alignment
      _dev_t st_rdev;         # 'I', 4
      _off_t st_size;         # 'l', 4
      time_t st_atime;        # 'l', 4
      time_t st_mtime;        # 'l', 4
      time_t st_ctime;        # 'l', 4
   };
=end

class File::Stat
   @@stat  = Win32API.new('msvcrt', '_stat', 'PP', 'I')

   def initialize(file)
      stat_buf = [0,0,0,0,0,0,0,0,0,0,0,0].pack('ISSssssIllll')

      @@stat.call(file, stat_buf)

      @dev   = stat_buf[0..3].unpack('I').first
      @ino   = stat_buf[4..5].unpack('S').first
      @mode  = stat_buf[6..7].unpack('S').first
      @nlink = stat_buf[8..9].unpack('s').first
      @uid   = stat_buf[10..11].unpack('s').first
      @gid   = stat_buf[12..13].unpack('s').first
      @rdev  = stat_buf[16..19].unpack('I').first
      @size  = stat_buf[20..23].unpack('l').first
      @atime = stat_buf[24..27].unpack('l').first
      @mtime = stat_buf[28..31].unpack('l').first
      @ctime = stat_buf[32..35].unpack('l').first

      puts "Dev: [#{@dev}]"
      puts "Ino: [#{@ino}]"
      puts "Mode: [#{@mode}]"
      puts "Nlink: [#{@nlink}]"
      puts "Uid: [#{@uid}]"
      puts "Gid: [#{@gid}]"
      puts "RDev: [#{@rdev}]" # Things start to look wrong here...
      puts "Size: [#{@size}]"
      puts "Atime: [" + Time.at(@atime).to_s + "]"
      puts "Mtime: [" + Time.at(@mtime).to_s + "]"
      puts "Ctime: [" + Time.at(@ctime).to_s + "]"
   end
end

if $0 == __FILE__
   File::Stat.new('r.rb')
end



Regards,

Park Heesob
Aee77dba395ece0a04c688b05b07cd63?d=identicon&s=25 Daniel Berger (Guest)
on 2006-04-01 04:27
(Received via mailing list)
Park Heesob wrote:
> >Ruby 1.8.4
> ># stat.rb
>
> Your code should be like this:

<snip>

Aha!  Thanks!

Dan
This topic is locked and can not be replied to.