recls-ruby 2.9.0 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +57 -10
- data/examples/find_files_and_directories.md +77 -0
- data/examples/find_files_and_directories.rb +19 -0
- data/examples/find_files_and_directories.recursive.md +304 -0
- data/examples/find_files_and_directories.recursive.rb +19 -0
- data/examples/show_hidden_files.md +39 -0
- data/examples/show_hidden_files.rb +2 -2
- data/examples/show_readonly_files.md +35 -0
- data/examples/show_readonly_files.rb +2 -2
- data/lib/recls/api.rb +20 -35
- data/lib/recls/combine_paths_1.rb +8 -4
- data/lib/recls/combine_paths_2plus.rb +12 -13
- data/lib/recls/entry.rb +39 -4
- data/lib/recls/file_search.rb +30 -21
- data/lib/recls/flags.rb +20 -4
- data/lib/recls/foreach.rb +44 -6
- data/lib/recls/obsolete.rb +119 -0
- data/lib/recls/recls.rb +31 -54
- data/lib/recls/stat.rb +71 -28
- data/lib/recls/util.rb +73 -4
- data/lib/recls/version.rb +9 -3
- data/lib/recls/ximpl/os.rb +31 -16
- data/lib/recls/ximpl/unix.rb +29 -16
- data/lib/recls/ximpl/util.rb +137 -36
- data/lib/recls/ximpl/windows.rb +56 -25
- data/test/fixtures/readonly/file-1 +0 -0
- data/test/fixtures/readonly/file-2 +0 -0
- data/test/scratch/test_entry.rb +1 -0
- data/test/scratch/test_pattern_arrays.rb +32 -0
- data/test/unit/tc_recls_ximpl_util.rb +107 -101
- metadata +33 -10
data/lib/recls/ximpl/util.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# ######################################################################### #
|
2
|
-
# File:
|
2
|
+
# File: recls/ximpl/util.rb
|
3
3
|
#
|
4
|
-
# Purpose:
|
4
|
+
# Purpose: Internal implementation constructs for the recls library.
|
5
5
|
#
|
6
|
-
# Created:
|
7
|
-
# Updated:
|
6
|
+
# Created: 24th July 2012
|
7
|
+
# Updated: 14th April 2019
|
8
8
|
#
|
9
|
-
# Author:
|
9
|
+
# Author: Matthew Wilson
|
10
10
|
#
|
11
11
|
# Copyright (c) 2012-2019, Matthew Wilson and Synesis Software
|
12
12
|
# All rights reserved.
|
@@ -41,13 +41,19 @@ require 'recls/flags'
|
|
41
41
|
|
42
42
|
require 'pathname'
|
43
43
|
|
44
|
-
|
44
|
+
=begin
|
45
|
+
=end
|
46
|
+
|
47
|
+
module Recls # :nodoc:
|
48
|
+
|
49
|
+
# :stopdoc:
|
45
50
|
|
46
|
-
module Ximpl
|
51
|
+
module Ximpl # :nodoc: all
|
47
52
|
|
48
|
-
module Util
|
53
|
+
module Util # :nodoc: all
|
49
54
|
|
50
|
-
|
55
|
+
# @!visibility private
|
56
|
+
def self.is_path_name_separator(c) # :nodoc:
|
51
57
|
|
52
58
|
return true if ?/ == c
|
53
59
|
|
@@ -62,7 +68,9 @@ module Recls
|
|
62
68
|
# Indicates whether a trailing slash is on the given path
|
63
69
|
#
|
64
70
|
# dependencies: none
|
65
|
-
|
71
|
+
#
|
72
|
+
# @!visibility private
|
73
|
+
def self.has_trailing_slash(p) # :nodoc:
|
66
74
|
|
67
75
|
return p if p.nil? or p.empty?
|
68
76
|
|
@@ -72,7 +80,9 @@ module Recls
|
|
72
80
|
# returns the trailing slash, or nil if none present
|
73
81
|
#
|
74
82
|
# dependencies: none
|
75
|
-
|
83
|
+
#
|
84
|
+
# @!visibility private
|
85
|
+
def self.get_trailing_slash(p, args = {}) # :nodoc:
|
76
86
|
|
77
87
|
return nil if p.nil?
|
78
88
|
return nil if p.empty?
|
@@ -84,7 +94,9 @@ module Recls
|
|
84
94
|
# present
|
85
95
|
#
|
86
96
|
# dependencies: none
|
87
|
-
|
97
|
+
#
|
98
|
+
# @!visibility private
|
99
|
+
def self.append_trailing_slash(p, slash = nil) # :nodoc:
|
88
100
|
|
89
101
|
return p if not p or p.empty?
|
90
102
|
|
@@ -99,7 +111,9 @@ module Recls
|
|
99
111
|
# root
|
100
112
|
#
|
101
113
|
# dependencies: none
|
102
|
-
|
114
|
+
#
|
115
|
+
# @!visibility private
|
116
|
+
def self.trim_trailing_slash(p) # :nodoc:
|
103
117
|
|
104
118
|
return p if not p or p.empty?
|
105
119
|
|
@@ -117,7 +131,9 @@ module Recls
|
|
117
131
|
# [ nil, nil ] if p is nil
|
118
132
|
#
|
119
133
|
# dependencies: none
|
120
|
-
|
134
|
+
#
|
135
|
+
# @!visibility private
|
136
|
+
def self.get_windows_root(p) # :nodoc:
|
121
137
|
|
122
138
|
return [ nil, nil ] if not p
|
123
139
|
|
@@ -161,7 +177,9 @@ module Recls
|
|
161
177
|
|
162
178
|
# obtains the parts from a path, including any Windows root and
|
163
179
|
# the file basename
|
164
|
-
|
180
|
+
#
|
181
|
+
# @!visibility private
|
182
|
+
def self.path_parts(path) # :nodoc:
|
165
183
|
|
166
184
|
return nil if path.nil?
|
167
185
|
return [] if path.empty?
|
@@ -201,7 +219,9 @@ module Recls
|
|
201
219
|
# f7. array of all path parts, which may be empty (not nil)
|
202
220
|
#
|
203
221
|
# dependencies: Util.path_parts, Util.get_windows_root
|
204
|
-
|
222
|
+
#
|
223
|
+
# @!visibility private
|
224
|
+
def self.split_path(p) # :nodoc:
|
205
225
|
|
206
226
|
f1_windows_root, remainder = self.get_windows_root p
|
207
227
|
f1_windows_root = nil if not f1_windows_root or f1_windows_root.empty?
|
@@ -267,14 +287,12 @@ module Recls
|
|
267
287
|
# f2. A boolean indicating whether to 'consume' the basename
|
268
288
|
#
|
269
289
|
# dependencies: OS.is_root_dir_, OS.get_number_of_dots_dir_,
|
270
|
-
|
290
|
+
#
|
291
|
+
# @!visibility private
|
292
|
+
def self.canonicalise_parts(parts, basename = nil) # :nodoc:
|
271
293
|
|
272
294
|
newParts = []
|
273
295
|
|
274
|
-
=begin
|
275
|
-
trailing_slash = parts.empty? ? nil : self.get_trailing_slash(parts[-1])
|
276
|
-
=end
|
277
|
-
|
278
296
|
lastSingleDots = nil
|
279
297
|
|
280
298
|
path_is_rooted = nil
|
@@ -423,18 +441,22 @@ module Recls
|
|
423
441
|
|
424
442
|
[ newParts.join(''), consume_basename ]
|
425
443
|
end
|
426
|
-
end
|
444
|
+
end # module Util
|
427
445
|
|
428
446
|
# Canonicalises a path
|
429
447
|
#
|
430
448
|
# Note: contains a trailing slash if, in the context of the given
|
431
449
|
# path, the last element of the canonicalised path is a directory
|
432
450
|
# unequivocally
|
433
|
-
|
451
|
+
#
|
452
|
+
# @!visibility private
|
453
|
+
def self.canonicalise_path(path) # :nodoc:
|
434
454
|
|
435
455
|
return nil if not path
|
436
456
|
return '' if path.empty?
|
437
457
|
|
458
|
+
path = File.expand_path(path) if '~' == path[0].to_s
|
459
|
+
|
438
460
|
f1_windows_root, f2_directory, f3_basename, dummy1, dummy2, directory_parts, dummy3 = Util.split_path(path)
|
439
461
|
|
440
462
|
# suppress unused warnings
|
@@ -454,8 +476,44 @@ module Recls
|
|
454
476
|
return "#{f1_windows_root}#{canonicalised_directory}#{f3_basename}"
|
455
477
|
end
|
456
478
|
|
479
|
+
# @!visibility private
|
480
|
+
def self.absolute_path?(path) # :nodoc:
|
481
|
+
|
482
|
+
case path
|
483
|
+
when nil
|
484
|
+
|
485
|
+
return nil
|
486
|
+
when ::String
|
487
|
+
|
488
|
+
return nil if path.empty?
|
489
|
+
|
490
|
+
path = File.expand_path(path) if '~' == path[0]
|
491
|
+
when ::Recls::Entry
|
492
|
+
|
493
|
+
return path
|
494
|
+
else
|
495
|
+
|
496
|
+
raise TypeError, "parameter path ('#{path}') is of type #{path.class} must be nil or an instance of #{::String} or #{::Recls::Entry}"
|
497
|
+
end
|
498
|
+
|
499
|
+
f1_windows_root, f2_directory, dummy1, dummy2, dummy3, dummy4, dummy5 = Util.split_path(path)
|
500
|
+
|
501
|
+
dummy1 = dummy2 = dummy3 = dummy4 = dummy5 = nil
|
502
|
+
|
503
|
+
unless f1_windows_root
|
504
|
+
|
505
|
+
return nil unless f2_directory
|
506
|
+
|
507
|
+
return nil unless Util.is_path_name_separator(f2_directory[0])
|
508
|
+
end
|
509
|
+
|
510
|
+
Recls::Ximpl.stat_prep(path, nil, Recls::DETAILS_LATER)
|
511
|
+
end
|
512
|
+
|
457
513
|
# determines the absolute path of a given path
|
458
|
-
|
514
|
+
#
|
515
|
+
# @!visibility private
|
516
|
+
def self.absolute_path(path, refdir = nil) # :nodoc:
|
459
517
|
|
460
518
|
case path
|
461
519
|
when ::NilClass
|
@@ -463,7 +521,10 @@ module Recls
|
|
463
521
|
return nil
|
464
522
|
when ::String
|
465
523
|
|
466
|
-
path
|
524
|
+
path = File.expand_path(path) if '~' == path[0]
|
525
|
+
when ::Recls::Entry
|
526
|
+
|
527
|
+
return path.path
|
467
528
|
else
|
468
529
|
|
469
530
|
raise TypeError, "parameter path ('#{path}') is of type #{path.class} must be an instance of #{::String} or Recls::Entry"
|
@@ -523,7 +584,8 @@ module Recls
|
|
523
584
|
# is
|
524
585
|
# ghi.jkl
|
525
586
|
#
|
526
|
-
|
587
|
+
# @!visibility private
|
588
|
+
def self.basename(path) # :nodoc:
|
527
589
|
|
528
590
|
return nil if not path
|
529
591
|
|
@@ -566,7 +628,9 @@ module Recls
|
|
566
628
|
# ghi.jkl
|
567
629
|
# is
|
568
630
|
# .jkl
|
569
|
-
|
631
|
+
#
|
632
|
+
# @!visibility private
|
633
|
+
def self.file_ext(path) # :nodoc:
|
570
634
|
|
571
635
|
return nil if not path
|
572
636
|
|
@@ -604,7 +668,8 @@ module Recls
|
|
604
668
|
|
605
669
|
# obtains the directory from the directory path
|
606
670
|
#
|
607
|
-
|
671
|
+
# @!visibility private
|
672
|
+
def self.directory_from_directory_path(directory_path) # :nodoc:
|
608
673
|
|
609
674
|
wr, rem = Util.get_windows_root(directory_path)
|
610
675
|
|
@@ -615,7 +680,9 @@ module Recls
|
|
615
680
|
end
|
616
681
|
|
617
682
|
# obtains the directory parts from a directory
|
618
|
-
|
683
|
+
#
|
684
|
+
# @!visibility private
|
685
|
+
def self.directory_parts_from_directory(directory) # :nodoc:
|
619
686
|
|
620
687
|
return nil if not directory
|
621
688
|
|
@@ -639,7 +706,9 @@ module Recls
|
|
639
706
|
|
640
707
|
# obtains the relative path of a given path and
|
641
708
|
# a reference directory
|
642
|
-
|
709
|
+
#
|
710
|
+
# @!visibility private
|
711
|
+
def self.derive_relative_path(origin, path) # :nodoc:
|
643
712
|
|
644
713
|
return nil if path.nil?
|
645
714
|
return nil if path.empty?
|
@@ -649,10 +718,16 @@ module Recls
|
|
649
718
|
path = self.canonicalise_path path
|
650
719
|
origin = self.canonicalise_path origin
|
651
720
|
|
721
|
+
path = self.absolute_path path
|
722
|
+
origin = self.absolute_path origin
|
723
|
+
|
724
|
+
return path if /^\.[\\\/]*$/ =~ origin
|
725
|
+
|
652
726
|
path_splits = Util.split_path(path)
|
653
727
|
origin_splits = Util.split_path(origin)
|
654
728
|
|
655
729
|
# if different windows root, then cannot provide relative
|
730
|
+
|
656
731
|
if path_splits[0] and origin_splits[0]
|
657
732
|
|
658
733
|
return path if path_splits[0] != origin_splits[0]
|
@@ -663,7 +738,7 @@ module Recls
|
|
663
738
|
path_parts = path_splits[6]
|
664
739
|
origin_parts = origin_splits[6]
|
665
740
|
|
666
|
-
|
741
|
+
loop do
|
667
742
|
|
668
743
|
break if path_parts.empty?
|
669
744
|
break if origin_parts.empty?
|
@@ -696,12 +771,14 @@ module Recls
|
|
696
771
|
return '../' * origin_parts.size + path_parts.join('')
|
697
772
|
end
|
698
773
|
|
699
|
-
|
700
|
-
def self.combine_paths(paths, options)
|
774
|
+
# @!visibility private
|
775
|
+
def self.combine_paths(paths, options) # :nodoc:
|
701
776
|
|
702
777
|
paths = [ paths ] unless ::Array === paths
|
703
778
|
abs_ix = 0
|
704
779
|
|
780
|
+
paths = paths.map { |path| '~' == path[0].to_s ? File.expand_path(path) : path }
|
781
|
+
|
705
782
|
paths.each_with_index do |path, index|
|
706
783
|
|
707
784
|
dummy1, f2_directory, dummy2, dummy3, dummy4, dummy5, dummy6 = Util.split_path(path)
|
@@ -752,7 +829,8 @@ module Recls
|
|
752
829
|
# * (Mac OSX) /dev/fd/<N> - some of these stat() as directories but
|
753
830
|
# Dir.new fails with ENOTDIR
|
754
831
|
#
|
755
|
-
|
832
|
+
# @!visibility private
|
833
|
+
def self.dir_entries_maybe(dir, flags) # :nodoc:
|
756
834
|
|
757
835
|
begin
|
758
836
|
|
@@ -770,8 +848,31 @@ module Recls
|
|
770
848
|
return []
|
771
849
|
end
|
772
850
|
end
|
773
|
-
|
774
|
-
|
851
|
+
|
852
|
+
# @!visibility private
|
853
|
+
def self.stat_prep(path, search_root, flags) # :nodoc:
|
854
|
+
|
855
|
+
begin
|
856
|
+
|
857
|
+
Recls::Entry.new(path, Recls::Ximpl::FileStat.stat(path), search_root, flags)
|
858
|
+
rescue Errno::ENOENT, Errno::ENXIO => x
|
859
|
+
|
860
|
+
x = x # suppress warning
|
861
|
+
|
862
|
+
if 0 != (flags & Recls::DETAILS_LATER)
|
863
|
+
|
864
|
+
Recls::Entry.new(path, nil, search_root, flags)
|
865
|
+
else
|
866
|
+
|
867
|
+
nil
|
868
|
+
end
|
869
|
+
end
|
870
|
+
end
|
871
|
+
end # module Ximpl
|
872
|
+
|
873
|
+
# :startdoc:
|
874
|
+
|
875
|
+
end # module Recls
|
775
876
|
|
776
877
|
# ############################## end of file ############################# #
|
777
878
|
|
data/lib/recls/ximpl/windows.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# ######################################################################### #
|
2
|
-
# File:
|
2
|
+
# File: recls/ximpl/windows.rb
|
3
3
|
#
|
4
|
-
# Purpose:
|
4
|
+
# Purpose: Windows-specific constructs for the recls library.
|
5
5
|
#
|
6
|
-
# Created:
|
7
|
-
# Updated:
|
6
|
+
# Created: 19th February 2014
|
7
|
+
# Updated: 14th April 2019
|
8
8
|
#
|
9
|
-
# Author:
|
9
|
+
# Author: Matthew Wilson
|
10
10
|
#
|
11
|
-
# Copyright (c) 2012-
|
11
|
+
# Copyright (c) 2012-2019, Matthew Wilson and Synesis Software
|
12
12
|
# All rights reserved.
|
13
13
|
#
|
14
14
|
# Redistribution and use in source and binary forms, with or without
|
@@ -38,11 +38,17 @@
|
|
38
38
|
|
39
39
|
require 'Win32API'
|
40
40
|
|
41
|
-
|
41
|
+
=begin
|
42
|
+
=end
|
42
43
|
|
43
|
-
|
44
|
+
module Recls # :nodoc:
|
44
45
|
|
45
|
-
|
46
|
+
# :stopdoc:
|
47
|
+
|
48
|
+
module Ximpl # :nodoc: all
|
49
|
+
|
50
|
+
# @!visibility private
|
51
|
+
class FileStat < File::Stat # :nodoc:
|
46
52
|
|
47
53
|
private
|
48
54
|
GetFileAttributes = Win32API.new('kernel32', 'GetFileAttributes', [ 'P' ], 'I')
|
@@ -70,9 +76,11 @@ module Recls
|
|
70
76
|
|
71
77
|
BHFI_pack_string = 'LQQQLLLLLL'
|
72
78
|
|
73
|
-
|
79
|
+
# @!visibility private
|
80
|
+
class ByHandleInformation # :nodoc:
|
74
81
|
|
75
|
-
|
82
|
+
# @!visibility private
|
83
|
+
def initialize(path) # :nodoc:
|
76
84
|
|
77
85
|
@volume_id = 0
|
78
86
|
@file_index = 0
|
@@ -101,19 +109,24 @@ module Recls
|
|
101
109
|
end
|
102
110
|
end
|
103
111
|
|
112
|
+
# @!visibility private
|
104
113
|
attr_reader :volume_id
|
114
|
+
# @!visibility private
|
105
115
|
attr_reader :file_index
|
116
|
+
# @!visibility private
|
106
117
|
attr_reader :num_links
|
107
118
|
end
|
108
119
|
|
109
120
|
private
|
110
|
-
|
121
|
+
# @!visibility private
|
122
|
+
def has_attribute_? (attr) # :nodoc:
|
111
123
|
|
112
124
|
0 != (attr & @attributes)
|
113
125
|
end
|
114
126
|
|
115
127
|
private
|
116
|
-
|
128
|
+
# @!visibility private
|
129
|
+
def initialize(path) # :nodoc:
|
117
130
|
|
118
131
|
@path = path
|
119
132
|
|
@@ -121,8 +134,10 @@ module Recls
|
|
121
134
|
attributes = GetFileAttributes.call("#{path}")
|
122
135
|
|
123
136
|
if 0xffffffff == attributes
|
137
|
+
|
124
138
|
@attributes = 0
|
125
139
|
else
|
140
|
+
|
126
141
|
@attributes = attributes
|
127
142
|
end
|
128
143
|
|
@@ -137,62 +152,78 @@ module Recls
|
|
137
152
|
end
|
138
153
|
|
139
154
|
public
|
155
|
+
# @!visibility private
|
140
156
|
attr_reader :attributes
|
157
|
+
# @!visibility private
|
141
158
|
attr_reader :path
|
159
|
+
# @!visibility private
|
142
160
|
attr_reader :by_handle_information
|
161
|
+
# @!visibility private
|
143
162
|
attr_reader :short_path
|
144
163
|
|
145
|
-
|
164
|
+
# @!visibility private
|
165
|
+
def hidden? # :nodoc:
|
146
166
|
|
147
167
|
0 != (FILE_ATTRIBUTE_HIDDEN & @attributes)
|
148
168
|
end
|
149
169
|
|
150
170
|
# Windows-specific attributes
|
151
171
|
|
152
|
-
|
172
|
+
# @!visibility private
|
173
|
+
def system? # :nodoc:
|
153
174
|
|
154
175
|
has_attribute_? FILE_ATTRIBUTE_SYSTEM
|
155
176
|
end
|
156
177
|
|
157
|
-
|
178
|
+
# @!visibility private
|
179
|
+
def archive? # :nodoc:
|
158
180
|
|
159
181
|
has_attribute_? FILE_ATTRIBUTE_ARCHIVE
|
160
182
|
end
|
161
183
|
|
162
|
-
|
184
|
+
# @!visibility private
|
185
|
+
def device? # :nodoc:
|
163
186
|
|
164
187
|
has_attribute_? FILE_ATTRIBUTE_DEVICE
|
165
188
|
end
|
166
189
|
|
167
|
-
|
190
|
+
# @!visibility private
|
191
|
+
def normal? # :nodoc:
|
168
192
|
|
169
193
|
has_attribute_? FILE_ATTRIBUTE_NORMAL
|
170
194
|
end
|
171
195
|
|
172
|
-
|
196
|
+
# @!visibility private
|
197
|
+
def temporary? # :nodoc:
|
173
198
|
|
174
199
|
has_attribute_? FILE_ATTRIBUTE_TEMPORARY
|
175
200
|
end
|
176
201
|
|
177
|
-
|
202
|
+
# @!visibility private
|
203
|
+
def compressed? # :nodoc:
|
178
204
|
|
179
205
|
has_attribute_? FILE_ATTRIBUTE_COMPRESSED
|
180
206
|
end
|
181
207
|
|
182
|
-
|
208
|
+
# @!visibility private
|
209
|
+
def encrypted? # :nodoc:
|
183
210
|
|
184
211
|
has_attribute_? FILE_ATTRIBUTE_ENCRYPTED
|
185
212
|
end
|
186
213
|
|
187
214
|
|
188
215
|
public
|
189
|
-
|
216
|
+
# @!visibility private
|
217
|
+
def FileStat.stat(path) # :nodoc:
|
190
218
|
|
191
219
|
Recls::Ximpl::FileStat.new(path)
|
192
220
|
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
221
|
+
end # class FileStat
|
222
|
+
end # module Ximpl
|
223
|
+
|
224
|
+
# :startdoc:
|
225
|
+
|
226
|
+
end # module Recls
|
196
227
|
|
197
228
|
# ############################## end of file ############################# #
|
198
229
|
|