recls-ruby 2.9.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|