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
|
||
|
||
|