# JTFTP - Python/AsyncIO TFTP Server # Copyright (C) 2022 Jeffrey C. Ollie # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class TFTPError(Exception): """Base exception class for this package""" class WireProtocolError(TFTPError): """Base exception class for wire-protocol level errors""" class InvalidOpcodeError(WireProtocolError): """An invalid opcode was encountered""" opcode: int def __init__(self, opcode: int): self.opcode = opcode super().__init__(f"Invalid opcode: {opcode}") class PayloadDecodeError(WireProtocolError): """Failed to parse the payload""" class OptionsDecodeError(PayloadDecodeError): """Failed to parse options in the WRQ/RRQ datagram. It is distinct from L{PayloadDecodeError} so that it can be caught and dealt with gracefully (pretend we didn't see any options at all, perhaps). """ class InvalidErrorcodeError(PayloadDecodeError): """An ERROR datagram has an error code, that does not correspond to any known error code values. @ivar errorcode: The error code, that we were unable to parse @type errorcode: C{int} """ error_code: int def __init__(self, error_code: int): self.error_code = error_code super().__init__(f"unknown error code: {error_code}") class BackendError(TFTPError): """Base exception class for backend errors""" class Unsupported(BackendError): """Requested operation (read/write) is not supported""" class AccessViolation(BackendError): """Illegal filesystem operation. Corresponds to the "(2) Access violation" TFTP error code. One of the prime examples of these is an attempt at directory traversal. """ class FileNotFound(BackendError): """File not found. Corresponds to the "(1) File not found" TFTP error code. @ivar file_path: Path to the file, that was requested @type file_path: C{bytes} or L{twisted.python.filepath.FilePath} """ def __init__(self, file_path): self.file_path = file_path def __str__(self): return f"File not found: {self.file_path}" class FileExists(BackendError): """File exists. Corresponds to the "(6) File already exists" TFTP error code. @ivar file_path: Path to file @type file_path: C{bytes} or L{twisted.python.filepath.FilePath} """ def __init__(self, file_path): self.file_path = file_path def __str__(self): return f"File already exists: {self.file_path}"