def on_rmdir(self, httpfs_request_args): """ Called when HttpFsRequest.OP_RMDIR is requested :param httpfs_request_args: The client request args dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) _error = None _err = None try: os.rmdir(path) except FileNotFoundError as e: logging.error("{} not found".format(path)) err = errno.ENOENT _error = e except OSError as e: err = e.errno _error = e except Exception as e: err = errno.EIO _error = e if _error != None: logging.error("Error during rmdir request: {}".format(_error)) response_obj.set_err_no(_err) response_obj.set_data({"message": str(_error)}) self.send_json_response(200, response_obj.as_dict())
def on_readdir(self, httpfs_request_args): """ Called when HttpFsRequest.OP_READDIR is requested :param httpfs_request_args: The client request args dict """ path = self.get_abs_path(httpfs_request_args["path"]) uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] file_stats = os.stat(path) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid response_obj = HttpFsResponse() if uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IRUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IRGRP else: access_ok = file_stats.st_mode & stat.S_IROTH if access_ok: dir_listing = os.listdir(path) dir_listing = [".", ".."] + dir_listing response_obj.set_data({"dir_listing": dir_listing}) else: logging.warning("Error during readdir request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) self.send_json_response(200, response_obj.as_dict())
def on_release(self, httpfs_request_args): """ Called when HttpFsRequest.OP_RELEASE is requested :param httpfs_request_args: The client request args dict """ response_obj = HttpFsResponse() try: os.close(httpfs_request_args["file_descriptor"]) except Exception as e: logging.error("Error during release request: {}".format(e)) response_obj.set_err_no(errno.EIO) self.send_json_response(200, response_obj.as_dict())
def on_flush(self, httpfs_request_args): """ Called when HttpFsRequest.OP_FLUSH is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() try: os.fsync(httpfs_request_args["file_descriptor"]) except Exception as e: logging.error("Error during flush request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_symlink(self, httpfs_request_args): """ Called when HttpFsRequest.OP_SYMLINK is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() source = self.get_abs_path(httpfs_request_args["source"]) target = self.get_abs_path(httpfs_request_args["target"]) try: os.symlink(source, target) except Exception as e: logging.error("Error during symlink request: {}".format(e)) response_obj.set_err_no(errno.EIO) self.send_json_response(200, response_obj.as_dict())
def on_mkdir(self, httpfs_request_args): """ Called when HttpFsRequest.OP_MKDIR is requested :param httpfs_request_args: The client request args dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) try: os.mkdir(path, mode=httpfs_request_args["mode"]) except Exception as e: logging.error("Error during mkdir request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_read(self, httpfs_request_args): """ Called when HttpFsRequest.OP_READ is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() file_descriptor = httpfs_request_args["file_descriptor"] offset = httpfs_request_args["offset"] size = httpfs_request_args["size"] uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] file_stats = os.stat(file_descriptor) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid if uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IRUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IRGRP else: access_ok = file_stats.st_mode & stat.S_IROTH try: if access_ok: with self.server.get_fs_lock(): os.lseek(file_descriptor, offset, os.SEEK_SET) bytes_read = os.read(file_descriptor, size) response_obj.set_data({ "bytes_read": base64.standard_b64encode(bytes_read).decode("utf-8") }) else: logging.warning("Error during read request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) except Exception as e: logging.error("Error during read request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_link(self, httpfs_request_args): """ Called when HttpFsRequest.OP_LINK is requested :param httpfs_request_args: The client request args dict """ target_path = self.get_abs_path(httpfs_request_args["target"]) source_path = self.get_abs_path(httpfs_request_args["source"]) response_obj = HttpFsResponse() try: os.link(source_path, target_path) except Exception as e: logging.error("Error during link request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_truncate(self, httpfs_request_args): """ Called when HttpFsRequest.OP_TRUNCATE is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) length = httpfs_request_args["length"] try: with open(path, 'r+') as f: f.truncate(length) except Exception as e: logging.error("Error during truncate request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(200, response_obj.as_dict())
def on_readlink(self, httpfs_request_args): # TODO: This doesn't work """ Called when HttpFsRequest.OP_RELEASE is requested :param httpfs_request_args: The client request args dict """ response_obj = HttpFsResponse() link_path = self.get_abs_path(httpfs_request_args["link_path"]) try: target = os.readlink(link_path) if target.startswith("/"): target = os.path.relpath(target, self.server.get_fs_root()) response_obj.set_data({"target": target}) except Exception as e: logging.error("Error during readlink request: {}".format(e)) response_obj.set_err_no(errno.EIO) self.send_json_response(200, response_obj.as_dict())
def on_create(self, httpfs_request_args): """ Called when HttpFsRequest.OP_ACCESS is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] dir_stats = os.stat(os.path.dirname(path)) is_dir_owner = dir_stats.st_uid == uid is_dir_group = dir_stats.st_gid == gid if uid == 0: access_ok = True elif is_dir_owner: access_ok = dir_stats.st_mode & stat.S_IWUSR elif is_dir_group: access_ok = dir_stats.st_mode & stat.S_IWGRP else: access_ok = dir_stats.st_mode & stat.S_IWOTH try: if access_ok: fd = os.open(path, flags=os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_ASYNC | os.O_NOATIME, mode=httpfs_request_args["mode"]) os.chown(path, uid, gid) response_obj.set_data({"file_descriptor": fd}) else: logging.warning("Error during create request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) except Exception as e: logging.error("Error during create request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_chown(self, httpfs_request_args): """ Called when HttpFsRequest.OP_FLUSH is received from the client :param httpfs_request_args: The client request arg dict """ client = self.client_address[0] response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] caller_uid = httpfs_request_args["caller_uid"] caller_gid = httpfs_request_args["caller_gid"] file_stats = os.stat(path) is_owner = file_stats.st_uid == caller_uid is_group = file_stats.st_gid == caller_gid if caller_uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IWUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IWGRP else: access_ok = file_stats.st_mode & stat.S_IWOTH # TODO: Don't let me if it isn't mine try: if access_ok: os.chown(path, uid, gid) logging.debug("Successful chown for {}".format(client)) else: response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) logging.warning("Error during chown request: Access denied") except Exception as e: logging.error("Error during chown request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_utimens(self, httpfs_request_args): """ Called when HttpFsRequest.OP_UTIMENS is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) times = httpfs_request_args["times"] if isinstance(times, list): times = tuple(times) uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] file_stats = os.stat(path) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid if uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IWUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IWGRP else: access_ok = file_stats.st_mode & stat.S_IWOTH try: if access_ok: os.utime(path, times) else: logging.warning("Error during write request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) except Exception as e: logging.error("Error during utimens request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_getattr(self, httpfs_request_args): """ Called when HttpFsRequest.OP_GET_ATTR is requested :param httpfs_request_args: The client request args dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) try: os_attrs = os.lstat(path) attrs = dict() for k in _HttpFsRequestHandler.GETATTR_KEYS: attrs[k] = getattr(os_attrs, k) response_obj.set_data(attrs) except FileNotFoundError: logging.warning("{} not found".format(path)) response_obj.set_err_no(errno.ENOENT) self.send_json_response(200, response_obj.as_dict())
def on_rename(self, httpfs_request_args): """ Called when HttpFsRequest.OP_RENAME is requested :param httpfs_request_args: The client request args dict """ old_path = self.get_abs_path(httpfs_request_args["old_path"]) new_path = self.get_abs_path(httpfs_request_args["new_path"]) uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] file_stats = os.stat(old_path) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid response_obj = HttpFsResponse() if uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IWUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IWGRP else: access_ok = file_stats.st_mode & stat.S_IWOTH try: if access_ok: os.rename(old_path, new_path) else: logging.warning("Error during rename request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) except Exception as e: logging.error("Error during rename request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_unlink(self, httpfs_request_args): """ Called when HttpFsRequest.OP_UNLINK is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] try: file_stats = os.stat(path) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid if uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IWUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IWGRP else: access_ok = file_stats.st_mode & stat.S_IWOTH if access_ok: os.unlink(path) else: logging.warning("Error during unlink request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) except OSError as e: logging.error("Error during unlink request: {}".format(e)) response_obj.set_err_no(e.errno) response_obj.set_data({"message": str(e)}) except Exception as e: logging.error("Error during unlink request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(200, response_obj.as_dict())
def on_open(self, httpfs_request_args): """ Called when HttpFsRequest.OP_OPEN is requested :param httpfs_request_args: The client request args dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) # Hardcode async and noatime flags = httpfs_request_args["flags"] | os.O_ASYNC | os.O_NOATIME uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] dir_stats = os.stat(os.path.dirname(path)) is_dir_owner = dir_stats.st_uid == uid is_dir_group = dir_stats.st_gid == gid if uid == 0: access_ok = True elif is_dir_owner: access_ok = dir_stats.st_mode & stat.S_IXUSR elif is_dir_group: access_ok = dir_stats.st_mode & stat.S_IXGRP else: access_ok = dir_stats.st_mode & stat.S_IXOTH if access_ok and os.path.exists(path): file_stats = os.stat(path) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid read_requested = (flags & os.O_RDONLY or flags & os.O_RDWR or flags & os.O_EXCL) write_requested = (flags & os.O_WRONLY or flags & os.O_RDWR or flags & os.O_APPEND) if uid == 0: access_ok = True elif is_owner: if read_requested: access_ok = file_stats.st_mode & stat.S_IRUSR elif write_requested: access_ok = file_stats.st_mode & stat.S_IWUSR elif is_group: if read_requested: access_ok = file_stats.st_mode & stat.S_IRGRP elif write_requested: access_ok = file_stats.st_mode & stat.S_IWGRP else: if read_requested: access_ok = file_stats.st_mode & stat.S_IROTH elif write_requested: access_ok = file_stats.st_mode & stat.S_IROTH try: if access_ok: fd = os.open(self.get_abs_path(httpfs_request_args["path"]), flags) response_obj.set_data({"file_descriptor": fd}) else: response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) logging.warning("Error during open request: Access denied") except Exception as e: logging.error("Error during open request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
def on_write(self, httpfs_request_args): """ Called when HttpFsRequest.OP_UTIMENS is received from the client :param httpfs_request_args: The client request arg dict """ start_time = time.time() response_obj = HttpFsResponse() file_descriptor = httpfs_request_args["file_descriptor"] data = base64.standard_b64decode(httpfs_request_args["data"]) offset = httpfs_request_args["offset"] uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] file_stats = os.stat(file_descriptor) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid if uid == 0: access_ok = True elif is_owner: access_ok = file_stats.st_mode & stat.S_IWUSR elif is_group: access_ok = file_stats.st_mode & stat.S_IWGRP else: access_ok = file_stats.st_mode & stat.S_IWOTH try: if access_ok: write_start_time = time.time() with self.server.get_fs_lock(): os.lseek(file_descriptor, offset, os.SEEK_SET) bytes_written = os.write(file_descriptor, data) logging.debug("{} wrote {} bytes".format( self.client_address[0], bytes_written)) response_obj.set_data({"bytes_written": bytes_written}) write_elapsed = time.time() - write_start_time logging.debug( "Took {:.2f}s to write {} bytes ({:.2f} MB/s)".format( write_elapsed, bytes_written, bytes_written / 1024**2 / write_elapsed)) else: logging.warning("Error during write request: Access denied") response_obj.set_err_no(errno.EACCES) response_obj.set_data({"message": "Access denied"}) except Exception as e: logging.error("Error during write request: {}".format(e)) response_obj.set_err_no(errno.EIO) response_obj.set_data({"message": str(e)}) # Send response self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict()) response_elapsed = time.time() - start_time # Print 1/10 of the time logging.debug( "Took {:.2f}s to complete write response ({:.2f} MB/s)".format( response_elapsed, bytes_written / 1024**2 / response_elapsed))
def on_access(self, httpfs_request_args): """ Called when HttpFsRequest.OP_ACCESS is received from the client :param httpfs_request_args: The client request arg dict """ response_obj = HttpFsResponse() path = self.get_abs_path(httpfs_request_args["path"]) mode = httpfs_request_args["mode"] uid = httpfs_request_args["uid"] gid = httpfs_request_args["gid"] file_stats = os.stat(path) is_owner = file_stats.st_uid == uid is_group = file_stats.st_gid == gid read_requested = bool(mode & os.R_OK) write_requested = bool(mode & os.W_OK) execute_requested = bool(mode & os.X_OK) exists_requested = mode == os.F_OK access_ok = True # Exists requested if exists_requested: access_ok = os.path.exists(path) # Owner access if is_owner: owner_readable = bool(file_stats.st_mode & stat.S_IRUSR) owner_writeable = bool(file_stats.st_mode & stat.S_IWUSR) owner_executable = bool(file_stats.st_mode & stat.S_IXUSR) if read_requested: access_ok = access_ok and owner_readable if write_requested: access_ok = access_ok and owner_writeable if execute_requested: access_ok = access_ok and owner_executable # Group access elif is_group: group_readable = bool(file_stats.st_mode & stat.S_IRGRP) group_writeable = bool(file_stats.st_mode & stat.S_IWGRP) group_executable = bool(file_stats.st_mode & stat.S_IXGRP) if read_requested: access_ok = access_ok and group_readable if write_requested: access_ok = access_ok and group_writeable if execute_requested: access_ok = access_ok and group_executable # World access else: world_readable = bool(file_stats.st_mode & stat.S_IROTH) world_writeable = bool(file_stats.st_mode & stat.S_IWOTH) world_executable = bool(file_stats.st_mode & stat.S_IXGRP) if read_requested: access_ok = access_ok and world_readable if write_requested: access_ok = access_ok and world_writeable if execute_requested: access_ok = access_ok and world_executable if not access_ok: logging.warning("Error during access request: Access denied") response_obj.set_err_no(errno.EACCES) self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())