DECLHIDDEN(int) rtThreadNativeCreate(PRTTHREADINT pThreadInt, PRTNATIVETHREAD pNativeThread) { /* * PsCreateSysemThread create a thread an give us a handle in return. * We requests the object for that handle and then close it, so what * we keep around is the pointer to the thread object and not a handle. * The thread will dereference the object before returning. */ HANDLE hThread = NULL; OBJECT_ATTRIBUTES ObjAttr; InitializeObjectAttributes(&ObjAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); NTSTATUS rc = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &ObjAttr, NULL /* ProcessHandle - kernel */, NULL /* ClientID - kernel */, rtThreadNativeMain, pThreadInt); if (NT_SUCCESS(rc)) { PVOID pvThreadObj; rc = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL /* object type */, KernelMode, &pvThreadObj, NULL /* handle info */); if (NT_SUCCESS(rc)) { ZwClose(hThread); *pNativeThread = (RTNATIVETHREAD)pvThreadObj; } else AssertMsgFailed(("%#x\n", rc)); } return RTErrConvertFromNtStatus(rc); }
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType) { *penmType = RTFSTYPE_UNKNOWN; AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER); AssertReturn(*pszFsPath, VERR_INVALID_PARAMETER); /* * Convert the path and try open it. */ PRTUTF16 pwszFsPath; int rc = RTStrToUtf16(pszFsPath, &pwszFsPath); if (RT_SUCCESS(rc)) { HANDLE hFile = CreateFileW(pwszFsPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile != INVALID_HANDLE_VALUE) { /* * Use the NT api directly to get the file system name. */ char abBuf[8192]; IO_STATUS_BLOCK Ios; NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, abBuf, sizeof(abBuf), FileFsAttributeInformation); if (rcNt >= 0) { PFILE_FS_ATTRIBUTE_INFORMATION pFsAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)abBuf; if (pFsAttrInfo->FIleSystemNameLength) { } #define IS_FS(szName) \ rtFsWinAreEqual(pFsAttrInfo->FileSystemName, pFsAttrInfo->FIleSystemNameLength, szName, sizeof(szName) - 1) if (IS_FS("NTFS")) *penmType = RTFSTYPE_NTFS; else if (IS_FS("FAT")) *penmType = RTFSTYPE_FAT; else if (IS_FS("FAT32")) *penmType = RTFSTYPE_FAT; else if (IS_FS("VBoxSharedFolderFS")) *penmType = RTFSTYPE_VBOXSHF; #undef IS_FS } else rc = RTErrConvertFromNtStatus(rcNt); CloseHandle(hFile); } else rc = RTErrConvertFromWin32(GetLastError()); RTUtf16Free(pwszFsPath); } return rc; }
RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType) { /* * Validate input. */ *penmType = RTFSTYPE_UNKNOWN; AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER); AssertReturn(*pszFsPath, VERR_INVALID_PARAMETER); /* * Open the file/dir/whatever. */ HANDLE hFile; int rc = rtNtPathOpen(pszFsPath, GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE, &hFile, NULL); if (RT_SUCCESS(rc)) { /* * Get the file system name. */ union { FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096]; } u; IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation); if (NT_SUCCESS(rcNt)) { #define IS_FS(a_szName) \ rtNtCompWideStrAndAscii(u.FsAttrInfo.FileSystemName, u.FsAttrInfo.FileSystemNameLength, RT_STR_TUPLE(a_szName)) if (IS_FS("NTFS")) *penmType = RTFSTYPE_NTFS; else if (IS_FS("FAT")) *penmType = RTFSTYPE_FAT; else if (IS_FS("FAT32")) *penmType = RTFSTYPE_FAT; else if (IS_FS("VBoxSharedFolderFS")) *penmType = RTFSTYPE_VBOXSHF; #undef IS_FS } else rc = RTErrConvertFromNtStatus(rcNt); rtNtPathClose(hFile); } return rc; }
int CollectorWin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle) { LogFlowThisFuncEnter(); FILETIME ftIdle, ftKernel, ftUser; if (mpfnGetSystemTimes) { if (!mpfnGetSystemTimes(&ftIdle, &ftKernel, &ftUser)) { DWORD dwError = GetLastError(); Log (("GetSystemTimes() -> 0x%x\n", dwError)); return RTErrConvertFromWin32(dwError); } *user = FILETTIME_TO_100NS(ftUser); *idle = FILETTIME_TO_100NS(ftIdle); *kernel = FILETTIME_TO_100NS(ftKernel) - *idle; } else { /* GetSystemTimes is not available, fall back to NtQuerySystemInformation */ if (!mpfnNtQuerySystemInformation) return VERR_NOT_IMPLEMENTED; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION sppi[MAXIMUM_PROCESSORS]; ULONG ulReturned; NTSTATUS status = mpfnNtQuerySystemInformation( SystemProcessorPerformanceInformation, &sppi, sizeof(sppi), &ulReturned); if (NT_ERROR(status)) { Log(("NtQuerySystemInformation() -> 0x%x\n", status)); return RTErrConvertFromNtStatus(status); } /* Sum up values across all processors */ *user = *kernel = *idle = 0; for (unsigned i = 0; i < ulReturned / sizeof(sppi[0]); ++i) { *idle += sppi[i].IdleTime.QuadPart; *kernel += sppi[i].KernelTime.QuadPart - sppi[i].IdleTime.QuadPart; *user += sppi[i].UserTime.QuadPart; } } LogFlowThisFunc(("user=%lu kernel=%lu idle=%lu\n", *user, *kernel, *idle)); LogFlowThisFuncLeave(); return VINF_SUCCESS; }
static int rtR0ThreadNtSleepCommon(RTMSINTERVAL cMillies) { LARGE_INTEGER Interval; Interval.QuadPart = -(int64_t)cMillies * 10000; NTSTATUS rcNt = KeDelayExecutionThread(KernelMode, TRUE, &Interval); switch (rcNt) { case STATUS_SUCCESS: return VINF_SUCCESS; case STATUS_ALERTED: case STATUS_USER_APC: return VERR_INTERRUPTED; default: return RTErrConvertFromNtStatus(rcNt); } }
/** * Internal I/O Control call worker. * * @returns VBox status code. * @param pDeviceObject The device object to call. * @param pFileObject The file object for the connection. * @param uReq The request. * @param pReq The request packet. */ static int supR0IdcNtCallInternal(PDEVICE_OBJECT pDeviceObject, PFILE_OBJECT pFileObject, uint32_t uReq, PSUPDRVIDCREQHDR pReq) { int rc; IO_STATUS_BLOCK IoStatusBlock; KEVENT Event; PIRP pIrp; NTSTATUS rcNt; /* * Build the request. */ KeInitializeEvent(&Event, NotificationEvent, FALSE); pIrp = IoBuildDeviceIoControlRequest(uReq, /* IoControlCode */ pDeviceObject, pReq, /* InputBuffer */ pReq->cb, /* InputBufferLength */ pReq, /* OutputBuffer */ pReq->cb, /* OutputBufferLength */ TRUE, /* InternalDeviceIoControl (=> IRP_MJ_INTERNAL_DEVICE_CONTROL) */ &Event, /* Event */ &IoStatusBlock); /* IoStatusBlock */ if (pIrp) { IoGetNextIrpStackLocation(pIrp)->FileObject = pFileObject; /* * Call the driver, wait for an async request to complete (should never happen). */ rcNt = IoCallDriver(pDeviceObject, pIrp); if (rcNt == STATUS_PENDING) { rcNt = KeWaitForSingleObject(&Event, /* Object */ Executive, /* WaitReason */ KernelMode, /* WaitMode */ FALSE, /* Alertable */ NULL); /* TimeOut */ rcNt = IoStatusBlock.Status; } if (NT_SUCCESS(rcNt)) rc = pReq->rc; else rc = RTErrConvertFromNtStatus(rcNt); } else rc = VERR_NO_MEMORY; return rc; }
/** * Queries information from a file or directory handle. * * This is shared between the RTPathQueryInfo, RTFileQueryInfo and * RTDirQueryInfo code. * * @returns IPRT status code. * @param hFile The handle to query information from. Must have * the necessary privileges. * @param pvBuf Pointer to a scratch buffer. * @param cbBuf The size of the buffer. This must be large * enough to hold a FILE_ALL_INFORMATION struct. * @param pObjInfo Where to return information about the handle. * @param enmAddAttr What extra info to return. * @param pszPath The path if this is a file (for exe detect). * @param uReparseTag The reparse tag number (0 if not applicable) for * symlink detection/whatnot. */ DECLHIDDEN(int) rtPathNtQueryInfoFromHandle(HANDLE hFile, void *pvBuf, size_t cbBuf, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, const char *pszPath, ULONG uReparseTag) { Assert(cbBuf >= sizeof(FILE_ALL_INFORMATION)); /** @todo Try optimize this for when RTFSOBJATTRADD_UNIX isn't set? */ IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pvBuf, sizeof(FILE_ALL_INFORMATION), FileAllInformation); if ( NT_SUCCESS(rcNt) || rcNt == STATUS_BUFFER_OVERFLOW) { FILE_ALL_INFORMATION *pAllInfo = (FILE_ALL_INFORMATION *)pvBuf; pObjInfo->cbObject = pAllInfo->StandardInformation.EndOfFile.QuadPart; pObjInfo->cbAllocated = pAllInfo->StandardInformation.AllocationSize.QuadPart; RTTimeSpecSetNtTime(&pObjInfo->BirthTime, pAllInfo->BasicInformation.CreationTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, pAllInfo->BasicInformation.LastAccessTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, pAllInfo->BasicInformation.LastWriteTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, pAllInfo->BasicInformation.ChangeTime.QuadPart); pObjInfo->Attr.fMode = rtFsModeFromDos( (pAllInfo->BasicInformation.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszPath, pszPath ? strlen(pszPath) : 0, uReparseTag); pObjInfo->Attr.enmAdditional = enmAddAttr; if (enmAddAttr == RTFSOBJATTRADD_UNIX) { pObjInfo->Attr.u.Unix.uid = ~0U; pObjInfo->Attr.u.Unix.gid = ~0U; pObjInfo->Attr.u.Unix.cHardlinks = RT_MAX(1, pAllInfo->StandardInformation.NumberOfLinks); pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /* below */ pObjInfo->Attr.u.Unix.INodeId = pAllInfo->InternalInformation.IndexNumber.QuadPart; pObjInfo->Attr.u.Unix.fFlags = 0; pObjInfo->Attr.u.Unix.GenerationId = 0; pObjInfo->Attr.u.Unix.Device = 0; /* Get the serial number. */ rcNt = NtQueryVolumeInformationFile(hFile, &Ios, pvBuf, (ULONG)RT_MIN(cbBuf, _2K), FileFsVolumeInformation); if (NT_SUCCESS(rcNt) || rcNt == STATUS_BUFFER_OVERFLOW) { FILE_FS_VOLUME_INFORMATION *pVolInfo = (FILE_FS_VOLUME_INFORMATION *)pvBuf; pObjInfo->Attr.u.Unix.INodeIdDevice = pVolInfo->VolumeSerialNumber; } } return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); } return RTErrConvertFromNtStatus(rcNt); }
/** * Retrieves the installation path of Guest Additions. * * @returns IPRT status value * @param ppszPath Receives pointer of allocated installation path string. * The returned pointer must be freed using * RTStrFree(). */ VBGLR3DECL(int) VbglR3GetAdditionsInstallationPath(char **ppszPath) { int rc; #ifdef RT_OS_WINDOWS HKEY hKey; rc = vbglR3QueryAdditionsWinStoragePath(&hKey); if (RT_SUCCESS(rc)) { /* Installation directory. */ DWORD dwType; DWORD dwSize = _MAX_PATH * sizeof(char); char *pszTmp = (char*)RTMemAlloc(dwSize + 1); if (pszTmp) { LONG l = RegQueryValueEx(hKey, "InstallDir", NULL, &dwType, (BYTE*)(LPCTSTR)pszTmp, &dwSize); if ((l != ERROR_SUCCESS) && (l != ERROR_FILE_NOT_FOUND)) { rc = RTErrConvertFromNtStatus(l); } else { if (dwType == REG_SZ) rc = RTStrDupEx(ppszPath, pszTmp); else rc = VERR_INVALID_PARAMETER; if (RT_SUCCESS(rc)) { /* Flip slashes. */ for (char *pszTmp2 = ppszPath[0]; *pszTmp2; ++pszTmp2) if (*pszTmp2 == '\\') *pszTmp2 = '/'; } } RTMemFree(pszTmp); } else rc = VERR_NO_MEMORY; rc = vbglR3CloseAdditionsWinStoragePath(hKey); } #else /** @todo implement me */ rc = VERR_NOT_IMPLEMENTED; #endif return rc; }
RTR3DECL(int) RTFsQuerySerial(const char *pszFsPath, uint32_t *pu32Serial) { /* * Validate & get valid root path. */ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER); AssertPtrReturn(pu32Serial, VERR_INVALID_POINTER); /* * Open the file/dir/whatever. */ HANDLE hFile; int rc = rtNtPathOpen(pszFsPath, GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE, &hFile, NULL); if (RT_SUCCESS(rc)) { /* * Get the volume information. */ union { FILE_FS_VOLUME_INFORMATION FsVolInfo; uint8_t abBuf[sizeof(FILE_FS_VOLUME_INFORMATION) + 4096]; } u; IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsVolumeInformation); if (NT_SUCCESS(rcNt)) *pu32Serial = u.FsVolInfo.VolumeSerialNumber; else rc = RTErrConvertFromNtStatus(rcNt); rtNtPathClose(hFile); } return rc; }
/** * Reverse of VBoxDrvNtErr2NtStatus * returns VBox status code. * @param rcNt NT status code. */ static int suplibConvertNtStatus(NTSTATUS rcNt) { switch (rcNt) { case STATUS_SUCCESS: return VINF_SUCCESS; case STATUS_NOT_SUPPORTED: return VERR_GENERAL_FAILURE; case STATUS_INVALID_PARAMETER: return VERR_INVALID_PARAMETER; case STATUS_UNKNOWN_REVISION: return VERR_INVALID_MAGIC; case STATUS_INVALID_HANDLE: return VERR_INVALID_HANDLE; case STATUS_INVALID_ADDRESS: return VERR_INVALID_POINTER; case STATUS_NOT_LOCKED: return VERR_LOCK_FAILED; case STATUS_IMAGE_ALREADY_LOADED: return VERR_ALREADY_LOADED; case STATUS_ACCESS_DENIED: return VERR_PERMISSION_DENIED; case STATUS_REVISION_MISMATCH: return VERR_VERSION_MISMATCH; } /* See VBoxDrvNtErr2NtStatus. */ if (SUP_NT_STATUS_IS_VBOX(rcNt)) return SUP_NT_STATUS_TO_VBOX(rcNt); /* Fall back on IPRT for the rest. */ return RTErrConvertFromNtStatus(rcNt); }
DECLHIDDEN(int) rtR0MpNotificationNativeInit(void) { /* * Try resolve the symbols. */ UNICODE_STRING RoutineName; RtlInitUnicodeString(&RoutineName, L"KeRegisterProcessorChangeCallback"); g_pfnKeRegisterProcessorChangeCallback = (PFNMYKEREGISTERPROCESSORCHANGECALLBACK)MmGetSystemRoutineAddress(&RoutineName); if (g_pfnKeRegisterProcessorChangeCallback) { RtlInitUnicodeString(&RoutineName, L"KeDeregisterProcessorChangeCallback"); g_pfnKeDeregisterProcessorChangeCallback = (PFNMYKEDEREGISTERPROCESSORCHANGECALLBACK)MmGetSystemRoutineAddress(&RoutineName); if (g_pfnKeDeregisterProcessorChangeCallback) { /* * Try call it. */ NTSTATUS ntRc = 0; g_hCallback = g_pfnKeRegisterProcessorChangeCallback(rtMpNotificationNtCallback, &ntRc, KE_PROCESSOR_CHANGE_ADD_EXISTING); if (g_hCallback != NULL) return VINF_SUCCESS; /* Genuine failure. */ int rc = RTErrConvertFromNtStatus(ntRc); AssertMsgFailed(("ntRc=%#x rc=%d\n", ntRc, rc)); return rc; } /* this shouldn't happen. */ AssertFailed(); } /* Not supported - success. */ g_pfnKeRegisterProcessorChangeCallback = NULL; g_pfnKeDeregisterProcessorChangeCallback = NULL; return VINF_SUCCESS; }
int VBOXCALL supR0IdcNativeOpen(PSUPDRVIDCHANDLE pHandle, PSUPDRVIDCREQCONNECT pReq) { PDEVICE_OBJECT pDeviceObject = NULL; PFILE_OBJECT pFileObject = NULL; UNICODE_STRING wszDeviceName; NTSTATUS rcNt; int rc; /* * Get the device object pointer. */ RtlInitUnicodeString(&wszDeviceName, DEVICE_NAME_NT); rcNt = IoGetDeviceObjectPointer(&wszDeviceName, FILE_ALL_ACCESS, &pFileObject, &pDeviceObject); if (NT_SUCCESS(rcNt)) { /* * Make the connection call. */ rc = supR0IdcNtCallInternal(pDeviceObject, pFileObject, SUPDRV_IDC_REQ_CONNECT, &pReq->Hdr); if (RT_SUCCESS(rc)) { pHandle->s.pDeviceObject = pDeviceObject; pHandle->s.pFileObject = pFileObject; return rc; } /* only the file object. */ ObDereferenceObject(pFileObject); } else rc = RTErrConvertFromNtStatus(rcNt); pHandle->s.pDeviceObject = NULL; pHandle->s.pFileObject = NULL; return rc; }
/** * Fetches more data from the file system. * * @returns IPRT status code * @param pThis The directory instance data. */ static int rtDirNtFetchMore(PRTDIR pThis) { Assert(!pThis->fDataUnread); /* * Allocate the buffer the first time around. * We do this in lazy fashion as some users of RTDirOpen will not actually * list any files, just open it for various reasons. */ bool fFirst = false; if (!pThis->pabBuffer) { fFirst = false; pThis->cbBufferAlloc = _256K; pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc); if (!pThis->pabBuffer) { do { pThis->cbBufferAlloc /= 4; pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc); } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K); if (!pThis->pabBuffer) return VERR_NO_MEMORY; } } /* * Read more. */ NTSTATUS rcNt; IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0) { #ifdef IPRT_WITH_NT_PATH_PASSTHRU if (pThis->enmInfoClass == FileMaximumInformation) { Ios.Information = 0; Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir, pThis->pabBuffer, pThis->cbBufferAlloc, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, FALSE /*RestartScan*/, &pThis->uObjDirCtx, (PULONG)&Ios.Information); } else #endif rcNt = NtQueryDirectoryFile(pThis->hDir, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, pThis->pabBuffer, pThis->cbBufferAlloc, pThis->enmInfoClass, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->pNtFilterStr, FALSE /*RestartScan */); } else { /* * The first time around we have figure which info class we can use. * We prefer one which gives us file IDs, but we'll settle for less. */ pThis->enmInfoClass = FileIdBothDirectoryInformation; rcNt = NtQueryDirectoryFile(pThis->hDir, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, pThis->pabBuffer, pThis->cbBufferAlloc, pThis->enmInfoClass, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->pNtFilterStr, FALSE /*RestartScan */); if (!NT_SUCCESS(rcNt)) { pThis->enmInfoClass = FileBothDirectoryInformation; rcNt = NtQueryDirectoryFile(pThis->hDir, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, pThis->pabBuffer, pThis->cbBufferAlloc, pThis->enmInfoClass, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->pNtFilterStr, FALSE /*RestartScan */); } } if (!NT_SUCCESS(rcNt)) { if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES) return VERR_NO_MORE_FILES; return RTErrConvertFromNtStatus(rcNt); } Assert(Ios.Information > sizeof(*pThis->uCurData.pBoth)); /* * Set up the data members. */ pThis->uCurData.u = (uintptr_t)pThis->pabBuffer; pThis->cbBuffer = Ios.Information; int rc = rtDirNtCheckRecord(pThis); pThis->fDataUnread = RT_SUCCESS(rc); return rc; }
RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties) { /* * Validate & get valid root path. */ AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER); AssertPtrReturn(pProperties, VERR_INVALID_POINTER); /* * Open the file/dir/whatever. */ HANDLE hFile; int rc = rtNtPathOpen(pszFsPath, GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE, &hFile, NULL); if (RT_SUCCESS(rc)) { /* * Get the volume information. */ union { FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; uint8_t abBuf[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 4096]; } u; IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &u, sizeof(u), FileFsAttributeInformation); if (NT_SUCCESS(rcNt)) { FILE_FS_DEVICE_INFORMATION FsDevInfo; rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsDevInfo, sizeof(FsDevInfo), FileFsDeviceInformation); if (NT_SUCCESS(rcNt)) { /* * Fill in the return structure. */ memset(pProperties, 0, sizeof(*pProperties)); pProperties->cbMaxComponent = u.FsAttrInfo.MaximumComponentNameLength; pProperties->fFileCompression = !!(u.FsAttrInfo.FileSystemAttributes & FILE_FILE_COMPRESSION); pProperties->fCompressed = !!(u.FsAttrInfo.FileSystemAttributes & FILE_VOLUME_IS_COMPRESSED); pProperties->fReadOnly = !!(u.FsAttrInfo.FileSystemAttributes & FILE_READ_ONLY_VOLUME); pProperties->fSupportsUnicode = !!(u.FsAttrInfo.FileSystemAttributes & FILE_UNICODE_ON_DISK); pProperties->fCaseSensitive = false; /* win32 is case preserving only */ /** @todo r=bird: What about FILE_CASE_SENSITIVE_SEARCH ? Is this set for NTFS * as well perchance? If so, better mention it instead of just setting * fCaseSensitive to false. */ /* figure the remote stuff */ pProperties->fRemote = RT_BOOL(FsDevInfo.Characteristics & FILE_REMOTE_DEVICE); } else rc = RTErrConvertFromNtStatus(rcNt); } else rc = RTErrConvertFromNtStatus(rcNt); rtNtPathClose(hFile); } return rc; }
RTR3DECL(int) RTFsQuerySizes(const char *pszFsPath, RTFOFF *pcbTotal, RTFOFF *pcbFree, uint32_t *pcbBlock, uint32_t *pcbSector) { AssertPtrReturn(pszFsPath, VERR_INVALID_POINTER); /* * Open the file/dir/whatever. */ HANDLE hFile; int rc = rtNtPathOpen(pszFsPath, GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT, OBJ_CASE_INSENSITIVE, &hFile, NULL); if (RT_SUCCESS(rc)) { /* * Get the volume information. */ FILE_FS_SIZE_INFORMATION FsSizeInfo; IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &FsSizeInfo, sizeof(FsSizeInfo), FileFsSizeInformation); if (NT_SUCCESS(rcNt)) { /* * Calculate the return values. */ if (pcbTotal) { *pcbTotal = FsSizeInfo.TotalAllocationUnits.QuadPart * FsSizeInfo.SectorsPerAllocationUnit * FsSizeInfo.BytesPerSector; if ( *pcbTotal / FsSizeInfo.SectorsPerAllocationUnit / FsSizeInfo.BytesPerSector != FsSizeInfo.TotalAllocationUnits.QuadPart) *pcbTotal = UINT64_MAX; } if (pcbFree) { *pcbFree = FsSizeInfo.AvailableAllocationUnits.QuadPart * FsSizeInfo.SectorsPerAllocationUnit * FsSizeInfo.BytesPerSector; if ( *pcbFree / FsSizeInfo.SectorsPerAllocationUnit / FsSizeInfo.BytesPerSector != FsSizeInfo.AvailableAllocationUnits.QuadPart) *pcbFree = UINT64_MAX; } if (pcbBlock) { *pcbBlock = FsSizeInfo.SectorsPerAllocationUnit * FsSizeInfo.BytesPerSector; if (*pcbBlock / FsSizeInfo.BytesPerSector != FsSizeInfo.SectorsPerAllocationUnit) rc = VERR_OUT_OF_RANGE; } if (pcbSector) *pcbSector = FsSizeInfo.BytesPerSector; } else rc = RTErrConvertFromNtStatus(rcNt); rtNtPathClose(hFile); } return rc; }
/** * Fetches more data from the file system. * * @returns IPRT status code * @param pThis The directory instance data. */ static int rtDirNtFetchMore(PRTDIRINTERNAL pThis) { Assert(!pThis->fDataUnread); /* * Allocate the buffer the first time around. * We do this in lazy fashion as some users of RTDirOpen will not actually * list any files, just open it for various reasons. * * We also reduce the buffer size for networked devices as the windows 7-8.1, * server 2012, ++ CIFS servers or/and IFSes screws up buffers larger than 64KB. * There is an alternative hack below, btw. We'll leave both in for now. */ bool fFirst = false; if (!pThis->pabBuffer) { pThis->cbBufferAlloc = _256K; if (true) /** @todo skip for known local devices, like the boot device? */ { IO_STATUS_BLOCK Ios2 = RTNT_IO_STATUS_BLOCK_INITIALIZER; FILE_FS_DEVICE_INFORMATION Info = { 0, 0 }; NTSTATUS rcNt2 = NtQueryVolumeInformationFile(pThis->hDir, &Ios2, &Info, sizeof(Info), FileFsDeviceInformation); if ( !NT_SUCCESS(rcNt2) || (Info.Characteristics & FILE_REMOTE_DEVICE) || Info.DeviceType == FILE_DEVICE_NETWORK || Info.DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM || Info.DeviceType == FILE_DEVICE_NETWORK_REDIRECTOR || Info.DeviceType == FILE_DEVICE_SMB) pThis->cbBufferAlloc = _64K; } fFirst = false; pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc); if (!pThis->pabBuffer) { do { pThis->cbBufferAlloc /= 4; pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc); } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K); if (!pThis->pabBuffer) return VERR_NO_MEMORY; } /* * Also try determining the device number. */ PFILE_FS_VOLUME_INFORMATION pVolInfo = (PFILE_FS_VOLUME_INFORMATION)pThis->pabBuffer; pVolInfo->VolumeSerialNumber = 0; IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt = NtQueryVolumeInformationFile(pThis->hDir, &Ios, pVolInfo, RT_MIN(_2K, pThis->cbBufferAlloc), FileFsVolumeInformation); if (NT_SUCCESS(rcNt) && NT_SUCCESS(Ios.Status)) pThis->uDirDev = pVolInfo->VolumeSerialNumber; else pThis->uDirDev = 0; AssertCompile(sizeof(pThis->uDirDev) == sizeof(pVolInfo->VolumeSerialNumber)); /** @todo Grow RTDEV to 64-bit and add low dword of VolumeCreationTime to the top of uDirDev. */ } /* * Read more. */ NTSTATUS rcNt; IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0) { #ifdef IPRT_WITH_NT_PATH_PASSTHRU if (pThis->enmInfoClass == FileMaximumInformation) { Ios.Information = 0; Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir, pThis->pabBuffer, pThis->cbBufferAlloc, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->fRestartScan, &pThis->uObjDirCtx, (PULONG)&Ios.Information); } else #endif rcNt = NtQueryDirectoryFile(pThis->hDir, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, pThis->pabBuffer, pThis->cbBufferAlloc, pThis->enmInfoClass, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->pNtFilterStr, pThis->fRestartScan); } else { /* * The first time around we have to figure which info class we can use * as well as the right buffer size. We prefer an info class which * gives us file IDs (Vista+ IIRC) and we prefer large buffers (for long * ReFS file names and such), but we'll settle for whatever works... * * The windows 7 thru 8.1 CIFS servers have been observed to have * trouble with large buffers, but weirdly only when listing large * directories. Seems 0x10000 is the max. (Samba does not exhibit * these problems, of course.) * * This complicates things. The buffer size issues causes an * STATUS_INVALID_PARAMETER error. Now, you would expect the lack of * FileIdBothDirectoryInformation support to return * STATUS_INVALID_INFO_CLASS, but I'm not entirely sure if we can 100% * depend on third IFSs to get that right. Nor, am I entirely confident * that we can depend on them to check the class before the buffer size. * * Thus the mess. */ if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */) pThis->enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */ else pThis->enmInfoClass = FileBothDirectoryInformation; rcNt = NtQueryDirectoryFile(pThis->hDir, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, pThis->pabBuffer, pThis->cbBufferAlloc, pThis->enmInfoClass, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->pNtFilterStr, pThis->fRestartScan); if (NT_SUCCESS(rcNt)) { /* likely */ } else { bool fRestartScan = pThis->fRestartScan; for (unsigned iRetry = 0; iRetry < 2; iRetry++) { if ( rcNt == STATUS_INVALID_INFO_CLASS || rcNt == STATUS_INVALID_PARAMETER_8 || iRetry != 0) pThis->enmInfoClass = FileBothDirectoryInformation; uint32_t cbBuffer = pThis->cbBufferAlloc; if ( rcNt == STATUS_INVALID_PARAMETER || rcNt == STATUS_INVALID_PARAMETER_7 || rcNt == STATUS_INVALID_NETWORK_RESPONSE || iRetry != 0) { cbBuffer = RT_MIN(cbBuffer / 2, _64K); fRestartScan = true; } for (;;) { rcNt = NtQueryDirectoryFile(pThis->hDir, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, pThis->pabBuffer, cbBuffer, pThis->enmInfoClass, RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */, pThis->pNtFilterStr, fRestartScan); if ( NT_SUCCESS(rcNt) || cbBuffer == pThis->cbBufferAlloc || cbBuffer <= sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260) break; /* Reduce the buffer size agressivly and try again. We fall back to FindFirstFile values for the final lap. This means we'll do 4 rounds with the current initial buffer size (64KB, 8KB, 1KB, 0x278/0x268). */ cbBuffer /= 8; if (cbBuffer < 1024) cbBuffer = pThis->enmInfoClass == FileIdBothDirectoryInformation ? sizeof(*pThis->uCurData.pBothId) + sizeof(WCHAR) * 260 : sizeof(*pThis->uCurData.pBoth) + sizeof(WCHAR) * 260; } if (NT_SUCCESS(rcNt)) { pThis->cbBufferAlloc = cbBuffer; break; } } } } if (!NT_SUCCESS(rcNt)) { /* Note! VBoxSVR and CIFS file systems both ends up with STATUS_NO_SUCH_FILE here instead of STATUS_NO_MORE_FILES. */ if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES || rcNt == STATUS_NO_SUCH_FILE) return VERR_NO_MORE_FILES; return RTErrConvertFromNtStatus(rcNt); } pThis->fRestartScan = false; AssertMsg( Ios.Information > (pThis->enmInfoClass == FileMaximumInformation ? sizeof(*pThis->uCurData.pObjDir) : sizeof(*pThis->uCurData.pBoth)), ("Ios.Information=%#x\n", Ios.Information)); /* * Set up the data members. */ pThis->uCurData.u = (uintptr_t)pThis->pabBuffer; pThis->cbBuffer = Ios.Information; int rc = rtDirNtCheckRecord(pThis); pThis->fDataUnread = RT_SUCCESS(rc); return rc; }
/** * Deal with getting info about something that could be in a directory object. * * @returns IPRT status code * @param pObjAttr The NT object attribute. * @param pObjInfo Where to return the info. * @param enmAddAttr Which extra attributes to get (/fake). * @param fFlags The flags. * @param pvBuf Query buffer space. * @param cbBuf Size of the buffer. ASSUMES lots of space. * @param rcNtCaller The status code that got us here. */ static int rtPathNtQueryInfoInDirectoryObject(OBJECT_ATTRIBUTES *pObjAttr, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags, void *pvBuf, size_t cbBuf, NTSTATUS rcNtCaller) { RT_NOREF(fFlags); /* * Special case: Root dir. */ if ( pObjAttr->RootDirectory == NULL && pObjAttr->ObjectName->Length == sizeof(RTUTF16) && pObjAttr->ObjectName->Buffer[0] == '\\') { pObjInfo->cbObject = 0; pObjInfo->cbAllocated = 0; RTTimeSpecSetNtTime(&pObjInfo->BirthTime, 0); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, 0); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, 0); RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, 0); pObjInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); } /* * We must open and scan the parent directory object. */ UNICODE_STRING NtDirName; UNICODE_STRING NtDirEntry; ntPathNtSplitName(pObjAttr->ObjectName, &NtDirName, &NtDirEntry, true /*fNoParentDirSlash*/); while ( NtDirEntry.Length > sizeof(RTUTF16) && NtDirEntry.Buffer[NtDirEntry.Length / sizeof(RTUTF16) - 1] == '\\') NtDirEntry.Length -= sizeof(RTUTF16); pObjAttr->ObjectName = &NtDirName; HANDLE hDir = RTNT_INVALID_HANDLE_VALUE; NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, pObjAttr); if (NT_SUCCESS(rcNt)) { ULONG uObjDirCtx = 0; for (;;) { ULONG cbReturned = 0; rcNt = NtQueryDirectoryObject(hDir, pvBuf, (ULONG)cbBuf, FALSE /*ReturnSingleEntry */, FALSE /*RestartScan*/, &uObjDirCtx, &cbReturned); if (!NT_SUCCESS(rcNt)) break; for (POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)pvBuf; pObjDir->Name.Length != 0; pObjDir++) { if ( pObjDir->Name.Length == NtDirEntry.Length && memcmp(pObjDir->Name.Buffer, NtDirEntry.Buffer, NtDirEntry.Length) == 0) { /* * Find it. Fill in the info we've got and return (see similar code in direnum-r3-nt.cpp). */ NtClose(hDir); pObjInfo->cbObject = 0; pObjInfo->cbAllocated = 0; RTTimeSpecSetNtTime(&pObjInfo->BirthTime, 0); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, 0); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, 0); RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, 0); if (ARE_UNICODE_STRINGS_EQUAL(&pObjDir->TypeName, L"Directory")) pObjInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; else if (ARE_UNICODE_STRINGS_EQUAL(&pObjDir->TypeName, L"SymbolicLink")) pObjInfo->Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777; else if (ARE_UNICODE_STRINGS_EQUAL(&pObjDir->TypeName, L"Device")) pObjInfo->Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666; else pObjInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666; pObjInfo->Attr.enmAdditional = enmAddAttr; return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); } } } NtClose(hDir); if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES || rcNt == STATUS_NO_SUCH_FILE) return VERR_FILE_NOT_FOUND; } else return RTErrConvertFromNtStatus(rcNtCaller); return RTErrConvertFromNtStatus(rcNt); }
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { /* * Don't try mess with an offline CPU. */ if (!RTMpIsCpuOnline(idCpu)) return !RTMpIsCpuPossible(idCpu) ? VERR_CPU_NOT_FOUND : VERR_CPU_OFFLINE; /* * Use the broadcast IPI routine if there are no more than two CPUs online, * or if the current IRQL is unsuitable for KeWaitForSingleObject. */ int rc; uint32_t cHits = 0; if ( g_pfnrtKeIpiGenericCall && ( RTMpGetOnlineCount() <= 2 || KeGetCurrentIrql() > APC_LEVEL) ) { rc = rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper, idCpu, NIL_RTCPUID, &cHits); if (RT_SUCCESS(rc)) { if (cHits == 1) return VINF_SUCCESS; rc = cHits == 0 ? VERR_CPU_OFFLINE : VERR_CPU_IPE_1; } return rc; } #if 0 rc = rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu, NIL_RTCPUID, &cHits); if (RT_SUCCESS(rc)) { if (cHits == 1) return VINF_SUCCESS; rc = cHits == 0 ? VERR_CPU_OFFLINE : VERR_CPU_IPE_1; } return rc; #else /* * Initialize the argument package and the objects within it. * The package is referenced counted to avoid unnecessary spinning to * synchronize cleanup and prevent stack corruption. */ PRTMPNTONSPECIFICARGS pArgs = (PRTMPNTONSPECIFICARGS)ExAllocatePoolWithTag(NonPagedPool, sizeof(*pArgs), (ULONG)'RTMp'); if (!pArgs) return VERR_NO_MEMORY; pArgs->cRefs = 2; pArgs->fExecuting = false; pArgs->fDone = false; pArgs->CallbackArgs.pfnWorker = pfnWorker; pArgs->CallbackArgs.pvUser1 = pvUser1; pArgs->CallbackArgs.pvUser2 = pvUser2; pArgs->CallbackArgs.idCpu = idCpu; pArgs->CallbackArgs.cHits = 0; pArgs->CallbackArgs.cRefs = 2; KeInitializeEvent(&pArgs->DoneEvt, SynchronizationEvent, FALSE /* not signalled */); KeInitializeDpc(&pArgs->Dpc, rtMpNtOnSpecificDpcWrapper, pArgs); KeSetImportanceDpc(&pArgs->Dpc, HighImportance); KeSetTargetProcessorDpc(&pArgs->Dpc, (int)idCpu); /* * Disable preemption while we check the current processor and inserts the DPC. */ KIRQL bOldIrql; KeRaiseIrql(DISPATCH_LEVEL, &bOldIrql); ASMCompilerBarrier(); /* paranoia */ if (RTMpCpuId() == idCpu) { /* Just execute the callback on the current CPU. */ pfnWorker(idCpu, pvUser1, pvUser2); KeLowerIrql(bOldIrql); ExFreePool(pArgs); return VINF_SUCCESS; } /* Different CPU, so queue it if the CPU is still online. */ if (RTMpIsCpuOnline(idCpu)) { BOOLEAN fRc = KeInsertQueueDpc(&pArgs->Dpc, 0, 0); Assert(fRc); KeLowerIrql(bOldIrql); uint64_t const nsRealWaitTS = RTTimeNanoTS(); /* * Wait actively for a while in case the CPU/thread responds quickly. */ uint32_t cLoopsLeft = 0x20000; while (cLoopsLeft-- > 0) { if (pArgs->fDone) { rtMpNtOnSpecificRelease(pArgs); return VINF_SUCCESS; } ASMNopPause(); } /* * It didn't respond, so wait on the event object, poking the CPU if it's slow. */ LARGE_INTEGER Timeout; Timeout.QuadPart = -10000; /* 1ms */ NTSTATUS rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout); if (rcNt == STATUS_SUCCESS) { rtMpNtOnSpecificRelease(pArgs); return VINF_SUCCESS; } /* If it hasn't respondend yet, maybe poke it and wait some more. */ if (rcNt == STATUS_TIMEOUT) { #ifndef IPRT_TARGET_NT4 if ( !pArgs->fExecuting && ( g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalSendSoftwareInterrupt || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiW7Plus || g_pfnrtMpPokeCpuWorker == rtMpPokeCpuUsingHalReqestIpiPreW7)) RTMpPokeCpu(idCpu); #endif Timeout.QuadPart = -1280000; /* 128ms */ rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout); if (rcNt == STATUS_SUCCESS) { rtMpNtOnSpecificRelease(pArgs); return VINF_SUCCESS; } } /* * Something weird is happening, try bail out. */ if (KeRemoveQueueDpc(&pArgs->Dpc)) { ExFreePool(pArgs); /* DPC was still queued, so we can return without further ado. */ LogRel(("RTMpOnSpecific(%#x): Not processed after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt)); } else { /* DPC is running, wait a good while for it to complete. */ LogRel(("RTMpOnSpecific(%#x): Still running after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt)); Timeout.QuadPart = -30*1000*1000*10; /* 30 seconds */ rcNt = KeWaitForSingleObject(&pArgs->DoneEvt, Executive, KernelMode, FALSE /* Alertable */, &Timeout); if (rcNt != STATUS_SUCCESS) LogRel(("RTMpOnSpecific(%#x): Giving up on running worker after %llu ns: rcNt=%#x\n", idCpu, RTTimeNanoTS() - nsRealWaitTS, rcNt)); } rc = RTErrConvertFromNtStatus(rcNt); } else { /* CPU is offline.*/ KeLowerIrql(bOldIrql); rc = !RTMpIsCpuPossible(idCpu) ? VERR_CPU_NOT_FOUND : VERR_CPU_OFFLINE; } rtMpNtOnSpecificRelease(pArgs); return rc; #endif }
/** * Worker for RTPathQueryInfoEx and RTDirRelPathQueryInfo. * * @returns IPRT status code. * @param hRootDir The root directory that pNtName is relative to. * @param pNtName The NT path which we want to query info for. * @param pObjInfo Where to return the info. * @param enmAddAttr What additional info to get/fake. * @param fFlags Query flags (RTPATH_F_XXX). * @param pszPath The path for detecting executables and such. * Pass empty string if not applicable/available. */ DECLHIDDEN(int) rtPathNtQueryInfoWorker(HANDLE hRootDir, UNICODE_STRING *pNtName, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags, const char *pszPath) { /* * There are a three different ways of doing this: * 1. Use NtQueryFullAttributesFile to the get basic file info. * 2. Open whatever the path points to and use NtQueryInformationFile. * 3. Open the parent directory and use NtQueryDirectoryFile like RTDirReadEx. * * The first two options may fail with sharing violations or access denied, * in which case we must use the last one as fallback. */ HANDLE hFile = RTNT_INVALID_HANDLE_VALUE; IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; NTSTATUS rcNt; OBJECT_ATTRIBUTES ObjAttr; union { FILE_NETWORK_OPEN_INFORMATION NetOpenInfo; FILE_ALL_INFORMATION AllInfo; FILE_FS_VOLUME_INFORMATION VolInfo; FILE_BOTH_DIR_INFORMATION Both; FILE_ID_BOTH_DIR_INFORMATION BothId; uint8_t abPadding[sizeof(FILE_ID_BOTH_DIR_INFORMATION) + RTPATH_MAX * sizeof(wchar_t)]; } uBuf; /* * We can only use the first option if no additional UNIX attribs are * requested and it isn't a symbolic link. NT directory object */ int rc = VINF_TRY_AGAIN; if ( enmAddAttr != RTFSOBJATTRADD_UNIX && g_pfnNtQueryFullAttributesFile) { InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &uBuf.NetOpenInfo); if (NT_SUCCESS(rcNt)) { if (!(uBuf.NetOpenInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { pObjInfo->cbObject = uBuf.NetOpenInfo.EndOfFile.QuadPart; pObjInfo->cbAllocated = uBuf.NetOpenInfo.AllocationSize.QuadPart; RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.NetOpenInfo.CreationTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.NetOpenInfo.LastAccessTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.NetOpenInfo.LastWriteTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.NetOpenInfo.ChangeTime.QuadPart); pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.NetOpenInfo.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszPath, strlen(pszPath), 0 /*uReparseTag*/); pObjInfo->Attr.enmAdditional = enmAddAttr; return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); } } else if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH || rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_INVALID_PARAMETER) { rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt); if (RT_SUCCESS(rc)) return rc; } else if ( rcNt != STATUS_ACCESS_DENIED && rcNt != STATUS_SHARING_VIOLATION) rc = RTErrConvertFromNtStatus(rcNt); else RTNT_IO_STATUS_BLOCK_REINIT(&Ios); } /* * Try the 2nd option. We might have to redo this if not following symbolic * links and the reparse point isn't a symbolic link but a mount point or similar. * We want to return information about the mounted root directory if we can, not * the directory in which it was mounted. */ if (rc == VINF_TRY_AGAIN) { static int volatile g_fReparsePoints = -1; uint32_t fOptions = FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT; int fReparsePoints = g_fReparsePoints; if (fReparsePoints != 0 && !(fFlags & RTPATH_F_FOLLOW_LINK)) fOptions |= FILE_OPEN_REPARSE_POINT; InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); rcNt = NtCreateFile(&hFile, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjAttr, &Ios, NULL /*pcbFile*/, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, fOptions, NULL /*pvEaBuffer*/, 0 /*cbEa*/); if ( ( rcNt == STATUS_INVALID_PARAMETER || rcNt == STATUS_INVALID_PARAMETER_9) && fReparsePoints == -1 && (fOptions & FILE_OPEN_REPARSE_POINT)) { fOptions &= ~FILE_OPEN_REPARSE_POINT; rcNt = NtCreateFile(&hFile, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjAttr, &Ios, NULL /*pcbFile*/, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, fOptions, NULL /*pvEaBuffer*/, 0 /*cbEa*/); if (rcNt != STATUS_INVALID_PARAMETER) g_fReparsePoints = fReparsePoints = 0; } if (NT_SUCCESS(rcNt)) { /* Query tag information first in order to try re-open non-symlink reparse points. */ FILE_ATTRIBUTE_TAG_INFORMATION TagInfo; rcNt = NtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), FileAttributeTagInformation); if (!NT_SUCCESS(rcNt)) TagInfo.FileAttributes = TagInfo.ReparseTag = 0; if ( !(TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || TagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK || (fFlags & RTPATH_F_FOLLOW_LINK)) { /* likely */ } else { /* Reparse point that isn't a symbolic link, try follow the reparsing. */ HANDLE hFile2; RTNT_IO_STATUS_BLOCK_REINIT(&Ios); rcNt = NtCreateFile(&hFile2, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjAttr, &Ios, NULL /*pcbFile*/, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, NULL /*pvEaBuffer*/, 0 /*cbEa*/); if (NT_SUCCESS(rcNt)) { NtClose(hFile); hFile = hFile2; TagInfo.FileAttributes = TagInfo.ReparseTag = 0; } } /* * Get the information we need and convert it. */ rc = rtPathNtQueryInfoFromHandle(hFile, &uBuf, sizeof(uBuf), pObjInfo, enmAddAttr, pszPath, TagInfo.ReparseTag); NtClose(hFile); if (RT_SUCCESS(rc)) return rc; if (RT_FAILURE(rc)) rc = VINF_TRY_AGAIN; } else if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH || rcNt == STATUS_OBJECT_NAME_INVALID /*|| rcNt == STATUS_INVALID_PARAMETER*/) { rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt); if (RT_SUCCESS(rc)) return rc; } else if ( rcNt != STATUS_ACCESS_DENIED && rcNt != STATUS_SHARING_VIOLATION) rc = RTErrConvertFromNtStatus(rcNt); else RTNT_IO_STATUS_BLOCK_REINIT(&Ios); } /* * Try the 3rd option if none of the other worked. * If none of the above worked, try open the directory and enumerate * the file we're after. This */ if (rc == VINF_TRY_AGAIN) { /* Split up the name into parent directory path and filename. */ UNICODE_STRING NtDirName; UNICODE_STRING NtFilter; ntPathNtSplitName(pNtName, &NtDirName, &NtFilter, false /*fNoParentDirSlash*/); /* Try open the directory. */ InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); rcNt = NtCreateFile(&hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE, &ObjAttr, &Ios, NULL /*pcbFile*/, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, NULL /*pvEaBuffer*/, 0 /*cbEa*/); if (NT_SUCCESS(rcNt)) { FILE_INFORMATION_CLASS enmInfoClass; if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */) enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */ else enmInfoClass = FileBothDirectoryInformation; rcNt = NtQueryDirectoryFile(hFile, NULL /* Event */, NULL /* ApcRoutine */, NULL /* ApcContext */, &Ios, &uBuf, RT_MIN(sizeof(uBuf), 0xfff0), enmInfoClass, TRUE /*ReturnSingleEntry */, &NtFilter, FALSE /*RestartScan */); if (NT_SUCCESS(rcNt)) { pObjInfo->cbObject = uBuf.Both.EndOfFile.QuadPart; pObjInfo->cbAllocated = uBuf.Both.AllocationSize.QuadPart; RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.Both.CreationTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.Both.LastAccessTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.Both.LastWriteTime.QuadPart); RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.Both.ChangeTime.QuadPart); pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.Both.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, pszPath, strlen(pszPath), uBuf.Both.EaSize); pObjInfo->Attr.enmAdditional = enmAddAttr; if (enmAddAttr == RTFSOBJATTRADD_UNIX) { pObjInfo->Attr.u.Unix.uid = ~0U; pObjInfo->Attr.u.Unix.gid = ~0U; pObjInfo->Attr.u.Unix.cHardlinks = 1; pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /* below */ pObjInfo->Attr.u.Unix.INodeId = enmInfoClass == FileIdBothDirectoryInformation ? uBuf.BothId.FileId.QuadPart : 0; pObjInfo->Attr.u.Unix.fFlags = 0; pObjInfo->Attr.u.Unix.GenerationId = 0; pObjInfo->Attr.u.Unix.Device = 0; /* Get the serial number. */ rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &uBuf, RT_MIN(sizeof(uBuf), _2K), FileFsVolumeInformation); if (NT_SUCCESS(rcNt)) pObjInfo->Attr.u.Unix.INodeIdDevice = uBuf.VolInfo.VolumeSerialNumber; } rc = rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); } else rc = RTErrConvertFromNtStatus(rcNt); NtClose(hFile); } /* * Quite possibly a object directory. */ else if ( rcNt == STATUS_OBJECT_NAME_INVALID /* with trailing slash */ || rcNt == STATUS_OBJECT_TYPE_MISMATCH /* without trailing slash */ ) { InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf), rcNt); if (RT_FAILURE(rc)) rc = RTErrConvertFromNtStatus(rcNt); } else rc = RTErrConvertFromNtStatus(rcNt); } return rc; }