-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathRamVolume.pas
161 lines (147 loc) · 6.03 KB
/
RamVolume.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
unit RamVolume;
interface
uses Windows,Definitions;
function GetRamDiskLetter(device:TDeviceNumber;portNumber:Cardinal;Var existing:TRamDisk): Char;
Function ImScsiOpenDiskByDeviceNumber(DeviceNumber: TDeviceNumber; PortNumber: DWORD; var DiskNumber: Integer):THandle;
implementation
uses Classes,StrUtils,SysUtils;
function FindFirstVolume(lpszVolumeName: LPSTR; cchBufferLength: DWORD): THANDLE; stdcall; External kernel32 name 'FindFirstVolumeA';
function FindNextVolume(hFindVolume: THANDLE; lpszVolumeName: LPSTR; cchBufferLength: DWORD): BOOL; stdcall; External kernel32 name 'FindNextVolumeA';
function FindVolumeClose(hFindVolume: THANDLE): BOOL; stdcall; External kernel32;
function GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames: LPCSTR; cchBufferLength: DWORD; var lpcchReturnLength: DWORD): BOOL; stdcall; External kernel32 name 'GetVolumePathNamesForVolumeNameA';
Function ImScsiOpenDiskByDeviceNumber(DeviceNumber: TDeviceNumber; PortNumber: DWORD; var DiskNumber: Integer):THandle;
Const
disk_prefix: WideString = 'PhysicalDrive';
var
dosdevs: string;
disk, adapter: THandle;
disk_number: Integer;
dw: DWORD;
dev_path: WideString;
config:TScsiDeviceConfig;
i, len: Integer;
devices: TStringList;
address: TScsiAddress;
device_number: TStorageDeviceNumber;
disk_size: Int64;
Begin
SetLength(dosDevs, MAX_DOS_NAMES);
disk_number:= -1;
Result:=INVALID_HANDLE_VALUE;
len:=QueryDosDevice(NIL, PAnsiChar(dosdevs), Length(dosdevs));
// ImScsiDebugMessage(L"Error opening SCSI port %1!i!: %2!ws!", PortNumber & 0xFF, (LPCWSTR)errmsg);
if len=0 then Exit;
adapter := ImScsiOpenScsiAdapterByScsiPortNumber(PortNumber);
if adapter = INVALID_HANDLE_VALUE then Exit;
config.DeviceNumber := DeviceNumber;
If not ImScsiQueryDevice(adapter, @config, SizeOf(TScsiDeviceConfig)) Then
begin
CloseHandle(adapter);
Exit;
end;
CloseHandle(adapter);
for i:=1 to len Do
if dosDevs[i] = #0 then dosDevs[i]:= #13;
devices:=Nil;
Try
devices:=TStringList.Create;
devices.Text:=dosDevs;
for i:=0 to devices.Count-1 do
Begin
if LeftStr(devices[i],Length(disk_prefix)) <> disk_prefix Then Continue;
if not TryStrToInt(Copy(devices[i],Length(disk_prefix)+1,10), disk_number) then continue;
dev_path := '\\?\' + devices[i];
disk := CreateFileW(PWideChar(dev_path), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0);
if disk = INVALID_HANDLE_VALUE then Continue;
if DeviceIoControl(disk, IOCTL_SCSI_GET_ADDRESS, NIL, 0, @address, sizeof(address), dw, NIL) then
Begin
if ((address.PortNumber = PortNumber) and
(address.PathId = DeviceNumber.PathId) and
(address.TargetId = DeviceNumber.TargetId) and
(address.Lun = DeviceNumber.Lun)) then
Begin
if DeviceIoControl(disk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NIL, 0, @device_number, sizeof(device_number), dw, NIL) then
Begin
if ((device_number.DeviceNumber = DWORD(disk_number)) and
(device_number.DeviceType = FILE_DEVICE_DISK) and
(device_number.PartitionNumber = 0)) then
Begin
DeviceIoControl(disk, FSCTL_ALLOW_EXTENDED_DASD_IO, NIL, 0, NIL, 0, dw, NIL);
disk_size := 0;
if DeviceIoControl(disk, IOCTL_DISK_GET_LENGTH_INFO, NIL, 0, @disk_size, sizeof(disk_size), dw, NIL) then
begin
if disk_size = config.DiskSize then
Begin
DiskNumber := disk_number;
Result:=disk;
Exit;
end;
end
end;
end;
end;
end
else Case GetLastError of
ERROR_INVALID_PARAMETER,
ERROR_INVALID_FUNCTION,
ERROR_NOT_SUPPORTED,
ERROR_IO_DEVICE: break;
end;
CloseHandle(disk);
end;
Finally
devices.Free;
end;
end;
Function GetRamDiskLetter(device:TDeviceNumber;portNumber:Cardinal;Var existing:TRamDisk):Char;
var
adapter, volHandle, volume: THandle;
tmp: DWORD;
address: TScsiAddress;
device_number: TStorageDeviceNumber;
volumeName: Array[0..49] of AnsiChar;
mountName: Array[0..250] Of AnsiChar;
Begin
Result:=#0;
adapter:= ImScsiOpenDiskByDeviceNumber(device, PortNumber, existing.diskNumber);
if adapter <> INVALID_HANDLE_VALUE then
begin
volume := FindFirstVolume(volumeName, Length(volumeName));
if volume <> INVALID_HANDLE_VALUE then
begin
repeat
volumeName[48] := #0;
volHandle:= CreateFileA(volumeName, 0, FILE_SHARE_READ or FILE_SHARE_WRITE, NIL, OPEN_EXISTING, 0, 0);
volumeName[48] := '\';
if volHandle = INVALID_HANDLE_VALUE then break;
if DeviceIoControl(volHandle, IOCTL_SCSI_GET_ADDRESS, NIL, 0, @address, sizeof(address), tmp, NIL) then
Begin
if ((address.PortNumber = portNumber) and
(address.PathId = device.PathId) and
(address.TargetId = device.TargetId) and
(address.Lun = device.Lun)) then
Begin
if DeviceIoControl(volHandle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NIL, 0, @device_number, sizeof(device_number), tmp, NIL) then
Begin
if (device_number.DeviceNumber = DWORD(existing.diskNumber)) and
(device_number.DeviceType = FILE_DEVICE_DISK) and
(device_number.PartitionNumber > 0) then
Begin
if GetVolumePathNamesForVolumeName(volumeName, mountName, Length(mountName), tmp) then
begin
CloseHandle(volHandle);
existing.volumeName:=volumeName;
Result:=Char(mountName[0]); // mountName is array of ASCIIZ, ending with empty ASCIIZ
Break;
end;
end;
end;
end;
end;
CloseHandle(volHandle);
until not FindNextVolume(volume, volumeName, Length(volumeName));
FindVolumeClose(volume);
end;
end;
end;
end.