blob: 5023fd00fa3444c7be340a26057064df30e2e018 [file] [log] [blame]
Bowgo Tsai741a70a2018-02-05 17:41:02 +08001# Copyright 2018 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""File-related utilities."""
16
17
18import os
19import shutil
20import tempfile
21
22
23def make_parent_dirs(file_path):
24 """Creates parent directories for the file_path."""
25 if os.path.exists(file_path):
26 return
27
28 parent_dir = os.path.dirname(file_path)
29 if parent_dir and not os.path.exists(parent_dir):
30 os.makedirs(parent_dir)
31
32
Inseob Kim5485a842025-03-17 18:14:08 +090033def remove_redundant_line_markers(lines):
34 """
35 Removes any redundant line markers.
36
37 Line markers are to support better error reporting for neverallow rules.
38 Line markers, possibly nested, look like:
39
40 ;;* lm(s|x) LINENO FILENAME
41 (CIL STATEMENTS)
42 ;;* lme
43
44 * lms is used when each of the following CIL statements corresponds to a line
45 in the original file.
46
47 * lmx is used when the following CIL statements are all expanded from a
48 single high-level language line.
49
50 * lme ends a line mark block.
51
52 Redundant line markers are markers without any statements inside. Normally
53 there are no such redundant line markers, but CIL files filtered out by
54 filter_out function below may contain those. remove_redundant_line_markers
55 find all such redundant line markers and removes all of them. See
56 file_utils_test.py for an example.
57 """
58
59 marker_stk = []
60 valid = [False] * len(lines)
61
62 for idx in range(len(lines)):
63 line = lines[idx]
64 if line.startswith(";;* lmx") or line.startswith(";;* lms"):
65 # line start marker
66 marker_stk.append(idx)
67 elif line.startswith(";;* lme"): # line end marker
68 if valid[marker_stk[-1]]:
69 valid[idx] = True
70 # propagate valid to parent markers
71 if len(marker_stk) >= 2:
72 valid[marker_stk[-2]] = True
73 marker_stk.pop()
74 else:
75 # any other expressions
76 valid[idx] = True
77 # set the current marker as valid
78 if marker_stk:
79 valid[marker_stk[-1]] = True
80
81 return [lines[idx] for idx in range(len(lines)) if valid[idx]]
82
Bowgo Tsai741a70a2018-02-05 17:41:02 +080083def filter_out(pattern_files, input_file):
84 """"Removes lines in input_file that match any line in pattern_files."""
85
86 # Prepares patterns.
87 patterns = []
88 for f in pattern_files:
Inseob Kim5485a842025-03-17 18:14:08 +090089 patterns.extend([x for x in open(f).readlines() if not x.startswith(";;*")])
Bowgo Tsai741a70a2018-02-05 17:41:02 +080090
91 # Copy lines that are not in the pattern.
ThiƩbaud Weksteenb05a1a12021-12-06 15:23:18 +110092 tmp_output = tempfile.NamedTemporaryFile(mode='w+')
Bowgo Tsai741a70a2018-02-05 17:41:02 +080093 with open(input_file, 'r') as in_file:
Inseob Kim5485a842025-03-17 18:14:08 +090094 lines = [line for line in in_file.readlines()
95 if line not in patterns and line.strip()]
96 lines = remove_redundant_line_markers(lines)
97 tmp_output.writelines(lines)
98
Felix0d6864a2020-03-31 17:56:49 +020099 # Append empty line because a completely empty file
100 # will trip up secilc later on:
101 tmp_output.write("\n")
Bowgo Tsai741a70a2018-02-05 17:41:02 +0800102 tmp_output.flush()
103
104 # Replaces the input_file.
105 shutil.copyfile(tmp_output.name, input_file)