def __getattribute__(self, attr): # Restrict access to methods that are implemented in AbstractFS class - Calling methods from base class may # not be safe to use. # FIXME: Need to fix these for only allow methods that are defined here. if not WrapFS: return method_list = [ x for x, y in WrapFS.__dict__.items() if type(y) == FunctionType ] if attr in method_list: if attr in super(AbstractFS, self).__getattribute__( "__dict__").keys() or attr not in ["match", "settext"]: # These methods have been overwritten and are safe to use. try: return super(AbstractFS, self).__getattribute__(attr) except KeyError as ke: raise FilesystemError("Invalid Path : {}".format(ke)) else: raise NotImplementedError( "The method requested is not supported by Conpot's VFS") else: try: return super(AbstractFS, self).__getattribute__(attr) except KeyError as ke: raise FilesystemError("Invalid Path : {}".format(ke))
def getfile(self, path, file, chunk_size=None, **options): # check where there exists a copy in the cache if (self.exists(self.norm_path(path)) and self.norm_path(path) in self._cache.keys()): self.setinfo(self.norm_path(path), {}) return self._wrap_fs.getfile(self.norm_path(path), file, chunk_size, **options) else: raise FilesystemError("Can't get. File does not exist!")
def norm_path(self, path): path = "/" if path == "." else path try: _path = (self.validatepath(self._cwd + path) if self._cwd not in path else self.validatepath(path)) return _path except fs.errors.FSError: logger.debug("Could not validate path: {}".format(path)) raise FilesystemError("Could not validate path: {}".format(path))
def register_user(self, name: str, uid: int) -> None: """Store all user related data for the file system.""" assert name and isinstance(name, str) self._users[uid] = {"user": name} # let us check for duplicate usernames/group names if len(set([v["user"] for k, v in self._users.items()])) != len( self._users.keys()): _uname = self._users.pop(uid)["user"] raise FilesystemError( "Can't add users with duplicate uname: {}.".format(_uname))
def norm_path(self, path): path = '/' if path == '.' else path try: _path = self.validatepath( self._cwd + path) if self._cwd not in path else self.validatepath(path) return _path except fs.errors.FSError: logger.debug('Could not validate path: {}'.format(path)) raise FilesystemError('Could not validate path: {}'.format(path))
def create_group(self, name: str, gid: int) -> None: """ Store all group related data for the file system. :param name: Name of the group :param gid: gid of the group """ assert name and isinstance(name, str) self._grps[gid] = {"group": name} if len(set([v["group"] for k, v in self._grps.items()])) != len( self._grps.keys()): _gname = self._grps.pop(gid) raise FilesystemError( "Can't create groups with duplicate names: {}.".format(_gname))
def chown(self, fs_path: str, uid: int, gid: int, recursive: Optional[bool] = False) -> None: """Change the owner of a specified file. Wrapper for os.chown :param fs_path: path or directory in the VFS where chown would be executed. :param uid: The `uid` of the user. **User must be a registered user on the filesystem or an exception would be thrown. :param gid: The `gid` of the group **Group must be a registered group on the filesystem or an exception would be thrown. :param recursive: If the given path is directory, then setting the recursive option to true would walk down the tree and recursive change permissions in the cache. ** `fs_path` needs to be the absolute path w.r.t to the vfs. If you are in a sub file system, please use `subvfs.getcwd()` to get the current directory. ** """ path = self.norm_path(fs_path) try: assert isinstance(uid, int) and isinstance(gid, int) except AssertionError: logger.exception("Integers expected got {} - {}".format(uid, gid)) if self.isdir(path) or self.isfile(path): assert self._grps[gid] and self._users[uid] chown_cache = { "access": { "user": self._users[uid]["user"], "uid": self._users[uid], "group": self._grps[gid]["group"], "gid": self._grps[gid], } } if self.isdir(path) and recursive: if self.norm_path(path) is not "/": self.setinfo(path, chown_cache) sub_dir = self.opendir(path) for _path, _ in sub_dir.walk.info(): assert self._cache[self.norm_path(path + _path)] self.setinfo(path + _path, chown_cache) sub_dir.close() else: self.setinfo(path, chown_cache) else: # TODO: map this to the actual output of os.chown raise FilesystemError("File not found for chown")
def add_users_to_group(self, gid: int, uids: List) -> None: """Add list of users to an existing group :param gid: Group id of the group. :param uids: List of registers users that belong to this group """ try: assert gid in self._grps.keys() for i in uids: if i not in self._users.keys(): raise AssertionError _uids = set(uids) if gid in self._user_grps.keys(): self._user_grps[gid] += _uids else: self._user_grps[gid] = _uids except AssertionError: raise FilesystemError( "uid/gid does not exist in the file system. Please register it via create_group/" "register_user method.")
def setinfo(self, path, info): """ Higher level function to directly change values in the file system. Dictionary specified here changes cache values. :param path: path of the file that is to be changed :param info: Raw Info object. Please check pyfilesystem2's docs for more info. """ assert path and isinstance(path, str) path = self.norm_path(path) if "lstat" not in info: try: if "details" in info: details = info["details"] if "accessed" in details or "modified" in details: return self._wrap_fs.setinfo(path, info) finally: try: assert self._cache[path] except (AssertionError, KeyError): # This is the first time we have seen this file. Let us create this entry. logger.debug( "Creating cache for file/directory : {}".format(path)) self._cache[path] = self._wrap_fs.getinfo(path, namespaces=[ "basic", "access", "details", "stat", "link" ]) # update the 'accessed' and 'modified' time. self.settimes(path) if "access" in info: access = info["access"] if "permissions" in access: self._cache[path].raw["access"][ "permissions"] = access["permissions"] self._cache[path].raw["details"][ "metadata_changed"] = fs.time.datetime_to_epoch( datetime.now()) if "user" in access or "uid" in access: try: if "user" in access or ("user" in access and "uid" in access): self._cache[path].raw["access"][ "user"] = access["user"] [_uid] = [ key for key, value in self._users.items() if value == { "user": access["user"] } ] self._cache[path].raw["access"]["uid"] = _uid self._cache[path].raw["details"][ "metadata_changed"] = fs.time.datetime_to_epoch( datetime.now()) else: # Must be 'uid' that is available. _uid = int(access["uid"]) # type: ignore self._cache[path].raw["access"]["uid"] = _uid self._cache[path].raw["access"][ "user"] = self._users[_uid]["user"] self._cache[path].raw["details"][ "metadata_changed"] = fs.time.datetime_to_epoch( datetime.now()) except (TypeError, AssertionError, KeyError): raise if "group" in access or "gid" in access: try: if "group" in access or ("group" in access and "gid" in access): self._cache[path].raw["access"][ "group"] = access["group"] [_gid] = [ key for key, value in self._grps.items() if value == { "group": access["group"] } ] self._cache[path].raw["access"]["gid"] = _gid self._cache[path].raw["details"][ "metadata_changed"] = fs.time.datetime_to_epoch( datetime.now()) else: # Must be 'gid' that is available. _gid = int(access["gid"]) # type: ignore self._cache[path].raw["access"]["gid"] = _gid self._cache[path].raw["access"][ "group"] = self._grps[_gid]["group"] self._cache[path].raw["details"][ "metadata_changed"] = fs.time.datetime_to_epoch( datetime.now()) except (TypeError, AssertionError, KeyError): raise else: raise FilesystemError("lstat is not currently supported!")
def setinfo(self, path, info): """ Higher level function to directly change values in the file system. Dictionary specified here changes cache values. :param path: path of the file that is to be changed :param info: Raw Info object. Please check pyfilesystem2's docs for more info. """ assert path and isinstance(path, str) path = self.norm_path(path) if 'lstat' not in info: try: if 'details' in info: details = info['details'] if 'accessed' in details or 'modified' in details: return self._wrap_fs.setinfo(path, info) finally: try: assert self._cache[path] except (AssertionError, KeyError): # This is the first time we have seen this file. Let us create this entry. logger.debug( 'Creating cache for file/directory : {}'.format(path)) self._cache[path] = self._wrap_fs.getinfo(path, namespaces=[ 'basic', 'access', 'details', 'stat', 'link' ]) # update the 'accessed' and 'modified' time. self.settimes(path) if 'access' in info: access = info['access'] if 'permissions' in access: self._cache[path].raw['access'][ 'permissions'] = access['permissions'] self._cache[path].raw['details'][ 'metadata_changed'] = fs.time.datetime_to_epoch( datetime.now()) if 'user' in access or 'uid' in access: try: if 'user' in access or ('user' in access and 'uid' in access): self._cache[path].raw['access'][ 'user'] = access['user'] [_uid] = [ key for key, value in self._users.items() if value == { 'user': access['user'] } ] self._cache[path].raw['access']['uid'] = _uid self._cache[path].raw['details'][ 'metadata_changed'] = fs.time.datetime_to_epoch( datetime.now()) else: # Must be 'uid' that is available. _uid = int(access['uid']) # type: ignore self._cache[path].raw['access']['uid'] = _uid self._cache[path].raw['access'][ 'user'] = self._users[_uid]['user'] self._cache[path].raw['details'][ 'metadata_changed'] = fs.time.datetime_to_epoch( datetime.now()) except (TypeError, AssertionError, KeyError): raise if 'group' in access or 'gid' in access: try: if 'group' in access or ('group' in access and 'gid' in access): self._cache[path].raw['access'][ 'group'] = access['group'] [_gid] = [ key for key, value in self._grps.items() if value == { 'group': access['group'] } ] self._cache[path].raw['access']['gid'] = _gid self._cache[path].raw['details'][ 'metadata_changed'] = fs.time.datetime_to_epoch( datetime.now()) else: # Must be 'gid' that is available. _gid = int(access['gid']) # type: ignore self._cache[path].raw['access']['gid'] = _gid self._cache[path].raw['access'][ 'group'] = self._grps[_gid]['group'] self._cache[path].raw['details'][ 'metadata_changed'] = fs.time.datetime_to_epoch( datetime.now()) except (TypeError, AssertionError, KeyError): raise else: raise FilesystemError('lstat is not currently supported!')