Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1463 lines
42 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dllfsd.c
Abstract:
This module implements the OS/2 V2.0 fsd-related APIs: DosQueryFsInfo,
DosSetFsInfo
Author:
Therese Stowell (thereses) 17-Jan-1990
Revision History:
Patrick Questembert (patrickq) 2-Feb-1992:
Fixed & enhanced the DosQueryFSAttach call.
--*/
#define INCL_OS2V20_ERRORS
#define INCL_OS2V20_FSD
#include "os2dll.h"
#include "os2win.h"
// macro to probe string arguments passed to APIs
#define PROBE_STRING(s) ((VOID) ((s) == NULL ? 0 : strlen(s)))
APIRET
ProcessLabel(
IN PVOLUMELABEL Buffer,
IN ULONG Length,
OUT PFILE_FS_LABEL_INFORMATION LabelBuffer
);
APIRET
OpenDrive(
IN ULONG DiskNumber,
IN ULONG RequestedAccess,
OUT PHANDLE DriveHandle
);
APIRET
DosSetCurrentDir(
IN PSZ DirectoryName
);
APIRET
DosQueryFSInfo(
IN ULONG DiskNumber,
IN ULONG FsInformationLevel,
IN PBYTE Buffer,
IN ULONG Length
)
/*++
Routine Description:
This routine returns allocation or label information for a volume.
Arguments:
DiskNumber - which volume to return information for
FsInformationLevel - what type of information to return
Buffer - where to return information
Length - length of buffer
Return Value:
ERROR_INVALID_LEVEL - invalid FsInformationLevel
ERROR_INVALID_DRIVE - specified volume does not exist
ERROR_BUFFER_OVERFLOW - requested information won't fit in buffer
--*/
{
APIRET RetCode;
NTSTATUS Status;
HANDLE DiskHandle;
IO_STATUS_BLOCK IoStatus;
struct LABEL_BUFFER {
FILE_FS_VOLUME_INFORMATION VolumeInfo;
WCHAR Label[MAX_LABEL_LENGTH];
} VolInfoBuffer;
FILE_FS_SIZE_INFORMATION FsSizeInfoBuffer;
PFSINFO FsInfoBuf;
PFSALLOCATE FsAllocBuf;
STRING LabelString;
UNICODE_STRING LabelString_U;
ULONG i;
if (FsInformationLevel > FSIL_VOLSER) {
return ERROR_INVALID_LEVEL;
}
if (DiskNumber > MAX_DRIVES) {
return ERROR_INVALID_DRIVE;
}
RetCode = OpenDrive(DiskNumber,
FILE_READ_DATA,
&DiskHandle
);
if (RetCode != NO_ERROR) {
return RetCode;
}
if (FsInformationLevel == FSIL_ALLOC) {
if (Length < sizeof(FSALLOCATE)) {
NtClose(DiskHandle);
return ERROR_BUFFER_OVERFLOW;
}
do {
Status = NtQueryVolumeInformationFile(DiskHandle,
&IoStatus,
&FsSizeInfoBuffer,
sizeof(FsSizeInfoBuffer),
FileFsSizeInformation
);
} while (RetryIO(Status, DiskHandle));
NtClose(DiskHandle);
if (!NT_SUCCESS(Status)) {
return ERROR_INVALID_DRIVE;
}
FsAllocBuf = (PFSALLOCATE) Buffer;
try {
FsAllocBuf->ulReserved = 0;
FsAllocBuf->cSectorUnit = FsSizeInfoBuffer.SectorsPerAllocationUnit;
// BUGBUG - what do we do here if .HighPart is non-zero
FsAllocBuf->cUnit = FsSizeInfoBuffer.TotalAllocationUnits.LowPart;
FsAllocBuf->cUnitAvail = FsSizeInfoBuffer.AvailableAllocationUnits.LowPart;
FsAllocBuf->cbSector = BYTES_PER_SECTOR;
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
}
else {
if (Length < (FIELD_OFFSET(FSINFO, vol) + 1)) {
NtClose(DiskHandle);
return ERROR_BUFFER_OVERFLOW;
}
do {
Status = NtQueryVolumeInformationFile(DiskHandle,
&IoStatus,
&VolInfoBuffer,
sizeof(VolInfoBuffer),
FileFsVolumeInformation
);
} while (RetryIO(Status, DiskHandle));
NtClose(DiskHandle);
if (!NT_SUCCESS(Status)) {
return ERROR_INVALID_DRIVE;
}
if (Length < (FIELD_OFFSET(FSINFO, vol)+(VolInfoBuffer.VolumeInfo.VolumeLabelLength / 2))) {
return ERROR_BUFFER_OVERFLOW;
}
FsInfoBuf = (PFSINFO) Buffer;
try {
for (i = 0; i < 12; i++) {
FsInfoBuf->vol.szVolLabel[i] = 0;
}
FsInfoBuf->ulVSN = VolInfoBuffer.VolumeInfo.VolumeSerialNumber;
LabelString_U.Length = (USHORT)(VolInfoBuffer.VolumeInfo.VolumeLabelLength);
LabelString_U.MaximumLength = (USHORT)(LabelString_U.Length +(USHORT)1);
LabelString_U.Buffer = VolInfoBuffer.VolumeInfo.VolumeLabel;
LabelString.Length = (USHORT)VolInfoBuffer.VolumeInfo.VolumeLabelLength;
LabelString.MaximumLength = LabelString.Length + (USHORT)1;
LabelString.Buffer = FsInfoBuf->vol.szVolLabel;
RetCode = Od2UnicodeStringToMBString(&LabelString,
&LabelString_U,
FALSE);
FsInfoBuf->vol.cch = (BYTE) LabelString.Length;
#if DBG
IF_OD2_DEBUG( FSD ) {
DbgPrint("volume label length is %d and label is %s\n",FsInfoBuf->vol.cch,FsInfoBuf->vol.szVolLabel);
}
#endif
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
}
return RetCode;
}
APIRET
DosSetFSInfo(
ULONG DiskNumber,
ULONG FsInformationLevel,
PBYTE Buffer,
ULONG Length
)
/*++
Routine Description:
This routine sets label information for a volume.
Arguments:
DiskNumber - which volume to set information for
FsInformationLevel - what type of information to set
Buffer - information to set
Length - length of buffer
Return Value:
ERROR_INVALID_LEVEL - invalid FsInformationLevel
ERROR_INVALID_DRIVE - specified volume does not exist
ERROR_INSUFFICIENT_BUFFER - buffer is too small to contain specified
information
--*/
{
APIRET RetCode;
NTSTATUS Status;
HANDLE DiskHandle;
IO_STATUS_BLOCK IoStatus;
struct LABEL_BUFFER {
FILE_FS_LABEL_INFORMATION LabelInfo;
WCHAR Label[MAX_LABEL_LENGTH];
} LabelBuffer;
if (DiskNumber > MAX_DRIVES) {
return ERROR_INVALID_DRIVE;
}
if (FsInformationLevel != FSIL_VOLSER) {
return ERROR_INVALID_LEVEL;
}
RetCode = OpenDrive(DiskNumber,
FILE_WRITE_DATA,
&DiskHandle
);
if (RetCode != NO_ERROR) {
return RetCode;
}
RetCode = ProcessLabel((PVOLUMELABEL) Buffer,
Length,
(PFILE_FS_LABEL_INFORMATION) &LabelBuffer
);
if (RetCode != NO_ERROR) {
NtClose(DiskHandle);
return RetCode;
}
do {
Status = NtSetVolumeInformationFile(DiskHandle,
&IoStatus,
&LabelBuffer,
sizeof(LabelBuffer),
FileFsLabelInformation
);
} while (RetryIO(Status, DiskHandle));
NtClose(DiskHandle);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_INVALID_VOLUME_LABEL)
return ERROR_INVALID_NAME;
else
return ERROR_INVALID_DRIVE;
}
return NO_ERROR;
}
APIRET
OpenDrive(
IN ULONG DiskNumber,
IN ULONG RequestedAccess,
OUT PHANDLE DriveHandle
)
/*++
Routine Description:
This routine opens a drive and returns a handle to it.
Arguments:
DiskNumber - which volume to open
RequestedAccess - requested open access to drive
DriveHandle - where to return open handle to drive
Return Value:
ERROR_INVALID_DRIVE - specified volume does not exist
--*/
{
CHAR DiskName[] = "\\OS2SS\\DRIVES\\D:\\";
STRING DiskNameString;
UNICODE_STRING DiskNameString_U;
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatus;
APIRET RetCode;
if (DiskNumber == 0) // default drive
DiskNumber = Od2CurrentDisk;
else
DiskNumber -= 1; // make drive 0-based
// BUGBUG when we add remote drives, need to fix this
DiskName[DRIVE_LETTER+FILE_PREFIX_LENGTH] = (CHAR) (DiskNumber + 'A');
Od2InitMBString(&DiskNameString,DiskName);
//
// UNICODE conversion -
//
RetCode = Od2MBStringToUnicodeString(
&DiskNameString_U,
&DiskNameString,
TRUE);
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("OpenDrive: no memory for Unicode Conversion\n");
}
#endif
return RetCode;
}
InitializeObjectAttributes(&Obja,
&DiskNameString_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
do {
Status = NtOpenFile(DriveHandle,
RequestedAccess | SYNCHRONIZE,
&Obja,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT
);
} while (RetryCreateOpen(Status, &Obja));
RtlFreeUnicodeString (&DiskNameString_U);
if (!NT_SUCCESS(Status)) {
return ERROR_INVALID_DRIVE;
}
return NO_ERROR;
}
APIRET
ProcessLabel(
IN PVOLUMELABEL Buffer,
IN ULONG Length,
OUT PFILE_FS_LABEL_INFORMATION LabelBuffer
)
/*++
Routine Description:
This routine checks a volume label for validity and copies it to an
NT buffer.
Arguments:
Buffer - buffer containing os/2 format volume label (unprobed)
Length - length of buffer
LabelBuffer - where to store processed label
Return Value:
ERROR_INSUFFICIENT_BUFFER - buffer is too small to contain the label
ERROR_LABEL_TOO_LONG - the volume label is too long
--*/
{
STRING LabelString;
APIRET RetCode;
UNICODE_STRING LabelString_U;
if (!Length)
return ERROR_INSUFFICIENT_BUFFER;
try {
LabelBuffer->VolumeLabelLength = Buffer->cch;
if ((LabelBuffer->VolumeLabelLength+1) > Length)
return ERROR_INSUFFICIENT_BUFFER;
if (LabelBuffer->VolumeLabelLength > MAX_LABEL_LENGTH)
return ERROR_LABEL_TOO_LONG;
Od2InitMBString(&LabelString,(PSZ)(Buffer->szVolLabel));
#ifdef DBCS
// MSKK Nov.04.1993 V-AkihiS
LabelString.Length = Buffer->cch;
#endif
//
// UNICODE conversion -
//
RetCode = Od2MBStringToUnicodeString(
&LabelString_U,
&LabelString,
TRUE);
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("ProcessLabel: no memory for Unicode Conversion\n");
}
#endif
return RetCode;
}
#ifdef DBCS
// MSKK Apr.18.1993 V-AkihiS
//
// Use UNICODE string length as volume label Length for DBCS support.
//
LabelBuffer->VolumeLabelLength = LabelString_U.Length;
#else
//
// Since we are talking WCHAR, double length
//
LabelBuffer->VolumeLabelLength = LabelBuffer->VolumeLabelLength * 2;
#endif
RtlMoveMemory(&(LabelBuffer->VolumeLabel),
LabelString_U.Buffer,
LabelBuffer->VolumeLabelLength);
RtlFreeUnicodeString (&LabelString_U);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return NO_ERROR;
}
APIRET
DosFSCtl(
IN PBYTE Data,
IN ULONG DataLength,
OUT PULONG ActualDataLength,
IN PBYTE Parameters,
IN ULONG ParametersLength,
IN OUT PULONG ActualParametersLength,
IN ULONG Function,
IN PSZ RouteName,
IN HFILE FileHandle,
IN ULONG RoutingMethod
)
/*++
Routine Description:
Arguments:
Return Value:
BUGBUG whenever this is sorted out, finish probing parms
--*/
{
#if 0
HANDLE NtHandle;
NTSTATUS Status;
APIRET RetCode;
STRING CanonicalNameString;
UNICODE_STRING CanonicalNameString_U;
ULONG FileType;
ULONG FileFlags;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatus;
PFILE_HANDLE hFileRecord;
#endif
#if DBG
PSZ RoutineName;
RoutineName = "DosFSCtl";
#endif
UNREFERENCED_PARAMETER(ParametersLength);
UNREFERENCED_PARAMETER(Data);
UNREFERENCED_PARAMETER(DataLength);
UNREFERENCED_PARAMETER(ActualDataLength);
UNREFERENCED_PARAMETER(Parameters);
UNREFERENCED_PARAMETER(ActualParametersLength);
UNREFERENCED_PARAMETER(Function);
UNREFERENCED_PARAMETER(RouteName);
UNREFERENCED_PARAMETER(FileHandle);
UNREFERENCED_PARAMETER(RoutingMethod);
return ERROR_INVALID_FUNCTION;
#if 0
if ((RoutingMethod < FSCTL_HANDLE) || (RoutingMethod > FSCTL_FSDNAME))
return ERROR_INVALID_LEVEL;
if (RoutingMethod == FSCTL_HANDLE) {
if (RouteName != NULL)
return ERROR_INVALID_PARAMETER;
AcquireFileLockShared(
#if DBG
RoutineName
#endif
);
RetCode = DereferenceFileHandle(FileHandle,&hFileRecord);
if (RetCode != NO_ERROR) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return RetCode;
}
if (hFileRecord->FileType &
(FILE_TYPE_DEV | FILE_TYPE_PIPE | FILE_TYPE_NMPIPE)) {
// BUGBUG at some point, NMPIPE and DEV will probably be ok
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
return ERROR_INVALID_HANDLE;
}
else {
NtHandle = hFileRecord->NtHandle;
}
}
else if (RoutingMethod == FSCTL_PATHNAME) {
if (FileHandle != (HFILE) -1)
return ERROR_INVALID_PARAMETER;
// BUGBUG need to append \ if d:
RetCode = Od2Canonicalize(RouteName,
CANONICALIZE_FILE_DEV_OR_PIPE,
&CanonicalNameString,
&NtHandle,
&FileFlags, // BUGBUG should we fail if root?
&FileType
);
if (RetCode != NO_ERROR) {
return ERROR_INVALID_PATH;
}
if (FileType & (FILE_TYPE_DEV | FILE_TYPE_PSDEV | FILE_TYPE_NMPIPE)) {
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
return ERROR_INVALID_PATH;
}
#if DBG
IF_OD2_DEBUG( FSD ) {
DbgPrint("canonicalize returned %s\n",CanonicalNameString.Buffer);
}
#endif
//
// UNICODE conversion -
//
RetCode = Od2MBStringToUnicodeString(
&CanonicalNameString_U,
&CanonicalNameString,
TRUE);
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("DosFSCtl: no memory for Unicode Conversion\n");
}
#endif
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
return RetCode;
}
InitializeObjectAttributes(&Obja,
&CanonicalNameString_U,
OBJ_CASE_INSENSITIVE,
NtHandle,
NULL);
do {
Status = NtOpenFile(&NtHandle,
SYNCHRONIZE,
&Obja,
&IoStatus,
FILE_SHARE_WRITE | FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT
);
} while (RetryCreateOpen(Status, &Obja));
RtlFreeUnicodeString (&CanonicalNameString_U);
if (!(NT_SUCCESS(Status))) {
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
#if DBG
IF_OD2_DEBUG( FSD ) {
DbgPrint("NtOpenFile returned %X\n",Status);
}
#endif
return ERROR_PATH_NOT_FOUND; // BUGBUG bogus error
}
}
else { // FSCTL_FSDNAME
if (FileHandle != (HFILE) -1)
return ERROR_INVALID_PARAMETER;
try {
Od2InitMBString(&CanonicalNameString,RouteName);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
//
// UNICODE conversion -
//
RetCode = Od2MBStringToUnicodeString(
&CanonicalNameString_U,
&CanonicalNameString,
TRUE);
if (RetCode)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("DosFSCtl: no memory for Unicode Conversion-2\n");
}
#endif
return RetCode;
}
InitializeObjectAttributes(&Obja,
&CanonicalNameString_U,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
do {
Status = NtOpenFile(&NtHandle,
SYNCHRONIZE,
&Obja,
&IoStatus,
FILE_SHARE_WRITE | FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT
);
} while (RetryCreateOpen(Status, &Obja));
RtlFreeUnicodeString (&CanonicalNameString_U);
if (!(NT_SUCCESS(Status))) {
#if DBG
IF_OD2_DEBUG( FSD ) {
DbgPrint("NtOpenFile returned %X\n",Status);
}
#endif
return ERROR_INVALID_FSD_NAME;
}
}
Status = NtFsControlFile(NtHandle,
(HANDLE) NULL,
(PIO_APC_ROUTINE) NULL,
(PVOID) NULL,
&IoStatus,
Function,
(PVOID) Parameters,
*ActualParametersLength,
(PVOID) Data,
DataLength
);
if (RoutingMethod == FSCTL_HANDLE) {
ReleaseFileLockShared(
#if DBG
RoutineName
#endif
);
}
else if (RoutingMethod == FSCTL_PATHNAME) {
NtClose(NtHandle);
RtlFreeHeap(Od2Heap, 0,CanonicalNameString.Buffer);
}
else { // FSCTL_FSDNAME
NtClose(NtHandle);
}
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_BUFFER_OVERFLOW)
return ERROR_BUFFER_OVERFLOW;
else
return ERROR_INVALID_FUNCTION; // BUGBUG errors should be mapped
}
else {
try {
*ActualDataLength = IoStatus.Information;
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
return NO_ERROR;
}
#endif
}
APIRET
DosFSAttach(
IN PSZ DeviceName,
IN PSZ FsName,
IN PBYTE FsData,
IN ULONG FsDataLength,
IN ULONG AttachFlags
)
/*++
Routine Description:
This function partially implements the DosFSAttach() API. The only valid FsName is "LAN".
The format expected for the arguments is as follows:
DeviceName -- device name, e.g. "J:", "LPT1:"
FsName -- "LAN"
FsData -- either "\01\0SHARENAME" for a regular connection or
"\02\0SHARENAME\0PASSWORD" for a password connection or
"\03\0SHARENAME\0PASSWORD\0USERNAME" for a username/password connection.
FsDataLength -- length of FsData
AttachFlags -- FS_ATTACH or FS_DETACH
The function connects to the network using WNetAdd/DelConnection(). Therefore it'll use the
multiple provider router to connect to any type of network for which NT has a redirector.
The SHARENAME format depends on the network you're trying to reach. for LanMan/MsNet networks
it's "\\\\sharename\\servername".
If DeviceName is a drive letter, the drive is automatically reset to the root directory after
a connection, and before a disconnection. This is for compatibility with OS/2.
Arguments:
see above + documentation of DosFSAttach().
Return Value:
error status.
--*/
{
NETRESOURCEA netr;
PSZ passwd = NULL;
PSZ username = NULL;
ULONG Drive = (ULONG)-1;
ULONG Length;
ULONG rc;
APIRET nrc;
CHAR DriveBuf[4];
try {
PROBE_STRING(DeviceName);
PROBE_STRING(FsName);
Od2ProbeForRead(FsData, FsDataLength, 1);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (FsName == NULL ||
_stricmp(FsName, "LAN") != 0) {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: Invalid FSD name\n"));
}
#endif
return(ERROR_INVALID_FSD_NAME);
}
if (DeviceName != NULL &&
DeviceName[0] != '\0' &&
DeviceName[1] == ':' &&
DeviceName[2] == '\0') { // is the device a disk drive?
int ch;
ch = toupper((UCHAR) DeviceName[0]);
if (isalpha(ch)) {
Drive = (ULONG) (ch - 'A');
if (Od2CurrentDisk == Drive) {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: attempt to attach/detach current drive = %ld\n", Drive));
}
#endif
return(ERROR_DEVICE_IN_USE);
}
DriveBuf[0] = (UCHAR) ch;
DriveBuf[1] = ':';
DriveBuf[2] = '\\';
DriveBuf[3] = '\0';
} else {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: Invalid drive letter = %c\n", ch));
}
#endif
return(ERROR_INVALID_DRIVE);
}
}
if (AttachFlags == FS_ATTACH) {
if (FsDataLength < 3 ||
FsData[0] == 0 ||
FsData[0] > 3 ||
FsData[1] != 0) {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: Unsupported FsData structure\n"));
}
#endif
return(ERROR_NOT_SUPPORTED);
}
netr.lpLocalName = DeviceName;
netr.lpRemoteName = (PSZ) FsData + 2;
try {
Length = strlen(netr.lpRemoteName);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
netr.lpProvider = NULL;
netr.dwType = RESOURCETYPE_ANY;
if (FsData[0] >= 2) {
passwd = netr.lpRemoteName + Length + 1;
if (FsData + FsDataLength <= passwd) {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: FsData overflow\n"));
}
#endif
return(ERROR_INVALID_PATH);
}
try {
Length = strlen(passwd);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
if (FsData[0] == 3) {
username = passwd + Length + 1;
if (FsData + FsDataLength <= username) {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: FsData overflow\n"));
}
#endif
return(ERROR_INVALID_PATH);
}
try {
(VOID) strlen(username);
} except( EXCEPTION_EXECUTE_HANDLER ) {
Od2ExitGP();
}
}
}
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: calling WNetAddConnection2()\n"));
}
#endif
rc = WNetAddConnection2A(&netr,
passwd,
username,
0);
if (rc == NO_ERROR && Drive != (ULONG)-1) {
//
// initialize the connection to the root directory on target drive
//
(VOID) DosSetCurrentDir(DriveBuf);
}
} else if (AttachFlags == FS_DETACH) {
if (Drive != (ULONG)-1) {
//
// go back to root directory on target drive
//
(VOID) DosSetCurrentDir(DriveBuf);
}
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: calling WNetCancelConnection2()\n"));
}
#endif
//
// In the case that the disk that will be deattached is the current disk
// (from Win32 point of view), change the current disk according to
// OS2 ss (Od2CurrentDisk).
//
{
PSZ pBuffer;
DWORD length;
length = GetCurrentDirectoryA(0, NULL);
pBuffer = RtlAllocateHeap(Od2Heap, 0, length);
GetCurrentDirectoryA(length, pBuffer);
if (toupper(pBuffer[0]) == toupper(DeviceName[0])) {
DriveBuf[0] = (UCHAR) Od2CurrentDisk + 'A';
DriveBuf[1] = ':';
DriveBuf[2] = '\0';
SetCurrentDirectoryA(DriveBuf);
}
RtlFreeHeap(Od2Heap, 0, pBuffer);
}
rc = WNetCancelConnection2A(DeviceName,
0,
TRUE);
} else {
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: Invalid level\n"));
}
#endif
return(ERROR_INVALID_LEVEL);
}
switch (rc) {
case NO_ERROR:
nrc = NO_ERROR;
break;
case ERROR_ACCESS_DENIED:
case ERROR_ALREADY_ASSIGNED:
case ERROR_BAD_DEV_TYPE:
case ERROR_INVALID_PASSWORD:
nrc = (APIRET) rc;
break;
case 1200L: /* ERROR_BAD_DEVICE */
case 2250L: /* ERROR_NOT_CONNECTED */
nrc = ERROR_INVALID_DRIVE;
break;
case ERROR_BAD_NET_NAME:
case 1203L: /* ERROR_NO_NET_OR_BAD_PATH */
case 2138L: /* ERROR_NO_NETWORK */
nrc = ERROR_INVALID_PATH;
break;
case 2404L: /* ERROR_DEVICE_IN_USE */
case 2401L: /* ERROR_OPEN_FILES */
nrc = ERROR_DEVICE_IN_USE;
break;
default:
nrc = ERROR_INVALID_PATH;
break;
}
#if DBG
IF_OD2_DEBUG( FSD ) {
KdPrint(("DosFSAttach: rc = %lx, nrc = %x\n", rc, nrc));
}
#endif
return(nrc);
}
/* Dos32FsAttach() */
/* Attact or detach */
//#define FS_ATTACH 0 /* Attach file server */
//#define FS_DETACH 1 /* Detach file server */
APIRET
DosQueryFSAttach(
IN PSZ DeviceName,
IN ULONG Ordinal,
IN ULONG FsInformationLevel,
OUT PBYTE FsAttributes,
IN OUT PULONG FsAttributesLength
)
/*++
Routine Description:
BUGBUG - Note that the FSAData[] field is left empty for local drives.
Query by ordinal is not supported.
Arguments:
Return Value:
--*/
{
ULONG DriveNumber;
USHORT NameLength;
PFSQBUFFER2 BufPtr;
char *StrPtr;
APIRET rc;
if ((FsInformationLevel < FSAIL_QUERYNAME) ||
(FsInformationLevel > FSAIL_DRVNUMBER)) {
return ERROR_INVALID_LEVEL;
}
BufPtr = (PFSQBUFFER2) FsAttributes;
try {
if (*FsAttributesLength < (sizeof(FSQBUFFER)-1))
return ERROR_BUFFER_OVERFLOW;
if (FsInformationLevel == FSAIL_QUERYNAME)
{
NTSTATUS Status;
STRING TargetCanonicalName;
UNICODE_STRING TargetUnicodeName;
ULONG TargetType;
ULONG TargetFlags;
OBJECT_ATTRIBUTES object_attributes;
ULONG attr_len;
char actual_file_name[256];
/* Local parameters for the NtOpenFile() call */
IO_STATUS_BLOCK io_status_block;
HANDLE hand;
/* For NtQueryInformationFile */
char tmp_buf[1024];
PFILE_FS_ATTRIBUTE_INFORMATION pFileFsInfo;
FILE_FS_DEVICE_INFORMATION DeviceInfo;
/* Handle the non X: case */
if (DeviceName[COLON] != ':')
{
STRING TargetCanonicalName;
ULONG TargetType;
ULONG TargetFlags;
/* If not a drive letter, then must be \DEV\xxx or
/DEV/xxx */
if ((_strnicmp(DeviceName,"\\DEV\\",5)) &&
(_strnicmp(DeviceName,"/DEV/",5)))
{
return ERROR_INVALID_PATH;
}
NameLength = (USHORT)strlen(DeviceName);
rc = Od2Canonicalize(DeviceName,
CANONICALIZE_FILE_OR_DEV,
&TargetCanonicalName,
NULL,
&TargetFlags,
&TargetType);
if (rc != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint(
"DosQueryFSAttach: Failed to Od2Canonicalize(\"%s\") - rc = %x\n",
DeviceName, rc);
}
#endif
return ERROR_INVALID_PATH;
}
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("Canonical name is <%s>\n",
TargetCanonicalName.Buffer);
}
#endif
/* BUGBUG - Check meaning of code below (from 'dllcopy.c, DosCopy()) */
if (TargetFlags & CANONICALIZE_META_CHARS_FOUND)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("DosQueryFSAttach: <%s> has META_CHARS\n",
DeviceName);
}
#endif
RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
return ERROR_INVALID_PATH;
}
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("Type = <%x>, Flags = <%x>\n",
TargetType, TargetFlags);
}
#endif
if (!(TargetType & FILE_TYPE_DEV) &&
!(TargetType & FILE_TYPE_PSDEV) &&
!(TargetType & FILE_TYPE_COM))
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("DosQueryFSAttach: <%s> is not a valid device\n",
DeviceName);
}
#endif
RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
return ERROR_INVALID_PATH;
}
/* Note that although some devices are marked as pseudo, under
OS/2 1.21, I found none such devices, hence the line below */
BufPtr->iType = FSAT_CHARDEV;
BufPtr->cbName = NameLength;
BufPtr->cbFSDName = 0;
BufPtr->cbFSAData = 0;
StrPtr = BufPtr->szName;
strncpy(StrPtr,DeviceName,NameLength+1);
_strupr(StrPtr); /* Convert string to uppercase, just like under OS/2 1.x */
StrPtr += NameLength+1;
StrPtr[0] = '\0'; /* "" - no file-system name for \\dev\xxx */
*FsAttributesLength = (ULONG)(StrPtr
+ BufPtr->cbFSDName + 1
+ BufPtr->cbFSAData
- (PBYTE)BufPtr);
RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
return NO_ERROR;
}
DriveNumber = (ULONG) (UCase(DeviceName[DRIVE_LETTER]) - 'A');
if ((DeviceName[FIRST_SLASH] != '\0') ||
(DriveNumber >= MAX_DRIVES))
{
return ERROR_INVALID_DRIVE;
}
strcpy(actual_file_name, DeviceName);
strcat(actual_file_name,"\\");
rc = Od2Canonicalize(actual_file_name,
CANONICALIZE_FILE_OR_DEV,
&TargetCanonicalName,
NULL,
&TargetFlags,
&TargetType);
if (rc != NO_ERROR)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint(
"DosQueryFSAttach: Failed to Od2Canonicalize(\"%s\") - rc = %x\n",
actual_file_name, rc);
}
#endif
return ERROR_INVALID_DRIVE;
}
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("Canonical name is <%s>\n",
TargetCanonicalName.Buffer);
}
#endif
rc = Od2MBStringToUnicodeString(
&TargetUnicodeName,
&TargetCanonicalName,
TRUE);
if (rc)
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint("DosQueryFSAttach: no memory for Unicode Conversion\n");
}
#endif
RtlFreeHeap(Od2Heap, 0,TargetCanonicalName.Buffer);
return rc;
}
RtlFreeHeap(Od2Heap, 0, TargetCanonicalName.Buffer);
InitializeObjectAttributes(
&object_attributes,
&TargetUnicodeName,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
NULL);
do {
Status = NtOpenFile(
&hand,
SYNCHRONIZE | FILE_READ_ATTRIBUTES,
&object_attributes,
&io_status_block,
FILE_SHARE_READ,
FILE_DIRECTORY_FILE
);
} while (RetryCreateOpen(Status, &object_attributes));
RtlFreeUnicodeString(&TargetUnicodeName);
if (!NT_SUCCESS(Status))
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint(
"DosQueryFSAttach: Failed to NtOpenFile (%s) - rc = %x\n",
DeviceName, Status);
}
#endif
return ERROR_INVALID_DRIVE;
}
do {
Status = NtQueryVolumeInformationFile(
hand,
&io_status_block,
tmp_buf,
1024,
FileFsAttributeInformation
);
} while (RetryIO(Status, hand));
if (!NT_SUCCESS(Status))
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint(
"DosQueryFSAttach: Failed to NtQueryVolumeInformation (%s) - rc = %x\n",
DeviceName, Status);
}
#endif
NtClose(hand);
return ERROR_INVALID_DRIVE;
}
do {
Status = NtQueryVolumeInformationFile(
hand,
&io_status_block,
&DeviceInfo,
sizeof (DeviceInfo),
FileFsDeviceInformation);
} while (RetryIO(Status, hand));
if (!NT_SUCCESS(Status))
{
#if DBG
IF_OD2_DEBUG( FILESYS )
{
DbgPrint(
"DosQueryFSAttach: Failed to NtQueryVolumeInformation (%s) - rc = %x\n",
DeviceName, Status);
}
#endif
NtClose(hand);
return ERROR_INVALID_DRIVE;
}
pFileFsInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)tmp_buf;
BufPtr->cbFSAData = 0;
StrPtr = BufPtr->szName;
strcpy(StrPtr,DeviceName);
BufPtr->cbName = (USHORT)strlen(StrPtr);
_strupr(StrPtr); /* Convert string to uppercase, just like under OS/2 1.x */
StrPtr += BufPtr->cbName + 1;
Od2nCopyWstrToStr(StrPtr, pFileFsInfo->FileSystemName,
pFileFsInfo->FileSystemNameLength/2);
if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE)
{
// NT returns FAT, HPFS & NTFS (xlated above to HPFS) even for
// LAN drives, so fix it to be 'LAN' as under OS/2
strcpy(StrPtr, "LAN");
}
//Translate NTFS to HPFS (the closest OS/2 equivalent)
else if (!strcmp(StrPtr, "NTFS"))
strcpy(StrPtr, "HPFS");
BufPtr->cbFSDName = (USHORT)strlen(StrPtr); /* File-system name length,
not including the \0 */
if (DeviceInfo.Characteristics & FILE_REMOTE_DEVICE)
{
char tmp_buf[256];
ULONG count = 256;
BufPtr->iType = FSAT_REMOTEDRV;
// Get the share name for the drive, if possible
if (!WNetGetConnectionA(
BufPtr->szName, // drive letter
tmp_buf, // result buffer
&count))
{
if ((ULONG)(StrPtr
+ BufPtr->cbFSDName + 1
+ BufPtr->cbFSAData
+ strlen(tmp_buf) + 1
- (PBYTE)BufPtr) <=
*FsAttributesLength)
{
try
{
strcpy(StrPtr + BufPtr->cbFSDName + 1,
tmp_buf);
#ifdef DBCS
// MSKK Jul.22.1993 V-AkihiS
// cbFSAData counts null.
BufPtr->cbFSAData = strlen(StrPtr + BufPtr->cbFSDName + 1) + 1;
#else
BufPtr->cbFSAData = strlen(StrPtr + BufPtr->cbFSDName + 1);
#endif
} except( EXCEPTION_EXECUTE_HANDLER )
{
// Just ignore error
BufPtr->cbFSAData = 0; // Just in case ...
}
}
}
}
else
BufPtr->iType = FSAT_LOCALDRV;
attr_len = (ULONG)(StrPtr
+ BufPtr->cbFSDName + 1
+ BufPtr->cbFSAData
- (PBYTE)BufPtr);
#if NEVER
/* If one is interested, here's the full list: */
switch (DeviceInfo.DeviceType)
{
case FILE_DEVICE_CD_ROM:
case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
case FILE_DEVICE_DISK:
case FILE_DEVICE_DISK_FILE_SYSTEM:
case FILE_DEVICE_FILE_SYSTEM:
case FILE_DEVICE_VIRTUAL_DISK:
case FILE_DEVICE_NETWORK:
case FILE_DEVICE_NETWORK_FILE_SYSTEM:
case FILE_DEVICE_TAPE:
case FILE_DEVICE_TAPE_FILE_SYSTEM:
case FILE_DEVICE_CONTROLLER:
case FILE_DEVICE_DATALINK:
case FILE_DEVICE_DFS:
case FILE_DEVICE_KEYBOARD:
case FILE_DEVICE_MAILSLOT:
case FILE_DEVICE_MOUSE:
case FILE_DEVICE_NAMED_PIPE:
case FILE_DEVICE_NULL:
case FILE_DEVICE_PARALLEL_PORT:
case FILE_DEVICE_PHYSICAL_NETCARD:
case FILE_DEVICE_PRINTER:
case FILE_DEVICE_SERIAL_PORT:
case FILE_DEVICE_SCREEN:
case FILE_DEVICE_SOUND:
case FILE_DEVICE_STREAMS:
case FILE_DEVICE_TRANSPORT:
case FILE_DEVICE_UNKNOWN:
case FILE_DEVICE_NETWORK_BROWSER:
case FILE_DEVICE_WAVE_IN:
case FILE_DEVICE_WAVE_OUT:
case FILE_DEVICE_8042_PORT:
case FILE_DEVICE_INPORT_PORT:
case FILE_DEVICE_SERIAL_MOUSE_PORT:
case FILE_DEVICE_BEEP:
case FILE_DEVICE_SCANNER:
case FILE_DEVICE_VIDEO:
case FILE_DEVICE_MULTIPLE_UNC_PROVIDER:
}
#endif /* NEVER */
/* Update the user-supplied output value only after all has succeeded */
/* BUGBUG - We should do that same for the FsInformation buffer */
*FsAttributesLength = attr_len;
NtClose(hand);
}
else
{
/* BUGBUG - Query by ordinal not supported */
if (!Ordinal)
{
return ERROR_INVALID_PARAMETER;
}
return ERROR_INVALID_FUNCTION;
}
} except ( EXCEPTION_EXECUTE_HANDLER )
{
Od2ExitGP();
}
return NO_ERROR;
}
/* DosQueryFSAttach() */
/* Information level types (defines method of query) */
//#define FSAIL_QUERYNAME 1 /* Return data for a Drive or Device */
//#define FSAIL_DEVNUMBER 2 /* Return data for Ordinal Device # */
//#define FSAIL_DRVNUMBER 3 /* Return data for Ordinal Drive # */
/* Item types (from data structure item "iType") */
//#define FSAT_CHARDEV 1 /* Resident character device */
//#define FSAT_PSEUDODEV 2 /* Pseudo-character device */
//#define FSAT_LOCALDRV 3 /* Local drive */
//#define FSAT_REMOTEDRV 4 /* Remote drive attached to FSD */