file_permissions 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Mixin containing helper methods
24
+ #
25
+ # @private
26
+ module HelperMixin
27
+
28
+ # @return [Array<Symbol>] possible output String formats
29
+ STRING_FORMAT = Set[:long, :short].freeze
30
+
31
+ protected
32
+
33
+ # Ensures that input is Pathname
34
+ #
35
+ # @param [Pathname, String] path a path
36
+ # @param [:forbid_nil, :allow_nil] nil_handling if set to :allow_nil,
37
+ # a nil path will be passed-through. Raises an exception otherwise
38
+ # @return [Pathname] the path as Pathname object
39
+ def to_pathname(path, nil_handling = :forbid_nil)
40
+ return nil if path.nil? if nil_handling == :allow_nil
41
+
42
+ path.is_a?(Pathname) ? path : Pathname.new(path)
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,156 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Represents one component of the normal file mode in POSIX environments.
24
+ #
25
+ # The Mode is basically an immutable bit set consisting of the digits
26
+ # :read, :write and :execute.
27
+ class Mode
28
+ include BitSet
29
+
30
+ octal_mode = /(?<octal_mode>[0-7])/
31
+ digit_mode = /(?<digit_mode>(?:-|r|w|x){1,3})/
32
+ blank = /\p{Blank}*?/
33
+
34
+ # Regular expression for parsing a Mode from a String representation.
35
+ PATTERN = /^#{blank}(?:#{digit_mode}|#{octal_mode})#{blank}$/
36
+
37
+ # Configuration for the GodObject:::BitSet object which is used to handle
38
+ # the state internally.
39
+ BIT_SET_CONFIGURATION = Configuration.new(
40
+ read: 'r',
41
+ write: 'w',
42
+ execute: 'x'
43
+ )
44
+
45
+ extend Forwardable
46
+ include ModeMixin
47
+ include Comparable
48
+
49
+ class << self
50
+ # @!parse include ModeMixin::ClassMethods
51
+
52
+ # Creates a new Mode object by parsing a String representation.
53
+ #
54
+ # @param [String] string a String containing a mode
55
+ # @return [GodObject::FilePermissions::Mode] a new Mode object
56
+ def parse(string)
57
+ result = string.match(PATTERN)
58
+
59
+ case
60
+ when !result
61
+ raise ParserError, 'Invalid format'
62
+ when result[:octal_mode]
63
+ new(result[:octal_mode].to_i)
64
+ else
65
+ mode_components = []
66
+
67
+ result[:digit_mode].scan(/r|w|x/).each do |digit|
68
+ mode_components << :read if digit == 'r'
69
+ mode_components << :write if digit == 'w'
70
+ mode_components << :execute if digit == 'x'
71
+ end
72
+
73
+ if mode_components.uniq!
74
+ raise ParserError,
75
+ "Duplicate digit in: #{string.inspect}"
76
+ end
77
+
78
+ new(mode_components)
79
+ end
80
+ end
81
+ end
82
+
83
+ # Initializes a new Mode
84
+ #
85
+ # @return [void]
86
+ #
87
+ # @overload initialize(numeric)
88
+ # @param [Integer] numeric a numeric representation
89
+ #
90
+ # @overload initialize(enabled_digits)
91
+ # @param [Array<:read, :write, :execute>] enabled_digits a list of
92
+ # enabled digits
93
+ def initialize(*mode_components)
94
+ @bit_set = BIT_SET_CONFIGURATION.new(*mode_components)
95
+ end
96
+
97
+ # @!method enabled_digits
98
+ # @!attribute [r] enabled_digits
99
+ # @return [Set<:read, :write, :execute>] a list of all digits which are
100
+ # enabled
101
+ #
102
+ # @!method disabled_digits
103
+ # @!attribute [r] disabled_digits
104
+ # @return [Set<:read, :write, :execute>] a list of all digits which are
105
+ # disabled
106
+ #
107
+ # @!method state
108
+ # @!attribute [r] state
109
+ # @return [{(:read, :write, :execute) => true, false}] a table of all
110
+ # digits and their states
111
+ #
112
+ # @!parse alias attributes state
113
+ #
114
+ # @!method read?
115
+ # @!attribute [r] read?
116
+ # @return [true, false] the current state of the read digit
117
+ #
118
+ # @!parse alias read read?
119
+ #
120
+ # @!method write?
121
+ # @!attribute [r] write?
122
+ # @return [true, false] the current state of the write digit
123
+ #
124
+ # @!parse alias write write?
125
+ #
126
+ # @!method execute?
127
+ # @!attribute [r] execute?
128
+ # @return [true, false] the current state of the execute digit
129
+ #
130
+ # @!parse alias execute execute?
131
+ #
132
+ # @!method [](digit)
133
+ # @param [:read, :write, :execute, Integer] digit name or index of a
134
+ # digit
135
+ # @return [true, false] current state of the given digit
136
+ #
137
+ # @!method to_i
138
+ # Represents a Mode as a binary Integer.
139
+ # @return [Integer] an Integer representation
140
+ #
141
+ # @!method to_s(format)
142
+ # Represents a Mode as String.
143
+ # @param [:long, :short] format the String format
144
+ # @return [String] a String representation
145
+ #
146
+ # @!method hash
147
+ # @return (see Object#hash) identity hash for hash table usage
148
+ def_delegators :@bit_set,
149
+ :attributes, :state, :[], :enabled_digits, :disabled_digits,
150
+ :read?, :read, :write?, :write, :execute?, :execute,
151
+ :to_i, :to_s, :hash
152
+
153
+ end
154
+
155
+ end
156
+ end
@@ -0,0 +1,163 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Common functionality of both Mode and SpecialMode
24
+ module ModeMixin
25
+
26
+ # Hook for automatic inclusion of the ClassMethods mixin
27
+ # @private
28
+ def self.included(base)
29
+ base.extend ClassMethods
30
+ end
31
+
32
+ # Class mixin for Mode and SpecialMode
33
+ module ClassMethods
34
+
35
+ # Either passes through or generates a new Mode object
36
+ #
37
+ # @return [GodObject::FilePermissions::ModeMixin]
38
+ #
39
+ # @overload build(mode)
40
+ # @param [GodObject::FilePermissions::ModeMixin] mode an already
41
+ # existing Mode
42
+ #
43
+ # @overload build(string)
44
+ # @param [String] string a String representation
45
+ #
46
+ # @overload build(numeric)
47
+ # @param [Integer] numeric a numeric representation
48
+ #
49
+ # @overload build(enabled_digits)
50
+ # @param [Array<Symbol>] enabled_digits a list of enabled digits
51
+ def build(mode)
52
+ case
53
+ when mode.kind_of?(self)
54
+ mode
55
+ when mode.respond_to?(:to_str)
56
+ parse(mode)
57
+ else
58
+ new(mode)
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with all
65
+ # digit states inverted
66
+ def invert
67
+ self.class.new(disabled_digits)
68
+ end
69
+
70
+ # @param [GodObject::FilePermissions::ModeMixin, Array<Symbol>] other
71
+ # another Mode
72
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
73
+ # enabled digits of the current and other
74
+ def +(other)
75
+ other = other.enabled_digits if other.respond_to?(:enabled_digits)
76
+
77
+ self.class.new(enabled_digits + other)
78
+ end
79
+
80
+ # @param [GodObject::FilePermissions::ModeMixin, Integer] other another
81
+ # Mode
82
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
83
+ # enabled digits of the current and other
84
+ def union(other)
85
+ other = other.to_i if other.respond_to?(:to_i)
86
+
87
+ self.class.new(to_i | other)
88
+ end
89
+
90
+ alias | union
91
+
92
+ # @param [GodObject::FilePermissions::ModeMixin, Array<Symbol>] other
93
+ # another Mode
94
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
95
+ # enabled digits of the current without the enabled digits of other
96
+ def difference(other)
97
+ other = other.enabled_digits if other.respond_to?(:enabled_digits)
98
+
99
+ self.class.new(enabled_digits - other)
100
+ end
101
+
102
+ alias - difference
103
+
104
+ # @param [GodObject::FilePermissions::ModeMixin, Integer] other another
105
+ # Mode
106
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with only
107
+ # those digits enabled which are enabled in both the current and other
108
+ def intersection(other)
109
+ other = other.to_i if other.respond_to?(:to_i)
110
+
111
+ self.class.new(to_i & other)
112
+ end
113
+
114
+ alias & intersection
115
+
116
+ # @param [GodObject::FilePermissions::ModeMixin, Integer] other another
117
+ # Mode
118
+ # @return [GodObject::FilePermissions::ModeMixin] a new Mode with the
119
+ # enabled digits which are enabled in only one of current and other
120
+ def symmetric_difference(other)
121
+ other = other.to_i if other.respond_to?(:to_i)
122
+
123
+ self.class.new(to_i ^ other)
124
+ end
125
+
126
+ alias ^ symmetric_difference
127
+
128
+ # Compares the Mode to another to determine its relative position.
129
+ #
130
+ # Relative position is defined by comparing the Integer representation.
131
+ #
132
+ # @note Only other Modes or Integer-likes are considered comparable.
133
+ #
134
+ # @param [Object] other other Object to be compared
135
+ # object
136
+ # @return [-1, 0, 1, nil] -1 if other is greater, 0 if other is equal and
137
+ # 1 if other is lesser than self, nil if comparison is impossible
138
+ def <=>(other)
139
+ to_i <=> other.to_i
140
+ rescue NoMethodError
141
+ nil
142
+ end
143
+
144
+ # Answers if another object is equal and of the same type family.
145
+ #
146
+ # @see GodObject::FilePermissions::ModeMixin#<=>
147
+ # @param [Object] other an object to be checked for equality
148
+ # @return [true, false] true if the object is considered equal and of the
149
+ # same type family, false otherwise
150
+ def eql?(other)
151
+ self == other && other.kind_of?(self.class)
152
+ end
153
+
154
+ # Represents a Mode as String for debugging.
155
+ #
156
+ # @return [String] a String representation for debugging
157
+ def inspect
158
+ "#<#{self.class}: #{to_s.inspect}>"
159
+ end
160
+ end
161
+
162
+ end
163
+ end
@@ -0,0 +1,149 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright GodObject Team <dev@godobject.net>, 2012-2016
4
+
5
+ This file is part of FilePermissions.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted, provided that the above
9
+ copyright notice and this permission notice appear in all copies.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ =end
19
+
20
+ module GodObject
21
+ module FilePermissions
22
+
23
+ # Represents one component of the normal file mode in POSIX environments.
24
+ #
25
+ # The SpecialMode is basically an immutable bit set consisting of the
26
+ # digits :setuid, :setgid and :sticky.
27
+ class SpecialMode
28
+ include BitSet
29
+
30
+ octal_mode = /(?<octal_mode>[0-7])/
31
+ digit_mode = /(?<digit_mode>(?:-|s){2}(?:-|t))/
32
+ blank = /\p{Blank}*?/
33
+
34
+ # Regular expression for parsing a SpecialMode from a String
35
+ # representation.
36
+ PATTERN = /^#{blank}(?:#{digit_mode}|#{octal_mode})#{blank}$/
37
+
38
+ # Configuration for the GodObject:::BitSet object which is used to handle
39
+ # the state internally.
40
+ BIT_SET_CONFIGURATION = Configuration.new(
41
+ setuid: 's',
42
+ setgid: 's',
43
+ sticky: 't'
44
+ )
45
+
46
+ extend Forwardable
47
+ include ModeMixin
48
+ include Comparable
49
+
50
+ class << self
51
+ # @!parse include ModeMixin::ClassMethods
52
+
53
+ # Creates a new SpecialMode object by parsing a String representation.
54
+ #
55
+ # @param [String] string a String containing a mode
56
+ # @return [GodObject::FilePermissions::SpecialMode] a new SpecialMode
57
+ # object
58
+ def parse(string)
59
+ result = string.match(PATTERN)
60
+
61
+ case
62
+ when !result
63
+ raise ParserError, 'Invalid format'
64
+ when result[:octal_mode]
65
+ new(result[:octal_mode].to_i)
66
+ else
67
+ mode_components = []
68
+
69
+ mode_components << :setuid if result[:digit_mode][0] == 's'
70
+ mode_components << :setgid if result[:digit_mode][1] == 's'
71
+ mode_components << :sticky if result[:digit_mode][2] == 't'
72
+
73
+ new(mode_components)
74
+ end
75
+ end
76
+ end
77
+
78
+ # Initializes a new SpecialMode
79
+ #
80
+ # @return [void]
81
+ #
82
+ # @overload initialize(numeric)
83
+ # @param [Integer] numeric a numeric representation
84
+ #
85
+ # @overload initialize(enabled_digits)
86
+ # @param [Array<:setuid, :setgid, :sticky>] enabled_digits a list of
87
+ # enabled digits
88
+ def initialize(*mode_components)
89
+ @bit_set = BIT_SET_CONFIGURATION.new(*mode_components)
90
+ end
91
+
92
+ # @!method enabled_digits
93
+ # @!attribute [r] enabled_digits
94
+ # @return [Set<:setuid, :setgid, :sticky>] a list of all digits which
95
+ # are enabled
96
+ #
97
+ # @!method disabled_digits
98
+ # @!attribute [r] disabled_digits
99
+ # @return [Set<:setuid, :setgid, :sticky>] a list of all digits which
100
+ # are disabled
101
+ #
102
+ # @!method state
103
+ # @!attribute [r] state
104
+ # @return [{(:read, :write, :execute) => true, false}] a table of all
105
+ # digits and their states
106
+ #
107
+ # @!method setuid?
108
+ # @!attribute [r] setuid?
109
+ # @return [true, false] the current state of the setuid digit
110
+ #
111
+ # @!parse alias setuid setuid?
112
+ #
113
+ # @!method setgid?
114
+ # @!attribute [r] setgid?
115
+ # @return [true, false] the current state of the setgid digit
116
+ #
117
+ # @!parse alias setgid setgid?
118
+ #
119
+ # @!method sticky?
120
+ # @attribute [r] sticky?
121
+ # @return [true, false] the current state of the sticky digit
122
+ #
123
+ # @!parse alias sticky sticky?
124
+ #
125
+ # @!method [](digit)
126
+ # @param [:setuid, :setgid, :sticky, Integer] digit name or index of a
127
+ # digit
128
+ # @return [true, false] current state of the given digit
129
+ #
130
+ # @!method to_i
131
+ # Represents a SpecialMode as a binary Integer.
132
+ # @return [Integer] an Integer representation
133
+ #
134
+ # @!method to_s(format)
135
+ # Represents a SpecialMode as String.
136
+ # @param [:long, :short] format the String format
137
+ # @return [String] a String representation
138
+ #
139
+ # @!method hash
140
+ # @return (see Object#hash) identity hash for hash table usage
141
+ def_delegators :@bit_set,
142
+ :attributes, :state, :[], :enabled_digits, :disabled_digits,
143
+ :setuid?, :setuid, :setgid?, :setgid, :sticky?, :sticky,
144
+ :to_i, :to_s, :hash
145
+
146
+ end
147
+
148
+ end
149
+ end