def install(self, pkgplan, orig): """Client-side method that installs a link.""" path = self.attrs["path"] target = self.attrs["target"] path = os.path.normpath( os.path.sep.join((pkgplan.image.get_root(), path))) if not os.path.exists(os.path.dirname(path)): self.makedirs(os.path.dirname(path), mode=0755) # XXX The exists-unlink-symlink path appears to be as safe as it # gets to modify a link with the current symlink(2) interface. if os.path.lexists(path): try: os.unlink(path) except EnvironmentError, e: if e.errno == errno.EPERM: # Unlinking a directory gives EPERM, # which is confusing, so ignore errno # and give a good message. path = self.attrs["path"] raise ActionExecutionError( self, e, "attempted to remove link '%s' but " "found a directory" % path, ignoreerrno=True) else: raise ActionExecutionError(self, e)
def install(self, pkgplan, orig): """Client-side method that installs a hard link.""" target = self.get_target_path() path = self.get_installed_path(pkgplan.image.get_root()) # Don't allow installation through symlinks. self.fsobj_checkpath(pkgplan, path) if not os.path.exists(os.path.dirname(path)): self.makedirs(os.path.dirname(path), mode=misc.PKG_DIR_MODE, fmri=pkgplan.destination_fmri) elif os.path.exists(path): self.remove(pkgplan) fulltarget = os.path.normpath(os.path.sep.join( (pkgplan.image.get_root(), target))) try: os.link(fulltarget, path) except EnvironmentError as e: if e.errno != errno.ENOENT: raise ActionExecutionError(self, error=e) # User or another process has removed target for # hardlink, a package hasn't declared correct # dependencies, or the target hasn't been installed # yet. err_txt = _("Unable to create hard link {path}; " "target {target} is missing.").format( path=path, target=fulltarget) raise ActionExecutionError(self, details=err_txt, error=e, fmri=pkgplan.destination_fmri)
def install(self, pkgplan, orig): """Client-side method that installs a hard link.""" path = self.attrs["path"] target = self.get_target_path() path = os.path.normpath(os.path.sep.join( (pkgplan.image.get_root(), path))) if not os.path.exists(os.path.dirname(path)): self.makedirs(os.path.dirname(path), mode=0755) elif os.path.exists(path): os.unlink(path) fulltarget = os.path.normpath(os.path.sep.join( (pkgplan.image.get_root(), target))) try: os.link(fulltarget, path) except EnvironmentError, e: if e.errno == errno.ENOENT: raise ActionExecutionError(self, e, "missing hard link target '%s'" % target) else: raise ActionExecutionError(self, e)
def install(self, pkgplan, orig): """Client-side method that installs the license.""" owner = 0 group = 0 # ensure "path" is initialized. it may not be if we've loaded # a plan that was previously prepared. self.preinstall(pkgplan, orig) stream = self.data() path = self.get_installed_path(pkgplan.image.get_root()) # make sure the directory exists and the file is writable if not os.path.exists(os.path.dirname(path)): self.makedirs(os.path.dirname(path), mode=misc.PKG_DIR_MODE, fmri=pkgplan.destination_fmri) elif os.path.exists(path): os.chmod(path, misc.PKG_FILE_MODE) lfile = open(path, "wb") try: hash_attr, hash_val, hash_func = \ digest.get_preferred_hash(self) shasum = misc.gunzip_from_stream(stream, lfile, hash_func=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: lfile.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)) os.chmod(path, misc.PKG_RO_FILE_MODE) try: portable.chown(path, owner, group) except OSError as e: if e.errno != errno.EPERM: raise
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)