def test_00_valid_operation(self): """Verify that operation information can be stored and retrieved. """ h = self.__h self.assertEqual(os.path.join(self.__scratch_dir, "history"), h.path) h.log_operation_start("install") self.__class__.__filename = os.path.basename(h.pathname) # Verify that a valid start time was set. misc.timestamp_to_time(h.operation_start_time) self.assertEqual("install", h.operation_name) self.assertEqual(self.__username, h.operation_username) self.assertEqual(self.__userid, h.operation_userid) h.operation_start_state = self.__ip_before self.assertEqual(self.__ip_before, h.operation_start_state) h.operation_end_state = self.__ip_after self.assertEqual(self.__ip_after, h.operation_end_state) h.operation_errors.extend(self.__errors) self.assertEqual(self.__errors, h.operation_errors) h.log_operation_end()
def test_03_client_load(self): """Verify that the saved history can be retrieved properly. """ h = history.History(root_dir=self.__scratch_dir, filename=self.__filename) # Verify that a valid start time and end time was set. misc.timestamp_to_time(h.operation_start_time) misc.timestamp_to_time(h.operation_end_time) self.assertEqual("install", h.operation_name) self.assertEqual(self.__username, h.operation_username) self.assertEqual(self.__userid, h.operation_userid) self.assertEqual(self.__ip_before, h.operation_start_state) self.assertEqual(self.__ip_after, h.operation_end_state) self.assertEqual(self.__errors, h.operation_errors) self.assertEqual(history.RESULT_SUCCEEDED, h.operation_result)
def verify(self, img, **args): """Returns a tuple of lists of the form (errors, warnings, info). The error list will be empty if the action has been correctly installed in the given image. In detail, this verifies that the file is present, and if the preserve attribute is not present, that the hashes and other attributes of the file match.""" if self.attrs.get("preserve") == "abandon": return [], [], [] path = self.get_installed_path(img.get_root()) lstat, errors, warnings, info, abort = \ self.verify_fsobj_common(img, stat.S_IFREG) if lstat: if not stat.S_ISREG(lstat.st_mode): self.replace_required = True if abort: assert errors self.replace_required = True return errors, warnings, info if path.lower().endswith("/bobcat") and args["verbose"] == True: # Returned as a purely informational (untranslated) # message so that no client should interpret it as a # reason to fail verification. info.append("Warning: package may contain bobcat! " "(http://xkcd.com/325/)") preserve = self.attrs.get("preserve") if (preserve is None and "timestamp" in self.attrs and lstat.st_mtime != misc.timestamp_to_time(self.attrs["timestamp"])): errors.append( _("Timestamp: {found} should be " "{expected}").format(found=misc.time_to_timestamp( lstat.st_mtime), expected=self.attrs["timestamp"])) # avoid checking pkg.size if we have any content-hashes present; # different size files may have the same content-hash pkg_size = int(self.attrs.get("pkg.size", 0)) if preserve is None and pkg_size > 0 and \ not set(digest.DEFAULT_GELF_HASH_ATTRS).intersection( set(self.attrs.keys())) and \ lstat.st_size != pkg_size: errors.append( _("Size: {found:d} bytes should be " "{expected:d}").format(found=lstat.st_size, expected=pkg_size)) if (preserve is not None and args["verbose"] == False or lstat is None): return errors, warnings, info if args["forever"] != True: return errors, warnings, info # # Check file contents. # try: # This is a generic mechanism, but only used for libc on # x86, where the "best" version of libc is lofs-mounted # on the canonical path, foiling the standard verify # checks. is_mtpt = self.attrs.get("mountpoint", "").lower() == "true" elfhash = None elferror = None elf_hash_attr, elf_hash_val, \ elf_hash_func = \ digest.get_preferred_hash(self, hash_type=pkg.digest.HASH_GELF) if elf_hash_attr and haveelf and not is_mtpt: # # It's possible for the elf module to # throw while computing the hash, # especially if the file is badly # corrupted or truncated. # try: # On path, only calculate the # content hash that matches # the preferred one on the # action get_elfhash = \ elf_hash_attr == "elfhash" get_sha256 = (not get_elfhash and elf_hash_func == digest.GELF_HASH_ALGS["gelf:sha256"]) get_sha512t_256 = ( not get_elfhash and elf_hash_func == digest.GELF_HASH_ALGS["gelf:sha512t_256"]) elfhash = elf.get_hashes( path, elfhash=get_elfhash, sha256=get_sha256, sha512t_256=get_sha512t_256)[elf_hash_attr] if get_elfhash: elfhash = [elfhash] else: elfhash = list(digest.ContentHash(elfhash).values()) except elf.ElfError as e: # Any ELF error means there is something bad # with the file, mark as needing to be replaced. elferror = _("ELF failure: {0}").format(e) if (elfhash is not None and elf_hash_val != elfhash[0]): elferror = _("ELF content hash: " "{found} " "should be {expected}").format( found=elfhash[0], expected=elf_hash_val) # Always check on the file hash because the ELF hash # check only checks on the ELF parts and does not # check for some other file integrity issues. if not is_mtpt: hash_attr, hash_val, hash_func = \ digest.get_preferred_hash(self) sha_hash, data = misc.get_data_digest(path, hash_func=hash_func) if sha_hash != hash_val: # Prefer the ELF content hash error message. if preserve is not None: info.append(_("editable file has " "been changed")) elif elferror: errors.append(elferror) self.replace_required = True else: errors.append( _("Hash: " "{found} should be " "{expected}").format(found=sha_hash, expected=hash_val)) self.replace_required = True # Check system attributes. # Since some attributes like 'archive' or 'av_modified' # are set automatically by the FS, it makes no sense to # check for 1:1 matches. So we only check that the # system attributes specified in the action are still # set on the file. sattr = self.attrs.get("sysattr", None) if sattr: if isinstance(sattr, list): sattr = ",".join(sattr) sattrs = sattr.split(",") if len(sattrs) == 1 and \ sattrs[0] not in portable.get_sysattr_dict(): # not a verbose attr, try as a compact set_attrs = portable.fgetattr(path, compact=True) sattrs = sattrs[0] else: set_attrs = portable.fgetattr(path) for a in sattrs: if a not in set_attrs: errors.append( _("System attribute '{0}' " "not set").format(a)) except EnvironmentError as e: if e.errno == errno.EACCES: errors.append(_("Skipping: Permission Denied")) else: errors.append(_("Unexpected Error: {0}").format(e)) except Exception as e: errors.append(_("Unexpected Exception: {0}").format(e)) return errors, warnings, info
def install(self, pkgplan, orig): """Client-side method that installs a file.""" mode = None try: mode = int(self.attrs.get("mode", None), 8) except (TypeError, ValueError): # Mode isn't valid, so let validate raise a more # informative error. self.validate(fmri=pkgplan.destination_fmri) owner, group = self.get_fsobj_uid_gid(pkgplan, pkgplan.destination_fmri) final_path = self.get_installed_path(pkgplan.image.get_root()) # Don't allow installation through symlinks. self.fsobj_checkpath(pkgplan, final_path) if not os.path.exists(os.path.dirname(final_path)): self.makedirs(os.path.dirname(final_path), mode=misc.PKG_DIR_MODE, fmri=pkgplan.destination_fmri) elif (not orig and not pkgplan.origin_fmri and "preserve" in self.attrs and self.attrs["preserve"] not in ("abandon", "install-only") and os.path.isfile(final_path)): # Unpackaged editable file is already present during # initial install; salvage it before continuing. pkgplan.salvage(final_path) # XXX If we're upgrading, do we need to preserve file perms from # existing file? # check if we have a save_file active; if so, simulate file # being already present rather than installed from scratch if "save_file" in self.attrs: orig = self.restore_file(pkgplan.image) # See if we need to preserve the file, and if so, set that up. # # XXX What happens when we transition from preserve to # non-preserve or vice versa? Do we want to treat a preserve # attribute as turning the action into a critical action? # # XXX We should save the originally installed file. It can be # used as an ancestor for a three-way merge, for example. Where # should it be stored? pres_type = self._check_preserve(orig, pkgplan) do_content = True old_path = None if pres_type == True or (pres_type and pkgplan.origin_fmri == pkgplan.destination_fmri): # File is marked to be preserved and exists so don't # reinstall content. do_content = False elif pres_type == "legacy": # Only rename old file if this is a transition to # preserve=legacy from something else. if orig.attrs.get("preserve", None) != "legacy": old_path = final_path + ".legacy" elif pres_type == "renameold.update": old_path = final_path + ".update" elif pres_type == "renameold": old_path = final_path + ".old" elif pres_type == "renamenew": final_path = final_path + ".new" elif pres_type == "abandon": return # If it is a directory (and not empty) then we should # salvage the contents. if os.path.exists(final_path) and \ not os.path.islink(final_path) and \ os.path.isdir(final_path): try: os.rmdir(final_path) except OSError as e: if e.errno == errno.ENOENT: pass elif e.errno in (errno.EEXIST, errno.ENOTEMPTY): pkgplan.salvage(final_path) elif e.errno != errno.EACCES: # this happens on Windows raise # XXX This needs to be modularized. if do_content and self.needsdata(orig, pkgplan): tfilefd, temp = tempfile.mkstemp(dir=os.path.dirname(final_path)) if not self.data: # The state of the filesystem changed after the # plan was prepared; attempt a one-off # retrieval of the data. self.data = self.__set_data(pkgplan) stream = self.data() tfile = os.fdopen(tfilefd, "wb") try: # Always verify using the most preferred hash hash_attr, hash_val, hash_func = \ digest.get_preferred_hash(self) shasum = misc.gunzip_from_stream(stream, tfile, hash_func) except zlib.error as e: raise ActionExecutionError( self, details=_("Error decompressing payload: " "{0}").format(" ".join([str(a) for a in e.args])), error=e) finally: tfile.close() stream.close() if shasum != hash_val: raise ActionExecutionError( self, details=_("Action data hash verification " "failure: expected: {expected} computed: " "{actual} action: {action}").format( expected=hash_val, actual=shasum, action=self)) else: temp = final_path try: os.chmod(temp, mode) except OSError as e: # If the file didn't exist, assume that's intentional, # and drive on. if e.errno != errno.ENOENT: raise else: return try: portable.chown(temp, owner, group) except OSError as e: if e.errno != errno.EPERM: raise # XXX There's a window where final_path doesn't exist, but we # probably don't care. if do_content and old_path: try: portable.rename(final_path, old_path) except OSError as e: if e.errno != errno.ENOENT: # Only care if file isn't gone already. raise # This is safe even if temp == final_path. try: portable.rename(temp, final_path) except OSError as e: raise api_errors.FileInUseException(final_path) # Handle timestamp if specified (and content was installed). if do_content and "timestamp" in self.attrs: t = misc.timestamp_to_time(self.attrs["timestamp"]) try: os.utime(final_path, (t, t)) except OSError as e: if e.errno != errno.EACCES: raise # On Windows, the time cannot be changed on a # read-only file os.chmod(final_path, stat.S_IRUSR | stat.S_IWUSR) os.utime(final_path, (t, t)) os.chmod(final_path, mode) # Handle system attributes. sattr = self.attrs.get("sysattr") if sattr: if isinstance(sattr, list): sattr = ",".join(sattr) sattrs = sattr.split(",") if len(sattrs) == 1 and \ sattrs[0] not in portable.get_sysattr_dict(): # not a verbose attr, try as a compact attr seq arg = sattrs[0] else: arg = sattrs try: portable.fsetattr(final_path, arg) except OSError as e: if e.errno != errno.EINVAL: raise warn = _("System attributes are not supported " "on the target image filesystem; 'sysattr'" " ignored for {0}").format(self.attrs["path"]) pkgplan.image.imageplan.pd.add_item_message( pkgplan.destination_fmri, misc.time_to_timestamp(time.time()), MSG_WARNING, warn) except ValueError as e: warn = _("Could not set system attributes for {path}" "'{attrlist}': {err}").format(attrlist=sattr, err=e, path=self.attrs["path"]) pkgplan.image.imageplan.pd.add_item_message( pkgplan.destination_fmri, misc.time_to_timestamp(time.time()), MSG_WARNING, warn)
def verify(self, img, **args): """Returns a tuple of lists of the form (errors, warnings, info). The error list will be empty if the action has been correctly installed in the given image. In detail, this verifies that the file is present, and if the preserve attribute is not present, that the hashes and other attributes of the file match.""" path = os.path.normpath(os.path.sep.join( (img.get_root(), self.attrs["path"]))) lstat, errors, warnings, info, abort = \ self.verify_fsobj_common(img, stat.S_IFREG) if lstat: if not stat.S_ISREG(lstat.st_mode): self.replace_required = True if abort: assert errors self.replace_required = True return errors, warnings, info if path.lower().endswith("/bobcat") and args["verbose"] == True: # Returned as a purely informational (untranslated) # message so that no client should interpret it as a # reason to fail verification. info.append("Warning: package may contain bobcat! " "(http://xkcd.com/325/)") if "preserve" not in self.attrs and \ "timestamp" in self.attrs and lstat.st_mtime != \ misc.timestamp_to_time(self.attrs["timestamp"]): errors.append(_("Timestamp: %(found)s should be " "%(expected)s") % { "found": misc.time_to_timestamp(lstat.st_mtime), "expected": self.attrs["timestamp"] }) # avoid checking pkg.size if elfhash present; # different size files may have the same elfhash if "preserve" not in self.attrs and \ "pkg.size" in self.attrs and \ "elfhash" not in self.attrs and \ lstat.st_size != int(self.attrs["pkg.size"]): errors.append(_("Size: %(found)d bytes should be " "%(expected)d") % { "found": lstat.st_size, "expected": int(self.attrs["pkg.size"]) }) if "preserve" in self.attrs: if args["verbose"] == False or lstat is None: return errors, warnings, info if args["forever"] != True: return errors, warnings, info # # Check file contents # try: # This is a generic mechanism, but only used for libc on # x86, where the "best" version of libc is lofs-mounted # on the canonical path, foiling the standard verify # checks. is_mtpt = self.attrs.get("mountpoint", "").lower() == "true" elfhash = None elferror = None if "elfhash" in self.attrs and haveelf and not is_mtpt: # # It's possible for the elf module to # throw while computing the hash, # especially if the file is badly # corrupted or truncated. # try: elfhash = elf.get_dynamic(path)["hash"] except RuntimeError, e: errors.append("Elfhash: %s" % e) if elfhash is not None and \ elfhash != self.attrs["elfhash"]: elferror = _("Elfhash: %(found)s " "should be %(expected)s") % { "found": elfhash, "expected": self.attrs["elfhash"] } # If we failed to compute the content hash, or the # content hash failed to verify, try the file hash. # If the content hash fails to match but the file hash # matches, it indicates that the content hash algorithm # changed, since obviously the file hash is a superset # of the content hash. if (elfhash is None or elferror) and not is_mtpt: hashvalue, data = misc.get_data_digest(path) if hashvalue != self.hash: # Prefer the content hash error message. if "preserve" in self.attrs: info.append(_( "editable file has" " been changed")) elif elferror: errors.append(elferror) else: errors.append(_("Hash: " "%(found)s should be " "%(expected)s") % { "found": hashvalue, "expected": self.hash }) self.replace_required = True
# XXX There's a window where final_path doesn't exist, but we # probably don't care. if do_content and old_path: try: portable.rename(final_path, old_path) except OSError, e: if e.errno != errno.ENOENT: # Only care if file isn't gone already. raise # This is safe even if temp == final_path. portable.rename(temp, final_path) # Handle timestamp if specified (and content was installed). if do_content and "timestamp" in self.attrs: t = misc.timestamp_to_time(self.attrs["timestamp"]) try: os.utime(final_path, (t, t)) except OSError, e: if e.errno != errno.EACCES: raise # On Windows, the time cannot be changed on a # read-only file os.chmod(final_path, stat.S_IRUSR|stat.S_IWUSR) os.utime(final_path, (t, t)) os.chmod(final_path, mode) def verify(self, img, **args): """Returns a tuple of lists of the form (errors, warnings, info). The error list will be empty if the action has been
def verify(self, img, **args): """Returns a tuple of lists of the form (errors, warnings, info). The error list will be empty if the action has been correctly installed in the given image. In detail, this verifies that the file is present, and if the preserve attribute is not present, that the hashes and other attributes of the file match.""" if self.attrs.get("preserve") == "abandon": return [], [], [] path = self.get_installed_path(img.get_root()) lstat, errors, warnings, info, abort = \ self.verify_fsobj_common(img, stat.S_IFREG) if lstat: if not stat.S_ISREG(lstat.st_mode): self.replace_required = True if abort: assert errors self.replace_required = True return errors, warnings, info if path.lower().endswith("/bobcat") and args["verbose"] == True: # Returned as a purely informational (untranslated) # message so that no client should interpret it as a # reason to fail verification. info.append("Warning: package may contain bobcat! " "(http://xkcd.com/325/)") if "preserve" not in self.attrs and \ "timestamp" in self.attrs and lstat.st_mtime != \ misc.timestamp_to_time(self.attrs["timestamp"]): errors.append(_("Timestamp: {found} should be " "{expected}").format( found=misc.time_to_timestamp(lstat.st_mtime), expected=self.attrs["timestamp"])) # avoid checking pkg.size if we have any content-hashes present; # different size files may have the same content-hash if "preserve" not in self.attrs and \ "pkg.size" in self.attrs and \ not set(digest.RANKED_CONTENT_HASH_ATTRS).intersection( set(self.attrs.keys())) and \ lstat.st_size != int(self.attrs["pkg.size"]): errors.append(_("Size: {found:d} bytes should be " "{expected:d}").format(found=lstat.st_size, expected=int(self.attrs["pkg.size"]))) if "preserve" in self.attrs: if args["verbose"] == False or lstat is None: return errors, warnings, info if args["forever"] != True: return errors, warnings, info # # Check file contents. At the moment, the only content-hash # supported in pkg(5) is for ELF files, so this will need work # when additional content-hashes are added. # try: # This is a generic mechanism, but only used for libc on # x86, where the "best" version of libc is lofs-mounted # on the canonical path, foiling the standard verify # checks. is_mtpt = self.attrs.get("mountpoint", "").lower() == "true" elfhash = None elferror = None ehash_attr, elfhash_val, hash_func = \ digest.get_preferred_hash(self, hash_type=pkg.digest.CONTENT_HASH) if ehash_attr and haveelf and not is_mtpt: # # It's possible for the elf module to # throw while computing the hash, # especially if the file is badly # corrupted or truncated. # try: # Annoying that we have to hardcode this if ehash_attr == \ "pkg.content-hash.sha256": get_sha256 = True get_sha1 = False else: get_sha256 = False get_sha1 = True elfhash = elf.get_dynamic(path, sha1=get_sha1, sha256=get_sha256)[ehash_attr] except RuntimeError as e: errors.append( "ELF content hash: {0}".format(e)) if elfhash is not None and \ elfhash != elfhash_val: elferror = _("ELF content hash: " "{found} " "should be {expected}").format( found=elfhash, expected=elfhash_val) # If we failed to compute the content hash, or the # content hash failed to verify, try the file hash. # If the content hash fails to match but the file hash # matches, it indicates that the content hash algorithm # changed, since obviously the file hash is a superset # of the content hash. if (elfhash is None or elferror) and not is_mtpt: hash_attr, hash_val, hash_func = \ digest.get_preferred_hash(self) sha_hash, data = misc.get_data_digest(path, hash_func=hash_func) if sha_hash != hash_val: # Prefer the content hash error message. if "preserve" in self.attrs: info.append(_( "editable file has " "been changed")) elif elferror: errors.append(elferror) self.replace_required = True else: errors.append(_("Hash: " "{found} should be " "{expected}").format( found=sha_hash, expected=hash_val)) self.replace_required = True # Check system attributes. # Since some attributes like 'archive' or 'av_modified' # are set automatically by the FS, it makes no sense to # check for 1:1 matches. So we only check that the # system attributes specified in the action are still # set on the file. sattr = self.attrs.get("sysattr", None) if sattr: sattrs = sattr.split(",") if len(sattrs) == 1 and \ sattrs[0] not in portable.get_sysattr_dict(): # not a verbose attr, try as a compact set_attrs = portable.fgetattr(path, compact=True) sattrs = sattrs[0] else: set_attrs = portable.fgetattr(path) for a in sattrs: if a not in set_attrs: errors.append( _("System attribute '{0}' " "not set").format(a)) except EnvironmentError as e: if e.errno == errno.EACCES: errors.append(_("Skipping: Permission Denied")) else: errors.append(_("Unexpected Error: {0}").format( e)) except Exception as e: errors.append(_("Unexpected Exception: {0}").format(e)) return errors, warnings, info
def __do_alter_verify(self, pfmri, verbose=False, quiet=False, exit=0, parsable=False): # Alter the owner, group, mode, and timestamp of all files (and # directories) to something different than the package declares. m = manifest.Manifest() m.set_content(self.get_img_manifest(pfmri)) ctime = time.time() - 1000 for a in m.gen_actions(): if a.name not in ("file", "dir"): # Only want file or dir actions. continue ubin = portable.get_user_by_name("bin", None, False) groot = portable.get_group_by_name("root", None, False) fname = a.attrs["path"] fpath = os.path.join(self.get_img_path(), fname) os.chown(fpath, ubin, groot) os.chmod(fpath, misc.PKG_RO_FILE_MODE) os.utime(fpath, (ctime, ctime)) # Call pkg fix to fix them. fix_cmd = "fix" if verbose: fix_cmd += " -v" if quiet: fix_cmd += " -q" if parsable: fix_cmd += " --parsable=0" self.pkg("{0} {1}".format(fix_cmd, pfmri), exit=exit) if exit != 0: return exit editables = [] # Now verify that fix actually fixed them. for a in m.gen_actions(): if a.name not in ("file", "dir"): # Only want file or dir actions. continue # Validate standard attributes. self.validate_fsobj_attrs(a) # Now validate attributes that require special handling. fname = a.attrs["path"] fpath = os.path.join(self.get_img_path(), fname) lstat = os.lstat(fpath) # Verify that preserved files don't get renamed, and # the new ones are not installed if the file wasn't # missing already. preserve = a.attrs.get("preserve") if preserve == "renamenew": self.assert_(not os.path.exists(fpath + ".new")) elif preserve == "renameold": self.assert_(not os.path.exists(fpath + ".old")) if preserve: editables.append("{0}".format(a.attrs["path"])) # Verify timestamp (if applicable). ts = a.attrs.get("timestamp") if ts: expected = misc.timestamp_to_time(ts) actual = lstat.st_mtime if preserve: self.assertNotEqual( expected, actual, "timestamp expected {expected} == " "actual {actual} for " "{fname}".format(expected=expected, actual=actual, fname=fname)) else: self.assertEqual( expected, actual, "timestamp expected {expected} != " "actual {actual} for " "{fname}".format(expected=expected, actual=actual, fname=fname)) # Verify the parsable output (if applicable). if parsable: if editables: self.assertEqualParsable( self.output, affect_packages=["{0}".format(pfmri)], change_editables=[["updated", editables]]) else: self.assertEqualParsable(self.output, affect_packages=["{0}".format(pfmri)])
def verify(self, img, **args): """Returns a tuple of lists of the form (errors, warnings, info). The error list will be empty if the action has been correctly installed in the given image. In detail, this verifies that the file is present, and if the preserve attribute is not present, that the hashes and other attributes of the file match.""" path = os.path.normpath( os.path.sep.join((img.get_root(), self.attrs["path"]))) lstat, errors, warnings, info, abort = \ self.verify_fsobj_common(img, stat.S_IFREG) if lstat: if not stat.S_ISREG(lstat.st_mode): self.replace_required = True if abort: assert errors return errors, warnings, info if path.lower().endswith("/bobcat") and args["verbose"] == True: # Returned as a purely informational (untranslated) # message so that no client should interpret it as a # reason to fail verification. info.append("Warning: package may contain bobcat! " "(http://xkcd.com/325/)") if "preserve" not in self.attrs and \ "timestamp" in self.attrs and lstat.st_mtime != \ misc.timestamp_to_time(self.attrs["timestamp"]): errors.append( _("Timestamp: %(found)s should be " "%(expected)s") % { "found": misc.time_to_timestamp(lstat.st_mtime), "expected": self.attrs["timestamp"] }) # avoid checking pkg.size if elfhash present; # different size files may have the same elfhash if "preserve" not in self.attrs and \ "pkg.size" in self.attrs and \ "elfhash" not in self.attrs and \ lstat.st_size != int(self.attrs["pkg.size"]): errors.append( _("Size: %(found)d bytes should be " "%(expected)d") % { "found": lstat.st_size, "expected": int(self.attrs["pkg.size"]) }) if "preserve" in self.attrs: return errors, warnings, info if args["forever"] != True: return errors, warnings, info # # Check file contents # try: elfhash = None elferror = None if "elfhash" in self.attrs and haveelf: # # It's possible for the elf module to # throw while computing the hash, # especially if the file is badly # corrupted or truncated. # try: elfhash = elf.get_dynamic(path)["hash"] except RuntimeError, e: errors.append("Elfhash: %s" % e) if elfhash is not None and \ elfhash != self.attrs["elfhash"]: elferror = _("Elfhash: %(found)s " "should be %(expected)s") % { "found": elfhash, "expected": self.attrs["elfhash"] } # If we failed to compute the content hash, or the # content hash failed to verify, try the file hash. # If the content hash fails to match but the file hash # matches, it indicates that the content hash algorithm # changed, since obviously the file hash is a superset # of the content hash. if elfhash is None or elferror: hashvalue, data = misc.get_data_digest(path) if hashvalue != self.hash: # Prefer the content hash error message. if elferror: errors.append(elferror) else: errors.append( _("Hash: " "%(found)s should be " "%(expected)s") % { "found": hashvalue, "expected": self.hash }) self.replace_required = True
portable.chown(temp, owner, group) except OSError, e: if e.errno != errno.EPERM: raise # XXX There's a window where final_path doesn't exist, but we # probably don't care. if do_content and pres_type == "renameold": portable.rename(final_path, old_path) # This is safe even if temp == final_path. portable.rename(temp, final_path) # Handle timestamp if specified (and content was installed). if do_content and "timestamp" in self.attrs: t = misc.timestamp_to_time(self.attrs["timestamp"]) try: os.utime(final_path, (t, t)) except OSError, e: if e.errno != errno.EACCES: raise # On Windows, the time cannot be changed on a # read-only file os.chmod(final_path, stat.S_IRUSR | stat.S_IWUSR) os.utime(final_path, (t, t)) os.chmod(final_path, mode) def verify(self, img, **args): """Returns a tuple of lists of the form (errors, warnings, info). The error list will be empty if the action has been
def verify(self, img, **args): """ verify that file is present and if preserve attribute not present, that hashes match""" path = os.path.normpath(os.path.sep.join( (img.get_root(), self.attrs["path"]))) lstat, errors, abort = \ self.verify_fsobj_common(img, stat.S_IFREG) if lstat: if not stat.S_ISREG(lstat.st_mode): self.replace_required = True if abort: assert errors return errors if path.lower().endswith("/cat") and args["verbose"] == True: errors.append("Warning: package may contain bobcat! " "(http://xkcd.com/325/)") if "timestamp" in self.attrs and lstat.st_mtime != \ misc.timestamp_to_time(self.attrs["timestamp"]): errors.append("Timestamp: %s should be %s" % (misc.time_to_timestamp(lstat.st_mtime), self.attrs["timestamp"])) # avoid checking pkg.size if elfhash present; # different size files may have the same elfhash if "preserve" not in self.attrs and \ "pkg.size" in self.attrs and \ "elfhash" not in self.attrs and \ lstat.st_size != int(self.attrs["pkg.size"]): errors.append("Size: %d bytes should be %d" % \ (lstat.st_size, int(self.attrs["pkg.size"]))) if "preserve" in self.attrs: return errors if args["forever"] != True: return errors # # Check file contents # try: elfhash = None elferror = None if "elfhash" in self.attrs and haveelf: # # It's possible for the elf module to # throw while computing the hash, # especially if the file is badly # corrupted or truncated. # try: elfhash = elf.get_dynamic(path)["hash"] except RuntimeError, e: errors.append("Elfhash: %s" % e) if elfhash is not None and \ elfhash != self.attrs["elfhash"]: elferror = "Elfhash: %s should be %s" % \ (elfhash, self.attrs["elfhash"]) # If we failed to compute the content hash, or the # content hash failed to verify, try the file hash. # If the content hash fails to match but the file hash # matches, it indicates that the content hash algorithm # changed, since obviously the file hash is a superset # of the content hash. if elfhash is None or elferror: hashvalue, data = misc.get_data_digest(path) if hashvalue != self.hash: # Prefer the content hash error message. if elferror: errors.append(elferror) else: errors.append("Hash: %s should be %s" % \ (hashvalue, self.hash)) self.replace_required = True
def verify(self, img, **args): """ verify that file is present and if preserve attribute not present, that hashes match""" path = os.path.normpath( os.path.sep.join((img.get_root(), self.attrs["path"]))) lstat, errors, abort = \ self.verify_fsobj_common(img, stat.S_IFREG) if lstat: if not stat.S_ISREG(lstat.st_mode): self.replace_required = True if abort: assert errors return errors if path.lower().endswith("/cat") and args["verbose"] == True: errors.append("Warning: package may contain bobcat! " "(http://xkcd.com/325/)") if "timestamp" in self.attrs and lstat.st_mtime != \ misc.timestamp_to_time(self.attrs["timestamp"]): errors.append("Timestamp: %s should be %s" % (misc.time_to_timestamp( lstat.st_mtime), self.attrs["timestamp"])) # avoid checking pkg.size if elfhash present; # different size files may have the same elfhash if "preserve" not in self.attrs and \ "pkg.size" in self.attrs and \ "elfhash" not in self.attrs and \ lstat.st_size != int(self.attrs["pkg.size"]): errors.append("Size: %d bytes should be %d" % \ (lstat.st_size, int(self.attrs["pkg.size"]))) if "preserve" in self.attrs: return errors if args["forever"] != True: return errors # # Check file contents # try: elfhash = None elferror = None if "elfhash" in self.attrs and haveelf: # # It's possible for the elf module to # throw while computing the hash, # especially if the file is badly # corrupted or truncated. # try: elfhash = elf.get_dynamic(path)["hash"] except RuntimeError, e: errors.append("Elfhash: %s" % e) if elfhash is not None and \ elfhash != self.attrs["elfhash"]: elferror = "Elfhash: %s should be %s" % \ (elfhash, self.attrs["elfhash"]) # If we failed to compute the content hash, or the # content hash failed to verify, try the file hash. # If the content hash fails to match but the file hash # matches, it indicates that the content hash algorithm # changed, since obviously the file hash is a superset # of the content hash. if elfhash is None or elferror: hashvalue, data = misc.get_data_digest(path) if hashvalue != self.hash: # Prefer the content hash error message. if elferror: errors.append(elferror) else: errors.append("Hash: %s should be %s" % \ (hashvalue, self.hash)) self.replace_required = True