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

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.