recls-ruby 2.8.2 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|