Exemple #1
0
def checksum_file(path: str) -> str:
    """
    Gets the checksum of a file

    Parameters
    ----------
    path : str
        The path to checksum

    Returns
    -------
    string
        Checksum
    """
    pprint_start("Getting MD5 hash...")
    result = run_piped_command([["md5sum", path], ["awk", "'{ print $1 }'"]])
    if result["exit_code"]:
        pprint_complete(
            "Failed! Exit code: {0}".format(result["exit_code"]), False, Color.ERROR
        )
        checksum = None
    else:
        pprint_complete("Complete", True)
        checksum = result["stdout"].strip()

    return checksum
Exemple #2
0
def get_device_uuid(mount_point: str) -> str:
    """
    Get the system UUID for a device

    Parameters
    ----------
    mount_point : str
        The mount point for the drive
    """
    message = "Checking device UUID..."
    pprint_start(message)

    uuid = None
    partition = __get_device_path(mount_point)
    if partition:
        commands = [["blkid", partition, "-o", "value"], ["head", "-1"]]
        output = run_piped_command(commands)

        if output["stdout"].strip():
            uuid = output["stdout"].strip().decode("utf-8")

    if uuid:
        pprint_complete(message + "Found " + uuid, True, Color.GREEN)
    else:
        pprint_complete(message + "No UUID found!", False, Color.ERROR)

    return uuid
Exemple #3
0
def get_device_serial(mount_point: str) -> str:
    """
    Get the serial ID for a device

    Parameters
    ----------
    mount_point : str
        The mount point for the drive
    """
    message = "Checking device serial..."
    pprint_start(message)

    serial = None
    partition = __get_device_path(mount_point)
    if partition:
        commands = [
            ["udevadm", "info", "--query=all", "--name=" + partition],
            ["grep", "ID_SERIAL_SHORT"],
            ["sed", "s/.*=//"],
        ]
        output = run_piped_command(commands)

        if output["stdout"].strip():
            serial = output["stdout"].strip().decode("utf-8")

    if serial:
        pprint_complete(message + "Found " + serial, True, Color.GREEN)
    else:
        pprint_complete(message + "No serial found!", False, Color.ERROR)

    return serial
Exemple #4
0
def get_file_security(path: str) -> dict:
    """
    Get security details for a file

    Parameters
    ----------
    path : str
        File path to get details about

    Returns
    -------
    dict
        Containing owner, group, and permissions
    """
    message = "Checking file permissions..."
    pprint_start(message)
    file_stats = os.stat(path)
    permission_mask = oct(file_stats.st_mode)[-3:]
    owner = pwd.getpwuid(file_stats.st_uid).pw_name
    group = grp.getgrgid(file_stats.st_gid).gr_name
    pprint_complete(message + "Done.", True)

    return {"permissions": permission_mask, "owner": owner, "group": group}
Exemple #5
0
def add_file(
    file_path: str, mount_point: str = None, size_checked: bool = False
) -> bool:
    """
    Will add a file to the backup archive

    Parameters
    ----------
    file_path : str
        The file path to add
    mount_point : str
        Optionally, the mount point to prefer
    size_checked : bool
        Used for folder addition to specific device
        True if the size of the specified device has already been checked
        for required capacity of file/s

    Returns
    -------
    bool
        True if added, False otherwise
          - due to database failure, hard drive failure, etc
          - or if it already exists
    """
    if db.file_exists(file_path):
        pprint("File is already backed up!", Color.ERROR)
        return False

    if mount_point and not size_checked:
        message = "Checking drive space..."
        pprint_start(message)
        file_size = utility.get_file_size(file_path)
        drive_space = utility.get_device_space(mount_point)
        if file_size >= drive_space:
            pprint_complete(message + "Insufficient space!", False, Color.ERROR)
            confirm = input("Switch drive? (Y/n, n exits) ")
            if confirm == "n":
                return False
            else:
                mount_point = None
        else:
            pprint_complete(message + "Done.", True, Color.BLUE)

    message = "Getting file size..."
    pprint_start(message)
    file_size = utility.get_file_size(file_path)
    pprint_complete(message + "Read. File is " + readable_bytes(file_size), True)

    # This also needs to happen if we unset it due to space problems
    if not mount_point:
        message = "Auto-selecting device to use..."
        pprint_start(message)

        devices = db.get_devices()
        for device in devices:
            path = device.device_path
            space = utility.get_device_space(path)
            if space > file_size:
                pprint_complete("Selected " + device.device_name, True)
                mount_point = path
                break

    security_details = utility.get_file_security(file_path)
    checksum = utility.checksum_file(file_path)
    if not checksum:
        return False

    new_name = utility.create_backup_name(file_path)
    new_path = os_path.join(mount_point, new_name)
    shutil.copyfile(file_path, new_path)

    checksum2 = utility.checksum_file(new_path)

    if checksum != checksum2:
        pprint("Checksum mismatch after copy!", Color.ERROR)
        os.remove(new_path)
        return False

    file_obj = File()
    file_obj.set_properties(os_path.basename(file_path), file_path, checksum)
    file_obj.set_security(**security_details)

    message = "Saving file record to DB..."
    pprint_start(message)
    succeeded = db.add_file(file_obj)
    if succeeded:
        pprint_complete(message + "Done.", True, Color.GREEN)
    else:
        pprint_complete(message + "Failed!", False, Color.ERROR)
        os.remove(new_path)

    return succeeded
Exemple #6
0
def add_device(mount_point: str) -> bool:
    """
    Adds a device to the database

    Parameters
    ----------
    mount_point : str
        The path to where the device is mounted

    Returns
    -------
    bool
        True if added, False otherwise
          - due to database failure, or if it path does not exist
    """
    device_name = input("Device name: ")
    identifier = utility.get_device_serial(mount_point)
    identifier_type = "Device Serial"
    if not identifier:
        identifier = utility.get_device_uuid(mount_point)
        identifier_type = "System UUID"

    if not identifier:
        identifier = input(
            "Unable to find systemic identifier. "
            "Please provide a unique identifier for the device: "
        )
        identifier_type = "User Specified"

    message = "Saving device..."
    pprint_start(message)

    device = Device()
    device.set(device_name, mount_point, identifier_type, identifier)
    result = db.add_device(device)

    if result == DatabaseError.SUCCESS:
        pprint_complete(message + "Done", True, Color.GREEN)
    else:
        message += "Failed. "
        if result == DatabaseError.INVALID_IDENTIFIER_TYPE:
            pprint_complete(
                message + "Unrecognized device identifier!", False, Color.ERROR
            )
        elif result == DatabaseError.DEVICE_NAME_EXISTS:
            pprint_complete(message + "Name already taken!", False, Color.ERROR)
        elif result == DatabaseError.DEVICE_PATH_EXISTS:
            pprint_complete(
                message + "Device already registered at mount point!",
                False,
                Color.ERROR,
            )
        elif result == DatabaseError.DEVICE_IDENTIFIER_EXISTS:
            pprint_complete(
                message + "Serial already registered for another device!",
                False,
                Color.ERROR,
            )
        elif result == DatabaseError.UNKNOWN_ERROR:
            pprint_complete(message + "Unknown error occurred!", False, Color.ERROR)
        else:
            pprint_complete(
                message + "Super-unknown error occurred!",
                False,
                Color.ERROR,
                formats=[Format.UNDERLINE],
            )

        return False

    return True