Raw Disk Access Unit


/ Published in: Delphi
Save to your folder(s)



Copy this code and paste it in your HTML
  1. //******************************************************************************
  2. //
  3. // UDiskAccess - A low-level disk I/O stream class (tested under Vista).
  4. // Copyright © 2009 Patryk Nusbaum.
  5. // All rights reserved.
  6. //
  7. // Last modified: 10.10.2009
  8. // WWW: www.pateman.net76.net
  9. //
  10. // License
  11. // -------------------
  12. // Redistribution and use in source and binary forms, with or without
  13. // modification, are permitted provided that the following conditions are
  14. // met:
  15. //
  16. // * Redistributions of source code must retain the above copyright notice,
  17. // this list of conditions and the following disclaimer.
  18. // * Redistributions in binary form must reproduce the above copyright
  19. // notice, this list of conditions and the following disclaimer in the
  20. // documentation and/or other materials provided with the distribution.
  21. // * Neither the name of Patryk Nusbaum nor the names of his contributors
  22. // may be used to endorse or promote products derived from this software
  23. // without specific prior written permission.
  24. //
  25. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  27. // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  28. // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  29. // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  30. // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  31. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  32. // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  33. // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  34. // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  35. // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. //******************************************************************************
  37. unit UDiskAccess;
  38.  
  39. interface
  40.  
  41. uses
  42. Classes;
  43.  
  44. const
  45. NTDLLFile = 'ntdll.dll';
  46.  
  47. FILE_SHARE_READ = $00000001;
  48. FILE_SHARE_WRITE = $00000002;
  49. FILE_READ_ACCESS = $0001;
  50. FILE_WRITE_ACCESS = $0002;
  51. FILE_OPEN = $00000001;
  52. FILE_SYNCHRONOUS_IO_NONALERT = $00000020;
  53.  
  54. SYNCHRONIZE = $00100000;
  55. OBJ_CASE_INSENSITIVE = $00000040;
  56.  
  57. type
  58. LONG = Longint;
  59. LONGLONG = Int64;
  60. ULONG_PTR = Longword;
  61. USHORT = Word;
  62. DWORD = Longword;
  63.  
  64. NTSTATUS = LONG;
  65. ACCESS_MASK = DWORD;
  66.  
  67. PWSTR = PWideChar;
  68. LPCWSTR = PWideChar;
  69.  
  70. PVOID = Pointer;
  71.  
  72. { .: HANDLE :. }
  73. HANDLE = Cardinal;
  74. PHANDLE = ^HANDLE;
  75.  
  76. { .: ULONG :. }
  77. ULONG = Longword;
  78. PULONG = ^ULONG;
  79.  
  80. { .: IO_STATUS_BLOCK :. }
  81. _IO_STATUS_BLOCK = record
  82. Status: NTSTATUS;
  83. Information: ULONG_PTR;
  84. end;
  85. IO_STATUS_BLOCK = _IO_STATUS_BLOCK;
  86. PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK;
  87.  
  88. { .: UNICODE_STRING :. }
  89. _UNICODE_STRING = record
  90. Length: USHORT;
  91. MaximumLength: USHORT;
  92. Buffer: PWSTR;
  93. end;
  94. UNICODE_STRING = _UNICODE_STRING;
  95. PUNICODE_STRING = ^UNICODE_STRING;
  96.  
  97. { .: OBJECT_ATTRIBUTES :. }
  98. _OBJECT_ATTRIBUTES = record
  99. Length: ULONG;
  100. RootDirectory: HANDLE;
  101. ObjectName: PUNICODE_STRING;
  102. Attributes: ULONG;
  103. SecurityDescriptor: PVOID;
  104. SecurityQualityOfService: PVOID;
  105. end;
  106. OBJECT_ATTRIBUTES = _OBJECT_ATTRIBUTES;
  107. POBJECT_ATTRIBUTES = ^OBJECT_ATTRIBUTES;
  108.  
  109. { .: LARGE_INTEGER :. }
  110. _LARGE_INTEGER = record
  111. case Integer of
  112. 0: (LowPart: DWORD;
  113. HighPart: LONG);
  114. 1: (QuadPart: LONGLONG);
  115. end;
  116. LARGE_INTEGER = _LARGE_INTEGER;
  117. PLARGE_INTEGER = ^LARGE_INTEGER;
  118.  
  119. { .: PIO_APC_ROUTINE :. }
  120. PIO_APC_ROUTINE = procedure(ApcContext: PVOID;
  121. IoStatusBlock: PIO_STATUS_BLOCK; Reserved: ULONG); stdcall;
  122.  
  123. { .: FS_INFORMATION_CLASS :. }
  124. _FSINFOCLASS = (FileFsVolumeInformation = 1,
  125. FileFsLabelInformation, // 2
  126. FileFsSizeInformation, // 3
  127. FileFsDeviceInformation, // 4
  128. FileFsAttributeInformation, // 5
  129. FileFsControlInformation, // 6
  130. FileFsFullSizeInformation, // 7
  131. FileFsObjectIdInformation, // 8
  132. FileFsDriverPathInformation, // 9
  133. FileFsVolumeFlagsInformation,// 10
  134. FileFsMaximumInformation);
  135. FS_INFORMATION_CLASS = _FSINFOCLASS;
  136.  
  137. { .: FILE_FS_SIZE_INFORMATION :. }
  138. _FILE_FS_SIZE_INFORMATION = record
  139. TotalAllocationUnits: LARGE_INTEGER;
  140. AvailableAllocationUnits: LARGE_INTEGER;
  141. SectorsPerAllocationUnit: ULONG;
  142. BytesPerSector: ULONG;
  143. end;
  144. FILE_FS_SIZE_INFORMATION = _FILE_FS_SIZE_INFORMATION;
  145. PFILE_FS_SIZE_INFORMATION = ^FILE_FS_SIZE_INFORMATION;
  146.  
  147. { .: TRawDiskAccessStream :. }
  148. TRawDiskAccessStream = class sealed(TStream)
  149. private
  150. { Private declarations }
  151. FHandleRead, FHandleWrite: HANDLE;
  152. FOffset: LARGE_INTEGER;
  153. FSize: Int64;
  154. FSectorCount: Cardinal;
  155. FSectorSize: Cardinal;
  156. protected
  157. { Protected declarations }
  158. function GetSize(): Int64; override;
  159. public
  160. { Public declarations }
  161. constructor Create(const ADriveLetter: Char);
  162. destructor Destroy(); override;
  163.  
  164. function SectorOffset(const ASector: Cardinal): Int64;
  165.  
  166. // the "Count" parameter is ignored
  167. function Read(var Buffer; Count: Longint): Longint; override;
  168. function Write(const Buffer; Count: Longint): Longint; override;
  169. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  170.  
  171. property SectorCount: Cardinal read FSectorCount;
  172. property SectorSize: Cardinal read FSectorSize;
  173. end;
  174.  
  175. procedure RtlInitUnicodeString(DestinationString: PUNICODE_STRING;
  176. SourceString: LPCWSTR); stdcall; external NTDLLFile name 'RtlInitUnicodeString';
  177. function NtCreateFile(FileHandle: PHANDLE; DesiredAccess: ACCESS_MASK;
  178. ObjectAttributes: POBJECT_ATTRIBUTES; IoStatusBlock: PIO_STATUS_BLOCK;
  179. AllocationSize: PLARGE_INTEGER; FileAttributes: ULONG; ShareAccess: ULONG;
  180. CreateDisposition: ULONG; CreateOptions: ULONG; EaBuffer: PVOID;
  181. EaLength: ULONG): NTSTATUS; stdcall; external NTDLLFile name 'NtCreateFile';
  182. function NtReadFile(FileHandle: HANDLE; Event: HANDLE;
  183. ApcRoutine: PIO_APC_ROUTINE; ApcContext: PVOID;
  184. IoStatusBlock: PIO_STATUS_BLOCK; Buffer: PVOID; Length: ULONG;
  185. ByteOffset: PLARGE_INTEGER; Key: PULONG): NTSTATUS; stdcall; external NTDLLFile name 'NtReadFile';
  186. function NtWriteFile(FileHandle: HANDLE; Event: HANDLE;
  187. ApcRoutine: PIO_APC_ROUTINE; ApcContext: PVOID;
  188. IoStatusBlock: PIO_STATUS_BLOCK; Buffer: PVOID; Length: ULONG;
  189. ByteOffset: PLARGE_INTEGER; Key: PULONG): NTSTATUS; stdcall; external NTDLLFile name 'NtWriteFile';
  190. function NtClose(Handle: HANDLE): NTSTATUS; stdcall; external NTDLLFile name 'NtClose';
  191. function NtQueryVolumeInformationFile(FileHandle: HANDLE;
  192. IoStatusBlock: PIO_STATUS_BLOCK; FsInformation: PVOID; Length: ULONG;
  193. FsInformationClass: FS_INFORMATION_CLASS): NTSTATUS; stdcall; external NTDLLFile name 'NtQueryVolumeInformationFile';
  194.  
  195. const
  196. INVALID_HANDLE_VALUE = DWORD(-1); // from Windows.pas
  197.  
  198. implementation
  199.  
  200. { .: NT_SUCCESS :. }
  201. function NT_SUCCESS(const Status: NTSTATUS): Boolean;
  202. begin
  203. Result := (Status >= 0);
  204. end;
  205.  
  206. { .: InitializeObjectAttributes :. }
  207. procedure InitializeObjectAttributes(p: POBJECT_ATTRIBUTES; n: PUNICODE_STRING;
  208. a: ULONG; r: HANDLE; s: PVOID);
  209. begin
  210. with p^ do
  211. begin
  212. Length := SizeOf(OBJECT_ATTRIBUTES);
  213. RootDirectory := r;
  214. Attributes := a;
  215. ObjectName := n;
  216. SecurityDescriptor := s;
  217. SecurityQualityOfService := nil;
  218. end;
  219. end;
  220.  
  221. { TRawDiskAccessStream }
  222.  
  223. constructor TRawDiskAccessStream.Create(const ADriveLetter: Char);
  224. var
  225. DiskHandle: HANDLE;
  226. IOStatus: IO_STATUS_BLOCK;
  227. Status: NTSTATUS;
  228. ObjectAttr: OBJECT_ATTRIBUTES;
  229. DiskName: UNICODE_STRING;
  230. X: _FILE_FS_SIZE_INFORMATION;
  231. begin
  232. inherited Create();
  233.  
  234. FHandleRead := INVALID_HANDLE_VALUE;
  235. FHandleWrite := INVALID_HANDLE_VALUE;
  236.  
  237. RtlInitUnicodeString(@DiskName, PChar('\DosDevices\' + ADriveLetter + ':'));
  238. InitializeObjectAttributes(@ObjectAttr, @DiskName, OBJ_CASE_INSENSITIVE, 0,
  239. nil);
  240.  
  241. Status := NtCreateFile(@DiskHandle, SYNCHRONIZE or FILE_READ_ACCESS,
  242. @ObjectAttr, @IOStatus, nil, 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
  243. FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, nil, 0);
  244. if (NT_SUCCESS(Status)) then
  245. FHandleRead := DiskHandle;
  246.  
  247. Status := NtCreateFile(@DiskHandle, SYNCHRONIZE or FILE_WRITE_ACCESS,
  248. @ObjectAttr, @IOStatus, nil, 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
  249. FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, nil, 0);
  250. if (NT_SUCCESS(Status)) then
  251. begin
  252. FHandleWrite := DiskHandle;
  253.  
  254. Status := NtQueryVolumeInformationFile(FHandleRead, @IOStatus, @X,
  255. SizeOf(X), FileFsSizeInformation);
  256.  
  257. FSectorCount := X.TotalAllocationUnits.QuadPart;
  258. FSectorSize := X.BytesPerSector;
  259. FSize := FSectorCount * FSectorSize;
  260. end;
  261. end;
  262.  
  263. destructor TRawDiskAccessStream.Destroy;
  264. begin
  265. if (FHandleRead <> INVALID_HANDLE_VALUE) and
  266. (FHandleWrite <> INVALID_HANDLE_VALUE) then
  267. begin
  268. NtClose(FHandleRead);
  269. NtClose(FHandleWrite);
  270.  
  271. FHandleRead := INVALID_HANDLE_VALUE;
  272. FHandleWrite := INVALID_HANDLE_VALUE;
  273. end;
  274.  
  275. inherited Destroy();
  276. end;
  277.  
  278. function TRawDiskAccessStream.GetSize: Int64;
  279. begin
  280. Result := FSize;
  281. end;
  282.  
  283. function TRawDiskAccessStream.Read(var Buffer; Count: Integer): Longint;
  284. var
  285. IOStatus: IO_STATUS_BLOCK;
  286. Status: NTSTATUS;
  287. begin
  288. Result := -1;
  289.  
  290. if (FHandleRead = INVALID_HANDLE_VALUE) then
  291. exit;
  292.  
  293. Status := NtReadFile(FHandleRead, 0, nil, nil, @IOStatus, @Buffer,
  294. FSectorSize, @FOffset, nil);
  295. if (NT_SUCCESS(Status)) then
  296. Result := FSectorSize
  297. else
  298. Result := 0;
  299. end;
  300.  
  301. function TRawDiskAccessStream.SectorOffset(const ASector: Cardinal): Int64;
  302. begin
  303. if (ASector < FSectorCount) then
  304. Result := ASector * FSectorSize
  305. else
  306. Result := -1;
  307. end;
  308.  
  309. function TRawDiskAccessStream.Seek(const Offset: Int64;
  310. Origin: TSeekOrigin): Int64;
  311. var
  312. X: Int64;
  313. begin
  314. case Origin of
  315. soBeginning:
  316. if (Offset <= GetSize()) then
  317. FOffset.QuadPart := Offset;
  318. soCurrent:
  319. begin
  320. X := FOffset.QuadPart + Offset;
  321. if (X <= GetSize()) then
  322. FOffset.QuadPart := X;
  323. end;
  324. soEnd:
  325. FOffset.QuadPart := GetSize() - Abs(Offset);
  326. end;
  327.  
  328. Result := FOffset.QuadPart;
  329. end;
  330.  
  331. function TRawDiskAccessStream.Write(const Buffer; Count: Integer): Longint;
  332. var
  333. IOStatus: IO_STATUS_BLOCK;
  334. Status: NTSTATUS;
  335. begin
  336. Result := -1;
  337.  
  338. if (FHandleWrite = INVALID_HANDLE_VALUE) then
  339. exit;
  340.  
  341. Status := NtWriteFile(FHandleWrite, 0, nil, nil, @IOStatus, @Buffer,
  342. FSectorSize, @FOffset, nil);
  343. if (NT_SUCCESS(Status)) then
  344. Result := FSectorSize
  345. else
  346. Result := 0;
  347. end;
  348.  
  349. end.

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.