unit BsoneUtil; interface uses System.SysUtils, System.IOUtils, System.Classes, System.StrUtils, Winapi.Windows, Winapi.Messages, Winapi.Winsock2, Winapi.IPHlpApi, Winapi.ActiveX, Winapi.WinSpool, System.Math, GlobalDefine, System.NetEncoding, BsoneDebug; const STATUS_SUCCESS = $00000000; // FS_INFORMATION_CLASS (enum °ªÀ» »ó¼ö·Î Á¤ÀÇ) FileFsVolumeInformation = 1; FileFsLabelInformation = 2; FileFsSizeInformation = 3; FileFsDeviceInformation = 4; // ¿ì¸®°¡ ÇÊ¿äÇÑ °ª FileFsAttributeInformation = 5; FileFsControlInformation = 6; FileFsFullSizeInformation = 7; FileFsObjectIdInformation = 8; FileFsDriverPathInformation = 9; FileFsVolumeFlagsInformation = 10; // GetOffLineType¿¡¼­ »ç¿ëÇÒ ¸®ÅÏ Å¸ÀÔ »ó¼ö OFFTYPE_UNKNOWN = 0; OFFTYPE_REMOVABLE = 1; OFFTYPE_FLOPPY = 2; OFFTYPE_NETWORKDRIVEOUT = 3; OFFTYPE_CDROM = 4; OFFTYPE_EXTERNALHDD = 5; IOCTL_STORAGE_QUERY_PROPERTY = $002D1400; StorageDeviceProperty = 0; // STORAGE_PROPERTY_ID PropertyStandardQuery = 0; // STORAGE_QUERY_TYPE type // ÀÌÀü Áú¹®¿¡¼­ Á¤ÀÇÇÑ STORAGE_BUS_TYPEÀÌ ÀÖ´Ù°í °¡Á¤ÇÕ´Ï´Ù. // ¸¸¾à ´Ù¸¥ À¯´Ö¿¡ ÀÖ´Ù¸é uses¿¡ Ãß°¡Çϰí ÀÌ Á¤ÀÇ´Â ÁÖ¼® ó¸®Çϼ¼¿ä. {$MINENUMSIZE 4} STORAGE_BUS_TYPE = ( BusTypeUnknown = $00, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID, BusTypeiScsi, BusTypeSas, BusTypeSata, BusTypeSd, BusTypeMmc, BusTypeVirtual, BusTypeFileBackedVirtual, BusTypeSpaces, BusTypeNvme, BusTypeSCM, BusTypeUfs, BusTypeNvmeof, BusTypeMax, BusTypeMaxReserved = $7F ); {$MINENUMSIZE 1} // STORAGE_PROPERTY_QUERY ±¸Á¶Ã¼ PSTORAGE_PROPERTY_QUERY = ^STORAGE_PROPERTY_QUERY; STORAGE_PROPERTY_QUERY = record PropertyId: DWORD; // STORAGE_PROPERTY_ID QueryType: DWORD; // STORAGE_QUERY_TYPE AdditionalParameters: array [0..0] of Byte; end; // STORAGE_DESCRIPTOR_HEADER ±¸Á¶Ã¼ STORAGE_DESCRIPTOR_HEADER = record Version: DWORD; Size: DWORD; end; // STORAGE_DEVICE_DESCRIPTOR ±¸Á¶Ã¼ (ÇÊ¿äÇÑ ºÎºÐ¸¸ Á¤ÀÇ) PSTORAGE_DEVICE_DESCRIPTOR = ^STORAGE_DEVICE_DESCRIPTOR; STORAGE_DEVICE_DESCRIPTOR = record Version: DWORD; Size: DWORD; DeviceType: Byte; DeviceTypeModifier: Byte; RemovableMedia: Boolean; CommandQueueing: Boolean; VendorIdOffset: DWORD; ProductIdOffset: DWORD; ProductRevisionOffset: DWORD; SerialNumberOffset: DWORD; BusType: STORAGE_BUS_TYPE; // ¿©±â¿¡ BusType À§Ä¡ RawPropertiesIncluded: DWORD; // ÀÌÈÄ °¡º¯ ±æÀÌ ¹è¿­... end; NTSTATUS = LongInt; PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK; IO_STATUS_BLOCK = record case Integer of 0: ( Status: NTSTATUS; Information: NativeUInt; ); 1: ( Pointer: Pointer; ); end; PFILE_FS_DEVICE_INFORMATION = ^FILE_FS_DEVICE_INFORMATION; FILE_FS_DEVICE_INFORMATION = record DeviceType: DWORD; Characteristics: ULONG; end; TNtQueryVolumeInformationFile = function( FileHandle: THandle; IoStatusBlock: PIO_STATUS_BLOCK; FsInformation: Pointer; Length: ULONG; FsInformationClass: Integer ): NTSTATUS; stdcall; function UtilGetDriveTypeEx(path: string): DWORD; stdcall; function UtilCompareCode(Src: PByte; Code: PByte; CodeSize: DWORD): BOOL; stdcall; function UtilFindCode(BaseAddress: PByte; BaseSize: DWORD; Code: PByte; CodeSize: DWORD; var nPos: Integer): PByte; stdcall; function UtilGetBufferHex(pData: PByte; ASize, AMaxSize: DWORD): string; procedure UtilSaveBufferToFile(sPath: string; pData: PByte; ASize: DWORD); function UtilGetDriveTypeAndCharacteristics(hDevice: THandle; out DeviceType: DWORD; out Characteristics: ULONG): Boolean; function UtilIsFileSizeOverBlockSize(const path: string; OutBlockSize: DWORD): Boolean; implementation function UtilGetDriveTypeEx(path: string): DWORD; stdcall; var driver: string; P3, P4: Integer; begin // driver := TPath.GetPathRoot(path); ÇØ´ç API ½ÇÇà ½Ã explorer°¡ Á×´Â Çö»óÀÌ ÀÖÀ½. if path = '' then begin Result := DRIVE_UNKNOWN; Exit; end; if (Length(path) >= 2) and (path[1] = '\') and (path[2] = '\') then // 2. UNC °æ·Î °Ë»ç (¿¹: \\Server\Share) begin P3 := PosEx('\', path, 3); // 3¹øÂ° '\' (e.g., \\Server[\ ]Share) if P3 = 0 then begin driver := path; // '\\Server' (·çÆ®°¡ µÊ) end else begin // 4¹øÂ° '\' (e.g., \\Server\Share[\ ]Folder) P4 := PosEx('\', path, P3 + 1); if P4 = 0 then driver := path else // '\\Server\Share\Folder' (·çÆ®´Â '\\Server\Share\') driver := Copy(path, 1, P4); end; end else if (Length(path) >= 3) and (path[2] = ':') and (path[3] = '\') then // 3. µå¶óÀÌºê ¹®ÀÚ °æ·Î °Ë»ç (¿¹: C:\) begin driver := Copy(path, 1, 3); // "C:\" end else if (Length(path) = 2) and (path[2] = ':') then // 4. µå¶óÀÌºê ¹®ÀÚ¸¸ °Ë»ç (¿¹: C:) begin driver := path + '\'; // "C:\" end else if path[1] = '\' then // 5. ·çÆ® µð·ºÅ丮 °Ë»ç (¿¹: \) begin driver := '\'; end // 6. À§ ¸ðµç °æ¿ì¿¡ ÇØ´çÇÏÁö ¾ÊÀ¸¸é »ó´ë °æ·Î·Î °£ÁÖ else begin // TPath.GetPathRoot´Â ºó ¹®ÀÚ¿­À» ¹Ýȯ -> DRIVE_UNKNOWN (ȤÀº NO_ROOT_DIR) Result := DRIVE_NO_ROOT_DIR; Exit; end; // LOG('UtilGetDriveTypeEx, GetPathRoot--(%s)', [PChar(driver)]); if driver = '' then begin // ·çÆ®°¡ ¾øÀ¸¸é(»ó´ë °æ·Î µî) C++ ¿øº»ÀÇ Àǵµ´ë·Î DRIVE_UNKNOWN ¹Ýȯ Result := DRIVE_UNKNOWN; end else begin // GetDriveType API´Â 'C:\' ¹× '\\Server\Share\' °°Àº UNC °æ·Î¸¦ // PChar·Î Àü´Þ¹Þ¾Æ ¿Ã¹Ù¸£°Ô ó¸®ÇÕ´Ï´Ù. Result := GetDriveType(PChar(driver)); end; end; function UtilCompareCode(Src: PByte; Code: PByte; CodeSize: DWORD): BOOL; stdcall; begin Result := CompareMem(Src, Code, CodeSize); end; function UtilFindCode(BaseAddress: PByte; BaseSize: DWORD; Code: PByte; CodeSize: DWORD; var nPos: Integer): PByte; stdcall; var i: Integer; p: PByte; c: PByte; Bytes: Integer; sBuff: string; begin Result := nil; nPos := -1; p := BaseAddress; c := Code; Bytes := Integer(BaseSize) - Integer(CodeSize); if Bytes < 0 then Exit; // LOG('UtilFindCode, %d : %d %d', [BaseSize, CodeSize, Bytes]); // for i := 0 to CodeSize - 1 do // sBuff := sBuff + IntToHex(Code[i], 2); // // LOG('UtilFindCode: Code(%s)', [sBuff]); // if Bytes = 0 then // Bytes := 1 // else // Bytes := Bytes; for i := 0 to Bytes do begin if CompareMem(p, c, CodeSize) then begin nPos := i; Result := p; Exit; end; Inc(p); end; end; function UtilGetBufferHex(pData: PByte; ASize, AMaxSize: DWORD): string; var i, inSize: DWORD; begin Result := ''; if (pData = nil) or (ASize = 0) then Exit; if ASize > AMaxSize then inSize := AMaxSize else inSize := ASize; for i := 0 to inSize - 1 do Result := Result + IntToHex(pData[i], 2); end; procedure UtilSaveBufferToFile(sPath: string; pData: PByte; ASize: DWORD); var fs: TFileStream; sFileName: string; begin if (pData = nil) or (ASize = 0) then Exit; try sFileName := TPath.Combine(sPath, 'wpd_data_' + FormatDateTime('yyyymmdd_hhnnss_zzz', Now) + '.bin'); fs := TFileStream.Create(sFileName, fmCreate); try fs.WriteBuffer(pData^, ASize); finally fs.Free; end; except on E: Exception do LOG('_DeviceIoControl: FAILED to save file. Error: %s', [PChar(E.Message)]); end; end; function UtilGetDriveTypeAndCharacteristics(hDevice: THandle; out DeviceType: DWORD; out Characteristics: ULONG): Boolean; var hNtDll: HMODULE; NtQueryVolumeInformationFile: TNtQueryVolumeInformationFile; status: NTSTATUS; IoStatusBlock: IO_STATUS_BLOCK; FileFsDeviceInfo: FILE_FS_DEVICE_INFORMATION; begin Result := False; DeviceType := 0; Characteristics := 0; // 1. ntdll.dll ÇÚµé ¾ò±â hNtDll := GetModuleHandle('ntdll.dll'); if hNtDll = 0 then Exit; // 2. ÇÔ¼ö ÁÖ¼Ò ¾ò±â @NtQueryVolumeInformationFile := GetProcAddress(hNtDll, 'NtQueryVolumeInformationFile'); if not Assigned(NtQueryVolumeInformationFile) then Exit; // 3. API È£Ãâ status := NtQueryVolumeInformationFile( hDevice, @IoStatusBlock, @FileFsDeviceInfo, SizeOf(FileFsDeviceInfo), FileFsDeviceInformation // = 4 ); // 4. °á°ú ó¸® (STATUS_SUCCESS == 0) if status = STATUS_SUCCESS then begin Result := True; DeviceType := FileFsDeviceInfo.DeviceType; Characteristics := FileFsDeviceInfo.Characteristics; end; end; function UtilIsFileSizeOverBlockSize(const path: string; OutBlockSize: DWORD): Boolean; var Attribute: TWin32FileAttributeData; CurrentFileSize: Int64; LimitSize: Int64; begin Result := False; if OutBlockSize = 0 then begin Result := True; Exit; end; // 1. ÆÄÀÏ ¼Ó¼º °¡Á®¿À±â if not GetFileAttributesEx(PChar(path), GetFileExInfoStandard, @Attribute) then begin // ½ÇÆÐ ½Ã 0À¸·Î °£ÁÖÇϰųª, ¿¹¿Ü ó¸® (¿©±â¼­´Â 0À¸·Î ÁøÇà) Attribute.nFileSizeLow := 0; Attribute.nFileSizeHigh := 0; end; // 2. [Áß¿ä] 64ºñÆ® ÆÄÀÏ Å©±â·Î º¯È¯ (High + Low) // 4GB ÀÌ»óÀÇ ´ë¿ë·® ÆÄÀϵµ Á¤È®ÇÏ°Ô ºñ±³Çϱâ À§ÇÔ CurrentFileSize := (Int64(Attribute.nFileSizeHigh) shl 32) or Attribute.nFileSizeLow; // 3. ·Î±× Ãâ·Â (ÇöÀç Å©±â vs Á¦ÇÑ Å©±â) // OutBlockSize´Â MB ´ÜÀ§¶ó°í °¡Á¤ OutputDebugString(PChar(Format('UtilIsFileSizeOverBlockSize File Size: %d Bytes, Limit: %d MB', [CurrentFileSize, OutBlockSize]))); // 4. MB ´ÜÀ§¸¦ Byte·Î º¯È¯ÇÏ¿© ºñ±³ // 1 MB = 1024 * 1024 Bytes (¶Ç´Â 1 shl 20) // Int64·Î ij½ºÆÃÇØ¾ß °ö¼À °úÁ¤¿¡¼­ ¿À¹öÇ÷ο찡 ¹ß»ýÇÏÁö ¾ÊÀ½ LimitSize := Int64(OutBlockSize) * 1024 * 1024; if CurrentFileSize > LimitSize then begin Result := True; end; end; end.