-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathRamVolume.pas
More file actions
177 lines (164 loc) · 6.65 KB
/
Copy pathRamVolume.pas
File metadata and controls
177 lines (164 loc) · 6.65 KB
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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, multiple: Integer;
devices: TStringList;
address: TScsiAddress;
device_number: TStorageDeviceNumber;
disk_size: Int64;
Begin
disk_number:= -1;
Result:=INVALID_HANDLE_VALUE;
multiple:=1;
Repeat
SetLength(dosDevs, MAX_DOS_NAMES * multiple);
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 Inc(multiple);
if multiple > 10 then
begin
DebugLog(Format('QueryDosDevice can not fit DOS device names inside %d bytes',[Length(dosdevs)]),EVENTLOG_ERROR_TYPE);
Exit;
end;
Until len <> 0;
adapter := ImScsiOpenScsiAdapterByScsiPortNumber(PortNumber);
if adapter = INVALID_HANDLE_VALUE then
Begin
DebugLog('Could not open SCSI adapter inside ImScsiOpenDiskByDeviceNumber',EVENTLOG_ERROR_TYPE);
Exit;
end;
config.DeviceNumber := DeviceNumber;
If not ImScsiQueryDevice(adapter, @config, SizeOf(TScsiDeviceConfig)) Then
begin
CloseHandle(adapter);
DebugLog('Could not get SCSI device config inside ImScsiOpenDiskByDeviceNumber',EVENTLOG_ERROR_TYPE);
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:
Begin
DebugLog(Format('Could not get the SCSI address of device %s',[devices[i]]),EVENTLOG_ERROR_TYPE);
break;
end;
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.