Module: wine Branch: master Commit: 73f4e23938142225efdc233f9db56334ce8e326f URL: http://source.winehq.org/git/wine.git/?a=commit;h=73f4e23938142225efdc233f9d...
Author: Alexandre Goujon ale.goujon@gmail.com Date: Thu Sep 1 16:30:15 2011 +0200
kernel32: Add UDF support.
Based on Steven Wallace work.
---
dlls/kernel32/volume.c | 160 +++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 144 insertions(+), 16 deletions(-)
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c index 25affc3..4a2a7b5 100644 --- a/dlls/kernel32/volume.c +++ b/dlls/kernel32/volume.c @@ -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 */ @@ -387,30 +389,106 @@ 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: