OK, as it's a little quiet... I'll ask a few questions I was saving for later.
According to MSDN for GetDiskFreeSpaceEx:
Quote from: MSDNThe GetDiskFreeSpaceEx function returns 0 (zero) for lpTotalNumberOfFreeBytes and lpFreeBytesAvailable for all CD requests unless the disk is an unwritten CD in a CD-RW drive. [MY ITALICS]
In my understanding, if a CD or a DVD is multi-session, as they normally are, then it's still writable, so if partially written there must be a way of getting the amount of space left available to write on it. This comment from MSDN suggests that may not be an obvious or simple task. Does anyone have any idea how to confirm the remaining space on a partially written CD/DVD disk?
Second question, about low-level access. I am aware that there is a program which allows you to extract any readable data from a CD/DVD disk if the OS refuses to read the files in the normal way, perhaps because the FAT is unreadable. This is a means of last-ditch data recovery in case of partial dye "fade" in the medium. Can anyone point me in the direction of APIs which would allow such recovery, avoiding normal file API procedures?
Ian_B
I would assume the windows functions will report there is never any free space left on a written cd. A hack way to get the remaining space would be to subtract the size of the written data from the total capacity :wink
For direct access, ASPI is generally used - I presume this will provide the necessary functionality.
Quote from: Tedd on July 27, 2006, 11:18:46 AMA hack way to get the remaining space would be to subtract the size of the written data from the total capacity :wink
And how would you get either of those values? :eek The closest API I saw to finding the size of a volume is DeviceIoControl with IOCTL_DISK_GET_LENGTH_INFO, which is useless to me as it is only available from WinXP up.
QuoteFor direct access, ASPI is generally used - I presume this will provide the necessary functionality.
OK, I can see from the fact that the entire Windows SDK contains exactly one passing reference to ASPI that this is not going to be a short investigation... :'(
Ian_B
Hmmmmmm... :dazzled:
Found a smattering of highly obscure low-level info, and even a copy of the ASPI SDK, so I have somewhere to start to research the data recovery problem. Still not sure it's going to help me with the apparently simpler problem of finding the quantity of available unwritten space on a CD/DVD disk.
But now there is an even more obvious problem - supposing I can use ASPI to query the available adapters and find a CD or DVD drive on a particular adapter with a particular ID/LUN, how can I convert that to check if it's the particular LOGICAL drive (ie. F: G: H: etc.) I want? :eek Is there anyone out there with ASPI programming expertise that can help?
Ian_B
do you have to use aspi?
why not use spti, its available from 2k onwards, works via createfile \\.\x: (where x = cd drive letter), and accessable like a file (setfilepointer, readfile and so on),
and supports dioc commands, which you can use to get the disk geometry etc.. much much much easier than aspi
Thanks for that suggestion, but there's even less information available for "SPTI" than there is for ASPI... :bdg I was also hoping to put together a solution that might work for preNT versions of Windows too.
Rummaging around the SDK for anything related, though, it appears that I can use DeviceIOControl with IOCTL_DISK_GET_DRIVE_GEOMETRY to retrieve the full disk size (by multiplying all the returned values together) and that will work on WinNT4+. That's a start... but still don't know how to find the amount of used space, and there don't seem to be any other relevant IOCTL codes even for later Win versions.
EDIT: I realised that I do actually have a hack-type solution for the used-space problem, although it's not ideal or exact. I am already doing a recursion to find all files in a subtree and get their sizes, and for a root path that would effectively be all files on the disk. So at that point I will have a count of the total file data written, although subtracting that from the media size reported may not be exactly the same as the total amount of space still available.
Ian_B
Related problem, an enum value returned in the DISK_GEOMETRY structure. I am interested in the RemovableMedia value if present... but what is the actual number? It's not explicitly defined in winioctl.h except for this C code. Does the enum start at 0 or 1, ie. is the RemovableMedia value 11 or 12?
typedef enum _MEDIA_TYPE
{
Unknown Format is unknown,
F5_1Pt2_512 A 5.25" floppy, with 1.2MB and 512 bytes/sector,
F3_1Pt44_512 A 3.5" floppy, with 1.44MB and 512 bytes/sector,
F3_2Pt88_512 A 3.5" floppy, with 2.88MB and 512 bytes/sector,
F3_20Pt8_512 A 3.5" floppy, with 20.8MB and 512 bytes/sector,
F3_720_512 A 3.5" floppy, with 720KB and 512 bytes/sector,
F5_360_512 A 5.25" floppy, with 360KB and 512 bytes/sector,
F5_320_512 A 5.25" floppy, with 320KB and 512 bytes/sector,
F5_320_1024 A 5.25" floppy, with 320KB and 1024 bytes/sector,
F5_180_512 A 5.25" floppy, with 180KB and 512 bytes/sector,
F5_160_512 A 5.25" floppy, with 160KB and 512 bytes/sector,
RemovableMedia Removable media other than floppy,
FixedMedia Fixed hard disk media,
F3_120M_512 A 3.5" floppy, with 120MB and 512 bytes/sector,
F3_640_512 A 3.5" floppy, with 640MB and 512 bytes/sector,
F5_640_512 A 5.25" floppy, with 640KB and 512 bytes/sector,
F5_720_512 A 5.25" floppy, with 720KB and 512 bytes/sector,
F3_1Pt2_512 A 3.5" floppy, with 1.2MB and 512 bytes/sector,
F3_1Pt23_1024 A 3.5" floppy, with 1.23MB and 1024 bytes/sector,
F5_1Pt23_1024 A 5.25" floppy, with 1.23KB and 1024 bytes/sector,
F3_128Mb_512 A 3.5" floppy, with 128MB and 512 bytes/sector,
F3_230Mb_512 A 3.5" floppy, with 230MB and 512 bytes/sector,
F8_256_128 An 8" floppy, with 256KB and 128 bytes/sector,
F3_200Mb_512 A 3.5" floppy, with 200MB and 512 bytes/sector. (HiFD),
F3_240M_512 A 3.5" floppy, with 240MB and 512 bytes/sector. (HiFD),
F3_32M_512 A 3.5" floppy, with 32MB and 512 bytes/sector.
} MEDIA_TYPE;
EDIT: Guess it's easier to ignore this and just test for DRIVE_CDROM returned by GetDriveType... :bg
EDIT 2: It's sad that no C-savvy programmer here bothered to reply. :'( Empirically, though, the enum starts at 0 and the RemovableMedia value is correctly returned as 11 for a CD drive using a IOCTL_DISK_GET_DRIVE_GEOMETRY call (see below).
Ian_B
Another issue I have just found with this general problem - to access a volume using DeviceIoControl requires the following:
Quote from: MSDNPhysical Disks and Volumes
You can use the CreateFile function to open a physical disk drive or a volume. The function returns a handle that can be used with the DeviceIoControl function. This enables you to access the disk partition table. However, it is potentially dangerous to do so, because an incorrect write to a disk could make its contents inaccessible. The following requirements must be met for such a call to succeed:
The caller must have administrative privileges.
So it seems you can't use this method to simply query a CD/DVD drive and find out the maximum size of the media it currently contains, unless you are running in admin privilege mode. How crazy is that? There HAS to be another method that works for all privilege levels, surely? :eek Unless we are back to ASPI...
Ian_B
Here's a minimal piece of code to answer some of these questions. The results initially seemed encouraging, except for the last mentioned issue of the CreateFile call for a disk volume only working at administrative privilege level...
.686
.MMX
.model flat, stdcall
option casemap:none
option noscoped
include masm32\include\windows.inc
include masm32\include\kernel32.inc
include masm32\include\masm32.inc
include masm32\macros\macros.asm
include masm32\macros\timers.asm
includelib masm32\lib\kernel32.lib
includelib masm32\lib\masm32.lib
Main proto
.data
DISK_GEOMETRY struct
CylindersLo DWORD ?
CylindersHi DWORD ?
MediaType DWORD ?
TracksPerCylinder DWORD ?
SectorsPerTrack DWORD ?
BytesPerSector DWORD ?
DISK_GEOMETRY ENDS
IOCTL_DISK_GET_DRIVE_GEOMETRY EQU 70000H
SzCDDrive db "\\.\R:",0
.data?
align 16
DG DISK_GEOMETRY <>
junk DWORD ?
.code
Start:
Invoke Main
Invoke ExitProcess, 0
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
align 16
Main proc
push ebx
push edi
push esi
mov eax, input("Press ENTER to begin...",13,10,13,10)
xor ebx, ebx
mov ecx, FILE_SHARE_READ+FILE_SHARE_WRITE ; must include FILE_SHARE_WRITE
invoke CreateFile, OFFSET SzCDDrive, ebx , ecx, ebx, OPEN_EXISTING, ebx, ebx
mov esi, eax
cmp eax, INVALID_HANDLE_VALUE
je AccessError
lea edi, DG
mov edx, IOCTL_DISK_GET_DRIVE_GEOMETRY
invoke DeviceIoControl, esi, edx, ebx, ebx, edi, SIZEOF DISK_GEOMETRY, OFFSET junk, ebx
test eax, eax
jz AccessError
ASSUME EDI:PTR DISK_GEOMETRY
print chr$("Drive R:",13,10,"CylindersLo: ")
mov eax, [edi].CylindersLo
print ustr$(eax)
print chr$(13,10,"CylindersHi: ")
mov eax, [edi].CylindersHi
print ustr$(eax)
print chr$(13,10,"MediaType: ")
mov eax, [edi].MediaType
print ustr$(eax)
print chr$(13,10,"TracksPerCylinder: ")
mov eax, [edi].TracksPerCylinder
print ustr$(eax)
print chr$(13,10,"SectorsPerTrack: ")
mov eax, [edi].SectorsPerTrack
print ustr$(eax)
print chr$(13,10,"BytesPerSector: ")
mov eax, [edi].BytesPerSector
print ustr$(eax)
ASSUME EDI:NOTHING
jmp @F
AccessError:
invoke GetLastError
mov ebx, eax
print chr$("I/O Error:")
print ustr$(ebx)
@@:
print chr$(13,10,13,10)
mov eax, input("Press ENTER to exit...")
pop esi
pop edi
pop ebx
ret
Main EndP
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
End Start
The output for my CD-writer:
Drive R:
CylindersLo: 163
CylindersHi: 0
MediaType: 11
TracksPerCylinder: 64
SectorsPerTrack: 32
BytesPerSector: 2048
So at least we find the answer to the enum query above, and that the size of a MEDIA_TYPE entry (which I have unsuccessfully searched high and low for on the net and through the SDK all day) is a DWORD, so the structure definition is valid...
However, multiplying up all the values gives a result of 652Mb for a pre-pressed CD (above), and 613Mb for a "700Mb" CD-RW I tested with 613Mb of data on it (as reported by Explorer, which also correctly said there was 67.1Mb still available to write), so by reporting the used space rather than the overall drive geometry as might have been expected it's doing no better than the count-all-the-files approach, and with the limitation of the admin privilege required. And the Explorer info shows there's definitely a method of getting the full media size that doesn't require ASPI.
So what the **** is it? :dazzled:
Ian_B
actually, i'd still use the createfile \\.\*: (* = cd/dvd letter), and you stated it needs admin, well it does
but theres a little 'backdoor'...
QueryDosDevice on the drive letter, it returns sz terminated strings, with 'different' access models (backdoorish)
you'll see something like Device\Cdrom0 etc...
CreateFile on \\.\Cdrom0 works (ie: one of the 'models' returned in the buffer.. stripped...cant remember if you need a : at the end..)
works in NON admin mode...
from then you have your interface, then you can do all the DeviceIoControl you like ;)
hope that helps (and again, only works on 2k upwards..)
oh yeah, and as for the size.. tried using GetFileSize on the handle you get from the CreateFile ? hmm, just checked, that doesnt work, how about GetDiskFreeSpace or something? i'd use the ioctl personally
and for sector reading, SetFilePointer (sectorsize*sector you want to read) then ReadFile works :)
Quote from: Ian_B on July 27, 2006, 09:28:25 AM
OK, as it's a little quiet... I'll ask a few questions I was saving for later.
According to MSDN for GetDiskFreeSpaceEx:
Quote from: MSDNThe GetDiskFreeSpaceEx function returns 0 (zero) for lpTotalNumberOfFreeBytes and lpFreeBytesAvailable for all CD requests unless the disk is an unwritten CD in a CD-RW drive. [MY ITALICS]
In my understanding, if a CD or a DVD is multi-session, as they normally are, then it's still writable, so if partially written there must be a way of getting the amount of space left available to write on it. This comment from MSDN suggests that may not be an obvious or simple task. Does anyone have any idea how to confirm the remaining space on a partially written CD/DVD disk?
Second question, about low-level access. I am aware that there is a program which allows you to extract any readable data from a CD/DVD disk if the OS refuses to read the files in the normal way, perhaps because the FAT is unreadable. This is a means of last-ditch data recovery in case of partial dye "fade" in the medium. Can anyone point me in the direction of APIs which would allow such recovery, avoiding normal file API procedures?
Ian_B
Did you test the 'GetDiskFreeSpace' function??
think it'd be the same as above - spti interface, using raw reads, not 'cooked' (different IOCTL code for that)