recls-ruby 2.8.2 → 2.11.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 +4 -4
- 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.rb +2 -0
- data/lib/recls/api.rb +70 -3
- data/lib/recls/combine_paths_1.rb +70 -0
- data/lib/recls/combine_paths_2plus.rb +76 -0
- data/lib/recls/entry.rb +40 -4
- data/lib/recls/file_search.rb +48 -14
- data/lib/recls/flags.rb +21 -4
- data/lib/recls/foreach.rb +45 -6
- data/lib/recls/obsolete.rb +119 -0
- data/lib/recls/recls.rb +27 -56
- data/lib/recls/stat.rb +96 -24
- data/lib/recls/util.rb +74 -23
- data/lib/recls/version.rb +10 -4
- data/lib/recls/ximpl/os.rb +29 -15
- data/lib/recls/ximpl/unix.rb +29 -16
- data/lib/recls/ximpl/util.rb +141 -39
- 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_display_parts.rb +9 -9
- data/test/scratch/test_entry.rb +11 -9
- data/test/scratch/test_files_and_directories.rb +17 -14
- data/test/scratch/test_foreach.rb +0 -3
- data/test/scratch/test_module_function.rb +10 -10
- data/test/scratch/test_pattern_arrays.rb +32 -0
- data/test/scratch/test_show_dev_and_ino.rb +1 -1
- data/test/scratch/test_show_hidden.rb +3 -3
- data/test/unit/tc_recls_util.rb +6 -0
- data/test/unit/tc_recls_ximpl_util.rb +156 -101
- data/test/unit/ts_all.rb +11 -9
- metadata +36 -11
data/lib/recls/ximpl/util.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
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
|
-
# 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
|
@@ -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:
|
45
48
|
|
46
|
-
|
49
|
+
# :stopdoc:
|
47
50
|
|
48
|
-
|
51
|
+
module Ximpl # :nodoc: all
|
49
52
|
|
50
|
-
|
53
|
+
module Util # :nodoc: all
|
54
|
+
|
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,18 +476,58 @@ 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
|
520
|
+
|
462
521
|
return nil
|
463
522
|
when ::String
|
523
|
+
|
524
|
+
path = File.expand_path(path) if '~' == path[0]
|
464
525
|
when ::Recls::Entry
|
465
|
-
|
526
|
+
|
527
|
+
return path.path
|
466
528
|
else
|
467
529
|
|
468
|
-
raise TypeError, "parameter path ('#{path}') is of type #{path.class} must be an instance of #{::String} or
|
530
|
+
raise TypeError, "parameter path ('#{path}') is of type #{path.class} must be an instance of #{::String} or Recls::Entry"
|
469
531
|
end
|
470
532
|
|
471
533
|
return '' if path.empty?
|
@@ -522,7 +584,8 @@ module Recls
|
|
522
584
|
# is
|
523
585
|
# ghi.jkl
|
524
586
|
#
|
525
|
-
|
587
|
+
# @!visibility private
|
588
|
+
def self.basename(path) # :nodoc:
|
526
589
|
|
527
590
|
return nil if not path
|
528
591
|
|
@@ -565,7 +628,9 @@ module Recls
|
|
565
628
|
# ghi.jkl
|
566
629
|
# is
|
567
630
|
# .jkl
|
568
|
-
|
631
|
+
#
|
632
|
+
# @!visibility private
|
633
|
+
def self.file_ext(path) # :nodoc:
|
569
634
|
|
570
635
|
return nil if not path
|
571
636
|
|
@@ -603,7 +668,8 @@ module Recls
|
|
603
668
|
|
604
669
|
# obtains the directory from the directory path
|
605
670
|
#
|
606
|
-
|
671
|
+
# @!visibility private
|
672
|
+
def self.directory_from_directory_path(directory_path) # :nodoc:
|
607
673
|
|
608
674
|
wr, rem = Util.get_windows_root(directory_path)
|
609
675
|
|
@@ -614,7 +680,9 @@ module Recls
|
|
614
680
|
end
|
615
681
|
|
616
682
|
# obtains the directory parts from a directory
|
617
|
-
|
683
|
+
#
|
684
|
+
# @!visibility private
|
685
|
+
def self.directory_parts_from_directory(directory) # :nodoc:
|
618
686
|
|
619
687
|
return nil if not directory
|
620
688
|
|
@@ -638,7 +706,9 @@ module Recls
|
|
638
706
|
|
639
707
|
# obtains the relative path of a given path and
|
640
708
|
# a reference directory
|
641
|
-
|
709
|
+
#
|
710
|
+
# @!visibility private
|
711
|
+
def self.derive_relative_path(origin, path) # :nodoc:
|
642
712
|
|
643
713
|
return nil if path.nil?
|
644
714
|
return nil if path.empty?
|
@@ -648,10 +718,16 @@ module Recls
|
|
648
718
|
path = self.canonicalise_path path
|
649
719
|
origin = self.canonicalise_path origin
|
650
720
|
|
721
|
+
path = self.absolute_path path
|
722
|
+
origin = self.absolute_path origin
|
723
|
+
|
724
|
+
return path if /^\.[\\\/]*$/ =~ origin
|
725
|
+
|
651
726
|
path_splits = Util.split_path(path)
|
652
727
|
origin_splits = Util.split_path(origin)
|
653
728
|
|
654
729
|
# if different windows root, then cannot provide relative
|
730
|
+
|
655
731
|
if path_splits[0] and origin_splits[0]
|
656
732
|
|
657
733
|
return path if path_splits[0] != origin_splits[0]
|
@@ -662,7 +738,7 @@ module Recls
|
|
662
738
|
path_parts = path_splits[6]
|
663
739
|
origin_parts = origin_splits[6]
|
664
740
|
|
665
|
-
|
741
|
+
loop do
|
666
742
|
|
667
743
|
break if path_parts.empty?
|
668
744
|
break if origin_parts.empty?
|
@@ -695,12 +771,14 @@ module Recls
|
|
695
771
|
return '../' * origin_parts.size + path_parts.join('')
|
696
772
|
end
|
697
773
|
|
698
|
-
|
699
|
-
def self.combine_paths(paths, options)
|
774
|
+
# @!visibility private
|
775
|
+
def self.combine_paths(paths, options) # :nodoc:
|
700
776
|
|
701
777
|
paths = [ paths ] unless ::Array === paths
|
702
778
|
abs_ix = 0
|
703
779
|
|
780
|
+
paths = paths.map { |path| '~' == path[0].to_s ? File.expand_path(path) : path }
|
781
|
+
|
704
782
|
paths.each_with_index do |path, index|
|
705
783
|
|
706
784
|
dummy1, f2_directory, dummy2, dummy3, dummy4, dummy5, dummy6 = Util.split_path(path)
|
@@ -721,7 +799,7 @@ module Recls
|
|
721
799
|
|
722
800
|
paths = paths[abs_ix..-1]
|
723
801
|
|
724
|
-
r = File.join
|
802
|
+
r = File.join(*paths)
|
725
803
|
|
726
804
|
cap = options[:canonicalise] || options[:canonicalize]
|
727
805
|
|
@@ -751,7 +829,8 @@ module Recls
|
|
751
829
|
# * (Mac OSX) /dev/fd/<N> - some of these stat() as directories but
|
752
830
|
# Dir.new fails with ENOTDIR
|
753
831
|
#
|
754
|
-
|
832
|
+
# @!visibility private
|
833
|
+
def self.dir_entries_maybe(dir, flags) # :nodoc:
|
755
834
|
|
756
835
|
begin
|
757
836
|
|
@@ -769,8 +848,31 @@ module Recls
|
|
769
848
|
return []
|
770
849
|
end
|
771
850
|
end
|
772
|
-
|
773
|
-
|
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
|
774
876
|
|
775
877
|
# ############################## end of file ############################# #
|
776
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
|
|