mirror of
https://github.com/uroni/urbackup_backend.git
synced 2025-10-26 11:36:50 +00:00
196 lines
5.4 KiB
C++
196 lines
5.4 KiB
C++
extern "C"
|
|
{
|
|
#include "device.h"
|
|
}
|
|
#include "../../../Interface/File.h"
|
|
#include <string>
|
|
|
|
namespace
|
|
{
|
|
class DiskDevice
|
|
{
|
|
public:
|
|
DiskDevice() {}
|
|
|
|
void Init(IFile* p_img, ULONGLONG DiskLength, ULONG DiskNumber)
|
|
{
|
|
img = p_img;
|
|
disk_length = DiskLength;
|
|
}
|
|
|
|
NTSTATUS InternalDeviceControl(PIRP Irp)
|
|
{
|
|
switch (Irp->StackLocation.Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_DISK_UPDATE_PROPERTIES:
|
|
return STATUS_SUCCESS;
|
|
case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION_EX layout_info = reinterpret_cast<PDRIVE_LAYOUT_INFORMATION_EX>(Irp->AssociatedIrp.SystemBuffer);
|
|
layout_info->PartitionCount = 0;
|
|
Irp->IoStatus.Information = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IOCTL_DISK_GET_LENGTH_INFO:
|
|
{
|
|
PGET_LENGTH_INFORMATION length_info = reinterpret_cast<PGET_LENGTH_INFORMATION>(Irp->AssociatedIrp.SystemBuffer);
|
|
length_info->Length.QuadPart = disk_length;
|
|
Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
|
|
{
|
|
PSTORAGE_DEVICE_NUMBER device_number = reinterpret_cast<PSTORAGE_DEVICE_NUMBER>(Irp->AssociatedIrp.SystemBuffer);
|
|
device_number->DeviceNumber = disk_number;
|
|
device_number->PartitionNumber = 0;
|
|
device_number->DeviceType = 0;
|
|
Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
|
|
{
|
|
PDISK_GEOMETRY disk_geom = reinterpret_cast<PDISK_GEOMETRY>(Irp->AssociatedIrp.SystemBuffer);
|
|
memset(disk_geom, 0, sizeof(DISK_GEOMETRY));
|
|
disk_geom->BytesPerSector = 4096;
|
|
Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
|
|
{
|
|
PMOUNTDEV_NAME mountdev_name = reinterpret_cast<PMOUNTDEV_NAME>(Irp->AssociatedIrp.SystemBuffer);
|
|
std::wstring name = L"\\Device\\Btrfs{foobar}";
|
|
mountdev_name->NameLength = static_cast<ULONG>((name.size() + 1)*sizeof(wchar_t));
|
|
|
|
if (Irp->StackLocation.Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG) + (name.size() + 1) * sizeof(wchar_t))
|
|
{
|
|
memcpy(mountdev_name->Name, name.data(), sizeof(wchar_t) * (name.size() + 1));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS Read(PIRP Irp, PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
bool has_read_err = false;
|
|
_u32 rc = img->Read(static_cast<int64>(Irp->StackLocation.Parameters.Read.ByteOffset.QuadPart),
|
|
reinterpret_cast<char*>(Irp->UserBuffer), Irp->StackLocation.Parameters.Read.Length,
|
|
&has_read_err);
|
|
|
|
if (has_read_err)
|
|
{
|
|
return STATUS_CRC_ERROR;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = rc;
|
|
|
|
Irp->CompletionRoutine(DeviceObject, Irp, Irp->CompletionRoutineContext);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS Write(PIRP Irp, PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
bool has_read_err = false;
|
|
_u32 rc = img->Write(static_cast<int64>(Irp->StackLocation.Parameters.Write.ByteOffset.QuadPart),
|
|
reinterpret_cast<char*>(Irp->UserBuffer), Irp->StackLocation.Parameters.Write.Length,
|
|
&has_read_err);
|
|
|
|
if (has_read_err)
|
|
{
|
|
return STATUS_CRC_ERROR;
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = rc;
|
|
|
|
Irp->CompletionRoutine(DeviceObject, Irp, Irp->CompletionRoutineContext);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS DeviceControl(PIRP Irp, PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
if (Irp->StackLocation.Parameters.DeviceIoControl.IoControlCode != IOCTL_ATA_PASS_THROUGH)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
if (Irp->StackLocation.Parameters.DeviceIoControl.InputBufferLength != sizeof(ATA_PASS_THROUGH_EX))
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
ATA_PASS_THROUGH_EX* ata = static_cast<ATA_PASS_THROUGH_EX*>(Irp->UserBuffer);
|
|
|
|
if (ata->CurrentTaskFile[6] == IDE_COMMAND_FLUSH_CACHE)
|
|
{
|
|
bool b = img->Sync();
|
|
Irp->IoStatus.Status = b ? STATUS_SUCCESS : STATUS_UNEXPECTED_IO_ERROR;
|
|
Irp->CompletionRoutine(DeviceObject, Irp, Irp->CompletionRoutineContext);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS Call(PIRP Irp, PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
switch (Irp->StackLocation.MajorFunction)
|
|
{
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
return InternalDeviceControl(Irp);
|
|
case IRP_MJ_READ:
|
|
return Read(Irp, DeviceObject);
|
|
case IRP_MJ_WRITE:
|
|
return Write(Irp, DeviceObject);
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
return DeviceControl(Irp, DeviceObject);
|
|
}
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
bool Flush()
|
|
{
|
|
return img->Sync();
|
|
}
|
|
|
|
private:
|
|
ULONGLONG disk_length;
|
|
ULONG disk_number;
|
|
|
|
IFile* img;
|
|
};
|
|
}
|
|
|
|
struct _DISK_DEVICE
|
|
{
|
|
DiskDevice disk_device;
|
|
};
|
|
|
|
NTSTATUS DiskDeviceCall(PDISK_DEVICE DiskDevice, PIRP Irp, PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
return DiskDevice->disk_device.Call(Irp, DeviceObject);
|
|
}
|
|
|
|
PDISK_DEVICE InitDiskDevice(void* img, ULONGLONG Length, ULONG Number)
|
|
{
|
|
PDISK_DEVICE ret = new _DISK_DEVICE;
|
|
ret->disk_device.Init(static_cast<IFile*>(img), Length, Number);
|
|
return ret;
|
|
}
|
|
|
|
NTSTATUS FlushDiskDevice(PDISK_DEVICE DiskDevice)
|
|
{
|
|
if (DiskDevice->disk_device.Flush())
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
return STATUS_UNEXPECTED_IO_ERROR;
|
|
}
|