def install(self, pkgplan, orig): """Client-side method that installs the license.""" mode = 0444 owner = 0 group = 0 path = self.attrs["path"] stream = self.data() path = os.path.normpath(os.path.sep.join( (pkgplan.image.get_root(), path))) # 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=0755) elif os.path.exists(path): os.chmod(path, 0644) lfile = file(path, "wb") # XXX Should throw an exception if shasum doesn't match # self.hash shasum = misc.gunzip_from_stream(stream, lfile) lfile.close() stream.close() os.chmod(path, mode) try: portable.chown(path, owner, group) except OSError, e: if e.errno != errno.EPERM: raise
def install(self, pkgplan, orig): """Client-side method that installs the license.""" owner = 0 group = 0 path = self.attrs["path"] stream = self.data() path = os.path.normpath( os.path.sep.join((pkgplan.image.get_root(), path))) # 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 = file(path, "wb") # XXX Should throw an exception if shasum doesn't match # self.hash shasum = misc.gunzip_from_stream(stream, lfile) lfile.close() stream.close() os.chmod(path, misc.PKG_RO_FILE_MODE) try: portable.chown(path, owner, group) except OSError, e: if e.errno != errno.EPERM: raise
def copyfile(src_path, dst_path): """copy a file, preserving attributes, ownership, etc. where possible""" fs = os.lstat(src_path) shutil.copy2(src_path, dst_path) try: portable.chown(dst_path, fs.st_uid, fs.st_gid) except OSError, e: if e.errno != errno.EPERM: raise
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 makedirs(path, **kw): """Make directory specified by 'path' with given permissions, as well as all missing parent directories. Permissions are specified by the keyword arguments 'mode', 'uid', and 'gid'. The difference between this and os.makedirs() is that the permissions specify only those of the leaf directory. Missing parent directories inherit the permissions of the deepest existing directory. The leaf directory will also inherit any permissions not explicitly set.""" # generate the components of the path. The first # element will be empty since all absolute paths # always start with a root specifier. pathlist = portable.split_path(path) # Fill in the first path with the root of the filesystem # (this ends up being something like C:\ on windows systems, # and "/" on unix. pathlist[0] = portable.get_root(path) g = enumerate(pathlist) for i, e in g: if not os.path.isdir(os.path.join(*pathlist[:i + 1])): break else: # XXX Because the filelist codepath may create # directories with incorrect permissions (see # pkgtarfile.py), we need to correct those permissions # here. Note that this solution relies on all # intermediate directories being explicitly created by # the packaging system; otherwise intermediate # directories will not get their permissions corrected. stat = os.stat(path) mode = kw.get("mode", stat.st_mode) uid = kw.get("uid", stat.st_uid) gid = kw.get("gid", stat.st_gid) try: if mode != stat.st_mode: os.chmod(path, mode) if uid != stat.st_uid or gid != stat.st_gid: portable.chown(path, uid, gid) except OSError, e: if e.errno != errno.EPERM and \ e.errno != errno.ENOSYS: raise return
# XXX Because the filelist codepath may create # directories with incorrect permissions (see # pkgtarfile.py), we need to correct those permissions # here. Note that this solution relies on all # intermediate directories being explicitly created by # the packaging system; otherwise intermediate # directories will not get their permissions corrected. fs = os.lstat(path) mode = kw.get("mode", fs.st_mode) uid = kw.get("uid", fs.st_uid) gid = kw.get("gid", fs.st_gid) try: if mode != fs.st_mode: os.chmod(path, mode) if uid != fs.st_uid or gid != fs.st_gid: portable.chown(path, uid, gid) except OSError, e: if e.errno != errno.EPERM and \ e.errno != errno.ENOSYS: raise return fs = os.stat(os.path.join(*pathlist[:i])) for i, e in g: p = os.path.join(*pathlist[:i]) try: os.mkdir(p, fs.st_mode) except OSError, e: if e.ernno != errno.ENOTDIR: raise err_txt = _("Unable to create %(path)s; a "
os.chmod(path, mode) if uid != stat.st_uid or gid != stat.st_gid: portable.chown(path, uid, gid) except OSError, e: if e.errno != errno.EPERM and \ e.errno != errno.ENOSYS: raise return stat = os.stat(os.path.join(*pathlist[:i])) for i, e in g: p = os.path.join(*pathlist[:i]) os.mkdir(p, stat.st_mode) os.chmod(p, stat.st_mode) try: portable.chown(p, stat.st_uid, stat.st_gid) except OSError, e: if e.errno != errno.EPERM: raise # Create the leaf with any requested permissions, substituting # missing perms with the parent's perms. mode = kw.get("mode", stat.st_mode) uid = kw.get("uid", stat.st_uid) gid = kw.get("gid", stat.st_gid) os.mkdir(path, mode) os.chmod(path, mode) try: portable.chown(path, uid, gid) except OSError, e: if e.errno != errno.EPERM:
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)
}) else: temp = final_path try: os.chmod(temp, mode) except OSError, 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, 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, e: if e.errno != errno.ENOENT: # Only care if file isn't gone already. raise # This is safe even if temp == final_path.
# self.hash else: temp = final_path try: os.chmod(temp, mode) except OSError, 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, 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"])
os.chmod(path, mode) # if we're salvaging contents, move 'em now. # directories with "salvage-from" attribute # set will scavenge any available contents # that matches specified directory and # move it underneath itself on install or update. # This is here to support directory rename # when old directory has unpackaged contents, or # consolidation of content from older directories. for salvage_from in self.attrlist("salvage-from"): pkgplan.salvage_from(salvage_from, path) if not orig or oowner != owner or ogroup != group: try: portable.chown(path, owner, group) except OSError, e: if e.errno != errno.EPERM and \ e.errno != errno.ENOSYS: raise 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.""" lstat, errors, warnings, info, abort = \ self.verify_fsobj_common(img, stat.S_IFDIR) return errors, warnings, info def remove(self, pkgplan):
# user, if we set perms u-w, we won't be able to put anything in # it, which is often not what we want at install time. We save # the chmods for the postinstall phase, but it's always possible # that a later package install will want to place something in # this directory and then be unable to. So perhaps we need to # (in all action types) chmod the parent directory to u+w on # failure, and chmod it back aftwards. The trick is to # recognize failure due to missing file_dac_write in contrast to # other failures. Or can we require that everyone simply have # file_dac_write who wants to use the tools. Probably not. elif mode != omode: os.chmod(path, mode) if not orig or oowner != owner or ogroup != group: try: portable.chown(path, owner, group) except OSError, e: if e.errno != errno.EPERM and \ e.errno != errno.ENOSYS: raise def verify(self, img, **args): """ make sure directory is correctly installed""" lstat, errors, abort = \ self.verify_fsobj_common(img, stat.S_IFDIR) return errors def remove(self, pkgplan): localpath = os.path.normpath(self.attrs["path"]) path = os.path.normpath(
def install(self, pkgplan, orig): """Client-side method that installs a directory.""" 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) omode = oowner = ogroup = None owner, group = self.get_fsobj_uid_gid(pkgplan, pkgplan.destination_fmri) if orig: try: omode = int(orig.attrs.get("mode", None), 8) except (TypeError, ValueError): # Mode isn't valid, so let validate raise a more # informative error. orig.validate(fmri=pkgplan.origin_fmri) oowner, ogroup = orig.get_fsobj_uid_gid(pkgplan, pkgplan.origin_fmri) path = self.get_installed_path(pkgplan.image.get_root()) # Don't allow installation through symlinks. self.fsobj_checkpath(pkgplan, path) # XXX Hack! (See below comment.) if not portable.is_admin(): mode |= stat.S_IWUSR if not orig: self.__create_directory(pkgplan, path, mode) # The downside of chmodding the directory is that as a non-root # user, if we set perms u-w, we won't be able to put anything in # it, which is often not what we want at install time. We save # the chmods for the postinstall phase, but it's always possible # that a later package install will want to place something in # this directory and then be unable to. So perhaps we need to # (in all action types) chmod the parent directory to u+w on # failure, and chmod it back aftwards. The trick is to # recognize failure due to missing file_dac_write in contrast to # other failures. Or can we require that everyone simply have # file_dac_write who wants to use the tools. Probably not. elif mode != omode: try: os.chmod(path, mode) except Exception as e: if e.errno != errno.EPERM and e.errno != \ errno.ENOSYS: # Assume chmod failed due to a # recoverable error. self.__create_directory(pkgplan, path, mode) omode = oowner = ogroup = None # if we're salvaging contents, move 'em now. # directories with "salvage-from" attribute # set will scavenge any available contents # that matches specified directory and # move it underneath itself on install or update. # This is here to support directory rename # when old directory has unpackaged contents, or # consolidation of content from older directories. for salvage_from in self.attrlist("salvage-from"): pkgplan.salvage_from(salvage_from, path) if not orig or oowner != owner or ogroup != group: try: portable.chown(path, owner, group) except OSError as e: if e.errno != errno.EPERM and \ e.errno != errno.ENOSYS: # Assume chown failed due to a # recoverable error. self.__create_directory(pkgplan, path, mode, uid=owner, gid=group)