def _archive_copy(src_st, src_path, dest_path): """ Copy file from src_path to dest_path. Regular files and symlinks are supported. If an EnvironmentError occurs, then it is logged to stderr. @param src_st: source file lstat result @type src_st: posix.stat_result @param src_path: source file path @type src_path: str @param dest_path: destination file path @type dest_path: str """ # Remove destination file in order to ensure that the following # symlink or copy2 call won't fail (see bug #535850). try: os.unlink(dest_path) except OSError: pass try: if stat.S_ISLNK(src_st.st_mode): os.symlink(os.readlink(src_path), dest_path) else: shutil.copy2(src_path, dest_path) except EnvironmentError as e: portage.util.writemsg( _('dispatch-conf: Error copying %(src_path)s to ' '%(dest_path)s: %(reason)s\n') % { "src_path": src_path, "dest_path": dest_path, "reason": e }, noiselevel=-1)
def _prepare_fake_distdir(settings, alist): orig_distdir = settings["DISTDIR"] edpath = os.path.join(settings["PORTAGE_BUILDDIR"], "distdir") portage.util.ensure_dirs(edpath, gid=portage_gid, mode=0o755) # Remove any unexpected files or directories. for x in os.listdir(edpath): symlink_path = os.path.join(edpath, x) st = os.lstat(symlink_path) if x in alist and stat.S_ISLNK(st.st_mode): continue if stat.S_ISDIR(st.st_mode): shutil.rmtree(symlink_path) else: os.unlink(symlink_path) # Check for existing symlinks and recreate if necessary. for x in alist: symlink_path = os.path.join(edpath, x) target = os.path.join(orig_distdir, x) try: link_target = os.readlink(symlink_path) except OSError: os.symlink(target, symlink_path) else: if link_target != target: os.unlink(symlink_path) os.symlink(target, symlink_path)
def _archive_copy(src_st, src_path, dest_path): """ Copy file from src_path to dest_path. Regular files and symlinks are supported. If an EnvironmentError occurs, then it is logged to stderr. @param src_st: source file lstat result @type src_st: posix.stat_result @param src_path: source file path @type src_path: str @param dest_path: destination file path @type dest_path: str """ # Remove destination file in order to ensure that the following # symlink or copy2 call won't fail (see bug #535850). try: os.unlink(dest_path) except OSError: pass try: if stat.S_ISLNK(src_st.st_mode): os.symlink(os.readlink(src_path), dest_path) else: shutil.copy2(src_path, dest_path) except EnvironmentError as e: portage.util.writemsg( _("dispatch-conf: Error copying %(src_path)s to " "%(dest_path)s: %(reason)s\n") % { "src_path": src_path, "dest_path": dest_path, "reason": e }, noiselevel=-1, )
def _prepare_fake_filesdir(settings): real_filesdir = settings["O"]+"/files" symlink_path = settings["FILESDIR"] try: link_target = os.readlink(symlink_path) except OSError: os.symlink(real_filesdir, symlink_path) else: if link_target != real_filesdir: os.unlink(symlink_path) os.symlink(real_filesdir, symlink_path)
def modify_files(dir_path): for name in os.listdir(dir_path): path = os.path.join(dir_path, name) st = os.lstat(path) if stat.S_ISREG(st.st_mode): with io.open(path, mode='a', encoding=_encodings["stdio"]) as f: f.write("modified at %d\n" % time.time()) elif stat.S_ISLNK(st.st_mode): old_dest = os.readlink(path) os.unlink(path) os.symlink(old_dest + " modified at %d" % time.time(), path)
def diff_mixed(func, file1, file2): tempdir = None try: if os.path.islink(file1) and \ not os.path.islink(file2) and \ os.path.isfile(file1) and \ os.path.isfile(file2): # If a regular file replaces a symlink to a regular # file, then show the diff between the regular files # (bug #330221). diff_files = (file2, file2) else: files = [file1, file2] diff_files = [file1, file2] for i in range(len(diff_files)): try: st = os.lstat(diff_files[i]) except OSError: st = None if st is not None and stat.S_ISREG(st.st_mode): continue if tempdir is None: tempdir = tempfile.mkdtemp() diff_files[i] = os.path.join(tempdir, "%d" % i) if st is None: content = "/dev/null\n" elif stat.S_ISLNK(st.st_mode): link_dest = os.readlink(files[i]) content = "SYM: %s -> %s\n" % \ (file1, link_dest) elif stat.S_ISDIR(st.st_mode): content = "DIR: %s\n" % (file1, ) elif stat.S_ISFIFO(st.st_mode): content = "FIF: %s\n" % (file1, ) else: content = "DEV: %s\n" % (file1, ) with io.open(diff_files[i], mode='w', encoding=_encodings['stdio']) as f: f.write(content) return func(diff_files[0], diff_files[1]) finally: if tempdir is not None: shutil.rmtree(tempdir)
def diff_mixed(func, file1, file2): tempdir = None try: if os.path.islink(file1) and \ not os.path.islink(file2) and \ os.path.isfile(file1) and \ os.path.isfile(file2): # If a regular file replaces a symlink to a regular # file, then show the diff between the regular files # (bug #330221). diff_files = (file2, file2) else: files = [file1, file2] diff_files = [file1, file2] for i in range(len(diff_files)): try: st = os.lstat(diff_files[i]) except OSError: st = None if st is not None and stat.S_ISREG(st.st_mode): continue if tempdir is None: tempdir = tempfile.mkdtemp() diff_files[i] = os.path.join(tempdir, "%d" % i) if st is None: content = "/dev/null\n" elif stat.S_ISLNK(st.st_mode): link_dest = os.readlink(files[i]) content = "SYM: %s -> %s\n" % \ (file1, link_dest) elif stat.S_ISDIR(st.st_mode): content = "DIR: %s\n" % (file1,) elif stat.S_ISFIFO(st.st_mode): content = "FIF: %s\n" % (file1,) else: content = "DEV: %s\n" % (file1,) with io.open(diff_files[i], mode='w', encoding=_encodings['stdio']) as f: f.write(content) return func(diff_files[0], diff_files[1]) finally: if tempdir is not None: shutil.rmtree(tempdir)
def pruneNonExisting(self): """ Remove all records for objects that no longer exist on the filesystem. """ os = _os_merge for cps in list(self._data): cpv, counter, _paths = self._data[cps] paths = [] hardlinks = set() symlinks = {} for f in _paths: f_abs = os.path.join(self._root, f.lstrip(os.sep)) try: lst = os.lstat(f_abs) except OSError: continue if stat.S_ISLNK(lst.st_mode): try: symlinks[f] = os.readlink(f_abs) except OSError: continue elif stat.S_ISREG(lst.st_mode): hardlinks.add(f) paths.append(f) # Only count symlinks as preserved if they still point to a hardink # in the same directory, in order to handle cases where a tool such # as eselect-opengl has updated the symlink to point to a hardlink # in a different directory (see bug #406837). The unused hardlink # is automatically found by _find_unused_preserved_libs, since the # soname symlink no longer points to it. After the hardlink is # removed by _remove_preserved_libs, it calls pruneNonExisting # which eliminates the irrelevant symlink from the registry here. for f, target in symlinks.items(): if abssymlink(f, target=target) in hardlinks: paths.append(f) if len(paths) > 0: self._data[cps] = (cpv, counter, paths) else: del self._data[cps]
def pruneNonExisting(self): """Remove all records for objects that no longer exist on the filesystem.""" os = _os_merge for cps in list(self._data): cpv, counter, _paths = self._data[cps] paths = [] hardlinks = set() symlinks = {} for f in _paths: f_abs = os.path.join(self._root, f.lstrip(os.sep)) try: lst = os.lstat(f_abs) except OSError: continue if stat.S_ISLNK(lst.st_mode): try: symlinks[f] = os.readlink(f_abs) except OSError: continue elif stat.S_ISREG(lst.st_mode): hardlinks.add(f) paths.append(f) # Only count symlinks as preserved if they still point to a hardink # in the same directory, in order to handle cases where a tool such # as eselect-opengl has updated the symlink to point to a hardlink # in a different directory (see bug #406837). The unused hardlink # is automatically found by _find_unused_preserved_libs, since the # soname symlink no longer points to it. After the hardlink is # removed by _remove_preserved_libs, it calls pruneNonExisting # which eliminates the irrelevant symlink from the registry here. for f, target in symlinks.items(): if abssymlink(f, target=target) in hardlinks: paths.append(f) if len(paths) > 0: self._data[cps] = (cpv, counter, paths) else: del self._data[cps]
def _prepare_workdir(mysettings): workdir_mode = 0o700 try: mode = mysettings["PORTAGE_WORKDIR_MODE"] if mode.isdigit(): parsed_mode = int(mode, 8) elif mode == "": raise KeyError() else: raise ValueError() if parsed_mode & 0o7777 != parsed_mode: raise ValueError("Invalid file mode: %s" % mode) else: workdir_mode = parsed_mode except KeyError as e: writemsg(_("!!! PORTAGE_WORKDIR_MODE is unset, using %s.\n") % oct(workdir_mode)) except ValueError as e: if len(str(e)) > 0: writemsg("%s\n" % e) writemsg(_("!!! Unable to parse PORTAGE_WORKDIR_MODE='%s', using %s.\n") % \ (mysettings["PORTAGE_WORKDIR_MODE"], oct(workdir_mode))) mysettings["PORTAGE_WORKDIR_MODE"] = oct(workdir_mode).replace('o', '') try: apply_secpass_permissions(mysettings["WORKDIR"], uid=portage_uid, gid=portage_gid, mode=workdir_mode) except FileNotFound: pass # ebuild.sh will create it if mysettings.get("PORTAGE_LOGDIR", "") == "": while "PORTAGE_LOGDIR" in mysettings: del mysettings["PORTAGE_LOGDIR"] if "PORTAGE_LOGDIR" in mysettings: try: modified = ensure_dirs(mysettings["PORTAGE_LOGDIR"]) if modified: # Only initialize group/mode if the directory doesn't # exist, so that we don't override permissions if they # were previously set by the administrator. # NOTE: These permissions should be compatible with our # default logrotate config as discussed in bug 374287. apply_secpass_permissions(mysettings["PORTAGE_LOGDIR"], uid=portage_uid, gid=portage_gid, mode=0o2770) except PortageException as e: writemsg("!!! %s\n" % str(e), noiselevel=-1) writemsg(_("!!! Permission issues with PORTAGE_LOGDIR='%s'\n") % \ mysettings["PORTAGE_LOGDIR"], noiselevel=-1) writemsg(_("!!! Disabling logging.\n"), noiselevel=-1) while "PORTAGE_LOGDIR" in mysettings: del mysettings["PORTAGE_LOGDIR"] compress_log_ext = '' if 'compress-build-logs' in mysettings.features: compress_log_ext = '.gz' logdir_subdir_ok = False if "PORTAGE_LOGDIR" in mysettings and \ os.access(mysettings["PORTAGE_LOGDIR"], os.W_OK): logdir = normalize_path(mysettings["PORTAGE_LOGDIR"]) logid_path = os.path.join(mysettings["PORTAGE_BUILDDIR"], ".logid") if not os.path.exists(logid_path): open(_unicode_encode(logid_path), 'w').close() logid_time = _unicode_decode(time.strftime("%Y%m%d-%H%M%S", time.gmtime(os.stat(logid_path).st_mtime)), encoding=_encodings['content'], errors='replace') if "split-log" in mysettings.features: log_subdir = os.path.join(logdir, "build", mysettings["CATEGORY"]) mysettings["PORTAGE_LOG_FILE"] = os.path.join( log_subdir, "%s:%s.log%s" % (mysettings["PF"], logid_time, compress_log_ext)) else: log_subdir = logdir mysettings["PORTAGE_LOG_FILE"] = os.path.join( logdir, "%s:%s:%s.log%s" % \ (mysettings["CATEGORY"], mysettings["PF"], logid_time, compress_log_ext)) if log_subdir is logdir: logdir_subdir_ok = True else: try: _ensure_log_subdirs(logdir, log_subdir) except PortageException as e: writemsg("!!! %s\n" % (e,), noiselevel=-1) if os.access(log_subdir, os.W_OK): logdir_subdir_ok = True else: writemsg("!!! %s: %s\n" % (_("Permission Denied"), log_subdir), noiselevel=-1) tmpdir_log_path = os.path.join( mysettings["T"], "build.log%s" % compress_log_ext) if not logdir_subdir_ok: # NOTE: When sesandbox is enabled, the local SELinux security policies # may not allow output to be piped out of the sesandbox domain. The # current policy will allow it to work when a pty is available, but # not through a normal pipe. See bug #162404. mysettings["PORTAGE_LOG_FILE"] = tmpdir_log_path else: # Create a symlink from tmpdir_log_path to PORTAGE_LOG_FILE, as # requested in bug #412865. make_new_symlink = False try: target = os.readlink(tmpdir_log_path) except OSError: make_new_symlink = True else: if target != mysettings["PORTAGE_LOG_FILE"]: make_new_symlink = True if make_new_symlink: try: os.unlink(tmpdir_log_path) except OSError: pass os.symlink(mysettings["PORTAGE_LOG_FILE"], tmpdir_log_path)