https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
		
			
				
	
	
		
			194 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
## @file
 | 
						|
# This file hooks file and directory creation and removal
 | 
						|
#
 | 
						|
# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
#
 | 
						|
# SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
#
 | 
						|
 | 
						|
'''
 | 
						|
File hook
 | 
						|
'''
 | 
						|
 | 
						|
import os
 | 
						|
import stat
 | 
						|
import time
 | 
						|
import zipfile
 | 
						|
from time import sleep
 | 
						|
from Library import GlobalData
 | 
						|
 | 
						|
__built_in_remove__ = os.remove
 | 
						|
__built_in_mkdir__  = os.mkdir
 | 
						|
__built_in_rmdir__  = os.rmdir
 | 
						|
__built_in_chmod__  = os.chmod
 | 
						|
__built_in_open__   = open
 | 
						|
 | 
						|
_RMFILE      = 0
 | 
						|
_MKFILE      = 1
 | 
						|
_RMDIR       = 2
 | 
						|
_MKDIR       = 3
 | 
						|
_CHMOD       = 4
 | 
						|
 | 
						|
gBACKUPFILE = 'file.backup'
 | 
						|
gEXCEPTION_LIST = ['Conf'+os.sep+'DistributionPackageDatabase.db', '.tmp', gBACKUPFILE]
 | 
						|
 | 
						|
class _PathInfo:
 | 
						|
    def __init__(self, action, path, mode=-1):
 | 
						|
        self.action = action
 | 
						|
        self.path = path
 | 
						|
        self.mode = mode
 | 
						|
 | 
						|
class RecoverMgr:
 | 
						|
    def __init__(self, workspace):
 | 
						|
        self.rlist = []
 | 
						|
        self.zip = None
 | 
						|
        self.workspace = os.path.normpath(workspace)
 | 
						|
        self.backupfile = gBACKUPFILE
 | 
						|
        self.zipfile = os.path.join(self.workspace, gBACKUPFILE)
 | 
						|
 | 
						|
    def _createzip(self):
 | 
						|
        if self.zip:
 | 
						|
            return
 | 
						|
        self.zip = zipfile.ZipFile(self.zipfile, 'w', zipfile.ZIP_DEFLATED)
 | 
						|
 | 
						|
    def _save(self, tmp, path):
 | 
						|
        if not self._tryhook(path):
 | 
						|
            return
 | 
						|
        self.rlist.append(_PathInfo(tmp, path))
 | 
						|
 | 
						|
    def bkrmfile(self, path):
 | 
						|
        arc = self._tryhook(path)
 | 
						|
        if arc and os.path.isfile(path):
 | 
						|
            self._createzip()
 | 
						|
            self.zip.write(path, arc.encode('utf_8'))
 | 
						|
            sta = os.stat(path)
 | 
						|
            oldmode = stat.S_IMODE(sta.st_mode)
 | 
						|
            self.rlist.append(_PathInfo(_CHMOD, path, oldmode))
 | 
						|
            self.rlist.append(_PathInfo(_RMFILE, path))
 | 
						|
        __built_in_remove__(path)
 | 
						|
 | 
						|
    def bkmkfile(self, path, mode, bufsize):
 | 
						|
        if not os.path.exists(path):
 | 
						|
            self._save(_MKFILE, path)
 | 
						|
        return __built_in_open__(path, mode, bufsize)
 | 
						|
 | 
						|
    def bkrmdir(self, path):
 | 
						|
        if os.path.exists(path):
 | 
						|
            sta = os.stat(path)
 | 
						|
            oldmode = stat.S_IMODE(sta.st_mode)
 | 
						|
            self.rlist.append(_PathInfo(_CHMOD, path, oldmode))
 | 
						|
            self._save(_RMDIR, path)
 | 
						|
        __built_in_rmdir__(path)
 | 
						|
 | 
						|
    def bkmkdir(self, path, mode):
 | 
						|
        if not os.path.exists(path):
 | 
						|
            self._save(_MKDIR, path)
 | 
						|
        __built_in_mkdir__(path, mode)
 | 
						|
 | 
						|
    def bkchmod(self, path, mode):
 | 
						|
        if self._tryhook(path) and os.path.exists(path):
 | 
						|
            sta = os.stat(path)
 | 
						|
            oldmode = stat.S_IMODE(sta.st_mode)
 | 
						|
            self.rlist.append(_PathInfo(_CHMOD, path, oldmode))
 | 
						|
        __built_in_chmod__(path, mode)
 | 
						|
 | 
						|
    def rollback(self):
 | 
						|
        if self.zip:
 | 
						|
            self.zip.close()
 | 
						|
            self.zip = None
 | 
						|
        index = len(self.rlist) - 1
 | 
						|
        while index >= 0:
 | 
						|
            item = self.rlist[index]
 | 
						|
            exist = os.path.exists(item.path)
 | 
						|
            if item.action == _MKFILE and exist:
 | 
						|
                #if not os.access(item.path, os.W_OK):
 | 
						|
                #    os.chmod(item.path, S_IWUSR)
 | 
						|
                __built_in_remove__(item.path)
 | 
						|
            elif item.action == _RMFILE and not exist:
 | 
						|
                if not self.zip:
 | 
						|
                    self.zip = zipfile.ZipFile(self.zipfile, 'r', zipfile.ZIP_DEFLATED)
 | 
						|
                arcname = os.path.normpath(item.path)
 | 
						|
                arcname = arcname[len(self.workspace)+1:].encode('utf_8')
 | 
						|
                if os.sep != "/" and os.sep in arcname:
 | 
						|
                    arcname = arcname.replace(os.sep, '/')
 | 
						|
                mtime = self.zip.getinfo(arcname).date_time
 | 
						|
                content = self.zip.read(arcname)
 | 
						|
                filep = __built_in_open__(item.path, "wb")
 | 
						|
                filep.write(content)
 | 
						|
                filep.close()
 | 
						|
                intime = time.mktime(mtime + (0, 0, 0))
 | 
						|
                os.utime(item.path, (intime, intime))
 | 
						|
            elif item.action == _MKDIR and exist:
 | 
						|
                while True:
 | 
						|
                    try:
 | 
						|
                        __built_in_rmdir__(item.path)
 | 
						|
                        break
 | 
						|
                    except IOError:
 | 
						|
                        # Sleep a short time and try again
 | 
						|
                        # The anti-virus software may delay the file removal in this directory
 | 
						|
                        sleep(0.1)
 | 
						|
            elif item.action == _RMDIR and not exist:
 | 
						|
                __built_in_mkdir__(item.path)
 | 
						|
            elif item.action == _CHMOD and exist:
 | 
						|
                try:
 | 
						|
                    __built_in_chmod__(item.path, item.mode)
 | 
						|
                except EnvironmentError:
 | 
						|
                    pass
 | 
						|
            index -= 1
 | 
						|
        self.commit()
 | 
						|
 | 
						|
    def commit(self):
 | 
						|
        if self.zip:
 | 
						|
            self.zip.close()
 | 
						|
            __built_in_remove__(self.zipfile)
 | 
						|
 | 
						|
    # Check if path needs to be hooked
 | 
						|
    def _tryhook(self, path):
 | 
						|
        path = os.path.normpath(path)
 | 
						|
        works = self.workspace if str(self.workspace).endswith(os.sep) else (self.workspace  + os.sep)
 | 
						|
        if not path.startswith(works):
 | 
						|
            return ''
 | 
						|
        for exceptdir in gEXCEPTION_LIST:
 | 
						|
            full = os.path.join(self.workspace, exceptdir)
 | 
						|
            if full == path or path.startswith(full + os.sep) or os.path.split(full)[0] == path:
 | 
						|
                return ''
 | 
						|
        return path[len(self.workspace)+1:]
 | 
						|
 | 
						|
