def detectDLLsWithDependencyWalker(binary_filename, scan_dirs): dwp_filename = binary_filename + ".dwp" output_filename = binary_filename + ".depends" # User query should only happen once if at all. with withFileLock( "Finding out dependency walker path and creating DWP file for %s" % binary_filename ): depends_exe = getDependsExePath() # Note: Do this under lock to avoid forked processes to hold # a copy of the file handle on Windows. putTextFileContents( dwp_filename, contents="""\ %(scan_dirs)s SxS """ % { "scan_dirs": "\n".join( "UserDir %s" % getExternalUsePath(dirname) for dirname in scan_dirs ) }, ) # Starting the process while locked, so file handles are not duplicated. # TODO: At least exit code should be checked, output goes to a filename, # but errors might be interesting potentially. _stdout, _stderr, _exit_code = executeProcess( command=( depends_exe, "-c", "-ot%s" % output_filename, "-d:%s" % dwp_filename, "-f1", "-pa1", "-ps1", binary_filename, ), external_cwd=True, ) if not os.path.exists(output_filename): inclusion_logger.sysexit( "Error, 'depends.exe' failed to produce expected output." ) # Opening the result under lock, so it is not getting locked by new processes. # Note: Do this under lock to avoid forked processes to hold # a copy of the file handle on Windows. result = parseDependsExeOutput(output_filename) deleteFile(output_filename, must_exist=True) deleteFile(dwp_filename, must_exist=True) return result
def detectDLLsWithDependencyWalker(binary_filename, scan_dirs): dwp_filename = binary_filename + ".dwp" output_filename = binary_filename + ".depends" # User query should only happen once if at all. with withFileLock( "Finding out dependency walker path and creating DWP file for %s" % binary_filename): depends_exe = getDependsExePath() # Note: Do this under lock to avoid forked processes to hold # a copy of the file handle on Windows. with open(dwp_filename, "w") as dwp_file: dwp_file.write( """\ %(scan_dirs)s SxS """ % { "scan_dirs": "\n".join("UserDir %s" % getExternalUsePath(dirname) for dirname in scan_dirs) }) # Starting the process while locked, so file handles are not duplicated. depends_exe_process = subprocess.Popen( ( depends_exe, "-c", "-ot%s" % output_filename, "-d:%s" % dwp_filename, "-f1", "-pa1", "-ps1", binary_filename, ), stdin=getNullInput(), cwd=getExternalUsePath(os.getcwd()), ) # TODO: Exit code should be checked. depends_exe_process.wait() if not os.path.exists(output_filename): inclusion_logger.sysexit( "Error, depends.exe failed to produce expected output.") # Opening the result under lock, so it is not getting locked by new processes. # Note: Do this under lock to avoid forked processes to hold # a copy of the file handle on Windows. result = _parseDependsExeOutput(output_filename) deleteFile(output_filename, must_exist=True) deleteFile(dwp_filename, must_exist=True) return result
def detectBinaryPathDLLsWindowsDependencyWalker( is_main_executable, source_dir, original_dir, binary_filename, package_name, use_cache, update_cache, ): # This is the caching mechanism and plugin handling for DLL imports. if use_cache or update_cache: cache_filename = _getCacheFilename( dependency_tool="depends.exe", is_main_executable=is_main_executable, source_dir=source_dir, original_dir=original_dir, binary_filename=binary_filename, ) if use_cache: with withFileLock(): if not os.path.exists(cache_filename): use_cache = False if use_cache: result = OrderedSet() for line in getFileContentByLine(cache_filename): line = line.strip() result.add(line) return result if Options.isShowProgress(): general.info("Analysing dependencies of '%s'." % binary_filename) scan_dirs = getScanDirectories(package_name, original_dir) result = detectDLLsWithDependencyWalker(binary_filename, scan_dirs) if update_cache: putTextFileContents(filename=cache_filename, contents=result) return result
def detectBinaryPathDLLsWindowsDependencyWalker( is_main_executable, source_dir, original_dir, binary_filename, package_name, use_cache, update_cache, ): # This is complex, as it also includes the caching mechanism # pylint: disable=too-many-locals result = set() if use_cache or update_cache: cache_filename = _getCacheFilename( dependency_tool="depends.exe", is_main_executable=is_main_executable, source_dir=source_dir, original_dir=original_dir, binary_filename=binary_filename, ) if use_cache: with withFileLock(): if not os.path.exists(cache_filename): use_cache = False if use_cache: for line in getFileContentByLine(cache_filename): line = line.strip() result.add(line) return result if Options.isShowProgress(): info("Analysing dependencies of '%s'." % binary_filename) scan_dirs = getScanDirectories(package_name, original_dir) dwp_filename = binary_filename + ".dwp" output_filename = binary_filename + ".depends" # User query should only happen once if at all. with _withLock( "Finding out dependency walker path and creating DWP file for %s" % binary_filename ): depends_exe = getDependsExePath() # Note: Do this under lock to avoid forked processes to hold # a copy of the file handle on Windows. with open(dwp_filename, "w") as dwp_file: dwp_file.write( """\ %(scan_dirs)s SxS """ % { "scan_dirs": "\n".join( "UserDir %s" % dirname for dirname in scan_dirs ) } ) # Starting the process while locked, so file handles are not duplicated. depends_exe_process = subprocess.Popen( ( depends_exe, "-c", "-ot%s" % output_filename, "-d:%s" % dwp_filename, "-f1", "-pa1", "-ps1", binary_filename, ), cwd=getExternalUsePath(os.getcwd()), ) # TODO: Exit code should be checked. depends_exe_process.wait() if not os.path.exists(output_filename): sys.exit("Error, depends.exe failed to product output.") # Opening the result under lock, so it is not getting locked by new processes. # Note: Do this under lock to avoid forked processes to hold # a copy of the file handle on Windows. _parseDependsExeOutput(output_filename, result) deleteFile(output_filename, must_exist=True) deleteFile(dwp_filename, must_exist=True) if update_cache: with open(cache_filename, "w") as cache_file: for dll_filename in result: print(dll_filename, file=cache_file) return result
def _parsePEFileOutput( binary_filename, scan_dirs, is_main_executable, source_dir, original_dir, use_cache, update_cache, ): # This is complex, as it also includes the caching mechanism # pylint: disable=too-many-branches,too-many-locals result = OrderedSet() if use_cache or update_cache: cache_filename = _getCacheFilename( dependency_tool="pefile", is_main_executable=is_main_executable, source_dir=source_dir, original_dir=original_dir, binary_filename=binary_filename, ) if use_cache: with withFileLock(): if not os.path.exists(cache_filename): use_cache = False if use_cache: # TODO: We are lazy with the format, pylint: disable=eval-used extracted = eval(getFileContents(cache_filename)) else: if Options.isShowProgress(): info("Analysing dependencies of '%s'." % binary_filename) extracted = getPEFileInformation(binary_filename) if update_cache: with withFileLock(): with open(cache_filename, "w") as cache_file: print(repr(extracted), file=cache_file) # Add native system directory based on pe file architecture and os architecture # Python 32: system32 = syswow64 = 32 bits systemdirectory # Python 64: system32 = 64 bits systemdirectory, syswow64 = 32 bits systemdirectory # Get DLL imports from PE file for dll_name in extracted["DLLs"]: dll_name = dll_name.upper() # Try determine DLL path from scan dirs for scan_dir in scan_dirs: dll_filename = os.path.normcase( os.path.abspath(os.path.join(scan_dir, dll_name)) ) if os.path.isfile(dll_filename): break else: if dll_name.startswith("API-MS-WIN-") or dll_name.startswith("EXT-MS-WIN-"): continue # Found via RC_MANIFEST as copied from Python. if dll_name == "MSVCR90.DLL": continue if dll_name.startswith("python") and dll_name.endswith(".dll"): dll_filename = os.path.join( os.environ["SYSTEMROOT"], "SysWOW64" if getArchitecture() == "x86_64" else "System32", dll_name, ) dll_filename = os.path.normcase(dll_filename) else: continue if dll_filename not in result: result.add(dll_filename) # TODO: Shouldn't be here. blocked = Plugins.removeDllDependencies( dll_filename=binary_filename, dll_filenames=result ) for to_remove in blocked: result.discard(to_remove) return result
def _writeClcacheLog(filename, cache_result): with withFileLock(): with open(os.environ["CLCACHE_LOG"], "a") as clcache_log: clcache_log.write("%s=%s\n" % (filename, cache_result))