From: John Carter Date: 2009-03-30T13:19:35+09:00 Subject: Re: Is there a ruby way to get the disk size of a directory? On Mon, 30 Mar 2009, Juan Zanos wrote: > I was wondering if there was something to du -h? Umm, it's pretty ugly what I do have... it invokes the Linux statfs system call... $ irb -r StatFs64.rb irb(main):001:0> a = StatFs64.new( "/home") => #0, "f_spare1"=>0, "f_files"=>5750784, "f_bfree"=>3332642, "f_bsize"=>4096, "f_spare2"=>0, "f_blocks"=>11299984, "f_spare3"=>0, "f_spare4"=>0, "f_ffree"=>4574344, "f_fsid0"=>1992275371, "f_fsid1"=>157862524, "f_frsize"=>4096, "f_namelen"=>255, "f_bavail"=>2758620, "f_type"=>61267}> irb(main):002:0> p a.free_gigabytes 10.5233001708984 => nil John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@tait.co.nz New Zealand ---------------------------------------------------------------------- =begin rdoc This stuff can depend on the exact version of linux you have. Ugly, I know. __extension__ typedef unsigned long long int __u_quad_t; __extension__ typedef __u_quad_t __fsblkcnt64_t; __extension__ typedef __u_quad_t __fsfilcnt64_t; __extension__ typedef struct { int __val[2]; } __fsid_t; struct statfs64 { int f_type; int f_bsize; __fsblkcnt64_t f_blocks; __fsblkcnt64_t f_bfree; __fsblkcnt64_t f_bavail; __fsfilcnt64_t f_files; __fsfilcnt64_t f_ffree; __fsid_t f_fsid; int f_namelen; int f_frsize; int f_spare[5]; }; #define __NR_statfs64 268 #define __NR_fstatfs64 269 I dug the above info out using the follow trick.... tmp = "/tmp/struct.c" open(tmp, 'w') do |c| c.puts " #define _GNU_SOURCE 1 #include #include struct statfs64 s; " end puts `gcc -E #{tmp}` =end require 'pp' class StatFs64 STRUCT_STATFS64 = [ [0, 'i', 'f_type'], [0, 'i', 'f_bsize'], [0, 'Q', 'f_blocks'], [0, 'Q', 'f_bfree'], [0, 'Q', 'f_bavail'], [0, 'Q', 'f_files'], [0, 'Q', 'f_ffree'], [0, 'i', 'f_fsid0'], [0, 'i', 'f_fsid1'], [0, 'i', 'f_namelen'], [0, 'i', 'f_frsize'], [0, 'i', 'f_spare0'], [0, 'i', 'f_spare1'], [0, 'i', 'f_spare2'], [0, 'i', 'f_spare3'], [0, 'i', 'f_spare4'], ] def syscall_pack( triplets) template = '' default = [] triplets.each do |value, directive, name| default << value template += directive end default.pack( template) end def syscall_unpack( triplets, string) template = '' names = [] triplets.each do |value, directive, name| names << name template += directive end result = {} values = string.unpack( template) names.each_with_index do |name,i| value = values[i] result[name] = value end result end def initialize( path) string = syscall_pack( STRUCT_STATFS64) result = syscall( 268, path, string.size, string) raise "Unexpected return value '#{result}'" unless result == 0 @statfs64 = syscall_unpack( STRUCT_STATFS64, string) end def free_megabytes (@statfs64['f_bavail'] * @statfs64['f_bsize']) / (1024 * 1024.0) end def free_gigabytes free_megabytes / 1024.0 end attr_reader :statfs64 end