/*++ 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