parent
b0dfa932b6
commit
73f4e23938
|
@ -46,7 +46,8 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(volume);
|
||||
|
||||
#define SUPERBLOCK_SIZE 2048
|
||||
#define BLOCK_SIZE 2048
|
||||
#define SUPERBLOCK_SIZE BLOCK_SIZE
|
||||
#define SYMBOLIC_LINK_QUERY 0x0001
|
||||
|
||||
#define CDFRAMES_PERSEC 75
|
||||
|
@ -63,7 +64,8 @@ enum fs_type
|
|||
FS_UNKNOWN, /* unknown file system */
|
||||
FS_FAT1216,
|
||||
FS_FAT32,
|
||||
FS_ISO9660
|
||||
FS_ISO9660,
|
||||
FS_UDF /* For reference [E] = Ecma-167.pdf, [U] = udf260.pdf */
|
||||
};
|
||||
|
||||
/* read a Unix symlink; returned buffer must be freed by caller */
|
||||
|
@ -386,31 +388,107 @@ static enum fs_type VOLUME_ReadFATSuperblock( HANDLE handle, BYTE *buff )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* VOLUME_ReadCDBlock
|
||||
*/
|
||||
static BOOL VOLUME_ReadCDBlock( HANDLE handle, BYTE *buff, INT offs )
|
||||
{
|
||||
DWORD size, whence = offs >= 0 ? FILE_BEGIN : FILE_END;
|
||||
|
||||
if (SetFilePointer( handle, offs, NULL, whence ) != offs ||
|
||||
!ReadFile( handle, buff, SUPERBLOCK_SIZE, &size, NULL ) ||
|
||||
size != SUPERBLOCK_SIZE)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* VOLUME_ReadCDSuperblock
|
||||
*/
|
||||
static enum fs_type VOLUME_ReadCDSuperblock( HANDLE handle, BYTE *buff )
|
||||
{
|
||||
DWORD size, offs = VOLUME_FindCdRomDataBestVoldesc( handle );
|
||||
int i;
|
||||
DWORD offs;
|
||||
|
||||
/* Check UDF first as UDF and ISO9660 structures can coexist on the same medium
|
||||
* Starting from sector 16, we may find :
|
||||
* - a CD-ROM Volume Descriptor Set (ISO9660) containing one or more Volume Descriptors
|
||||
* - an Extented Area (UDF) -- [E] 2/8.3.1 and [U] 2.1.7
|
||||
* There is no explicit end so read 16 sectors and then give up */
|
||||
for( i=16; i<16+16; i++)
|
||||
{
|
||||
if (!VOLUME_ReadCDBlock(handle, buff, i*BLOCK_SIZE))
|
||||
continue;
|
||||
|
||||
/* We are supposed to check "BEA01", "NSR0x" and "TEA01" IDs + verify tag checksum
|
||||
* but we assume the volume is well-formatted */
|
||||
if (!memcmp(&buff[1], "BEA01", 5)) return FS_UDF;
|
||||
}
|
||||
|
||||
offs = VOLUME_FindCdRomDataBestVoldesc( handle );
|
||||
if (!offs) return FS_UNKNOWN;
|
||||
|
||||
if (SetFilePointer( handle, offs, NULL, FILE_BEGIN ) != offs ||
|
||||
!ReadFile( handle, buff, SUPERBLOCK_SIZE, &size, NULL ) ||
|
||||
size != SUPERBLOCK_SIZE)
|
||||
if (!VOLUME_ReadCDBlock(handle, buff, offs))
|
||||
return FS_ERROR;
|
||||
|
||||
/* check for iso9660 present */
|
||||
/* check for the iso9660 identifier */
|
||||
if (!memcmp(&buff[1], "CD001", 5)) return FS_ISO9660;
|
||||
return FS_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* UDF_Find_PVD
|
||||
* Find the Primary Volume Descriptor
|
||||
*/
|
||||
static BOOL UDF_Find_PVD( HANDLE handle, BYTE pvd[] )
|
||||
{
|
||||
int i;
|
||||
DWORD offset;
|
||||
INT locations[] = { 256, -1, -257, 512 };
|
||||
|
||||
for(i=0; i<sizeof(locations)/sizeof(locations[0]); i++)
|
||||
{
|
||||
if (!VOLUME_ReadCDBlock(handle, pvd, locations[i]*BLOCK_SIZE))
|
||||
return FALSE;
|
||||
|
||||
/* Tag Identifier of Anchor Volume Descriptor Pointer is 2 -- [E] 3/10.2.1 */
|
||||
if (pvd[0]==2 && pvd[1]==0)
|
||||
{
|
||||
/* Tag location (Uint32) at offset 12, little-endian */
|
||||
offset = pvd[20 + 0];
|
||||
offset |= pvd[20 + 1] << 8;
|
||||
offset |= pvd[20 + 2] << 16;
|
||||
offset |= pvd[20 + 3] << 24;
|
||||
offset *= BLOCK_SIZE;
|
||||
|
||||
if (!VOLUME_ReadCDBlock(handle, pvd, offset))
|
||||
return FALSE;
|
||||
|
||||
/* Check for the Primary Volume Descriptor Tag Id -- [E] 3/10.1.1 */
|
||||
if (pvd[0]!=1 || pvd[1]!=0)
|
||||
return FALSE;
|
||||
|
||||
/* 8 or 16 bits per character -- [U] 2.1.1 */
|
||||
if (!(pvd[24]==8 || pvd[24]==16))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* VOLUME_GetSuperblockLabel
|
||||
*/
|
||||
static void VOLUME_GetSuperblockLabel( const UNICODE_STRING *device, enum fs_type type,
|
||||
const BYTE *superblock, WCHAR *label, DWORD len )
|
||||
static void VOLUME_GetSuperblockLabel( const UNICODE_STRING *device, HANDLE handle,
|
||||
enum fs_type type, const BYTE *superblock,
|
||||
WCHAR *label, DWORD len )
|
||||
{
|
||||
const BYTE *label_ptr = NULL;
|
||||
DWORD label_len;
|
||||
|
@ -451,6 +529,34 @@ static void VOLUME_GetSuperblockLabel( const UNICODE_STRING *device, enum fs_typ
|
|||
label_len = 32;
|
||||
break;
|
||||
}
|
||||
case FS_UDF:
|
||||
{
|
||||
BYTE pvd[BLOCK_SIZE];
|
||||
|
||||
if(!UDF_Find_PVD(handle, pvd))
|
||||
{
|
||||
label_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* [E] 3/10.1.4 and [U] 2.1.1 */
|
||||
if(pvd[24]==8)
|
||||
{
|
||||
label_ptr = pvd + 24 + 1;
|
||||
label_len = pvd[24+32-1];
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
label_len = 1 + pvd[24+32-1];
|
||||
for(i=0; i<label_len && i<len; i+=2)
|
||||
label[i/2] = (pvd[24+1 +i] << 8) | pvd[24+1 +i+1];
|
||||
label[label_len] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (label_len) RtlMultiByteToUnicodeN( label, (len-1) * sizeof(WCHAR),
|
||||
&label_len, (LPCSTR)label_ptr, label_len );
|
||||
|
@ -463,8 +569,8 @@ static void VOLUME_GetSuperblockLabel( const UNICODE_STRING *device, enum fs_typ
|
|||
/**************************************************************************
|
||||
* VOLUME_GetSuperblockSerial
|
||||
*/
|
||||
static DWORD VOLUME_GetSuperblockSerial( const UNICODE_STRING *device, enum fs_type type,
|
||||
const BYTE *superblock )
|
||||
static DWORD VOLUME_GetSuperblockSerial( const UNICODE_STRING *device, HANDLE handle,
|
||||
enum fs_type type, const BYTE *superblock )
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
@ -476,6 +582,17 @@ static DWORD VOLUME_GetSuperblockSerial( const UNICODE_STRING *device, enum fs_t
|
|||
return GETLONG( superblock, 0x27 );
|
||||
case FS_FAT32:
|
||||
return GETLONG( superblock, 0x33 );
|
||||
case FS_UDF:
|
||||
{
|
||||
BYTE block[BLOCK_SIZE];
|
||||
|
||||
if (!VOLUME_ReadCDBlock(handle, block, 257*BLOCK_SIZE))
|
||||
break;
|
||||
|
||||
superblock = block;
|
||||
|
||||
/* fallthrough */
|
||||
}
|
||||
case FS_ISO9660:
|
||||
{
|
||||
BYTE sum[4];
|
||||
|
@ -495,7 +612,7 @@ static DWORD VOLUME_GetSuperblockSerial( const UNICODE_STRING *device, enum fs_t
|
|||
* Me$$ysoft chose to reverse the serial number in NT4/W2K.
|
||||
* It's true and nobody will ever be able to change it.
|
||||
*/
|
||||
if (GetVersion() & 0x80000000)
|
||||
if (GetVersion() & 0x80000000 || type == FS_UDF)
|
||||
return (sum[3] << 24) | (sum[2] << 16) | (sum[1] << 8) | sum[0];
|
||||
else
|
||||
return (sum[0] << 24) | (sum[1] << 16) | (sum[2] << 8) | sum[3];
|
||||
|
@ -546,6 +663,7 @@ BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len,
|
|||
static const WCHAR fat32W[] = {'F','A','T','3','2',0};
|
||||
static const WCHAR ntfsW[] = {'N','T','F','S',0};
|
||||
static const WCHAR cdfsW[] = {'C','D','F','S',0};
|
||||
static const WCHAR udfW[] = {'U','D','F',0};
|
||||
static const WCHAR default_rootW[] = {'\\',0};
|
||||
|
||||
HANDLE handle;
|
||||
|
@ -618,12 +736,16 @@ BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len,
|
|||
type = VOLUME_ReadFATSuperblock( handle, superblock );
|
||||
if (type == FS_UNKNOWN) type = VOLUME_ReadCDSuperblock( handle, superblock );
|
||||
}
|
||||
CloseHandle( handle );
|
||||
TRACE( "%s: found fs type %d\n", debugstr_w(nt_name.Buffer), type );
|
||||
if (type == FS_ERROR) goto done;
|
||||
if (type == FS_ERROR)
|
||||
{
|
||||
CloseHandle( handle );
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (label && label_len) VOLUME_GetSuperblockLabel( &nt_name, type, superblock, label, label_len );
|
||||
if (serial) *serial = VOLUME_GetSuperblockSerial( &nt_name, type, superblock );
|
||||
if (label && label_len) VOLUME_GetSuperblockLabel( &nt_name, handle, type, superblock, label, label_len );
|
||||
if (serial) *serial = VOLUME_GetSuperblockSerial( &nt_name, handle, type, superblock );
|
||||
CloseHandle( handle );
|
||||
goto fill_fs_info;
|
||||
}
|
||||
else TRACE( "cannot open device %s: %x\n", debugstr_w(nt_name.Buffer), status );
|
||||
|
@ -657,6 +779,12 @@ fill_fs_info: /* now fill in the information that depends on the file system ty
|
|||
if (filename_len) *filename_len = 221;
|
||||
if (flags) *flags = FILE_READ_ONLY_VOLUME;
|
||||
break;
|
||||
case FS_UDF:
|
||||
if (fsname) lstrcpynW( fsname, udfW, fsname_len );
|
||||
if (filename_len) *filename_len = 255;
|
||||
if (flags)
|
||||
*flags = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH;
|
||||
break;
|
||||
case FS_FAT1216:
|
||||
if (fsname) lstrcpynW( fsname, fatW, fsname_len );
|
||||
case FS_FAT32:
|
||||
|
|
Loading…
Reference in New Issue