Pastey IsUsbDevice with pack
- Posted by ne1uno Dec 29, 2011
--win api, show free space and info on devices. -- cut back features & docs for debugging. -- for testing, there should be some USB storage drive installed. -- -- IsUsbDevice -- http://banderlogi.blogspot.com/2011/06/enum-drive-letters-attached-for-usb.html -- http://www.codeproject.com/KB/winsdk/usbdisks.aspx -- -- seems to have struct access or dll version conlict -- memstruct STORAGE_PROPERTY_QUERY with pack 4 -- double AdditionalParameters[1] works -- UCHAR AdditionalParameters[1] fails when accessing the struct -- UCHAR AdditionalParameters[4] fails, until recently was silent exit. -- UCHAR AdditionalParameters[1+3] syntax or other error. bug. -- see --FIXME -- -- pack doesn't seem to work or at least is the same without pack -- since UCHAR AdditionalParameters[4] also doesn't work -- I can't be sure it's related to packing. -- comments on various forum suggest ddk structs are pack sensitive. -- -- should not be getting BusTypeUnknown on some of my drives. -- I know it needs more work to determine removable from floppy. -- other fixed disk and cd/dvd are not marked as USB and should be. -- may have to reconvert back to c to find out if it's buggy there too include std/dll.e include std/machine.e include std/io.e include std/filesys.e include std/memstruct/windows.e include std/math.e include std/map.e atom BYTE_STANDARD = 1024000 --A.G. --paste in or include winerror reporting module ifdef WINDOWS then include std/dll.e include std/error.e include std/io.e include std/machine.e include std/console.e constant kernel32 = dll:open_dll("kernel32.dll") ,xOutputDebugString = dll:define_c_proc(kernel32 ,"OutputDebugStringA",{dll:C_POINTER}) ,xSetLastError = dll:define_c_proc(kernel32 , "SetLastError", {dll:C_DWORD}), FORMAT_MESSAGE_ALLOCATE_BUFFER = #00000100, FORMAT_MESSAGE_IGNORE_INSERTS = #00000200, FORMAT_MESSAGE_FROM_STRING = #00000400, FORMAT_MESSAGE_FROM_HMODULE = #00000800, FORMAT_MESSAGE_FROM_SYSTEM = #00001000, FORMAT_MESSAGE_ARGUMENT_ARRAY = #00002000, FORMAT_MESSAGE_MAX_WIDTH_MASK = #000000FF ,xSetErrMode = dll:define_c_proc(kernel32 , "SetErrMode", {dll:C_DWORD}) ,SEM_FAILCRITICALERRORS = #0001 ,SEM_NOGPFAULTERRORBOX = #0002 ,SEM_NOALIGNMENTFAULTEXCEPT = #0004 ,SEM_NOOPENFILEERRORBOX = #8000 if kernel32 = dll:NULL then crash("kernel32 or dll not found") end if procedure OutputDebugString(sequence text) ifdef WINDOWS then atom lptext = machine:allocate_string(text,1) c_proc(xOutputDebugString,{lptext}) elsedef -- printf(2,"Db, %s ",{text}) end ifdef end procedure public function OutputDebugStringf(sequence text) OutputDebugString(text) return sprintf("%s",{text}) end function procedure log_file(object fn, sequence lines, sequence mode="a") object rtn if eu:compare(mode, "a")=0 then rtn = io:append_lines(fn, lines) else rtn = io:write_lines(fn, lines) end if if rtn then --can't write? end if end procedure function GetLastError() integer cGetLastError = define_c_func(kernel32, "GetLastError", {}, C_DWORD) return c_func(cGetLastError,{}) end function function FormatMessage(atom dwFlags, atom lpSource , atom dwMessageId, atom dwLanguageId ,object lpBuffer, atom nSize, atom Arguments) integer xFormatMessage = define_c_func(kernel32, "FormatMessageA" ,{C_DWORD, C_POINTER, C_DWORD, C_DWORD ,C_POINTER, C_DWORD, C_POINTER}, C_DWORD) if sequence(lpBuffer) then lpBuffer = allocate_string(lpBuffer, 1) end if return c_func(xFormatMessage ,{dwFlags,lpSource,dwMessageId,dwLanguageId ,lpBuffer,nSize, Arguments}) end function function get_winerror_string(atom eror = GetLastError() ) integer MSGSIZE = 1022 atom lpMsgBuf = allocate(MSGSIZE+2, 1) FormatMessage( or_all({ FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS}), NULL, eror, 0, -- Default language lpMsgBuf, --NULL MSGSIZE, --0 NULL ) return sprintf("0x%x %s", {eror, peek_string(lpMsgBuf)}) end function OutputDebugString("eu4 Dbg ") end ifdef --error reporting public constant DRIVE_UNKNOWN = 0, DRIVE_NO_ROOT_DIR = 1, DRIVE_REMOVABLE = 2, DRIVE_FIXED = 3, DRIVE_REMOTE = 4, DRIVE_CDROM = 5, DRIVE_RAMDISK = 6, $ public constant --C.B. WRITE_WATCH_FLAG_RESET = #01 ,FILE_READ_DATA = #0001 ,FILE_LIST_DIRECTORY = #0001 ,FILE_WRITE_DATA = #0002 ,FILE_ADD_FILE = #0002 ,FILE_APPEND_DATA = #0004 ,FILE_ADD_SUBDIRECTORY = #0004 ,FILE_CREATE_PIPE_INSTANCE = #0004 ,FILE_READ_EA = #0008 ,FILE_WRITE_EA = #0010 ,FILE_EXECUTE = #0020 ,FILE_TRAVERSE = #0020 ,FILE_DELETE_CHILD = #0040 ,FILE_READ_ATTRIBUTES = #0080 ,FILE_WRITE_ATTRIBUTES = #0100 ,FILE_SHARE_READ = #00000001 ,FILE_SHARE_WRITE = #00000002 ,FILE_SHARE_DELETE = #00000004 ,FILE_ATTRIBUTE_READONLY = #00000001 ,FILE_ATTRIBUTE_HIDDEN = #00000002 ,FILE_ATTRIBUTE_SYSTEM = #00000004 ,FILE_ATTRIBUTE_DIRECTORY = #00000010 ,FILE_ATTRIBUTE_ARCHIVE = #00000020 ,FILE_ATTRIBUTE_DEVICE = #00000040 ,FILE_ATTRIBUTE_NORMAL = #00000080 ,FILE_ATTRIBUTE_TEMPORARY = #00000100 ,FILE_ATTRIBUTE_SPARSE_FILE = #00000200 ,FILE_ATTRIBUTE_REPARSE_POINT = #00000400 ,FILE_ATTRIBUTE_COMPRESSED = #00000800 ,FILE_ATTRIBUTE_OFFLINE = #00001000 ,FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = #00002000 ,FILE_ATTRIBUTE_ENCRYPTED = #00004000 ,FILE_NOTIFY_CHANGE_FILE_NAME = #00000001 ,FILE_NOTIFY_CHANGE_DIR_NAME = #00000002 ,FILE_NOTIFY_CHANGE_ATTRIBUTES = #00000004 ,FILE_NOTIFY_CHANGE_SIZE = #00000008 ,FILE_NOTIFY_CHANGE_LAST_WRITE = #00000010 ,FILE_NOTIFY_CHANGE_LAST_ACCESS = #00000020 ,FILE_NOTIFY_CHANGE_CREATION = #00000040 ,FILE_NOTIFY_CHANGE_SECURITY = #00000100 ,FILE_ACTION_ADDED = #00000001 ,FILE_ACTION_REMOVED = #00000002 ,FILE_ACTION_MODIFIED = #00000003 ,FILE_ACTION_RENAMED_OLD_NAME = #00000004 ,FILE_ACTION_RENAMED_NEW_NAME = #00000005 ,FILE_CASE_SENSITIVE_SEARCH = #00000001 ,FILE_CASE_PRESERVED_NAMES = #00000002 ,FILE_UNICODE_ON_DISK = #00000004 ,FILE_PERSISTENT_ACLS = #00000008 ,FILE_FILE_COMPRESSION = #00000010 ,FILE_VOLUME_QUOTAS = #00000020 ,FILE_SUPPORTS_SPARSE_FILES = #00000040 ,FILE_SUPPORTS_REPARSE_POINTS = #00000080 ,FILE_SUPPORTS_REMOTE_STORAGE = #00000100 ,FILE_VOLUME_IS_COMPRESSED = #00008000 ,FILE_SUPPORTS_OBJECT_IDS = #00010000 ,FILE_SUPPORTS_ENCRYPTION = #00020000 ,FILE_NAMED_STREAMS = #00040000 ,CREATE_NEW = 1 ,CREATE_ALWAYS = 2 ,OPEN_EXISTING = 3 ,OPEN_ALWAYS = 4 ,TRUNCATE_EXISTING = 5 public constant cGetDriveTypeA = define_c_func(kernel32, "GetDriveTypeA", {C_POINTER}, C_UINT) public function GetDriveType(object lpRootPathName) if sequence(lpRootPathName) then lpRootPathName = allocate_string(lpRootPathName, 1) end if return c_func(cGetDriveTypeA,{lpRootPathName}) end function public constant cGetLogicalDriveStringsA = define_c_func(kernel32, "GetLogicalDriveStringsA", {C_DWORD,C_POINTER}, C_DWORD) -- some code from the petzold wrap in archive -- hardwiring to just return a sequence of drives public function GetLogicalDriveStrings() atom bufferSize = c_func(cGetLogicalDriveStringsA,{NULL, NULL}) atom pBuffer = allocate(bufferSize) bufferSize = c_func(cGetLogicalDriveStringsA,{bufferSize, pBuffer}) sequence buffer = peek({pBuffer,bufferSize}) free(pBuffer) sequence drives = {}, cur = "" for i = 1 to length(buffer) do if buffer[i] = 0 then if length(cur) > 0 then drives &= {cur} cur = "" end if else cur &= buffer[i] end if end for return drives end function public function CreateFile(atom lpFileName, atom dwDesiredAccess, atom dwShareMode, atom lpSecurityAttributes, atom dwCreationDisposition, atom dwFlagsAndAttributes, atom hTemplateFile) integer cCreateFile = define_c_func(kernel32, "CreateFileA", { C_POINTER,C_POINTER,C_POINTER, C_POINTER,C_POINTER,C_POINTER,C_POINTER}, C_POINTER) return c_func(cCreateFile,{lpFileName,dwDesiredAccess,dwShareMode,lpSecurityAttributes, dwCreationDisposition,dwFlagsAndAttributes,hTemplateFile}) end function --tested w/C version. returns correct value public function CTL_CODE(atom t,atom f,atom m,atom a) --#define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m)) atom tmp = or_bits( shift_bits(f, -2), m) --| << tmp = or_bits(tmp, shift_bits(a, -14))--| << tmp = or_bits(tmp, shift_bits(t, -16)) --<< return tmp end function /* winioctl.h */ public constant METHOD_BUFFERED = 0 ,METHOD_IN_DIRECT = 1 ,METHOD_OUT_DIRECT = 2 ,METHOD_NEITHER = 3 /* Also in ddk/winddk.h */ ,FILE_ANY_ACCESS = 0x00000000 ,FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS ,FILE_READ_ACCESS = 0x00000001 ,FILE_WRITE_ACCESS = 0x00000002 -- ,DEVICE_TYPE = DWORD ,FILE_DEVICE_BEEP = 1 ,FILE_DEVICE_CD_ROM = 2 ,FILE_DEVICE_CD_ROM_FILE_SYSTEM = 3 ,FILE_DEVICE_CONTROLLER = 4 ,FILE_DEVICE_DATALINK = 5 ,FILE_DEVICE_DFS = 6 ,FILE_DEVICE_DISK = 7 ,FILE_DEVICE_DISK_FILE_SYSTEM = 8 ,FILE_DEVICE_FILE_SYSTEM = 9 ,FILE_DEVICE_INPORT_PORT = 10 ,FILE_DEVICE_KEYBOARD = 11 ,FILE_DEVICE_MAILSLOT = 12 ,FILE_DEVICE_MIDI_IN = 13 ,FILE_DEVICE_MIDI_OUT = 14 ,FILE_DEVICE_MOUSE = 15 ,FILE_DEVICE_MULTI_UNC_PROVIDER = 16 ,FILE_DEVICE_NAMED_PIPE = 17 ,FILE_DEVICE_NETWORK = 18 ,FILE_DEVICE_NETWORK_BROWSER = 19 ,FILE_DEVICE_NETWORK_FILE_SYSTEM = 20 ,FILE_DEVICE_NULL = 21 ,FILE_DEVICE_PARALLEL_PORT = 22 ,FILE_DEVICE_PHYSICAL_NETCARD = 23 ,FILE_DEVICE_PRINTER = 24 ,FILE_DEVICE_SCANNER = 25 ,FILE_DEVICE_SERIAL_MOUSE_PORT = 26 ,FILE_DEVICE_SERIAL_PORT = 27 ,FILE_DEVICE_SCREEN = 28 ,FILE_DEVICE_SOUND = 29 ,FILE_DEVICE_STREAMS = 30 ,FILE_DEVICE_TAPE = 31 ,FILE_DEVICE_TAPE_FILE_SYSTEM = 32 ,FILE_DEVICE_TRANSPORT = 33 ,FILE_DEVICE_UNKNOWN = 34 ,FILE_DEVICE_VIDEO = 35 ,FILE_DEVICE_VIRTUAL_DISK = 36 ,FILE_DEVICE_WAVE_IN = 37 ,FILE_DEVICE_WAVE_OUT = 38 ,FILE_DEVICE_8042_PORT = 39 ,FILE_DEVICE_NETWORK_REDIRECTOR = 40 ,FILE_DEVICE_BATTERY = 41 ,FILE_DEVICE_BUS_EXTENDER = 42 ,FILE_DEVICE_MODEM = 43 ,FILE_DEVICE_VDM = 44 ,FILE_DEVICE_MASS_STORAGE = 45 ,FILE_DEVICE_SMB = 46 ,FILE_DEVICE_KS = 47 ,FILE_DEVICE_CHANGER = 48 ,FILE_DEVICE_SMARTCARD = 49 ,FILE_DEVICE_ACPI = 50 ,FILE_DEVICE_DVD = 51 ,FILE_DEVICE_FULLSCREEN_VIDEO = 52 ,FILE_DEVICE_DFS_FILE_SYSTEM = 53 ,FILE_DEVICE_DFS_VOLUME = 54 ,FILE_DEVICE_SERENUM = 55 ,FILE_DEVICE_TERMSRV = 56 ,FILE_DEVICE_KSEC = 57 ,PARTITION_ENTRY_UNUSED = 0 ,PARTITION_FAT_12 = 1 ,PARTITION_XENIX_1 = 2 ,PARTITION_XENIX_2 = 3 ,PARTITION_FAT_16 = 4 ,PARTITION_EXTENDED = 5 ,PARTITION_HUGE = 6 ,PARTITION_IFS = 7 ,PARTITION_FAT32 = 0x0B ,PARTITION_FAT32_XINT13 = 0x0C ,PARTITION_XINT13 = 0x0E ,PARTITION_XINT13_EXTENDED = 0x0F ,PARTITION_PREP = 0x41 ,PARTITION_LDM = 0x42 ,PARTITION_UNIX = 0x63 ,PARTITION_NTFT = 128 ,VALID_NTFT = 0xC0 ,SERIAL_LSRMST_ESCAPE = 0 ,SERIAL_LSRMST_LSR_DATA = 1 ,SERIAL_LSRMST_LSR_NODATA = 2 ,SERIAL_LSRMST_MST = 3 ,IOCTL_STORAGE_BASE = FILE_DEVICE_MASS_STORAGE atom IOCTL_STORAGE_QUERY_PROPERTY = CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) printf(1,"IOCTL_STORAGE_QUERY_PROPERTY %d 0x%x\n",{ IOCTL_STORAGE_QUERY_PROPERTY, IOCTL_STORAGE_QUERY_PROPERTY}) enum --typedef _STORAGE_PROPERTY_ID { StorageDeviceProperty = 0, StorageAdapterProperty, StorageDeviceIdProperty --} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; enum --typedef _STORAGE_QUERY_TYPE { PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined --} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; memtype unsigned char as UCHAR memstruct STORAGE_PROPERTY_QUERY with pack 4 short PropertyId --STORAGE_PROPERTY_ID short QueryType --STORAGE_QUERY_TYPE --UCHAR AdditionalParameters[1] --FIXME double AdditionalParameters[1] -- object instead of uchar same, double ok -- pack 4 or [4] doesn't solve problem end memstruct ?sizeof(STORAGE_PROPERTY_QUERY) --should be 12 using UCHAR memstruct STORAGE_DEVICE_DESCRIPTOR --with pack 4 ULONG Version ULONG Size UCHAR DeviceType UCHAR DeviceTypeModifier BOOL RemovableMedia BOOL CommandQueueing ULONG VendorIdOffset ULONG ProductIdOffset ULONG ProductRevisionOffset ULONG SerialNumberOffset --UINT BusType --FIXME enum STORAGE_BUS_TYPE UCHAR BusType --UCHAR seems to work better than UINT ULONG RawPropertiesLength UCHAR RawDeviceProperties[1] --double RawDeviceProperties[1] --double no diff here end memstruct enum --typedef _STORAGE_BUS_TYPE { BusTypeUnknown = 0x00, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID, BusTypeMaxReserved = 0x7F --} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE map BusTypeMap = map:new() map:put(BusTypeMap, BusTypeUnknown,"BusTypeUnknown") map:put(BusTypeMap, BusTypeScsi,"BusTypeScsi") map:put(BusTypeMap, BusTypeAtapi,"BusTypeAtapi") map:put(BusTypeMap, BusTypeAta,"BusTypeAta") map:put(BusTypeMap, BusType1394,"BusType1394") map:put(BusTypeMap, BusTypeSsa,"BusTypeSsa") map:put(BusTypeMap, BusTypeFibre,"BusTypeFibre") map:put(BusTypeMap, BusTypeUsb,"BusTypeUsb") map:put(BusTypeMap, BusTypeRAID,"BusTypeRAID") map:put(BusTypeMap, BusTypeMaxReserved,"BusTypeMaxReserved") public function DeviceIoControl(atom hDevice, atom dwIoControlCode, atom lpInBuffer, atom nInBufferSize, atom lpOutBuffer, atom nOutBufferSize, atom lpBytesReturned, atom lpOverlapped) integer cDeviceIoControl = define_c_func(kernel32, "DeviceIoControl", { C_HANDLE,C_DWORD, C_POINTER,C_DWORD, C_POINTER,C_DWORD,C_POINTER,C_POINTER}, C_BOOL) return c_func(cDeviceIoControl,{hDevice,dwIoControlCode, lpInBuffer,nInBufferSize, lpOutBuffer,nOutBufferSize,lpBytesReturned,lpOverlapped}) end function public function CloseHandle(atom hObject) integer cCloseHandle = define_c_func(kernel32, "CloseHandle", {C_POINTER}, C_BOOL) return c_func(cCloseHandle,{hObject}) end function function IsUsbDevice( integer letter ) --was bool sequence volumeAccessPath = "\\\\.\\X:" volumeAccessPath[5] = letter atom deviceHandle = CreateFile( allocate_string(volumeAccessPath, 1), 0, -- no access to the drive, non admin or_all({FILE_SHARE_READ, -- | share mode FILE_SHARE_WRITE}), NULL, -- default security attributes OPEN_EXISTING, -- disposition 0, -- file attributes NULL) -- do not copy file attributes --printf(1,"%s CreateFile er=%s ",{volumeAccessPath, get_winerror_string()}) c_proc( xSetLastError, {0} ) -- setup query atom query = allocate(sizeof(STORAGE_PROPERTY_QUERY), 1) mem_set(query, 0, sizeof(STORAGE_PROPERTY_QUERY)) query.STORAGE_PROPERTY_QUERY.PropertyId = StorageDeviceProperty query.STORAGE_PROPERTY_QUERY.QueryType = PropertyStandardQuery -- issue query atom bytes = allocate(8, 1 ) -- max pointer just in case atom devd = allocate(sizeof(STORAGE_DEVICE_DESCRIPTOR), 1) integer busType = BusTypeUnknown if DeviceIoControl(deviceHandle, IOCTL_STORAGE_QUERY_PROPERTY, query, sizeof(STORAGE_PROPERTY_QUERY), --& devd, sizeof(STORAGE_DEVICE_DESCRIPTOR), --& bytes, NULL) --& then busType = devd.STORAGE_DEVICE_DESCRIPTOR.BusType else atom eror = GetLastError() printf(1, "\n\tFailed to define bus type for: %s: winerr%s\n", { letter, get_winerror_string(eror) }) end if CloseHandle(deviceHandle) return busType -- was BusTypeUsb= end function sequence drives = GetLogicalDriveStrings() --?drives --printf(1,"%s\n",{hexdump( join(drives, " _ ") ) }) -- drives = { -- "A:\\", -- "U:\\" -- } for x = 1 to length(drives) do sequence warn = "", bar = "" atom min_file_size = 0 integer rstate = GetDriveType(drives[x]) atom bt = IsUsbDevice(drives[x][1]) if rstate = DRIVE_REMOVABLE then bar = sprintf(" -----\tREMOVABLE/FLOPPY ", {}) elsif rstate = DRIVE_CDROM then bar = sprintf(" -----\tDRIVE_CDROM ", {}) elsif rstate != DRIVE_FIXED then bar = sprintf(" -----\tDRIVE_UNKNOWN %d ", {rstate}) else end if if length(bar) then bar &= map:get(BusTypeMap, bt,"BTUNKNOWN") else sequence res = disk_size(drives[x]) printf(1, "Drive %s has %3.0f%% free space %s\n", { drives[x], res[FREE_BYTES] / res[TOTAL_BYTES]*100, map:get(BusTypeMap, bt,"BTUNKNOWN") }) res = disk_metrics(drives[x]) min_file_size = res[SECTORS_PER_CLUSTER] * res[BYTES_PER_SECTOR] atom tot= (res[TOTAL_NUMBER_OF_CLUSTERS] *res[BYTES_PER_SECTOR] *res[SECTORS_PER_CLUSTER])/BYTE_STANDARD atom fs = (((res[SECTORS_PER_CLUSTER]) *(res[BYTES_PER_SECTOR]) *(res[NUMBER_OF_FREE_CLUSTERS]))/1048576) bar = sprintf("%d MB %s %d",{ fs/1000, "-------------", tot/1000}) end if printf(1,"%s %s \t%s %d\n",{warn, drives[x][1], bar, rstate}) end for /* Failed to define bus type for: A: winerr0x1 Incorrect function. A ----- REMOVABLE/FLOPPY BusTypeUnknown 2 Drive C:\ has 17% free space BusTypeUnknown C 1 MB ------------- 10 3 F ----- DRIVE_CDROM BusTypeUnknown 5 G ----- DRIVE_CDROM BusTypeSsa 5 H ----- REMOVABLE/FLOPPY BusTypeUnknown 2 Drive U:\ has 21% free space BusTypeUnknown U 2 MB ------------- 12 3 G,H,U are USB */


