423 lines
12 KiB
C
423 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
object.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Resource DLL for disks.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Rod Gamache (rodga) 18-Dec-1995
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "nt.h"
|
|||
|
#include "ntrtl.h"
|
|||
|
#include "nturtl.h"
|
|||
|
#include "windows.h"
|
|||
|
#include "windef.h"
|
|||
|
#include "stdio.h"
|
|||
|
#include "stdlib.h"
|
|||
|
#include "disksp.h"
|
|||
|
|
|||
|
#define ATTR_DIR 0x00000001
|
|||
|
#define ATTR_DEVICE 0x00000002
|
|||
|
#define ATTR_FILE 0x00000004
|
|||
|
#define ATTR_SYMLINK 0x00000008
|
|||
|
|
|||
|
#define DIRECTORYTYPE L"Directory"
|
|||
|
#define DEVICETYPE L"Device"
|
|||
|
#define FILETYPE L"File"
|
|||
|
#define SYMLINKTYPE L"SymbolicLink"
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Converts the type-name into an attribute value */
|
|||
|
|
|||
|
LONG CalcAttributes(
|
|||
|
PUNICODE_STRING Type
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING TypeName;
|
|||
|
|
|||
|
RtlInitUnicodeString(&TypeName, DIRECTORYTYPE);
|
|||
|
if (RtlEqualString((PSTRING)Type, (PSTRING)&TypeName, TRUE)) {
|
|||
|
return ATTR_DIR;
|
|||
|
}
|
|||
|
RtlInitUnicodeString(&TypeName, DEVICETYPE);
|
|||
|
if (RtlEqualString((PSTRING)Type, (PSTRING)&TypeName, TRUE)) {
|
|||
|
return ATTR_DEVICE;
|
|||
|
}
|
|||
|
RtlInitUnicodeString(&TypeName, FILETYPE);
|
|||
|
if (RtlEqualString((PSTRING)Type, (PSTRING)&TypeName, TRUE)) {
|
|||
|
return ATTR_FILE;
|
|||
|
}
|
|||
|
RtlInitUnicodeString(&TypeName, SYMLINKTYPE);
|
|||
|
if (RtlEqualString((PSTRING)Type, (PSTRING)&TypeName, TRUE)) {
|
|||
|
return ATTR_SYMLINK;
|
|||
|
}
|
|||
|
return(0);
|
|||
|
|
|||
|
} // CalcAttributes
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*--------------------------------------------------------------------------*/
|
|||
|
/* */
|
|||
|
/* StripObjectSpec() - */
|
|||
|
/* */
|
|||
|
/*--------------------------------------------------------------------------*/
|
|||
|
|
|||
|
/* Remove the filespec portion from a path (including the backslash). */
|
|||
|
|
|||
|
VOID StripObjectSpec(LPSTR lpszPath)
|
|||
|
{
|
|||
|
LPSTR p;
|
|||
|
|
|||
|
#ifdef DBCS
|
|||
|
p = lpszPath + lstrlen(lpszPath);
|
|||
|
while ((*p != '\\') && (p != lpszPath))
|
|||
|
p = AnsiPrev(lpszPath, p);
|
|||
|
#else
|
|||
|
p = lpszPath + lstrlen(lpszPath);
|
|||
|
while ((*p != '\\') && (p != lpszPath))
|
|||
|
p--;
|
|||
|
#endif
|
|||
|
|
|||
|
/* Don't strip backslash from root directory entry. */
|
|||
|
if ((p == lpszPath) && (*p == '\\')) {
|
|||
|
p++;
|
|||
|
}
|
|||
|
|
|||
|
*p = '\000';
|
|||
|
|
|||
|
} // StripObjectSpec
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*--------------------------------------------------------------------------*/
|
|||
|
/* */
|
|||
|
/* StripObjectPath() - */
|
|||
|
/* */
|
|||
|
/*--------------------------------------------------------------------------*/
|
|||
|
|
|||
|
/* Extract only the filespec portion from a path. */
|
|||
|
|
|||
|
VOID StripObjectPath(LPSTR lpszPath)
|
|||
|
{
|
|||
|
LPSTR p;
|
|||
|
|
|||
|
p = lpszPath + lstrlen(lpszPath);
|
|||
|
#ifdef DBCS
|
|||
|
while ((*p != '\\') && (p != lpszPath))
|
|||
|
p = AnsiPrev(lpszPath, p);
|
|||
|
#else
|
|||
|
while ((*p != '\\') && (p != lpszPath))
|
|||
|
p--;
|
|||
|
#endif
|
|||
|
|
|||
|
if (*p == '\\')
|
|||
|
p++;
|
|||
|
|
|||
|
if (p != lpszPath)
|
|||
|
lstrcpy(lpszPath, p);
|
|||
|
|
|||
|
} // StripObjectPath
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
GetSymbolicLink(
|
|||
|
IN PCHAR RootName,
|
|||
|
IN OUT PCHAR ObjectName, // Assume this points at a MAX_PATH len buffer
|
|||
|
IN PDISK_INFO DiskInfo
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
OBJECT_ATTRIBUTES Object_Attributes;
|
|||
|
HANDLE LinkHandle;
|
|||
|
STRING String;
|
|||
|
WCHAR UnicodeBuffer[MAX_PATH];
|
|||
|
CHAR Buffer[2*MAX_PATH];
|
|||
|
UNICODE_STRING UnicodeString;
|
|||
|
|
|||
|
strcpy( Buffer, RootName );
|
|||
|
strcat( Buffer, ObjectName );
|
|||
|
|
|||
|
RtlInitString(&String, Buffer);
|
|||
|
Status = RtlAnsiStringToUnicodeString( &UnicodeString,
|
|||
|
&String,
|
|||
|
TRUE );
|
|||
|
ASSERT( NT_SUCCESS( Status ) );
|
|||
|
|
|||
|
InitializeObjectAttributes(&Object_Attributes,
|
|||
|
&UnicodeString,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
// Open the given symbolic link object
|
|||
|
Status = NtOpenSymbolicLinkObject(&LinkHandle,
|
|||
|
GENERIC_ALL,
|
|||
|
&Object_Attributes);
|
|||
|
RtlFreeUnicodeString(&UnicodeString);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
printf( "Open symbolic link failed, status = %u.\n",
|
|||
|
Status);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Set up our String variable to point at the object name buffer
|
|||
|
|
|||
|
String.Length = 0;
|
|||
|
String.MaximumLength = (USHORT)(MAX_PATH);
|
|||
|
String.Buffer = ObjectName;
|
|||
|
|
|||
|
// Go get the target of the symbolic link
|
|||
|
|
|||
|
UnicodeString.Buffer = UnicodeBuffer;
|
|||
|
UnicodeString.MaximumLength = sizeof(UnicodeBuffer);
|
|||
|
|
|||
|
Status = NtQuerySymbolicLinkObject(LinkHandle, &UnicodeString, NULL);
|
|||
|
|
|||
|
NtClose(LinkHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
printf("Query symbolic link failed, status = %u.\n",
|
|||
|
Status);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Copy the symbolic target into return buffer
|
|||
|
|
|||
|
Status = RtlUnicodeStringToAnsiString(&String, &UnicodeString, FALSE);
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
|
|||
|
// Add NULL terminator
|
|||
|
String.Buffer[String.Length] = 0;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/* Open the object given only its name.
|
|||
|
* First find the object type by enumerating the directory entries.
|
|||
|
* Then call the type-specific open routine to get a handle
|
|||
|
*/
|
|||
|
|
|||
|
HANDLE
|
|||
|
OpenObject(
|
|||
|
LPSTR lpstrDirectory,
|
|||
|
LPSTR lpstrObject,
|
|||
|
PDISK_INFO DiskInfo
|
|||
|
)
|
|||
|
{
|
|||
|
#define BUFFER_SIZE 1024
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
HANDLE DirectoryHandle;
|
|||
|
ULONG Context = 0;
|
|||
|
ULONG ReturnedLength;
|
|||
|
CHAR Buffer[BUFFER_SIZE];
|
|||
|
CHAR StringBuffer[BUFFER_SIZE];
|
|||
|
CHAR CompareBuffer[MAX_PATH];
|
|||
|
CHAR ReturnBuffer[MAX_PATH];
|
|||
|
ANSI_STRING AnsiString;
|
|||
|
POBJECT_DIRECTORY_INFORMATION DirInfo;
|
|||
|
WCHAR ObjectNameBuf[MAX_PATH];
|
|||
|
UNICODE_STRING ObjectName;
|
|||
|
WCHAR ObjectTypeBuf[MAX_PATH];
|
|||
|
UNICODE_STRING ObjectType;
|
|||
|
HANDLE ObjectHandle;
|
|||
|
OBJECT_ATTRIBUTES Attributes;
|
|||
|
UNICODE_STRING DirectoryName;
|
|||
|
IO_STATUS_BLOCK IOStatusBlock;
|
|||
|
BOOL NotFound;
|
|||
|
|
|||
|
//DbgPrint("Open object: raw full name = <%s>\n", lpstrObject);
|
|||
|
#if 0
|
|||
|
// Remove drive letter
|
|||
|
while ((*lpstrObject != 0) && (*lpstrObject != '\\')) {
|
|||
|
lpstrObject++;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//DbgPrint("Open object: full name = <%s%s>\n", lpstrDirectory, lpstrObject);
|
|||
|
|
|||
|
// Initialize the object type buffer
|
|||
|
ObjectType.Buffer = ObjectTypeBuf;
|
|||
|
ObjectType.MaximumLength = sizeof(ObjectTypeBuf);
|
|||
|
|
|||
|
// Initialize the object name string
|
|||
|
//strcpy(Buffer, lpstrObject);
|
|||
|
//StripObjectPath(Buffer);
|
|||
|
RtlInitAnsiString(&AnsiString, lpstrObject);
|
|||
|
|
|||
|
ObjectName.Buffer = ObjectNameBuf;
|
|||
|
ObjectName.MaximumLength = sizeof(ObjectNameBuf);
|
|||
|
|
|||
|
Status = RtlAnsiStringToUnicodeString(&ObjectName, &AnsiString, FALSE);
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
|
|||
|
//DbgPrint("Open object: name only = <%wZ>\n", &ObjectName);
|
|||
|
|
|||
|
// Form buffer to compare Object entries against.
|
|||
|
strcpy(CompareBuffer, lpstrObject );
|
|||
|
//StripObjectSpec( CompareBuffer );
|
|||
|
|
|||
|
//
|
|||
|
// Open the directory for list directory access
|
|||
|
//
|
|||
|
|
|||
|
strcpy(StringBuffer, lpstrDirectory);
|
|||
|
//StripObjectSpec(Buffer);
|
|||
|
|
|||
|
RtlInitAnsiString(&AnsiString, StringBuffer);
|
|||
|
|
|||
|
Status = RtlAnsiStringToUnicodeString( &DirectoryName, &AnsiString, TRUE);
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
|
|||
|
InitializeObjectAttributes( &Attributes,
|
|||
|
&DirectoryName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL );
|
|||
|
|
|||
|
//DbgPrint("Open object: dir only = <%wZ>\n", &DirectoryName);
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status = NtOpenDirectoryObject( &DirectoryHandle,
|
|||
|
STANDARD_RIGHTS_READ |
|
|||
|
DIRECTORY_QUERY |
|
|||
|
DIRECTORY_TRAVERSE,
|
|||
|
&Attributes ) )) {
|
|||
|
|
|||
|
if (Status == STATUS_OBJECT_TYPE_MISMATCH) {
|
|||
|
DbgPrint( "%wZ is not a valid Object Directory Object name\n",
|
|||
|
&DirectoryName );
|
|||
|
} else {
|
|||
|
DbgPrint("OpenObject: failed to open directory, status = 0x%lx\n\r", Status);
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&DirectoryName);
|
|||
|
|
|||
|
printf("Unable to open object.\n");
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
RtlFreeUnicodeString(&DirectoryName);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Query the entire directory in one sweep
|
|||
|
//
|
|||
|
NotFound = TRUE;
|
|||
|
|
|||
|
for (Status = NtQueryDirectoryObject( DirectoryHandle,
|
|||
|
Buffer,
|
|||
|
sizeof(Buffer),
|
|||
|
// LATER FALSE,
|
|||
|
TRUE, // one entry at a time for now
|
|||
|
TRUE,
|
|||
|
&Context,
|
|||
|
&ReturnedLength );
|
|||
|
NotFound;
|
|||
|
Status = NtQueryDirectoryObject( DirectoryHandle,
|
|||
|
Buffer,
|
|||
|
sizeof(Buffer),
|
|||
|
// LATER FALSE,
|
|||
|
TRUE, // one entry at a time for now
|
|||
|
FALSE,
|
|||
|
&Context,
|
|||
|
&ReturnedLength ) ) {
|
|||
|
//
|
|||
|
// Check the status of the operation.
|
|||
|
//
|
|||
|
|
|||
|
if (!NT_SUCCESS( Status )) {
|
|||
|
if (Status != STATUS_NO_MORE_ENTRIES) {
|
|||
|
printf("Failed to query directory object, status = %%1!u!.",
|
|||
|
Status);
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// For every record in the buffer get the symbolic link and
|
|||
|
// compare the name of the symbolic link with the one we're
|
|||
|
// looking for.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Point to the first record in the buffer, we are guaranteed to have
|
|||
|
// one otherwise Status would have been No More Files
|
|||
|
//
|
|||
|
|
|||
|
DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
|
|||
|
|
|||
|
RtlCopyString( (PSTRING)&ObjectType, (PSTRING)&DirInfo->TypeName);
|
|||
|
|
|||
|
AnsiString.MaximumLength = BUFFER_SIZE;
|
|||
|
|
|||
|
while ( DirInfo->Name.Length != 0 ) {
|
|||
|
|
|||
|
//DbgPrint("Found object <%wZ>\n", &(DirInfo->Name));
|
|||
|
|
|||
|
RtlCopyString( (PSTRING)&ObjectType, (PSTRING)&DirInfo->TypeName);
|
|||
|
|
|||
|
if ( CalcAttributes(&ObjectType) == ATTR_SYMLINK ) {
|
|||
|
RtlUnicodeStringToAnsiString( &AnsiString,
|
|||
|
&(DirInfo->Name),
|
|||
|
FALSE );
|
|||
|
|
|||
|
strcpy( ReturnBuffer, AnsiString.Buffer );
|
|||
|
GetSymbolicLink( "\\DosDevices\\", ReturnBuffer, DiskInfo);
|
|||
|
|
|||
|
if ( strncmp( ReturnBuffer, CompareBuffer, strlen(CompareBuffer) ) == 0 &&
|
|||
|
AnsiString.Buffer[strlen(AnsiString.Buffer)-1] == ':' ) {
|
|||
|
|
|||
|
NotFound = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DirInfo++;
|
|||
|
}
|
|||
|
} // for
|
|||
|
|
|||
|
NtClose(DirectoryHandle);
|
|||
|
if ( NotFound ) {
|
|||
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
// We now have the type of the object in ObjectType
|
|||
|
// We still have the full object name in lpstrObject
|
|||
|
// Use the appropriate open routine to get a handle
|
|||
|
|
|||
|
sprintf( Buffer, "\\\\.\\%s", AnsiString.Buffer );
|
|||
|
|
|||
|
ObjectHandle = CreateFile( Buffer,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
OPEN_EXISTING,
|
|||
|
0,
|
|||
|
NULL );
|
|||
|
|
|||
|
return(ObjectHandle);
|
|||
|
|
|||
|
} // OpenObject
|
|||
|
|
|||
|
|