1421ccda3079077dd613308526e02d797f5cc356aHess Chen## @file 2421ccda3079077dd613308526e02d797f5cc356aHess Chen# This file hooks file and directory creation and removal 3421ccda3079077dd613308526e02d797f5cc356aHess Chen# 4421ccda3079077dd613308526e02d797f5cc356aHess Chen# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR> 5421ccda3079077dd613308526e02d797f5cc356aHess Chen# 6421ccda3079077dd613308526e02d797f5cc356aHess Chen# This program and the accompanying materials are licensed and made available 7421ccda3079077dd613308526e02d797f5cc356aHess Chen# under the terms and conditions of the BSD License which accompanies this 8421ccda3079077dd613308526e02d797f5cc356aHess Chen# distribution. The full text of the license may be found at 9421ccda3079077dd613308526e02d797f5cc356aHess Chen# http://opensource.org/licenses/bsd-license.php 10421ccda3079077dd613308526e02d797f5cc356aHess Chen# 11421ccda3079077dd613308526e02d797f5cc356aHess Chen# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12421ccda3079077dd613308526e02d797f5cc356aHess Chen# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13421ccda3079077dd613308526e02d797f5cc356aHess Chen# 14421ccda3079077dd613308526e02d797f5cc356aHess Chen 15421ccda3079077dd613308526e02d797f5cc356aHess Chen''' 16421ccda3079077dd613308526e02d797f5cc356aHess ChenFile hook 17421ccda3079077dd613308526e02d797f5cc356aHess Chen''' 18421ccda3079077dd613308526e02d797f5cc356aHess Chen 19421ccda3079077dd613308526e02d797f5cc356aHess Chenimport os 20421ccda3079077dd613308526e02d797f5cc356aHess Chenimport stat 21421ccda3079077dd613308526e02d797f5cc356aHess Chenimport time 22421ccda3079077dd613308526e02d797f5cc356aHess Chenimport zipfile 23421ccda3079077dd613308526e02d797f5cc356aHess Chenfrom time import sleep 24421ccda3079077dd613308526e02d797f5cc356aHess Chenfrom Library import GlobalData 25421ccda3079077dd613308526e02d797f5cc356aHess Chen 26421ccda3079077dd613308526e02d797f5cc356aHess Chen__built_in_remove__ = os.remove 27421ccda3079077dd613308526e02d797f5cc356aHess Chen__built_in_mkdir__ = os.mkdir 28421ccda3079077dd613308526e02d797f5cc356aHess Chen__built_in_rmdir__ = os.rmdir 29421ccda3079077dd613308526e02d797f5cc356aHess Chen__built_in_chmod__ = os.chmod 30421ccda3079077dd613308526e02d797f5cc356aHess Chen__built_in_open__ = open 31421ccda3079077dd613308526e02d797f5cc356aHess Chen 32421ccda3079077dd613308526e02d797f5cc356aHess Chen_RMFILE = 0 33421ccda3079077dd613308526e02d797f5cc356aHess Chen_MKFILE = 1 34421ccda3079077dd613308526e02d797f5cc356aHess Chen_RMDIR = 2 35421ccda3079077dd613308526e02d797f5cc356aHess Chen_MKDIR = 3 36421ccda3079077dd613308526e02d797f5cc356aHess Chen_CHMOD = 4 37421ccda3079077dd613308526e02d797f5cc356aHess Chen 38421ccda3079077dd613308526e02d797f5cc356aHess ChengBACKUPFILE = 'file.backup' 39421ccda3079077dd613308526e02d797f5cc356aHess ChengEXCEPTION_LIST = ['Conf'+os.sep+'DistributionPackageDatabase.db', '.tmp', gBACKUPFILE] 40421ccda3079077dd613308526e02d797f5cc356aHess Chen 41421ccda3079077dd613308526e02d797f5cc356aHess Chenclass _PathInfo: 42421ccda3079077dd613308526e02d797f5cc356aHess Chen def __init__(self, action, path, mode=-1): 43421ccda3079077dd613308526e02d797f5cc356aHess Chen self.action = action 44421ccda3079077dd613308526e02d797f5cc356aHess Chen self.path = path 45421ccda3079077dd613308526e02d797f5cc356aHess Chen self.mode = mode 46421ccda3079077dd613308526e02d797f5cc356aHess Chen 47421ccda3079077dd613308526e02d797f5cc356aHess Chenclass RecoverMgr: 48421ccda3079077dd613308526e02d797f5cc356aHess Chen def __init__(self, workspace): 49421ccda3079077dd613308526e02d797f5cc356aHess Chen self.rlist = [] 50421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip = None 51421ccda3079077dd613308526e02d797f5cc356aHess Chen self.workspace = os.path.normpath(workspace) 52421ccda3079077dd613308526e02d797f5cc356aHess Chen self.backupfile = gBACKUPFILE 53421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zipfile = os.path.join(self.workspace, gBACKUPFILE) 54421ccda3079077dd613308526e02d797f5cc356aHess Chen 55421ccda3079077dd613308526e02d797f5cc356aHess Chen def _createzip(self): 56421ccda3079077dd613308526e02d797f5cc356aHess Chen if self.zip: 57421ccda3079077dd613308526e02d797f5cc356aHess Chen return 58421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip = zipfile.ZipFile(self.zipfile, 'w', zipfile.ZIP_DEFLATED) 59421ccda3079077dd613308526e02d797f5cc356aHess Chen 60421ccda3079077dd613308526e02d797f5cc356aHess Chen def _save(self, tmp, path): 61421ccda3079077dd613308526e02d797f5cc356aHess Chen if not self._tryhook(path): 62421ccda3079077dd613308526e02d797f5cc356aHess Chen return 63421ccda3079077dd613308526e02d797f5cc356aHess Chen self.rlist.append(_PathInfo(tmp, path)) 64421ccda3079077dd613308526e02d797f5cc356aHess Chen 65421ccda3079077dd613308526e02d797f5cc356aHess Chen def bkrmfile(self, path): 66421ccda3079077dd613308526e02d797f5cc356aHess Chen arc = self._tryhook(path) 67421ccda3079077dd613308526e02d797f5cc356aHess Chen if arc and os.path.isfile(path): 68421ccda3079077dd613308526e02d797f5cc356aHess Chen self._createzip() 69421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip.write(path, arc.encode('utf_8')) 70421ccda3079077dd613308526e02d797f5cc356aHess Chen sta = os.stat(path) 71421ccda3079077dd613308526e02d797f5cc356aHess Chen oldmode = stat.S_IMODE(sta.st_mode) 72421ccda3079077dd613308526e02d797f5cc356aHess Chen self.rlist.append(_PathInfo(_CHMOD, path, oldmode)) 73421ccda3079077dd613308526e02d797f5cc356aHess Chen self.rlist.append(_PathInfo(_RMFILE, path)) 74421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_remove__(path) 75421ccda3079077dd613308526e02d797f5cc356aHess Chen 76421ccda3079077dd613308526e02d797f5cc356aHess Chen def bkmkfile(self, path, mode, bufsize): 77421ccda3079077dd613308526e02d797f5cc356aHess Chen if not os.path.exists(path): 78421ccda3079077dd613308526e02d797f5cc356aHess Chen self._save(_MKFILE, path) 79421ccda3079077dd613308526e02d797f5cc356aHess Chen return __built_in_open__(path, mode, bufsize) 80421ccda3079077dd613308526e02d797f5cc356aHess Chen 81421ccda3079077dd613308526e02d797f5cc356aHess Chen def bkrmdir(self, path): 82421ccda3079077dd613308526e02d797f5cc356aHess Chen if os.path.exists(path): 83421ccda3079077dd613308526e02d797f5cc356aHess Chen sta = os.stat(path) 84421ccda3079077dd613308526e02d797f5cc356aHess Chen oldmode = stat.S_IMODE(sta.st_mode) 85421ccda3079077dd613308526e02d797f5cc356aHess Chen self.rlist.append(_PathInfo(_CHMOD, path, oldmode)) 86421ccda3079077dd613308526e02d797f5cc356aHess Chen self._save(_RMDIR, path) 87421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_rmdir__(path) 88421ccda3079077dd613308526e02d797f5cc356aHess Chen 89421ccda3079077dd613308526e02d797f5cc356aHess Chen def bkmkdir(self, path, mode): 90421ccda3079077dd613308526e02d797f5cc356aHess Chen if not os.path.exists(path): 91421ccda3079077dd613308526e02d797f5cc356aHess Chen self._save(_MKDIR, path) 92421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_mkdir__(path, mode) 93421ccda3079077dd613308526e02d797f5cc356aHess Chen 94421ccda3079077dd613308526e02d797f5cc356aHess Chen def bkchmod(self, path, mode): 95421ccda3079077dd613308526e02d797f5cc356aHess Chen if self._tryhook(path) and os.path.exists(path): 96421ccda3079077dd613308526e02d797f5cc356aHess Chen sta = os.stat(path) 97421ccda3079077dd613308526e02d797f5cc356aHess Chen oldmode = stat.S_IMODE(sta.st_mode) 98421ccda3079077dd613308526e02d797f5cc356aHess Chen self.rlist.append(_PathInfo(_CHMOD, path, oldmode)) 99421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_chmod__(path, mode) 100421ccda3079077dd613308526e02d797f5cc356aHess Chen 101421ccda3079077dd613308526e02d797f5cc356aHess Chen def rollback(self): 102421ccda3079077dd613308526e02d797f5cc356aHess Chen if self.zip: 103421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip.close() 104421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip = None 105421ccda3079077dd613308526e02d797f5cc356aHess Chen index = len(self.rlist) - 1 106421ccda3079077dd613308526e02d797f5cc356aHess Chen while index >= 0: 107421ccda3079077dd613308526e02d797f5cc356aHess Chen item = self.rlist[index] 108421ccda3079077dd613308526e02d797f5cc356aHess Chen exist = os.path.exists(item.path) 109421ccda3079077dd613308526e02d797f5cc356aHess Chen if item.action == _MKFILE and exist: 110421ccda3079077dd613308526e02d797f5cc356aHess Chen #if not os.access(item.path, os.W_OK): 111421ccda3079077dd613308526e02d797f5cc356aHess Chen # os.chmod(item.path, S_IWUSR) 112421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_remove__(item.path) 113421ccda3079077dd613308526e02d797f5cc356aHess Chen elif item.action == _RMFILE and not exist: 114421ccda3079077dd613308526e02d797f5cc356aHess Chen if not self.zip: 115421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip = zipfile.ZipFile(self.zipfile, 'r', zipfile.ZIP_DEFLATED) 116421ccda3079077dd613308526e02d797f5cc356aHess Chen arcname = os.path.normpath(item.path) 117421ccda3079077dd613308526e02d797f5cc356aHess Chen arcname = arcname[len(self.workspace)+1:].encode('utf_8') 118421ccda3079077dd613308526e02d797f5cc356aHess Chen if os.sep != "/" and os.sep in arcname: 119421ccda3079077dd613308526e02d797f5cc356aHess Chen arcname = arcname.replace(os.sep, '/') 120421ccda3079077dd613308526e02d797f5cc356aHess Chen mtime = self.zip.getinfo(arcname).date_time 121421ccda3079077dd613308526e02d797f5cc356aHess Chen content = self.zip.read(arcname) 122421ccda3079077dd613308526e02d797f5cc356aHess Chen filep = __built_in_open__(item.path, "wb") 123421ccda3079077dd613308526e02d797f5cc356aHess Chen filep.write(content) 124421ccda3079077dd613308526e02d797f5cc356aHess Chen filep.close() 125421ccda3079077dd613308526e02d797f5cc356aHess Chen intime = time.mktime(mtime + (0, 0, 0)) 126421ccda3079077dd613308526e02d797f5cc356aHess Chen os.utime(item.path, (intime, intime)) 127421ccda3079077dd613308526e02d797f5cc356aHess Chen elif item.action == _MKDIR and exist: 128421ccda3079077dd613308526e02d797f5cc356aHess Chen while True: 129421ccda3079077dd613308526e02d797f5cc356aHess Chen try: 130421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_rmdir__(item.path) 131421ccda3079077dd613308526e02d797f5cc356aHess Chen break 132421ccda3079077dd613308526e02d797f5cc356aHess Chen except IOError: 133421ccda3079077dd613308526e02d797f5cc356aHess Chen # Sleep a short time and try again 134421ccda3079077dd613308526e02d797f5cc356aHess Chen # The anti-virus software may delay the file removal in this directory 135421ccda3079077dd613308526e02d797f5cc356aHess Chen sleep(0.1) 136421ccda3079077dd613308526e02d797f5cc356aHess Chen elif item.action == _RMDIR and not exist: 137421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_mkdir__(item.path) 138421ccda3079077dd613308526e02d797f5cc356aHess Chen elif item.action == _CHMOD and exist: 139421ccda3079077dd613308526e02d797f5cc356aHess Chen try: 140421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_chmod__(item.path, item.mode) 141421ccda3079077dd613308526e02d797f5cc356aHess Chen except EnvironmentError: 142421ccda3079077dd613308526e02d797f5cc356aHess Chen pass 143421ccda3079077dd613308526e02d797f5cc356aHess Chen index -= 1 144421ccda3079077dd613308526e02d797f5cc356aHess Chen self.commit() 145421ccda3079077dd613308526e02d797f5cc356aHess Chen 146421ccda3079077dd613308526e02d797f5cc356aHess Chen def commit(self): 147421ccda3079077dd613308526e02d797f5cc356aHess Chen if self.zip: 148421ccda3079077dd613308526e02d797f5cc356aHess Chen self.zip.close() 149421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_remove__(self.zipfile) 150421ccda3079077dd613308526e02d797f5cc356aHess Chen 151421ccda3079077dd613308526e02d797f5cc356aHess Chen # Check if path needs to be hooked 152421ccda3079077dd613308526e02d797f5cc356aHess Chen def _tryhook(self, path): 153421ccda3079077dd613308526e02d797f5cc356aHess Chen path = os.path.normpath(path) 154421ccda3079077dd613308526e02d797f5cc356aHess Chen works = self.workspace if str(self.workspace).endswith(os.sep) else (self.workspace + os.sep) 155421ccda3079077dd613308526e02d797f5cc356aHess Chen if not path.startswith(works): 156421ccda3079077dd613308526e02d797f5cc356aHess Chen return '' 157421ccda3079077dd613308526e02d797f5cc356aHess Chen for exceptdir in gEXCEPTION_LIST: 158421ccda3079077dd613308526e02d797f5cc356aHess Chen full = os.path.join(self.workspace, exceptdir) 159421ccda3079077dd613308526e02d797f5cc356aHess Chen if full == path or path.startswith(full + os.sep) or os.path.split(full)[0] == path: 160421ccda3079077dd613308526e02d797f5cc356aHess Chen return '' 161421ccda3079077dd613308526e02d797f5cc356aHess Chen return path[len(self.workspace)+1:] 162421ccda3079077dd613308526e02d797f5cc356aHess Chen 163421ccda3079077dd613308526e02d797f5cc356aHess Chendef _hookrm(path): 164421ccda3079077dd613308526e02d797f5cc356aHess Chen if GlobalData.gRECOVERMGR: 165421ccda3079077dd613308526e02d797f5cc356aHess Chen GlobalData.gRECOVERMGR.bkrmfile(path) 166421ccda3079077dd613308526e02d797f5cc356aHess Chen else: 167421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_remove__(path) 168421ccda3079077dd613308526e02d797f5cc356aHess Chen 169421ccda3079077dd613308526e02d797f5cc356aHess Chendef _hookmkdir(path, mode=0777): 170421ccda3079077dd613308526e02d797f5cc356aHess Chen if GlobalData.gRECOVERMGR: 171421ccda3079077dd613308526e02d797f5cc356aHess Chen GlobalData.gRECOVERMGR.bkmkdir(path, mode) 172421ccda3079077dd613308526e02d797f5cc356aHess Chen else: 173421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_mkdir__(path, mode) 174421ccda3079077dd613308526e02d797f5cc356aHess Chen 175421ccda3079077dd613308526e02d797f5cc356aHess Chendef _hookrmdir(path): 176421ccda3079077dd613308526e02d797f5cc356aHess Chen if GlobalData.gRECOVERMGR: 177421ccda3079077dd613308526e02d797f5cc356aHess Chen GlobalData.gRECOVERMGR.bkrmdir(path) 178421ccda3079077dd613308526e02d797f5cc356aHess Chen else: 179421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_rmdir__(path) 180421ccda3079077dd613308526e02d797f5cc356aHess Chen 181421ccda3079077dd613308526e02d797f5cc356aHess Chendef _hookmkfile(path, mode='r', bufsize=-1): 182421ccda3079077dd613308526e02d797f5cc356aHess Chen if GlobalData.gRECOVERMGR: 183421ccda3079077dd613308526e02d797f5cc356aHess Chen return GlobalData.gRECOVERMGR.bkmkfile(path, mode, bufsize) 184421ccda3079077dd613308526e02d797f5cc356aHess Chen return __built_in_open__(path, mode, bufsize) 185421ccda3079077dd613308526e02d797f5cc356aHess Chen 186421ccda3079077dd613308526e02d797f5cc356aHess Chendef _hookchmod(path, mode): 187421ccda3079077dd613308526e02d797f5cc356aHess Chen if GlobalData.gRECOVERMGR: 188421ccda3079077dd613308526e02d797f5cc356aHess Chen GlobalData.gRECOVERMGR.bkchmod(path, mode) 189421ccda3079077dd613308526e02d797f5cc356aHess Chen else: 190421ccda3079077dd613308526e02d797f5cc356aHess Chen __built_in_chmod__(path, mode) 191421ccda3079077dd613308526e02d797f5cc356aHess Chen 192421ccda3079077dd613308526e02d797f5cc356aHess Chendef SetRecoverMgr(mgr): 193421ccda3079077dd613308526e02d797f5cc356aHess Chen GlobalData.gRECOVERMGR = mgr 194421ccda3079077dd613308526e02d797f5cc356aHess Chen 195421ccda3079077dd613308526e02d797f5cc356aHess Chenos.remove = _hookrm 196421ccda3079077dd613308526e02d797f5cc356aHess Chenos.mkdir = _hookmkdir 197421ccda3079077dd613308526e02d797f5cc356aHess Chenos.rmdir = _hookrmdir 198421ccda3079077dd613308526e02d797f5cc356aHess Chenos.chmod = _hookchmod 199421ccda3079077dd613308526e02d797f5cc356aHess Chen__FileHookOpen__ = _hookmkfile 200