1# Copyright 2017 - 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"""Base classes to implement Mounter classes.""" 15 16import abc 17import logging 18 19 20class MounterFile(object): 21 22 def __init__(self, filename, cleanup_func=None): 23 self._filename = filename 24 self._clean_up_func = cleanup_func 25 26 def _handle_get_filename(self): 27 return self._filename 28 29 def _handle_clean_up(self): 30 if self._clean_up_func: 31 self._clean_up_func() 32 33 def __enter__(self): 34 return self._handle_get_filename() 35 36 def __exit__(self, exc_type, exc_val, exc_tb): 37 self._handle_clean_up() 38 39 def get_filename(self): 40 return self._handle_get_filename() 41 42 def clean_up(self): 43 self._handle_clean_up() 44 45 46class MounterFileList(object): 47 48 def __init__(self, file_list): 49 self._file_list = file_list 50 51 def _handle_get_filenames(self): 52 return [x.get_filename() for x in self._file_list] 53 54 def _handle_clean_up(self): 55 for x in reversed(self._file_list): 56 x.clean_up() 57 58 def __enter__(self): 59 return self._handle_get_filenames() 60 61 def __exit__(self, exc_type, exc_val, exc_tb): 62 self._handle_clean_up() 63 64 def get_filenames(self): 65 return self._handle_get_filenames() 66 67 def clean_up(self): 68 self._handle_clean_up() 69 70 71class BaseFileAccessor(object): 72 """An abstract class to implement the file accessors. 73 74 A mounter returns a file accessor when it is mounted. A file accessor must 75 override the method _handle_prepare_file() to return the file name of 76 the requested file in the storage. However, files in some mounter storages 77 couldn't be access directly, e.g. the file accessor of AdbMounter, which 78 accesses the file in a device by adb. In this case, file accessor could 79 return a temp file which contains the content. A file accessor could give the 80 cleanup_func when creating MounterFile to cleanup the temp file. 81 """ 82 83 __metaclass__ = abc.ABCMeta 84 85 def __init__(self, path_prefix='/'): 86 logging.debug('BaseFileAccessor(path_prefix=%s)', path_prefix) 87 self._path_prefix = path_prefix 88 89 def _get_pathfile_to_access(self, file_to_map): 90 path_prefix = self._path_prefix 91 92 if not file_to_map.startswith(path_prefix): 93 raise RuntimeError('"%s" does not start with "%s"', file_to_map, 94 path_prefix) 95 96 return file_to_map[len(path_prefix):] 97 98 @abc.abstractmethod 99 def _handle_prepare_file(self, filename_in_storage): 100 """Override this method to prepare the given file in the storage. 101 102 Args: 103 filename_in_storage: the file in the storage to be prepared 104 105 Returns: 106 Return an MounterFile instance. Return None if the request file is not 107 in the mount. 108 """ 109 110 def prepare_file(self, filename_in_mount): 111 """Return the accessable file name in the storage. 112 113 The function prepares a accessable file which contains the content of the 114 filename_in_mount. 115 116 See BaseFileAccessor for the detail. 117 118 Args: 119 filename_in_mount: the file to map. 120 filename_in_mount should be a full path file as the path in a real 121 device, and must start with a '/'. For example: '/system/build.prop', 122 '/vendor/default.prop', '/init.rc', etc. 123 124 Returns: 125 A MounterFile instance. Return None if the file is not exit in the 126 storage. 127 """ 128 filename_in_storage = self._get_pathfile_to_access(filename_in_mount) 129 ret = self._handle_prepare_file(filename_in_storage) 130 return ret if ret else MounterFile(None) 131 132 def prepare_multi_files(self, filenames_in_mount): 133 file_list = [self.prepare_file(x) for x in filenames_in_mount] 134 return MounterFileList(file_list) 135 136 137class BaseMounter(object): 138 139 __metaclass__ = abc.ABCMeta 140 141 @abc.abstractmethod 142 def _handle_mount(self): 143 """Override this method to handle mounting and return a file accessor. 144 145 File accessor must inherit from BaseFileAccessor. 146 """ 147 148 def _handle_unmount(self): 149 """Override this method to handle cleanup this mounting.""" 150 # default is do nothing 151 return 152 153 def _process_mount(self): 154 if self._mounted: 155 raise RuntimeError('The mounter had been mounted.') 156 157 file_accessor = self._handle_mount() 158 self._mounted = True 159 160 return file_accessor 161 162 def _process_unmount(self): 163 if self._mounted: 164 self._handle_unmount() 165 self._mounted = False 166 167 def __init__(self): 168 self._mounted = False 169 170 def __enter__(self): 171 return self._process_mount() 172 173 def __exit__(self, exc_type, exc_val, exc_tb): 174 self._process_unmount() 175 176 def mount(self): 177 return self._process_mount() 178 179 def unmount(self): 180 self._process_unmount() 181