Reimplemented GetVolumeInformation and SetVolumeLabel; volume label
and serial number are now stored in the filesystem instead of in the config file (partly based on a patch by Eric Pouech).
This commit is contained in:
parent
b8fc5282a8
commit
954c570ae3
|
@ -75,6 +75,7 @@ C_SRCS = \
|
|||
utthunk.c \
|
||||
version.c \
|
||||
virtual.c \
|
||||
volume.c \
|
||||
vxd.c \
|
||||
win87em.c \
|
||||
windebug.c \
|
||||
|
|
|
@ -0,0 +1,626 @@
|
|||
/*
|
||||
* Volume management functions
|
||||
*
|
||||
* Copyright 1993 Erik Bos
|
||||
* Copyright 1996, 2004 Alexandre Julliard
|
||||
* Copyright 1999 Petr Tomasek
|
||||
* Copyright 2000 Andreas Mohr
|
||||
* Copyright 2003 Eric Pouech
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "winnls.h"
|
||||
#include "winternl.h"
|
||||
#include "ntstatus.h"
|
||||
#include "winioctl.h"
|
||||
#include "ntddstor.h"
|
||||
#include "ntddcdrm.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(volume);
|
||||
|
||||
#define SUPERBLOCK_SIZE 2048
|
||||
|
||||
#define CDFRAMES_PERSEC 75
|
||||
#define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
|
||||
#define FRAME_OF_ADDR(a) ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])
|
||||
#define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc)->TrackData[(idx) - (toc)->FirstTrack].Address)
|
||||
|
||||
#define GETWORD(buf,off) MAKEWORD(buf[(off)],buf[(off+1)])
|
||||
#define GETLONG(buf,off) MAKELONG(GETWORD(buf,off),GETWORD(buf,off+2))
|
||||
|
||||
enum fs_type
|
||||
{
|
||||
FS_ERROR, /* error accessing the device */
|
||||
FS_UNKNOWN, /* unknown file system */
|
||||
FS_FAT1216,
|
||||
FS_FAT32,
|
||||
FS_ISO9660
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* VOLUME_FindCdRomDataBestVoldesc
|
||||
*/
|
||||
static DWORD VOLUME_FindCdRomDataBestVoldesc( HANDLE handle )
|
||||
{
|
||||
BYTE cur_vd_type, max_vd_type = 0;
|
||||
BYTE buffer[16];
|
||||
DWORD size, offs, best_offs = 0, extra_offs = 0;
|
||||
|
||||
for (offs = 0x8000; offs <= 0x9800; offs += 0x800)
|
||||
{
|
||||
/* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
|
||||
* the volume label is displaced forward by 8
|
||||
*/
|
||||
if (SetFilePointer( handle, offs, NULL, FILE_BEGIN ) != offs) break;
|
||||
if (!ReadFile( handle, buffer, sizeof(buffer), &size, NULL )) break;
|
||||
if (size != sizeof(buffer)) break;
|
||||
/* check for non-ISO9660 signature */
|
||||
if (!memcmp( buffer + 11, "ROM", 3 )) extra_offs = 8;
|
||||
cur_vd_type = buffer[extra_offs];
|
||||
if (cur_vd_type == 0xff) /* voldesc set terminator */
|
||||
break;
|
||||
if (cur_vd_type > max_vd_type)
|
||||
{
|
||||
max_vd_type = cur_vd_type;
|
||||
best_offs = offs + extra_offs;
|
||||
}
|
||||
}
|
||||
return best_offs;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* VOLUME_ReadFATSuperblock
|
||||
*/
|
||||
static enum fs_type VOLUME_ReadFATSuperblock( HANDLE handle, BYTE *buff )
|
||||
{
|
||||
DWORD size;
|
||||
|
||||
/* try a fixed disk, with a FAT partition */
|
||||
if (SetFilePointer( handle, 0, NULL, FILE_BEGIN ) != 0 ||
|
||||
!ReadFile( handle, buff, SUPERBLOCK_SIZE, &size, NULL ) ||
|
||||
size != SUPERBLOCK_SIZE)
|
||||
return FS_ERROR;
|
||||
|
||||
if (buff[0] == 0xE9 || (buff[0] == 0xEB && buff[2] == 0x90))
|
||||
{
|
||||
/* guess which type of FAT we have */
|
||||
unsigned int sz, nsect, nclust;
|
||||
sz = GETWORD(buff, 0x16);
|
||||
if (!sz) sz = GETLONG(buff, 0x24);
|
||||
nsect = GETWORD(buff, 0x13);
|
||||
if (!nsect) nsect = GETLONG(buff, 0x20);
|
||||
nsect -= GETWORD(buff, 0x0e) + buff[0x10] * sz +
|
||||
(GETWORD(buff, 0x11) * 32 + (GETWORD(buff, 0x0b) - 1)) / GETWORD(buff, 0x0b);
|
||||
nclust = nsect / buff[0x0d];
|
||||
|
||||
if (nclust < 65525)
|
||||
{
|
||||
if (buff[0x26] == 0x29 && !memcmp(buff+0x36, "FAT", 3))
|
||||
{
|
||||
/* FIXME: do really all FAT have their name beginning with
|
||||
* "FAT" ? (At least FAT12, FAT16 and FAT32 have :)
|
||||
*/
|
||||
return FS_FAT1216;
|
||||
}
|
||||
}
|
||||
else if (!memcmp(buff+0x52, "FAT", 3)) return FS_FAT32;
|
||||
}
|
||||
return FS_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* VOLUME_ReadCDSuperblock
|
||||
*/
|
||||
static enum fs_type VOLUME_ReadCDSuperblock( HANDLE handle, BYTE *buff )
|
||||
{
|
||||
DWORD size, 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)
|
||||
return FS_ERROR;
|
||||
|
||||
/* check for iso9660 present */
|
||||
if (!memcmp(&buff[1], "CD001", 5)) return FS_ISO9660;
|
||||
return FS_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* VOLUME_GetSuperblockLabel
|
||||
*/
|
||||
static void VOLUME_GetSuperblockLabel( enum fs_type type, const BYTE *superblock,
|
||||
WCHAR *label, DWORD len )
|
||||
{
|
||||
const BYTE *label_ptr = NULL;
|
||||
DWORD label_len;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case FS_ERROR:
|
||||
case FS_UNKNOWN:
|
||||
label_len = 0;
|
||||
break;
|
||||
case FS_FAT1216:
|
||||
label_ptr = superblock + 0x2b;
|
||||
label_len = 11;
|
||||
break;
|
||||
case FS_FAT32:
|
||||
label_ptr = superblock + 0x47;
|
||||
label_len = 11;
|
||||
break;
|
||||
case FS_ISO9660:
|
||||
{
|
||||
BYTE ver = superblock[0x5a];
|
||||
|
||||
if (superblock[0x58] == 0x25 && superblock[0x59] == 0x2f && /* Unicode ID */
|
||||
((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
|
||||
{ /* yippee, unicode */
|
||||
int i;
|
||||
|
||||
if (len > 17) len = 17;
|
||||
for (i = 0; i < len-1; i++)
|
||||
label[i] = (superblock[40+2*i] << 8) | superblock[41+2*i];
|
||||
label[i] = 0;
|
||||
while (i && label[i-1] == ' ') label[--i] = 0;
|
||||
return;
|
||||
}
|
||||
label_ptr = superblock + 40;
|
||||
label_len = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (label_len) RtlMultiByteToUnicodeN( label, (len-1) * sizeof(WCHAR),
|
||||
&label_len, label_ptr, label_len );
|
||||
label_len /= sizeof(WCHAR);
|
||||
label[label_len] = 0;
|
||||
while (label_len && label[label_len-1] == ' ') label[--label_len] = 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* VOLUME_SetSuperblockLabel
|
||||
*/
|
||||
static BOOL VOLUME_SetSuperblockLabel( enum fs_type type, HANDLE handle, const WCHAR *label )
|
||||
{
|
||||
BYTE label_data[11];
|
||||
DWORD offset, len;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case FS_FAT1216:
|
||||
offset = 0x2b;
|
||||
break;
|
||||
case FS_FAT32:
|
||||
offset = 0x47;
|
||||
break;
|
||||
default:
|
||||
SetLastError( ERROR_ACCESS_DENIED );
|
||||
return FALSE;
|
||||
}
|
||||
RtlUnicodeToMultiByteN( label_data, sizeof(label_data), &len,
|
||||
label, strlenW(label) * sizeof(WCHAR) );
|
||||
if (len < sizeof(label_data))
|
||||
memset( label_data + len, ' ', sizeof(label_data) - len );
|
||||
|
||||
return (SetFilePointer( handle, offset, NULL, FILE_BEGIN ) == offset &&
|
||||
WriteFile( handle, label_data, sizeof(label_data), &len, NULL ));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* VOLUME_GetSuperblockSerial
|
||||
*/
|
||||
static DWORD VOLUME_GetSuperblockSerial( enum fs_type type, const BYTE *superblock )
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case FS_ERROR:
|
||||
case FS_UNKNOWN:
|
||||
break;
|
||||
case FS_FAT1216:
|
||||
return GETLONG( superblock, 0x27 );
|
||||
case FS_FAT32:
|
||||
return GETLONG( superblock, 0x33 );
|
||||
case FS_ISO9660:
|
||||
{
|
||||
BYTE sum[4];
|
||||
int i;
|
||||
|
||||
sum[0] = sum[1] = sum[2] = sum[3] = 0;
|
||||
for (i = 0; i < 2048; i += 4)
|
||||
{
|
||||
/* DON'T optimize this into DWORD !! (breaks overflow) */
|
||||
sum[0] += superblock[i+0];
|
||||
sum[1] += superblock[i+1];
|
||||
sum[2] += superblock[i+2];
|
||||
sum[3] += superblock[i+3];
|
||||
}
|
||||
/*
|
||||
* OK, another braindead one... argh. Just believe it.
|
||||
* 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)
|
||||
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];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* VOLUME_GetAudioCDSerial
|
||||
*/
|
||||
static DWORD VOLUME_GetAudioCDSerial( const CDROM_TOC *toc )
|
||||
{
|
||||
DWORD serial = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= toc->LastTrack - toc->FirstTrack; i++)
|
||||
serial += ((toc->TrackData[i].Address[1] << 16) |
|
||||
(toc->TrackData[i].Address[2] << 8) |
|
||||
toc->TrackData[i].Address[3]);
|
||||
|
||||
/*
|
||||
* dwStart, dwEnd collect the beginning and end of the disc respectively, in
|
||||
* frames.
|
||||
* There it is collected for correcting the serial when there are less than
|
||||
* 3 tracks.
|
||||
*/
|
||||
if (toc->LastTrack - toc->FirstTrack + 1 < 3)
|
||||
{
|
||||
DWORD dwStart = FRAME_OF_TOC(toc, toc->FirstTrack);
|
||||
DWORD dwEnd = FRAME_OF_TOC(toc, toc->LastTrack + 1);
|
||||
serial += dwEnd - dwStart;
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetVolumeInformationW (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label, DWORD label_len,
|
||||
DWORD *serial, DWORD *filename_len, DWORD *flags,
|
||||
LPWSTR fsname, DWORD fsname_len )
|
||||
{
|
||||
static const WCHAR audiocdW[] = {'A','u','d','i','o',' ','C','D',0};
|
||||
static const WCHAR fatW[] = {'F','A','T',0};
|
||||
static const WCHAR cdfsW[] = {'C','D','F','S',0};
|
||||
|
||||
WCHAR device[] = {'\\','\\','.','\\','A',':',0};
|
||||
HANDLE handle;
|
||||
enum fs_type type = FS_UNKNOWN;
|
||||
|
||||
if (!root)
|
||||
{
|
||||
WCHAR path[MAX_PATH];
|
||||
GetCurrentDirectoryW( MAX_PATH, path );
|
||||
device[4] = path[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!root[0] || root[1] != ':')
|
||||
{
|
||||
SetLastError( ERROR_INVALID_NAME );
|
||||
return FALSE;
|
||||
}
|
||||
device[4] = root[0];
|
||||
}
|
||||
|
||||
/* try to open the device */
|
||||
|
||||
handle = CreateFileW( device, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BYTE superblock[SUPERBLOCK_SIZE];
|
||||
CDROM_TOC toc;
|
||||
DWORD br;
|
||||
|
||||
/* check for audio CD */
|
||||
/* FIXME: we only check the first track for now */
|
||||
if (DeviceIoControl( handle, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, 0 ))
|
||||
{
|
||||
if (!(toc.TrackData[0].Control & 0x04)) /* audio track */
|
||||
{
|
||||
TRACE( "%s: found audio CD\n", debugstr_w(device) );
|
||||
if (label) lstrcpynW( label, audiocdW, label_len );
|
||||
if (serial) *serial = VOLUME_GetAudioCDSerial( &toc );
|
||||
CloseHandle( handle );
|
||||
type = FS_ISO9660;
|
||||
goto fill_fs_info;
|
||||
}
|
||||
type = VOLUME_ReadCDSuperblock( handle, superblock );
|
||||
}
|
||||
else
|
||||
{
|
||||
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(device), type );
|
||||
if (type == FS_ERROR) return FALSE;
|
||||
|
||||
if (label && label_len) VOLUME_GetSuperblockLabel( type, superblock, label, label_len );
|
||||
if (serial) *serial = VOLUME_GetSuperblockSerial( type, superblock );
|
||||
goto fill_fs_info;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE( "cannot open device %s: err %ld\n", debugstr_w(device), GetLastError() );
|
||||
if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
|
||||
}
|
||||
|
||||
/* we couldn't open the device, fallback to default strategy */
|
||||
|
||||
switch(GetDriveTypeW( root ))
|
||||
{
|
||||
case DRIVE_UNKNOWN:
|
||||
case DRIVE_NO_ROOT_DIR:
|
||||
SetLastError( ERROR_NOT_READY );
|
||||
return FALSE;
|
||||
case DRIVE_REMOVABLE:
|
||||
case DRIVE_FIXED:
|
||||
case DRIVE_REMOTE:
|
||||
case DRIVE_RAMDISK:
|
||||
type = FS_UNKNOWN;
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
type = FS_ISO9660;
|
||||
break;
|
||||
}
|
||||
|
||||
if (label && label_len)
|
||||
{
|
||||
WCHAR labelW[] = {'A',':','\\','.','w','i','n','d','o','w','s','-','l','a','b','e','l',0};
|
||||
|
||||
labelW[0] = device[4];
|
||||
handle = CreateFileW( labelW, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, 0, 0 );
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char buffer[256], *p;
|
||||
DWORD size;
|
||||
|
||||
if (!ReadFile( handle, buffer, sizeof(buffer)-1, &size, NULL )) size = 0;
|
||||
CloseHandle( handle );
|
||||
p = buffer + size;
|
||||
while (p > buffer && (p[-1] == ' ' || p[-1] == '\r' || p[-1] == '\n')) p--;
|
||||
*p = 0;
|
||||
if (!MultiByteToWideChar( CP_UNIXCP, 0, buffer, -1, label, label_len ))
|
||||
label[label_len-1] = 0;
|
||||
}
|
||||
else label[0] = 0;
|
||||
}
|
||||
if (serial)
|
||||
{
|
||||
WCHAR serialW[] = {'A',':','\\','.','w','i','n','d','o','w','s','-','s','e','r','i','a','l',0};
|
||||
|
||||
serialW[0] = device[4];
|
||||
handle = CreateFileW( serialW, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, 0, 0 );
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char buffer[32];
|
||||
DWORD size;
|
||||
|
||||
if (!ReadFile( handle, buffer, sizeof(buffer)-1, &size, NULL )) size = 0;
|
||||
CloseHandle( handle );
|
||||
buffer[size] = 0;
|
||||
*serial = strtoul( buffer, NULL, 16 );
|
||||
}
|
||||
else *serial = 0;
|
||||
}
|
||||
|
||||
fill_fs_info: /* now fill in the information that depends on the file system type */
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case FS_ISO9660:
|
||||
if (fsname) lstrcpynW( fsname, cdfsW, fsname_len );
|
||||
if (filename_len) *filename_len = 221;
|
||||
if (flags) *flags = FILE_READ_ONLY_VOLUME;
|
||||
break;
|
||||
case FS_FAT1216:
|
||||
case FS_FAT32:
|
||||
default: /* default to FAT file system (FIXME) */
|
||||
if (fsname) lstrcpynW( fsname, fatW, fsname_len );
|
||||
if (filename_len) *filename_len = 255;
|
||||
if (flags) *flags = FILE_CASE_PRESERVED_NAMES; /* FIXME */
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetVolumeInformationA (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
|
||||
DWORD label_len, DWORD *serial,
|
||||
DWORD *filename_len, DWORD *flags,
|
||||
LPSTR fsname, DWORD fsname_len )
|
||||
{
|
||||
UNICODE_STRING rootW;
|
||||
LPWSTR labelW, fsnameW;
|
||||
BOOL ret;
|
||||
|
||||
if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
|
||||
else rootW.Buffer = NULL;
|
||||
labelW = label ? HeapAlloc(GetProcessHeap(), 0, label_len * sizeof(WCHAR)) : NULL;
|
||||
fsnameW = fsname ? HeapAlloc(GetProcessHeap(), 0, fsname_len * sizeof(WCHAR)) : NULL;
|
||||
|
||||
if ((ret = GetVolumeInformationW(rootW.Buffer, labelW, label_len, serial,
|
||||
filename_len, flags, fsnameW, fsname_len)))
|
||||
{
|
||||
if (label) WideCharToMultiByte(CP_ACP, 0, labelW, -1, label, label_len, NULL, NULL);
|
||||
if (fsname) WideCharToMultiByte(CP_ACP, 0, fsnameW, -1, fsname, fsname_len, NULL, NULL);
|
||||
}
|
||||
|
||||
RtlFreeUnicodeString(&rootW);
|
||||
if (labelW) HeapFree( GetProcessHeap(), 0, labelW );
|
||||
if (fsnameW) HeapFree( GetProcessHeap(), 0, fsnameW );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SetVolumeLabelW (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI SetVolumeLabelW( LPCWSTR root, LPCWSTR label )
|
||||
{
|
||||
WCHAR device[] = {'\\','\\','.','\\','A',':',0};
|
||||
HANDLE handle;
|
||||
enum fs_type type = FS_UNKNOWN;
|
||||
|
||||
if (!root)
|
||||
{
|
||||
WCHAR path[MAX_PATH];
|
||||
GetCurrentDirectoryW( MAX_PATH, path );
|
||||
device[4] = path[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!root[0] || root[1] != ':')
|
||||
{
|
||||
SetLastError( ERROR_INVALID_NAME );
|
||||
return FALSE;
|
||||
}
|
||||
device[4] = root[0];
|
||||
}
|
||||
|
||||
/* try to open the device */
|
||||
|
||||
handle = CreateFileW( device, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* try read-only */
|
||||
handle = CreateFileW( device, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, 0, 0 );
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* device can be read but not written, return error */
|
||||
CloseHandle( handle );
|
||||
SetLastError( ERROR_ACCESS_DENIED );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
BYTE superblock[SUPERBLOCK_SIZE];
|
||||
BOOL ret;
|
||||
|
||||
type = VOLUME_ReadFATSuperblock( handle, superblock );
|
||||
ret = VOLUME_SetSuperblockLabel( type, handle, label );
|
||||
CloseHandle( handle );
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE( "cannot open device %s: err %ld\n", debugstr_w(device), GetLastError() );
|
||||
if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE;
|
||||
}
|
||||
|
||||
/* we couldn't open the device, fallback to default strategy */
|
||||
|
||||
switch(GetDriveTypeW( root ))
|
||||
{
|
||||
case DRIVE_UNKNOWN:
|
||||
case DRIVE_NO_ROOT_DIR:
|
||||
SetLastError( ERROR_NOT_READY );
|
||||
break;
|
||||
case DRIVE_REMOVABLE:
|
||||
case DRIVE_FIXED:
|
||||
{
|
||||
WCHAR labelW[] = {'A',':','\\','.','w','i','n','d','o','w','s','-','l','a','b','e','l',0};
|
||||
|
||||
labelW[0] = device[4];
|
||||
handle = CreateFileW( labelW, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
CREATE_ALWAYS, 0, 0 );
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char buffer[64];
|
||||
DWORD size;
|
||||
|
||||
if (!WideCharToMultiByte( CP_UNIXCP, 0, label, -1, buffer, sizeof(buffer), NULL, NULL ))
|
||||
buffer[sizeof(buffer)-1] = 0;
|
||||
WriteFile( handle, buffer, strlen(buffer), &size, NULL );
|
||||
CloseHandle( handle );
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DRIVE_REMOTE:
|
||||
case DRIVE_RAMDISK:
|
||||
case DRIVE_CDROM:
|
||||
SetLastError( ERROR_ACCESS_DENIED );
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SetVolumeLabelA (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname)
|
||||
{
|
||||
UNICODE_STRING rootW, volnameW;
|
||||
BOOL ret;
|
||||
|
||||
if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
|
||||
else rootW.Buffer = NULL;
|
||||
if (volname) RtlCreateUnicodeStringFromAsciiz(&volnameW, volname);
|
||||
else volnameW.Buffer = NULL;
|
||||
|
||||
ret = SetVolumeLabelW( rootW.Buffer, volnameW.Buffer );
|
||||
|
||||
RtlFreeUnicodeString(&rootW);
|
||||
RtlFreeUnicodeString(&volnameW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetVolumeNameForVolumeMountPointW (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size)
|
||||
{
|
||||
FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size);
|
||||
return 0;
|
||||
}
|
|
@ -227,7 +227,7 @@ static DWORD FILE_GetNtStatus(void)
|
|||
case EINVAL:
|
||||
case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break;
|
||||
case EPIPE: nt = STATUS_PIPE_BROKEN; break;
|
||||
case EIO: nt = STATUS_DISK_CORRUPT_ERROR; break;
|
||||
case EIO: nt = STATUS_DEVICE_NOT_READY; break;
|
||||
case ENOEXEC: /* ?? */
|
||||
case ESPIPE: /* ?? */
|
||||
case EEXIST: /* ?? */
|
||||
|
|
|
@ -11,8 +11,6 @@ WINE REGISTRY Version 2
|
|||
;; [Drive X]
|
||||
;; "Path"="xxx" (Unix path for drive root)
|
||||
;; "Type"="xxx" (supported types are 'floppy', 'hd', 'cdrom' and 'network')
|
||||
;; "Label"="xxx" (drive label, at most 11 characters)
|
||||
;; "Serial"="xxx" (serial number, 8 characters hexadecimal number)
|
||||
;; "Filesystem"="xxx" (supported types are 'msdos'/'dos'/'fat', 'win95'/'vfat', 'unix')
|
||||
;; This is the FS Wine is supposed to emulate on a certain
|
||||
;; directory structure.
|
||||
|
@ -25,21 +23,17 @@ WINE REGISTRY Version 2
|
|||
[Drive A]
|
||||
"Path" = "/mnt/fd0"
|
||||
"Type" = "floppy"
|
||||
"Label" = "Floppy"
|
||||
"Filesystem" = "win95"
|
||||
"Serial" = "87654321"
|
||||
"Device" = "/dev/fd0"
|
||||
|
||||
[Drive C]
|
||||
"Path" = "/c"
|
||||
"Type" = "hd"
|
||||
"Label" = "MS-DOS"
|
||||
"Filesystem" = "win95"
|
||||
|
||||
[Drive D]
|
||||
"Path" = "/cdrom"
|
||||
"Type" = "cdrom"
|
||||
"Label" = "CD-Rom"
|
||||
"Filesystem" = "win95"
|
||||
; make sure that device is correct and has proper permissions !
|
||||
"Device" = "/dev/cdrom"
|
||||
|
@ -47,19 +41,16 @@ WINE REGISTRY Version 2
|
|||
[Drive E]
|
||||
"Path" = "/tmp"
|
||||
"Type" = "hd"
|
||||
"Label" = "Tmp Drive"
|
||||
"Filesystem" = "win95"
|
||||
|
||||
[Drive F]
|
||||
"Path" = "%HOME%"
|
||||
"Type" = "network"
|
||||
"Label" = "Home"
|
||||
"Filesystem" = "win95"
|
||||
|
||||
[Drive Z]
|
||||
"Path" = "/"
|
||||
"Type" = "hd"
|
||||
"Label" = "Root"
|
||||
"Filesystem" = "win95"
|
||||
|
||||
[wine]
|
||||
|
|
|
@ -60,19 +60,6 @@ Used to specify the drive type this drive appears as in Windows
|
|||
or DOS programs; supported types are "floppy", "hd", "cdrom"
|
||||
and "network".
|
||||
.PP
|
||||
.I format: """Label""=""<label>"""
|
||||
.br
|
||||
default: "Drive X"
|
||||
.br
|
||||
Used to specify the drive label; limited to 11 characters.
|
||||
.PP
|
||||
.I format: """Serial""=""<serial>"""
|
||||
.br
|
||||
default: "12345678"
|
||||
.br
|
||||
Used to specify the drive serial number, as an 8-character hexadecimal
|
||||
number.
|
||||
.PP
|
||||
.I format: """Filesystem""=""<fstype>"""
|
||||
.br
|
||||
default: "win95"
|
||||
|
|
779
files/drive.c
779
files/drive.c
|
@ -39,24 +39,9 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
# include <sys/statvfs.h>
|
||||
#endif
|
||||
#ifdef STATFS_DEFINED_BY_SYS_VFS
|
||||
# include <sys/vfs.h>
|
||||
#else
|
||||
# ifdef STATFS_DEFINED_BY_SYS_MOUNT
|
||||
# include <sys/mount.h>
|
||||
# else
|
||||
# ifdef STATFS_DEFINED_BY_SYS_STATFS
|
||||
# include <sys/statfs.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
@ -86,9 +71,6 @@ typedef struct
|
|||
LPWSTR dos_cwd; /* cwd in DOS format without leading or trailing \ */
|
||||
char *unix_cwd; /* cwd in Unix format without leading or trailing / */
|
||||
char *device; /* raw device path */
|
||||
WCHAR label_conf[12]; /* drive label as cfg'd in wine config */
|
||||
WCHAR label_read[12]; /* drive label as read from device */
|
||||
DWORD serial_conf; /* drive serial number as cfg'd in wine config */
|
||||
UINT type; /* drive type */
|
||||
UINT flags; /* drive flags */
|
||||
dev_t dev; /* unix device number */
|
||||
|
@ -199,15 +181,10 @@ int DRIVE_Init(void)
|
|||
UNICODE_STRING nameW;
|
||||
|
||||
static const WCHAR PathW[] = {'P','a','t','h',0};
|
||||
static const WCHAR LabelW[] = {'L','a','b','e','l',0};
|
||||
static const WCHAR SerialW[] = {'S','e','r','i','a','l',0};
|
||||
static const WCHAR TypeW[] = {'T','y','p','e',0};
|
||||
static const WCHAR FilesystemW[] = {'F','i','l','e','s','y','s','t','e','m',0};
|
||||
static const WCHAR DeviceW[] = {'D','e','v','i','c','e',0};
|
||||
static const WCHAR ReadVolInfoW[] = {'R','e','a','d','V','o','l','I','n','f','o',0};
|
||||
static const WCHAR FailReadOnlyW[] = {'F','a','i','l','R','e','a','d','O','n','l','y',0};
|
||||
static const WCHAR driveC_labelW[] = {'D','r','i','v','e',' ','C',' ',' ',' ',' ',0};
|
||||
|
||||
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = 0;
|
||||
|
@ -283,29 +260,6 @@ int DRIVE_Init(void)
|
|||
}
|
||||
else drive->type = DRIVE_FIXED;
|
||||
|
||||
/* Get the drive label */
|
||||
RtlInitUnicodeString( &nameW, LabelW );
|
||||
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
|
||||
{
|
||||
WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
|
||||
lstrcpynW( drive->label_conf, data, 12 );
|
||||
}
|
||||
if ((len = strlenW(drive->label_conf)) < 11)
|
||||
{
|
||||
/* Pad label with spaces */
|
||||
while(len < 11) drive->label_conf[len++] = ' ';
|
||||
drive->label_conf[11] = '\0';
|
||||
}
|
||||
|
||||
/* Get the serial number */
|
||||
RtlInitUnicodeString( &nameW, SerialW );
|
||||
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
|
||||
{
|
||||
WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
|
||||
drive->serial_conf = strtoulW( data, NULL, 16 );
|
||||
}
|
||||
else drive->serial_conf = 12345678;
|
||||
|
||||
/* Get the filesystem type */
|
||||
RtlInitUnicodeString( &nameW, FilesystemW );
|
||||
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
|
||||
|
@ -324,14 +278,6 @@ int DRIVE_Init(void)
|
|||
drive->device = HeapAlloc(GetProcessHeap(), 0, len);
|
||||
WideCharToMultiByte(CP_UNIXCP, 0, data, -1, drive->device, len, NULL, NULL);
|
||||
|
||||
RtlInitUnicodeString( &nameW, ReadVolInfoW );
|
||||
if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, tmp, sizeof(tmp), &dummy ))
|
||||
{
|
||||
WCHAR *data = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)tmp)->Data;
|
||||
if (IS_OPTION_TRUE(data[0])) drive->flags |= DRIVE_READ_VOL_INFO;
|
||||
}
|
||||
else drive->flags |= DRIVE_READ_VOL_INFO;
|
||||
|
||||
if (drive->type == DRIVE_CDROM)
|
||||
{
|
||||
int cd_fd;
|
||||
|
@ -356,11 +302,9 @@ int DRIVE_Init(void)
|
|||
DRIVE_CurDrive = i;
|
||||
|
||||
count++;
|
||||
TRACE("Drive %c: path=%s type=%s label=%s serial=%08lx "
|
||||
"flags=%08x dev=%x ino=%x\n",
|
||||
TRACE("Drive %c: path=%s type=%s flags=%08x dev=%x ino=%x\n",
|
||||
'A' + i, drive->root, debugstr_w(DRIVE_Types[drive->type]),
|
||||
debugstr_w(drive->label_conf), drive->serial_conf, drive->flags,
|
||||
(int)drive->dev, (int)drive->ino );
|
||||
drive->flags, (int)drive->dev, (int)drive->ino );
|
||||
}
|
||||
|
||||
next:
|
||||
|
@ -374,8 +318,6 @@ int DRIVE_Init(void)
|
|||
DOSDrives[2].root = heap_strdup( "/" );
|
||||
DOSDrives[2].dos_cwd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DOSDrives[2].dos_cwd[0]));
|
||||
DOSDrives[2].unix_cwd = heap_strdup( "" );
|
||||
strcpyW( DOSDrives[2].label_conf, driveC_labelW );
|
||||
DOSDrives[2].serial_conf = 12345678;
|
||||
DOSDrives[2].type = DRIVE_FIXED;
|
||||
DOSDrives[2].device = NULL;
|
||||
DOSDrives[2].flags = 0;
|
||||
|
@ -653,531 +595,6 @@ const char * DRIVE_GetDevice( int drive )
|
|||
return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* static WORD CDROM_Data_FindBestVoldesc
|
||||
*
|
||||
*
|
||||
*/
|
||||
static WORD CDROM_Data_FindBestVoldesc(int fd)
|
||||
{
|
||||
BYTE cur_vd_type, max_vd_type = 0;
|
||||
unsigned int offs, best_offs = 0, extra_offs = 0;
|
||||
char sig[3];
|
||||
|
||||
for (offs = 0x8000; offs <= 0x9800; offs += 0x800)
|
||||
{
|
||||
/* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
|
||||
* the volume label is displaced forward by 8
|
||||
*/
|
||||
lseek(fd, offs + 11, SEEK_SET); /* check for non-ISO9660 signature */
|
||||
read(fd, &sig, 3);
|
||||
if ((sig[0] == 'R') && (sig[1] == 'O') && (sig[2]=='M'))
|
||||
{
|
||||
extra_offs = 8;
|
||||
}
|
||||
lseek(fd, offs + extra_offs, SEEK_SET);
|
||||
read(fd, &cur_vd_type, 1);
|
||||
if (cur_vd_type == 0xff) /* voldesc set terminator */
|
||||
break;
|
||||
if (cur_vd_type > max_vd_type)
|
||||
{
|
||||
max_vd_type = cur_vd_type;
|
||||
best_offs = offs + extra_offs;
|
||||
}
|
||||
}
|
||||
return best_offs;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_ReadSuperblock
|
||||
*
|
||||
* NOTE
|
||||
* DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
|
||||
* to check, that they are writing on a FAT filesystem !
|
||||
*/
|
||||
int DRIVE_ReadSuperblock (int drive, char * buff)
|
||||
{
|
||||
#define DRIVE_SUPER 96
|
||||
int fd;
|
||||
off_t offs;
|
||||
int ret = 0;
|
||||
struct stat stat_buf;
|
||||
|
||||
memset(buff, 0, DRIVE_SUPER);
|
||||
/* O_NONBLOCK in case we're opening FIFO; will be reset later */
|
||||
if ((fd = open(DOSDrives[drive].device, O_RDONLY|O_NOCTTY|O_NONBLOCK)) != -1) {
|
||||
if (fstat(fd, &stat_buf) < 0) { /* shouldn't happen since we just opened that file */
|
||||
ERR("fstat() failed for opened device '%s' (drive %c:) ! IT SHOULDN'T HAPPEN !!!\n",
|
||||
DOSDrives[drive].device, 'A'+drive);
|
||||
ret = -1;
|
||||
} else if (!S_ISBLK(stat_buf.st_mode)) {
|
||||
ERR("Device '%s' (drive %c:) is not a block device - check your config\n",
|
||||
DOSDrives[drive].device, 'A'+drive);
|
||||
ret = -1;
|
||||
/* reset O_NONBLOCK */
|
||||
} else if (fcntl(fd, F_SETFL, 0) < 0 || fcntl(fd, F_GETFL) & O_NONBLOCK) {
|
||||
ERR("fcntl() failed to reset O_NONBLOCK for device '%s' (drive %c:)\n",
|
||||
DOSDrives[drive].device, 'A'+drive);
|
||||
ret = -1;
|
||||
}
|
||||
if (ret) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
} else {
|
||||
if (!DOSDrives[drive].device)
|
||||
ERR("No device configured for drive %c: !\n", 'A'+drive);
|
||||
else
|
||||
ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives[drive].device, 'A'+drive,
|
||||
(stat(DOSDrives[drive].device, &stat_buf)) ?
|
||||
"not available or symlink not valid ?" : "no permission");
|
||||
}
|
||||
if (fd == -1) {
|
||||
ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(DOSDrives[drive].type)
|
||||
{
|
||||
case DRIVE_REMOVABLE:
|
||||
case DRIVE_FIXED:
|
||||
offs = 0;
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
offs = CDROM_Data_FindBestVoldesc(fd);
|
||||
break;
|
||||
default:
|
||||
offs = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((offs) && (lseek(fd,offs,SEEK_SET)!=offs))
|
||||
{
|
||||
ret = -4;
|
||||
goto the_end;
|
||||
}
|
||||
if (read(fd,buff,DRIVE_SUPER)!=DRIVE_SUPER)
|
||||
{
|
||||
ret = -2;
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
switch(DOSDrives[drive].type)
|
||||
{
|
||||
case DRIVE_REMOVABLE:
|
||||
case DRIVE_FIXED:
|
||||
if ((buff[0x26]!=0x29) || /* Check for FAT present */
|
||||
/* FIXME: do really all FAT have their name beginning with
|
||||
"FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
|
||||
memcmp( buff+0x36,"FAT",3))
|
||||
{
|
||||
ERR("The filesystem is not FAT !! (device=%s)\n",
|
||||
DOSDrives[drive].device);
|
||||
ret = -3;
|
||||
goto the_end;
|
||||
}
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
if (strncmp(&buff[1],"CD001",5)) /* Check for iso9660 present */
|
||||
{
|
||||
ret = -3;
|
||||
goto the_end;
|
||||
}
|
||||
/* FIXME: do we need to check for "CDROM", too ? (high sierra) */
|
||||
break;
|
||||
default:
|
||||
ret = -3;
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
return close(fd);
|
||||
the_end:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_WriteSuperblockEntry
|
||||
*
|
||||
* NOTE
|
||||
* We are writing as little as possible (ie. not the whole SuperBlock)
|
||||
* not to interfere with kernel. The drive can be mounted !
|
||||
*/
|
||||
int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if ((fd=open(DOSDrives[drive].device,O_WRONLY))==-1)
|
||||
{
|
||||
ERR("Cannot open the device %s (for writing)\n",
|
||||
DOSDrives[drive].device);
|
||||
return -1;
|
||||
}
|
||||
if (lseek(fd,ofs,SEEK_SET)!=ofs)
|
||||
{
|
||||
ERR("lseek failed on device %s !\n",
|
||||
DOSDrives[drive].device);
|
||||
close(fd);
|
||||
return -2;
|
||||
}
|
||||
if (write(fd,buff,len)!=len)
|
||||
{
|
||||
close(fd);
|
||||
ERR("Cannot write on %s !\n",
|
||||
DOSDrives[drive].device);
|
||||
return -3;
|
||||
}
|
||||
return close (fd);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* static HANDLE CDROM_Open
|
||||
*
|
||||
*
|
||||
*/
|
||||
static HANDLE CDROM_Open(int drive)
|
||||
{
|
||||
WCHAR root[] = {'\\','\\','.','\\','A',':',0};
|
||||
root[4] += drive;
|
||||
return CreateFileW(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CDROM_Data_GetLabel [internal]
|
||||
*/
|
||||
DWORD CDROM_Data_GetLabel(int drive, WCHAR *label)
|
||||
{
|
||||
#define LABEL_LEN 32+1
|
||||
int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
|
||||
WORD offs = CDROM_Data_FindBestVoldesc(dev);
|
||||
WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
|
||||
DWORD unicode_id = 0;
|
||||
|
||||
if (offs)
|
||||
{
|
||||
if ((lseek(dev, offs+0x58, SEEK_SET) == offs+0x58)
|
||||
&& (read(dev, &unicode_id, 3) == 3))
|
||||
{
|
||||
int ver = (unicode_id & 0xff0000) >> 16;
|
||||
|
||||
if ((lseek(dev, offs+0x28, SEEK_SET) != offs+0x28)
|
||||
|| (read(dev, &label_read, LABEL_LEN) != LABEL_LEN))
|
||||
goto failure;
|
||||
|
||||
close(dev);
|
||||
if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
|
||||
&& ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
|
||||
{ /* yippee, unicode */
|
||||
int i;
|
||||
WORD ch;
|
||||
for (i=0; i<LABEL_LEN;i++)
|
||||
{ /* Motorola -> Intel Unicode conversion :-\ */
|
||||
ch = label_read[i];
|
||||
label_read[i] = (ch << 8) | (ch >> 8);
|
||||
}
|
||||
strncpyW(label, label_read, 11);
|
||||
label[11] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MultiByteToWideChar(CP_UNIXCP, 0, (LPSTR)label_read, -1, label, 11);
|
||||
label[11] = '\0';
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
failure:
|
||||
close(dev);
|
||||
ERR("error reading label !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CDROM_GetLabel [internal]
|
||||
*/
|
||||
static DWORD CDROM_GetLabel(int drive, WCHAR *label)
|
||||
{
|
||||
HANDLE h;
|
||||
CDROM_DISK_DATA cdd;
|
||||
DWORD br, ret = 1;
|
||||
BOOL r;
|
||||
|
||||
h = CDROM_Open(drive);
|
||||
if( !h )
|
||||
return 0;
|
||||
r = DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL,
|
||||
0, &cdd, sizeof(cdd), &br, 0);
|
||||
CloseHandle( h );
|
||||
if( !r )
|
||||
return 0;
|
||||
|
||||
switch (cdd.DiskData & 0x03)
|
||||
{
|
||||
case CDROM_DISK_DATA_TRACK:
|
||||
if (!CDROM_Data_GetLabel(drive, label))
|
||||
ret = 0;
|
||||
break;
|
||||
case CDROM_DISK_AUDIO_TRACK:
|
||||
{
|
||||
static const WCHAR audioCD[] = {'A','u','d','i','o',' ','C','D',' ',' ',' ',0};
|
||||
strcpyW(label, audioCD);
|
||||
break;
|
||||
}
|
||||
case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
|
||||
FIXME("Need to get the label of a mixed mode CD!\n");
|
||||
/* This assumes that the first track is a data track! */
|
||||
/* I guess the correct way would be to enumerate all data tracks
|
||||
and check each for the title */
|
||||
if (!CDROM_Data_GetLabel(drive, label))
|
||||
ret = 0;
|
||||
break;
|
||||
case 0:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
TRACE("CD: label is %s\n", debugstr_w(label));
|
||||
|
||||
return ret;
|
||||
}
|
||||
/***********************************************************************
|
||||
* DRIVE_GetLabel
|
||||
*/
|
||||
LPCWSTR DRIVE_GetLabel( int drive )
|
||||
{
|
||||
int read = 0;
|
||||
char buff[DRIVE_SUPER];
|
||||
int offs = -1;
|
||||
|
||||
if (!DRIVE_IsValid( drive )) return NULL;
|
||||
if (DOSDrives[drive].type == DRIVE_CDROM)
|
||||
{
|
||||
read = CDROM_GetLabel(drive, DOSDrives[drive].label_read);
|
||||
}
|
||||
else
|
||||
if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
|
||||
{
|
||||
if (DRIVE_ReadSuperblock(drive,(char *) buff))
|
||||
ERR("Invalid or unreadable superblock on %s (%c:).\n",
|
||||
DOSDrives[drive].device, (char)(drive+'A'));
|
||||
else {
|
||||
if (DOSDrives[drive].type == DRIVE_REMOVABLE ||
|
||||
DOSDrives[drive].type == DRIVE_FIXED)
|
||||
offs = 0x2b;
|
||||
|
||||
/* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
|
||||
if (offs != -1)
|
||||
MultiByteToWideChar(CP_UNIXCP, 0, buff+offs, 11,
|
||||
DOSDrives[drive].label_read, 11);
|
||||
DOSDrives[drive].label_read[11]='\0';
|
||||
read = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (read) ?
|
||||
DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
|
||||
}
|
||||
|
||||
#define CDFRAMES_PERSEC 75
|
||||
#define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
|
||||
#define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
|
||||
#define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
|
||||
|
||||
/**************************************************************************
|
||||
* CDROM_Audio_GetSerial [internal]
|
||||
*/
|
||||
static DWORD CDROM_Audio_GetSerial(HANDLE h)
|
||||
{
|
||||
unsigned long serial = 0;
|
||||
int i;
|
||||
WORD wMagic;
|
||||
DWORD dwStart, dwEnd, br;
|
||||
CDROM_TOC toc;
|
||||
|
||||
if (!DeviceIoControl(h, IOCTL_CDROM_READ_TOC, NULL, 0, &toc, sizeof(toc), &br, 0))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* wMagic collects the wFrames from track 1
|
||||
* dwStart, dwEnd collect the beginning and end of the disc respectively, in
|
||||
* frames.
|
||||
* There it is collected for correcting the serial when there are less than
|
||||
* 3 tracks.
|
||||
*/
|
||||
wMagic = toc.TrackData[0].Address[2];
|
||||
dwStart = FRAME_OF_TOC(toc, toc.FirstTrack);
|
||||
|
||||
for (i = 0; i <= toc.LastTrack - toc.FirstTrack; i++) {
|
||||
serial += (toc.TrackData[i].Address[0] << 16) |
|
||||
(toc.TrackData[i].Address[1] << 8) | toc.TrackData[i].Address[2];
|
||||
}
|
||||
dwEnd = FRAME_OF_TOC(toc, toc.LastTrack + 1);
|
||||
|
||||
if (toc.LastTrack - toc.FirstTrack + 1 < 3)
|
||||
serial += wMagic + (dwEnd - dwStart);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CDROM_Data_GetSerial [internal]
|
||||
*/
|
||||
static DWORD CDROM_Data_GetSerial(int drive)
|
||||
{
|
||||
int dev = open(DOSDrives[drive].device, O_RDONLY|O_NONBLOCK);
|
||||
WORD offs;
|
||||
union {
|
||||
unsigned long val;
|
||||
unsigned char p[4];
|
||||
} serial;
|
||||
BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
|
||||
|
||||
|
||||
if (dev == -1) return 0;
|
||||
offs = CDROM_Data_FindBestVoldesc(dev);
|
||||
|
||||
serial.val = 0;
|
||||
if (offs)
|
||||
{
|
||||
BYTE buf[2048];
|
||||
RTL_OSVERSIONINFOEXW ovi;
|
||||
int i;
|
||||
|
||||
lseek(dev, offs, SEEK_SET);
|
||||
read(dev, buf, 2048);
|
||||
/*
|
||||
* OK, another braindead one... argh. Just believe it.
|
||||
* Me$$ysoft chose to reverse the serial number in NT4/W2K.
|
||||
* It's true and nobody will ever be able to change it.
|
||||
*/
|
||||
ovi.dwOSVersionInfoSize = sizeof(ovi);
|
||||
RtlGetVersion(&ovi);
|
||||
if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT) && (ovi.dwMajorVersion >= 4))
|
||||
{
|
||||
b0 = 3; b1 = 2; b2 = 1; b3 = 0;
|
||||
}
|
||||
for (i = 0; i < 2048; i += 4)
|
||||
{
|
||||
/* DON'T optimize this into DWORD !! (breaks overflow) */
|
||||
serial.p[b0] += buf[i+b0];
|
||||
serial.p[b1] += buf[i+b1];
|
||||
serial.p[b2] += buf[i+b2];
|
||||
serial.p[b3] += buf[i+b3];
|
||||
}
|
||||
}
|
||||
close(dev);
|
||||
return serial.val;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CDROM_GetSerial [internal]
|
||||
*/
|
||||
static DWORD CDROM_GetSerial(int drive)
|
||||
{
|
||||
DWORD serial = 0;
|
||||
HANDLE h;
|
||||
CDROM_DISK_DATA cdd;
|
||||
DWORD br;
|
||||
BOOL r;
|
||||
|
||||
TRACE("%d\n", drive);
|
||||
|
||||
h = CDROM_Open(drive);
|
||||
if( !h )
|
||||
return 0;
|
||||
r = DeviceIoControl(h, IOCTL_CDROM_DISK_TYPE, NULL,
|
||||
0, &cdd, sizeof(cdd), &br, 0);
|
||||
if (!r)
|
||||
{
|
||||
CloseHandle(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (cdd.DiskData & 0x03)
|
||||
{
|
||||
case CDROM_DISK_DATA_TRACK:
|
||||
/* hopefully a data CD */
|
||||
serial = CDROM_Data_GetSerial(drive);
|
||||
break;
|
||||
case CDROM_DISK_AUDIO_TRACK:
|
||||
/* fall thru */
|
||||
case CDROM_DISK_DATA_TRACK|CDROM_DISK_AUDIO_TRACK:
|
||||
serial = CDROM_Audio_GetSerial(h);
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
|
||||
if (serial)
|
||||
TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial), LOWORD(serial));
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_GetSerialNumber
|
||||
*/
|
||||
DWORD DRIVE_GetSerialNumber( int drive )
|
||||
{
|
||||
DWORD serial = 0;
|
||||
char buff[DRIVE_SUPER];
|
||||
|
||||
TRACE("drive %d, type = %d\n", drive, DOSDrives[drive].type);
|
||||
|
||||
if (!DRIVE_IsValid( drive )) return 0;
|
||||
|
||||
if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
|
||||
{
|
||||
switch(DOSDrives[drive].type)
|
||||
{
|
||||
case DRIVE_REMOVABLE:
|
||||
case DRIVE_FIXED:
|
||||
if (DRIVE_ReadSuperblock(drive,(char *) buff))
|
||||
MESSAGE("Invalid or unreadable superblock on %s (%c:)."
|
||||
" Maybe not FAT?\n" ,
|
||||
DOSDrives[drive].device, 'A'+drive);
|
||||
else
|
||||
serial = *((DWORD*)(buff+0x27));
|
||||
break;
|
||||
case DRIVE_CDROM:
|
||||
serial = CDROM_GetSerial(drive);
|
||||
break;
|
||||
default:
|
||||
FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive+'A');
|
||||
}
|
||||
}
|
||||
|
||||
return (serial) ? serial : DOSDrives[drive].serial_conf;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_SetSerialNumber
|
||||
*/
|
||||
int DRIVE_SetSerialNumber( int drive, DWORD serial )
|
||||
{
|
||||
char buff[DRIVE_SUPER];
|
||||
|
||||
if (!DRIVE_IsValid( drive )) return 0;
|
||||
|
||||
if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
|
||||
{
|
||||
if ((DOSDrives[drive].type != DRIVE_REMOVABLE) &&
|
||||
(DOSDrives[drive].type != DRIVE_FIXED)) return 0;
|
||||
/* check, if the drive has a FAT filesystem */
|
||||
if (DRIVE_ReadSuperblock(drive, buff)) return 0;
|
||||
if (DRIVE_WriteSuperblockEntry(drive, 0x27, 4, (char *) &serial)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (DOSDrives[drive].type == DRIVE_CDROM) return 0;
|
||||
DOSDrives[drive].serial_conf = serial;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_GetType
|
||||
*/
|
||||
|
@ -1253,36 +670,6 @@ int DRIVE_Chdir( int drive, LPCWSTR path )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_Disable
|
||||
*/
|
||||
int DRIVE_Disable( int drive )
|
||||
{
|
||||
if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_DRIVE );
|
||||
return 0;
|
||||
}
|
||||
DOSDrives[drive].flags |= DRIVE_DISABLED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DRIVE_Enable
|
||||
*/
|
||||
int DRIVE_Enable( int drive )
|
||||
{
|
||||
if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
|
||||
{
|
||||
SetLastError( ERROR_INVALID_DRIVE );
|
||||
return 0;
|
||||
}
|
||||
DOSDrives[drive].flags &= ~DRIVE_DISABLED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* DefineDosDeviceA (KERNEL32.@)
|
||||
*/
|
||||
|
@ -1352,9 +739,6 @@ BOOL WINAPI DefineDosDeviceW(DWORD flags,LPCWSTR devname,LPCWSTR targetpath)
|
|||
strcpyW(new->dos_cwd, old->dos_cwd);
|
||||
new->unix_cwd = heap_strdup( old->unix_cwd );
|
||||
new->device = heap_strdup( old->device );
|
||||
memcpy ( new->label_conf, old->label_conf, 12 );
|
||||
memcpy ( new->label_read, old->label_read, 12 );
|
||||
new->serial_conf = old->serial_conf;
|
||||
new->type = old->type;
|
||||
new->flags = old->flags;
|
||||
new->dev = old->dev;
|
||||
|
@ -1980,162 +1364,3 @@ DWORD WINAPI GetLogicalDrives(void)
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetVolumeInformationW (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label,
|
||||
DWORD label_len, DWORD *serial,
|
||||
DWORD *filename_len, DWORD *flags,
|
||||
LPWSTR fsname, DWORD fsname_len )
|
||||
{
|
||||
int drive;
|
||||
LPWSTR cp;
|
||||
|
||||
/* FIXME, SetLastError()s missing */
|
||||
|
||||
if (!root) drive = DRIVE_GetCurrentDrive();
|
||||
else
|
||||
{
|
||||
if (root[0] && root[1] != ':')
|
||||
{
|
||||
WARN("invalid root %s\n", debugstr_w(root));
|
||||
return FALSE;
|
||||
}
|
||||
drive = toupperW(root[0]) - 'A';
|
||||
}
|
||||
if (!DRIVE_IsValid( drive )) return FALSE;
|
||||
if (label && label_len)
|
||||
{
|
||||
strncpyW( label, DRIVE_GetLabel(drive), label_len );
|
||||
label[label_len - 1] = 0; /* ensure 0 termination */
|
||||
cp = label + strlenW(label);
|
||||
while (cp != label && *(cp-1) == ' ') cp--;
|
||||
*cp = '\0';
|
||||
}
|
||||
if (serial) *serial = DRIVE_GetSerialNumber(drive);
|
||||
|
||||
/* Set the filesystem information */
|
||||
/* Note: we only emulate a FAT fs at present */
|
||||
|
||||
if (filename_len) {
|
||||
if (DOSDrives[drive].flags & DRIVE_SHORT_NAMES)
|
||||
*filename_len = 12;
|
||||
else
|
||||
*filename_len = 255;
|
||||
}
|
||||
if (flags)
|
||||
{
|
||||
*flags=0;
|
||||
if (DOSDrives[drive].flags & DRIVE_CASE_SENSITIVE)
|
||||
*flags|=FS_CASE_SENSITIVE;
|
||||
if (DOSDrives[drive].flags & DRIVE_CASE_PRESERVING)
|
||||
*flags|=FS_CASE_IS_PRESERVED;
|
||||
}
|
||||
if (fsname && fsname_len)
|
||||
{
|
||||
/* Diablo checks that return code ... */
|
||||
if (DOSDrives[drive].type == DRIVE_CDROM)
|
||||
{
|
||||
static const WCHAR cdfsW[] = {'C','D','F','S',0};
|
||||
strncpyW( fsname, cdfsW, fsname_len );
|
||||
}
|
||||
else
|
||||
{
|
||||
static const WCHAR fatW[] = {'F','A','T',0};
|
||||
strncpyW( fsname, fatW, fsname_len );
|
||||
}
|
||||
fsname[fsname_len - 1] = 0; /* ensure 0 termination */
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetVolumeInformationA (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
|
||||
DWORD label_len, DWORD *serial,
|
||||
DWORD *filename_len, DWORD *flags,
|
||||
LPSTR fsname, DWORD fsname_len )
|
||||
{
|
||||
UNICODE_STRING rootW;
|
||||
LPWSTR labelW, fsnameW;
|
||||
BOOL ret;
|
||||
|
||||
if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
|
||||
else rootW.Buffer = NULL;
|
||||
labelW = label ? HeapAlloc(GetProcessHeap(), 0, label_len * sizeof(WCHAR)) : NULL;
|
||||
fsnameW = fsname ? HeapAlloc(GetProcessHeap(), 0, fsname_len * sizeof(WCHAR)) : NULL;
|
||||
|
||||
if ((ret = GetVolumeInformationW(rootW.Buffer, labelW, label_len, serial,
|
||||
filename_len, flags, fsnameW, fsname_len)))
|
||||
{
|
||||
if (label) WideCharToMultiByte(CP_ACP, 0, labelW, -1, label, label_len, NULL, NULL);
|
||||
if (fsname) WideCharToMultiByte(CP_ACP, 0, fsnameW, -1, fsname, fsname_len, NULL, NULL);
|
||||
}
|
||||
|
||||
RtlFreeUnicodeString(&rootW);
|
||||
if (labelW) HeapFree( GetProcessHeap(), 0, labelW );
|
||||
if (fsnameW) HeapFree( GetProcessHeap(), 0, fsnameW );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SetVolumeLabelW (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI SetVolumeLabelW( LPCWSTR root, LPCWSTR volname )
|
||||
{
|
||||
int drive;
|
||||
|
||||
/* FIXME, SetLastErrors missing */
|
||||
|
||||
if (!root) drive = DRIVE_GetCurrentDrive();
|
||||
else
|
||||
{
|
||||
if ((root[1]) && (root[1] != ':'))
|
||||
{
|
||||
WARN("invalid root %s\n", debugstr_w(root));
|
||||
return FALSE;
|
||||
}
|
||||
drive = toupperW(root[0]) - 'A';
|
||||
}
|
||||
if (!DRIVE_IsValid( drive )) return FALSE;
|
||||
|
||||
/* some copy protection stuff check this */
|
||||
if (DOSDrives[drive].type == DRIVE_CDROM) return FALSE;
|
||||
|
||||
strncpyW(DOSDrives[drive].label_conf, volname, 12);
|
||||
DOSDrives[drive].label_conf[12 - 1] = 0; /* ensure 0 termination */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SetVolumeLabelA (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI SetVolumeLabelA(LPCSTR root, LPCSTR volname)
|
||||
{
|
||||
UNICODE_STRING rootW, volnameW;
|
||||
BOOL ret;
|
||||
|
||||
if (root) RtlCreateUnicodeStringFromAsciiz(&rootW, root);
|
||||
else rootW.Buffer = NULL;
|
||||
if (volname) RtlCreateUnicodeStringFromAsciiz(&volnameW, volname);
|
||||
else volnameW.Buffer = NULL;
|
||||
|
||||
ret = SetVolumeLabelW( rootW.Buffer, volnameW.Buffer );
|
||||
|
||||
RtlFreeUnicodeString(&rootW);
|
||||
RtlFreeUnicodeString(&volnameW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* GetVolumeNameForVolumeMountPointW (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI GetVolumeNameForVolumeMountPointW(LPCWSTR str, LPWSTR dst, DWORD size)
|
||||
{
|
||||
FIXME("(%s, %p, %lx): stub\n", debugstr_w(str), dst, size);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#define DRIVE_CASE_SENSITIVE 0x0004 /* Drive fs is case sensitive */
|
||||
#define DRIVE_CASE_PRESERVING 0x0008 /* Drive fs is case preserving */
|
||||
#define DRIVE_FAIL_READ_ONLY 0x0010 /* Fail opening read-only files for writing */
|
||||
#define DRIVE_READ_VOL_INFO 0x0020 /* Try to read volume info from the device? */
|
||||
|
||||
extern int DRIVE_Init(void);
|
||||
extern int DRIVE_IsValid( int drive );
|
||||
|
@ -44,13 +43,8 @@ extern const char * DRIVE_GetRoot( int drive );
|
|||
extern LPCWSTR DRIVE_GetDosCwd( int drive );
|
||||
extern const char * DRIVE_GetUnixCwd( int drive );
|
||||
extern const char * DRIVE_GetDevice( int drive );
|
||||
extern LPCWSTR DRIVE_GetLabel( int drive );
|
||||
extern DWORD DRIVE_GetSerialNumber( int drive );
|
||||
extern int DRIVE_SetSerialNumber( int drive, DWORD serial );
|
||||
extern UINT DRIVE_GetFlags( int drive );
|
||||
extern int DRIVE_Chdir( int drive, LPCWSTR path );
|
||||
extern int DRIVE_Disable( int drive );
|
||||
extern int DRIVE_Enable( int drive );
|
||||
extern WCHAR *DRIVE_BuildEnv(void);
|
||||
|
||||
#endif /* __WINE_DRIVE_H */
|
||||
|
|
|
@ -3305,6 +3305,10 @@ typedef enum tagSID_NAME_USE {
|
|||
#define FILE_PERSISTENT_ACLS 0x00000008
|
||||
#define FILE_FILE_COMPRESSION 0x00000010
|
||||
#define FILE_VOLUME_IS_COMPRESSED 0x00008000
|
||||
#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
|
||||
#define FILE_SUPPORTS_ENCRYPTION 0x00020000
|
||||
#define FILE_NAMED_STREAMS 0x00040000
|
||||
#define FILE_READ_ONLY_VOLUME 0x00080000
|
||||
|
||||
/* File alignments (NT) */
|
||||
#define FILE_BYTE_ALIGNMENT 0x00000000
|
||||
|
|
Loading…
Reference in New Issue