recls-ruby 2.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,197 @@
1
+ # ######################################################################### #
2
+ # File: recls/ximpl/windows.rb
3
+ #
4
+ # Purpose: Windows-specific constructs for the recls library.
5
+ #
6
+ # Created: 19th February 2014
7
+ # Updated: 29th December 2015
8
+ #
9
+ # Author: Matthew Wilson
10
+ #
11
+ # Copyright (c) 2012-2015, Matthew Wilson and Synesis Software
12
+ # All rights reserved.
13
+ #
14
+ # Redistribution and use in source and binary forms, with or without
15
+ # modification, are permitted provided that the following conditions are met:
16
+ #
17
+ # * Redistributions of source code must retain the above copyright notice,
18
+ # this list of conditions and the following disclaimer.
19
+ #
20
+ # * Redistributions in binary form must reproduce the above copyright notice,
21
+ # this list of conditions and the following disclaimer in the documentation
22
+ # and/or other materials provided with the distribution.
23
+ #
24
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
28
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
+ # POSSIBILITY OF SUCH DAMAGE.
35
+ #
36
+ # ######################################################################### #
37
+
38
+
39
+ require 'Win32API'
40
+
41
+ module Recls
42
+
43
+ module Ximpl
44
+
45
+ class FileStat < File::Stat
46
+
47
+ private
48
+ GetFileAttributes = Win32API.new('kernel32', 'GetFileAttributes', [ 'P' ], 'I')
49
+ GetFileInformationByHandle = Win32API.new('kernel32', 'GetFileInformationByHandle', [ 'L', 'P' ], 'I')
50
+ GetShortPathName = Win32API.new('kernel32', 'GetShortPathName', [ 'P', 'P', 'L' ], 'L')
51
+ CreateFile = Win32API.new('kernel32', 'CreateFile', [ 'P', 'L', 'L', 'L', 'L', 'L', 'L' ], 'L')
52
+ CloseHandle = Win32API.new('kernel32', 'CloseHandle', [ 'L' ], 'L')
53
+ FILE_ATTRIBUTE_READONLY = 0x00000001
54
+ FILE_ATTRIBUTE_HIDDEN = 0x00000002
55
+ FILE_ATTRIBUTE_SYSTEM = 0x00000004
56
+ FILE_ATTRIBUTE_DIRECTORY = 0x00000010
57
+ FILE_ATTRIBUTE_ARCHIVE = 0x00000020
58
+ FILE_ATTRIBUTE_DEVICE = 0x00000040
59
+ FILE_ATTRIBUTE_NORMAL = 0x00000080
60
+ FILE_ATTRIBUTE_TEMPORARY = 0x00000100
61
+ FILE_ATTRIBUTE_COMPRESSED = 0x00000800
62
+ FILE_ATTRIBUTE_ENCRYPTED = 0x00004000
63
+
64
+ OPEN_EXISTING = 0x00000003
65
+ FILE_FLAG_OVERLAPPED = 0x40000000
66
+ NULL = 0x00000000
67
+ INVALID_HANDLE_VALUE = 0xFFFFFFFF
68
+
69
+ MAX_PATH = 260
70
+
71
+ BHFI_pack_string = 'LQQQLLLLLL'
72
+
73
+ class ByHandleInformation
74
+
75
+ def initialize(path)
76
+
77
+ @volume_id = 0
78
+ @file_index = 0
79
+ @num_links = 0
80
+
81
+ # for some reason not forcing this new string causes 'can't modify frozen string (TypeError)' (in Ruby 1.8.x)
82
+ hFile = CreateFile.call("#{path}", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
83
+ if INVALID_HANDLE_VALUE != hFile
84
+
85
+ begin
86
+ bhfi = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
87
+ bhfi = bhfi.pack(BHFI_pack_string)
88
+
89
+ if GetFileInformationByHandle.call(hFile, bhfi)
90
+
91
+ bhfi = bhfi.unpack(BHFI_pack_string)
92
+
93
+ @volume_id = bhfi[4]
94
+ @file_index = (bhfi[8] << 32) | bhfi[9]
95
+ @num_links = bhfi[7]
96
+ else
97
+ end
98
+ ensure
99
+ CloseHandle.call(hFile)
100
+ end
101
+ end
102
+ end
103
+
104
+ attr_reader :volume_id
105
+ attr_reader :file_index
106
+ attr_reader :num_links
107
+ end
108
+
109
+ private
110
+ def has_attribute_? (attr)
111
+
112
+ 0 != (attr & @attributes)
113
+ end
114
+
115
+ private
116
+ def initialize(path)
117
+
118
+ @path = path
119
+
120
+ # for some reason not forcing this new string causes 'can't modify frozen string (TypeError)'
121
+ attributes = GetFileAttributes.call("#{path}")
122
+
123
+ if 0xffffffff == attributes
124
+ @attributes = 0
125
+ else
126
+ @attributes = attributes
127
+ end
128
+
129
+ super(path)
130
+
131
+ @by_handle_information = ByHandleInformation.new(path)
132
+
133
+ buff = ' ' * MAX_PATH
134
+ n = GetShortPathName.call(path, buff, buff.length)
135
+ @short_path = (0 == n) ? nil : buff[0...n]
136
+ end
137
+
138
+ public
139
+ attr_reader :attributes
140
+ attr_reader :path
141
+ attr_reader :by_handle_information
142
+ attr_reader :short_path
143
+
144
+ def hidden?
145
+
146
+ 0 != (FILE_ATTRIBUTE_HIDDEN & @attributes)
147
+ end
148
+
149
+ # Windows-specific attributes
150
+
151
+ def system?
152
+
153
+ has_attribute_? FILE_ATTRIBUTE_SYSTEM
154
+ end
155
+
156
+ def archive?
157
+
158
+ has_attribute_? FILE_ATTRIBUTE_ARCHIVE
159
+ end
160
+
161
+ def device?
162
+
163
+ has_attribute_? FILE_ATTRIBUTE_DEVICE
164
+ end
165
+
166
+ def normal?
167
+
168
+ has_attribute_? FILE_ATTRIBUTE_NORMAL
169
+ end
170
+
171
+ def temporary?
172
+
173
+ has_attribute_? FILE_ATTRIBUTE_TEMPORARY
174
+ end
175
+
176
+ def compressed?
177
+
178
+ has_attribute_? FILE_ATTRIBUTE_COMPRESSED
179
+ end
180
+
181
+ def encrypted?
182
+
183
+ has_attribute_? FILE_ATTRIBUTE_ENCRYPTED
184
+ end
185
+
186
+
187
+ public
188
+ def FileStat.stat(path)
189
+
190
+ Recls::Ximpl::FileStat.new(path)
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ # ############################## end of file ############################# #
197
+
@@ -0,0 +1,40 @@
1
+ #! /usr/bin/ruby
2
+ #
3
+ # test Recls entry methods
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
6
+
7
+ require 'recls'
8
+
9
+ Recls::FileSearch.new(nil, nil, Recls::FILES | Recls::RECURSIVE).each do |fe|
10
+
11
+ puts
12
+ puts fe.path
13
+ puts fe.short_path
14
+ puts fe.directory_path
15
+ puts fe.drive
16
+ puts "".ljust(fe.drive.size) + fe.directory
17
+ puts "".ljust(fe.directory_path.size) + fe.file
18
+ puts "".ljust(fe.directory_path.size) + fe.file_short_name
19
+ puts "".ljust(fe.directory_path.size) + fe.stem
20
+ puts "".ljust(fe.directory_path.size + fe.stem.size) + fe.extension
21
+ n = fe.drive.size
22
+ fe.directory_parts.each do |part|
23
+
24
+ puts "".ljust(n) + part
25
+ n += part.size
26
+ end
27
+
28
+ puts fe.search_directory
29
+ puts "".ljust(fe.search_directory.size) + fe.search_relative_path
30
+ puts "".ljust(fe.search_directory.size) + fe.search_relative_directory_path
31
+ puts "".ljust(fe.search_directory.size) + fe.search_relative_directory
32
+
33
+ n = fe.search_directory.size
34
+ fe.search_relative_directory_parts.each do |part|
35
+
36
+ puts "".ljust(n) + part
37
+ n += part.size
38
+ end
39
+ end
40
+
@@ -0,0 +1,81 @@
1
+ #! /usr/bin/ruby
2
+ #
3
+ # test Recls entry methods
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
6
+
7
+ require 'recls'
8
+
9
+ puts "PATH_NAME_SEPARATOR:\t[#{Recls::PATH_NAME_SEPARATOR}]"
10
+ puts "PATH_SEPARATOR:\t[#{Recls::PATH_SEPARATOR}]"
11
+ puts "WILDCARDS_ALL:\t[#{Recls::WILDCARDS_ALL}]"
12
+
13
+ def show_entry f
14
+
15
+ puts "entry:"
16
+ puts "\t#{'(entry)'.ljust(20)}\t#{f}"
17
+ puts "\t#{'f.path'.ljust(20)}\t#{f.path}"
18
+ puts "\t#{'f.drive'.ljust(20)}\t#{f.drive}"
19
+ puts "\t#{'f.directory_path'.ljust(20)}\t#{f.directory_path}"
20
+ puts "\t#{'f.directory'.ljust(20)}\t#{f.directory}"
21
+ directory_parts = f.directory_parts
22
+ puts "\t#{'f.directory_parts'.ljust(20)}\t[#{directory_parts.size}]"
23
+ directory_parts.each do |part|
24
+ puts "\t#{''.ljust(20)}\t\t#{part}"
25
+ end
26
+ search_relative_directory_parts = f.search_relative_directory_parts
27
+ puts "\t#{'f.search_relative_directory_parts'.ljust(20)}\t[#{search_relative_directory_parts.size}]"
28
+ search_relative_directory_parts.each do |part|
29
+ puts "\t#{''.ljust(20)}\t\t#{part}"
30
+ end
31
+ puts "\t#{'f.file_full_name'.ljust(20)}\t#{f.file_full_name}"
32
+ puts "\t#{'f.file_short_name'.ljust(20)}\t#{f.file_short_name}"
33
+ puts "\t#{'f.file_name_only'.ljust(20)}\t#{f.file_name_only}"
34
+ puts "\t#{'f.stem'.ljust(20)}\t#{f.stem}"
35
+ puts "\t#{'f.file_extension'.ljust(20)}\t#{f.file_extension}"
36
+ puts "\t#{'f.search_directory'.ljust(20)}\t#{f.search_directory}"
37
+ puts "\t#{'f.search_relative_path'.ljust(20)}\t#{f.search_relative_path}"
38
+ puts "\t#{'f.search_relative_directory'.ljust(20)}\t#{f.search_relative_directory}"
39
+ puts "\t#{'f.search_relative_directory_path'.ljust(20)}\t#{f.search_relative_directory_path}"
40
+
41
+ puts "\t#{'f.size'.ljust(20)}\t#{f.size}"
42
+
43
+ puts "\t#{'f.exist?'.ljust(20)}\t#{f.exist?}"
44
+ puts "\t#{'f.hidden?'.ljust(20)}\t#{f.hidden?}"
45
+ puts "\t#{'f.readonly?'.ljust(20)}\t#{f.readonly?}"
46
+ puts "\t#{'f.directory?'.ljust(20)}\t#{f.directory?}"
47
+ puts "\t#{'f.file?'.ljust(20)}\t#{f.file?}"
48
+ puts "\t#{'f.socket?'.ljust(20)}\t#{f.socket?}"
49
+
50
+ puts "\t#{'f.modification_time'.ljust(20)}\t#{f.modification_time}"
51
+ puts "\t#{'f.last_access_time'.ljust(20)}\t#{f.last_access_time}"
52
+ end
53
+
54
+ puts
55
+ puts "stat of '.':"
56
+ show_entry Recls::stat '.'
57
+
58
+ puts
59
+ puts "stat of '~':"
60
+ show_entry Recls::stat '~'
61
+
62
+ puts
63
+ puts "directories:"
64
+ num_directories = 0
65
+ Recls::FileSearch.new('.', '*', Recls::DIRECTORIES).each do |fe|
66
+
67
+ num_directories += 1
68
+ puts "\t[#{fe.search_relative_path}]"
69
+ end
70
+ puts " #{num_directories} directories"
71
+
72
+ puts
73
+ puts "files:"
74
+ num_files = 0
75
+ Recls::FileSearch.new('.', '*.rb', Recls::RECURSIVE | Recls::FILES).each do |fe|
76
+
77
+ num_files += 1
78
+ puts "\t<#{fe.search_relative_path}>"
79
+ end
80
+ puts " #{num_files} file(s)"
81
+
@@ -0,0 +1,41 @@
1
+ #! /usr/bin/ruby
2
+ #
3
+ # test Recls search methods
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
6
+
7
+
8
+ #require 'recls/util'
9
+ require 'recls/foreach'
10
+ #require 'recls'
11
+
12
+ puts
13
+ puts "with given block:"
14
+ count_1 = 0
15
+ Recls.foreach(Recls::FileSearch.new(nil, '*.rb', Recls::RECURSIVE)).each do |line, line_number, fe|
16
+
17
+ line = line.chomp
18
+ line_number = 1 + line_number
19
+
20
+ puts "#{fe.search_relative_path}(#{line_number + 1}): #{line}"
21
+
22
+ count_1 += 1
23
+ break if 20 == count_1
24
+ end
25
+
26
+ puts
27
+ puts "as returned enumerator:"
28
+ e = Recls.foreach(Recls::FileSearch.new(nil, '*.rb', Recls::RECURSIVE))
29
+ count_2 = 0
30
+ e.each do |line, line_number, fe|
31
+
32
+ line = line.chomp
33
+ line_number = 1 + line_number
34
+
35
+ puts "#{fe.search_relative_path}(#{line_number + 1}): #{line}"
36
+
37
+ count_2 += 1
38
+ break if 20 == count_2
39
+ end
40
+
41
+
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Demonstrates use of dev and ino attributes
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
6
+
7
+ require 'recls'
8
+
9
+ Recls::FileSearch.new('.', Recls::WILDCARDS_ALL, Recls::FILES | Recls::RECURSIVE).each do |fe|
10
+
11
+ puts "#{fe.search_relative_path}\t#{fe.dev}\t#{fe.ino}\t#{fe.nlink}"
12
+ end
13
+
@@ -0,0 +1,30 @@
1
+ #! /usr/bin/ruby
2
+ #
3
+ # Demonstrates search of hidden files
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
6
+
7
+ require 'recls'
8
+
9
+ puts
10
+ puts "Hidden directories:"
11
+ Recls::FileSearch.new(nil, nil, Recls::RECURSIVE | Recls::DIRECTORIES | Recls::SHOW_HIDDEN).each do |fe|
12
+
13
+ puts "\t#{fe.search_relative_path}" if fe.hidden?
14
+ end
15
+
16
+ puts
17
+ puts "Hidden files:"
18
+ Recls::FileSearch.new(nil, nil, Recls::RECURSIVE | Recls::FILES | Recls::SHOW_HIDDEN).each do |fe|
19
+
20
+ puts "\t#{fe.search_relative_path}" if fe.hidden?
21
+ end
22
+
23
+
24
+ puts
25
+ puts "Hidden directories & files:"
26
+ Recls::FileSearch.new(nil, nil, Recls::RECURSIVE | Recls::DIRECTORIES | Recls::FILES | Recls::MARK_DIRECTORIES | Recls::SHOW_HIDDEN).each do |fe|
27
+
28
+ puts "\t#{fe.search_relative_path}" if fe.hidden?
29
+ end
30
+
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # test Recls entries
4
+
5
+ $:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
6
+
7
+
8
+ require 'recls'
9
+
10
+ require 'test/unit'
11
+
12
+ class Test_Recls_entries < Test::Unit::TestCase
13
+
14
+ unless defined? assert_false
15
+ def assert_false arg0, *args
16
+ assert !arg0, *args
17
+ end
18
+ end
19
+
20
+ def test_entries_in_directory_have_unique_names
21
+
22
+ entries = Recls::FileSearch.new('~', Recls::WILDCARDS_ALL, Recls::FILES).to_a
23
+
24
+ hashed_entries = Hash[entries.each_with_index.map { |fe, index| [ fe, index] }]
25
+
26
+ # ensure that no duplicates in hash (and hence Entry.hash and Entry.<=> work)
27
+ assert_equal entries.size, hashed_entries.size
28
+
29
+ entries.each_with_index do |entry, index|
30
+
31
+ entry_a = entries[index]
32
+ entry_b = Recls.stat(entries[index].path)
33
+
34
+ # ensure that different entry instances representing the same path evaluate
35
+ # equal (and hence Entry.eq? and Entry.== work)
36
+
37
+ assert entry_a.eql? entry_a
38
+ assert entry_a.eql? entry_b
39
+ assert_false entry_a.eql? entry_a.path
40
+ assert_false entry_a.eql? entry_b.path
41
+
42
+ assert_equal entry_a, entry_a
43
+ assert_equal entry_a, entry_b
44
+ assert_equal entry_a, entry_a.path
45
+ assert_equal entry_a, entry_b.path
46
+
47
+ assert_same entry_a, entries[index]
48
+ assert_not_same entry_a, entry_b
49
+
50
+ assert_equal index, hashed_entries[entry_a]
51
+ assert_equal index, hashed_entries[entry_b]
52
+ end
53
+ end
54
+ end
55
+