def _hookrm(path):
 | 
						|
    if GlobalData.gRECOVERMGR:
 | 
						|
        GlobalData.gRECOVERMGR.bkrmfile(path)
 | 
						|
    else:
 | 
						|
        __built_in_remove__(path)
 | 
						|
 | 
						|
def _hookmkdir(path, mode=0o777):
 | 
						|
    if GlobalData.gRECOVERMGR:
 | 
						|
        GlobalData.gRECOVERMGR.bkmkdir(path, mode)
 | 
						|
    else:
 | 
						|
        __built_in_mkdir__(path, mode)
 | 
						|
 | 
						|
def _hookrmdir(path):
 | 
						|
    if GlobalData.gRECOVERMGR:
 | 
						|
        GlobalData.gRECOVERMGR.bkrmdir(path)
 | 
						|
    else:
 | 
						|
        __built_in_rmdir__(path)
 | 
						|
 | 
						|
def _hookmkfile(path, mode='r', bufsize=-1):
 | 
						|
    if GlobalData.gRECOVERMGR:
 | 
						|
        return GlobalData.gRECOVERMGR.bkmkfile(path, mode, bufsize)
 | 
						|
    return __built_in_open__(path, mode, bufsize)
 | 
						|
 | 
						|
def _hookchmod(path, mode):
 | 
						|
    if GlobalData.gRECOVERMGR:
 | 
						|
        GlobalData.gRECOVERMGR.bkchmod(path, mode)
 | 
						|
    else:
 | 
						|
        __built_in_chmod__(path, mode)
 | 
						|
 | 
						|
def SetRecoverMgr(mgr):
 | 
						|
    GlobalData.gRECOVERMGR = mgr
 | 
						|
 | 
						|
os.remove   = _hookrm
 | 
						|
os.mkdir    = _hookmkdir
 | 
						|
os.rmdir    = _hookrmdir
 | 
						|
os.chmod    = _hookchmod
 | 
						|
__FileHookOpen__    = _hookmkfile
 |