ext/dl/sample/stream.rb


DEFINITIONS

This source file includes following functions.


   1  # -*- ruby -*-
   2  # Display a file name and stream names of a file with those size.
   3  
   4  require 'dl'
   5  require 'dl/import'
   6  
   7  module NTFS
   8    extend DL::Importable
   9  
  10    dlload "kernel32.dll"
  11  
  12    OPEN_EXISTING         = 3
  13    GENERIC_READ          = 0x80000000
  14    BACKUP_DATA           = 0x00000001
  15    BACKUP_ALTERNATE_DATA = 0x00000004
  16    FILE_SHARE_READ       = 0x00000001
  17    FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
  18  
  19    typealias "LPSECURITY_ATTRIBUTES", "void*"
  20  
  21    extern "BOOL BackupRead(HANDLE, PBYTE, DWORD, PDWORD, BOOL, BOOL, PVOID)"
  22    extern "BOOL BackupSeek(HANDLE, DWORD, DWORD, PDWORD, PDWORD, PVOID)"
  23    extern "BOOL CloseHandle(HANDLE)"
  24    extern "HANDLE CreateFile(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES,
  25                              DWORD, DWORD, HANDLE)"
  26  
  27    module_function
  28  
  29    def streams(filename)
  30      status = []
  31      h = createFile(filename,GENERIC_READ,FILE_SHARE_READ,nil,
  32                     OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0)
  33      if( h != 0 )
  34        begin
  35          # allocate the memory for backup data used in backupRead().
  36          data = DL.malloc(DL.sizeof("L5"))
  37          data.struct!("LLLLL", :id, :attrs, :size_low, :size_high, :name_size)
  38  
  39          # allocate memories for references to long values used in backupRead().
  40          context = DL.malloc(DL.sizeof("L"))
  41          lval = DL.malloc(DL.sizeof("L"))
  42  
  43          while( backupRead(h, data, data.size, lval, false, false, context) )
  44            size = data[:size_low] + (data[:size_high] << (DL.sizeof("I") * 8))
  45            case data[:id]
  46            when BACKUP_ALTERNATE_DATA
  47              stream_name = DL.malloc(data[:name_size])
  48              backupRead(h, stream_name, stream_name.size,
  49                         lval, false, false, context)
  50              name = stream_name[0, stream_name.size]
  51              name.tr!("\000","")
  52              if( name =~ /^:(.*?):.*$/ )
  53                status.push([$1,size])
  54              end
  55            when BACKUP_DATA
  56              status.push([nil,size])
  57            else
  58              raise(RuntimeError, "unknown data type #{data[:id]}.")
  59            end
  60            l1 = DL.malloc(DL.sizeof("L"))
  61            l2 = DL.malloc(DL.sizeof("L"))
  62            if( !backupSeek(h, data[:size_low], data[:size_high], l1, l2, context) )
  63              break
  64            end
  65          end
  66        ensure
  67          backupRead(h, nil, 0, lval, true, false, context)
  68          closeHandle(h)
  69        end
  70        return status
  71      else
  72        raise(RuntimeError, "can't open #{filename}.\n")
  73      end
  74    end
  75  end
  76  
  77  ARGV.each{|filename|
  78    if( File.exist?(filename) )
  79      NTFS.streams(filename).each{|name,size|
  80        if( name )
  81          print("#{filename}:#{name}\t#{size}bytes\n")
  82        else
  83          print("#{filename}\t#{size}bytes\n")
  84        end
  85      }
  86    end
  87  }