1#
2# Copyright 2017 - The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import logging
17from vts.runners.host import asserts
18from vts.runners.host import const
19
20_PERMISSION_GROUPS = 3  # 3 permission groups: owner, group, all users
21_READ_PERMISSION = 4
22_WRITE_PERMISSION = 2
23_EXECUTE_PERMISSION = 1
24
25def Exists(filepath, shell):
26    """Determines if a file exists.
27
28    Args:
29        filepath: string, path to file
30        shell: an instance of the VTS shell
31
32    Returns:
33        True if the file exists, False otherwise"""
34    cmd = "ls %s" % filepath
35    results = shell.Execute(cmd)
36    if results[const.EXIT_CODE][0] != 0:
37        return False
38
39    out_str = str(results[const.STDOUT][0]).strip()
40    return out_str.find(filepath) == 0
41
42def FindFiles(shell, path, name_pattern):
43    """Searches a path for files on device.
44
45    Args:
46        shell: the ShellMirrorObject.
47        path: string, the path to search on device.
48        name_pattern: string, the file name pattern.
49
50    Returns:
51        list of strings, the paths to the found files.
52
53    Raises:
54        IOError if the pattern contains quotes, or the path does not exist.
55    """
56    if '"' in name_pattern or "'" in name_pattern:
57        raise IOError("File name pattern contains quotes")
58    cmd = "find %s -name \"%s\"" % (path, name_pattern)
59    results = shell.Execute(cmd)
60    logging.info("%s: Shell command '%s' results: %s", path, cmd, results)
61
62    if results[const.EXIT_CODE][0] != 0:
63        raise IOError(results[const.STDERR][0])
64
65    stdout = str(results[const.STDOUT][0])
66    return stdout.strip().split("\n")
67
68def ReadFileContent(filepath, shell):
69    """Read the content of a file and perform assertions.
70
71    Args:
72        filepath: string, path to file
73        shell: an instance of the VTS shell
74
75    Returns:
76        string, content of file
77
78    Raises:
79        IOError if the file does not exist."""
80    cmd = "cat %s" % filepath
81    results = shell.Execute(cmd)
82    logging.info("%s: Shell command '%s' results: %s", filepath, cmd,
83                 results)
84
85    # checks the exit code
86    if results[const.EXIT_CODE][0] != 0:
87        raise IOError(results[const.STDERR][0])
88
89    return results[const.STDOUT][0]
90
91def GetPermission(path, shell):
92    """Read the file permission bits of a path.
93
94    Args:
95        filepath: string, path to a file or directory
96        shell: an instance of the VTS shell
97
98    Returns:
99        String, octal permission bits for the path
100
101    Raises:
102        IOError if the path does not exist or has invalid permission bits.
103    """
104    cmd = "stat -c %%a %s" % path
105    results = shell.Execute(cmd)
106    logging.info("%s: Shell command '%s' results: %s", path, cmd,
107                 results)
108
109    # checks the exit code
110    if results[const.EXIT_CODE][0] != 0:
111        raise IOError(results[const.STDERR][0])
112
113    accessBits = results[const.STDOUT][0].strip()
114    if len(accessBits) != 3:
115        raise IOError("%s: Wrong number of access bits (%s)" %
116                      (path, accessBits))
117    return accessBits
118
119def _HasPermission(permission_bits, groupIndex, permission):
120    """Determines if the permission bits grant a permission to a group.
121
122    Args:
123        permission_bits: string, the octal permissions string (e.g. 741)
124        groupIndex: int, the index of the group into the permissions string.
125                    (e.g. 0 is owner group). If set to -1, then all groups are
126                    checked.
127        permission: the value of the permission.
128
129    Returns:
130        True if the group(s) has read permission.
131
132    Raises:
133        ValueError if the group or permission bits are invalid"""
134    if groupIndex >= _PERMISSION_GROUPS:
135        raise ValueError("Invalid group: %s" % str(groupIndex))
136
137    if len(permission_bits) != _PERMISSION_GROUPS:
138        raise ValueError("Invalid permission bits: %s" % str(permission_bits))
139
140    # Define the start/end group index
141    start = groupIndex
142    end = groupIndex + 1
143    if groupIndex < 0:
144        start = 0
145        end = _PERMISSION_GROUPS
146
147    for i in range(start, end):
148        perm = int(permission_bits[i])  # throws ValueError if not an integer
149        if perm > 7:
150            raise ValueError("Invalid permission bit: %s" % str(perm))
151        if perm & permission == 0:
152            # Return false if any group lacks the permission
153            return False
154    # Return true if no group lacks the permission
155    return True
156
157def IsReadable(permission_bits):
158    """Determines if the permission bits grant read permission to any group.
159
160    Args:
161        permission_bits: string, the octal permissions string (e.g. 741)
162
163    Returns:
164        True if any group has read permission.
165
166    Raises:
167        ValueError if the group or permission bits are invalid"""
168    return any([_HasPermission(permission_bits, i, _READ_PERMISSION) for i in
169                range(_PERMISSION_GROUPS)])
170
171def IsWritable(permission_bits):
172    """Determines if the permission bits grant write permission to any group.
173
174    Args:
175        permission_bits: string, the octal permissions string (e.g. 741)
176
177    Returns:
178        True if any group has write permission.
179
180    Raises:
181        ValueError if the group or permission bits are invalid"""
182    return any([_HasPermission(permission_bits, i, _WRITE_PERMISSION) for i in
183                range(_PERMISSION_GROUPS)])
184
185def IsExecutable(permission_bits):
186    """Determines if the permission bits grant execute permission to any group.
187
188    Args:
189        permission_bits: string, the octal permissions string (e.g. 741)
190
191    Returns:
192        True if any group has execute permission.
193
194    Raises:
195        ValueError if the group or permission bits are invalid"""
196    return any([_HasPermission(permission_bits, i, _EXECUTE_PERMISSION) for i in
197                range(_PERMISSION_GROUPS)])
198
199def IsReadOnly(permission_bits):
200    """Determines if the permission bits grant read-only permission.
201
202    Read-only permission is granted if some group has read access but no group
203    has write access.
204
205    Args:
206        permission_bits: string, the octal permissions string (e.g. 741)
207
208    Returns:
209        True if any group has read permission, none have write.
210
211    Raises:
212        ValueError if the group or permission bits are invalid"""
213    return IsReadable(permission_bits) and not IsWritable(permission_bits)
214
215def IsWriteOnly(permission_bits):
216    """Determines if the permission bits grant write-only permission.
217
218    Write-only permission is granted if some group has write access but no group
219    has read access.
220
221    Args:
222        permission_bits: string, the octal permissions string (e.g. 741)
223
224    Returns:
225        True if any group has write permission, none have read.
226
227    Raises:
228        ValueError if the group or permission bits are invalid"""
229    return IsWritable(permission_bits) and not IsReadable(permission_bits)
230
231def IsReadWrite(permission_bits):
232    """Determines if the permission bits grant read/write permissions.
233
234    Read-write permission is granted if some group has read access and some has
235    write access. The groups may be different.
236
237    Args:
238        permission_bits: string, the octal permissions string (e.g. 741)
239
240    Returns:
241        True if read and write permissions are granted to any group(s).
242
243    Raises:
244        ValueError if the group or permission bits are invalid"""
245    return IsReadable(permission_bits) and IsWritable(permission_bits)
246
247def assertPermissionsAndExistence(shell, path, check_permission):
248    """Asserts that the specified path exists and has the correct permission.
249
250    Args:
251        path: string, path to validate existence and permissions
252        check_permission: function which takes unix permissions in octal
253                          format and returns True if the permissions are
254                          correct, False otherwise.
255    """
256    asserts.assertTrue(
257        Exists(path, shell),
258        "%s: File does not exist." % path)
259    try:
260        permission = GetPermission(path, shell)
261        asserts.assertTrue(
262            check_permission(permission),
263            "%s: File has invalid permissions (%s)" %
264            (path, permission))
265    except (ValueError, IOError) as e:
266        asserts.fail("Failed to assert permissions: %s" % str(e))
267